Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From trunk To js-hamburger-menu
2024-05-15
| ||
21:11 | In /chat, add a config option to audibly notify only for the first message received when the tab is not visible, and then remain silent until chat is visited again. (Leaf check-in: df86fa33 user: stephan tags: trunk) | |
14:54 | Add options to the 'tag' command to list tag values, as suggested by forum post d4fb9400f9. (check-in: ea1b76bc user: danield tags: trunk) | |
2019-01-02
| ||
15:31 | Enhancements to the hamburger menu mechanism. (check-in: 724a9b8f user: drh tags: trunk) | |
07:24 | Oops, fallen for testing built-in versus customized skin, fix the previous check-in. (Closed-Leaf check-in: dac9293b user: florian tags: js-hamburger-menu) | |
07:03 | Less rigid string-to-number conversion for the custom "data-anim-ms" attribute. (check-in: e4a18b67 user: florian tags: js-hamburger-menu) | |
Added .dockerignore.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | _FOSSIL_ .fslckout ajax art autosetup bld compat debian fossil fossil.exe setup src test tools win wbld win www *.a *.lib *.log *.manifest *.o *.obj *.pdb *.res |
Deleted .editorconfig.
|
| < < < < < < < < < < < < < < |
Changes to .fossil-settings/binary-glob.
1 2 3 4 5 6 7 | *.gif *.ico *.jpg *.odp *.dia *.pdf *.png | < < | 1 2 3 4 5 6 7 8 9 10 11 | *.gif *.ico *.jpg *.odp *.dia *.pdf *.png compat/zlib/contrib/blast/test.pk compat/zlib/contrib/dotzlib/DotZLib.chm compat/zlib/contrib/puff/zeros.raw compat/zlib/zlib.3.pdf |
Changes to .fossil-settings/clean-glob.
1 2 3 4 5 6 7 8 9 10 11 | *.a *.lib *.manifest *.o *.obj *.pdb *.res Makefile autosetup/jimsh0 autosetup/jimsh0.exe bld/* | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | *.a *.lib *.manifest *.o *.obj *.pdb *.res Makefile autosetup/jimsh0 autosetup/jimsh0.exe bld/* wbld/* win/*.c win/*.h win/*.exe win/headers win/linkopts autoconfig.h |
︙ | ︙ |
Changes to .fossil-settings/ignore-glob.
1 2 | compat/openssl* compat/tcl* | < < | 1 2 3 4 5 6 7 | compat/openssl* compat/tcl* fossil fossil.exe win/fossil.exe *shell-see.* *sqlite3-see.* |
Changes to BUILD.txt.
︙ | ︙ | |||
53 54 55 56 57 58 59 | * The configure script (if used) examines the options given and runs various tests with the C compiler to create Makefile from the Makefile.in template as well as autoconfig.h * The Makefile just sets up a few macros and then invokes the real makefile in src/main.mk. The src/main.mk makefile is | | | | | | | | | | 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 | * The configure script (if used) examines the options given and runs various tests with the C compiler to create Makefile from the Makefile.in template as well as autoconfig.h * The Makefile just sets up a few macros and then invokes the real makefile in src/main.mk. The src/main.mk makefile is automatically generated by a TCL script found at src/makemake.tcl. Do not edit src/main.mk directly. Update src/makemake.tcl and then rerun it. * The *.h header files are automatically generated using a program called "makeheaders". Source code to the makeheaders program is found in src/makeheaders.c. Documentation is found in src/makeheaders.html. * Most *.c source files are preprocessed using a program called "translate". The sources to translate are found in src/translate.c. A header comment in src/translate.c explains in detail what it does. * The src/mkindex.c program generates some C code that implements static lookup tables. See the header comment in the source code for details on what it does. Additional information on the build process is available from http://www.fossil-scm.org/fossil/doc/trunk/www/makefile.wiki |
Changes to Dockerfile.
|
| > | < > > < < | | < < < < < < < < | < < < < < < < < > < < < < < < < | < < < < > | < < < < < < > < | < < < | < < < < < < < < < < < | < < < | < < < < < < | < < < < < < | < < < < < | 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 | ### # Dockerfile for Fossil ### FROM fedora:28 ### Now install some additional parts we will need for the build RUN dnf update -y && dnf install -y gcc make tcl tcl-devel zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil ### If you want to build "trunk", change the next line accordingly. ENV FOSSIL_INSTALL_VERSION release RUN curl "https://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl=1 --with-tcl-stubs --with-tcl-private-stubs RUN cd fossil-src/src && mv main.c main.c.orig && sed s/\"now\"/0/ <main.c.orig >main.c RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil ### Build is done, remove modules no longer needed RUN dnf remove -y gcc make zlib-devel tcl-devel openssl-devel tar && dnf clean all USER fossil ENV HOME /opt/fossil EXPOSE 8080 CMD ["/usr/bin/fossil", "server", "--create", "--user", "admin", "/opt/fossil/repository.fossil"] |
Changes to Makefile.classic.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = ./src | < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = ./src #### The directory into which object code files should be written. # # OBJDIR = ./bld #### C Compiler and options for use in building executables that |
︙ | ︙ | |||
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 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # #TCC = gcc -O6 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage TCC = gcc -g -Os -Wall # To add support for HTTPS TCC += -DFOSSIL_ENABLE_SSL #### We sometimes add the -static option here so that we can build a # static executable that will run in a chroot jail. #LIB = -static TCC += -DFOSSIL_DYNAMIC_BUILD=1 TCCFLAGS = $(CFLAGS) # We don't attempt to use libedit or libreadline in this simplified # build system (contrast auto.def and Makefile.in) so use the included # copy of linenoise. MinGW can't make use of this, but linenoise is # ifdef'd out elsewhere for that platform. Note that this is a make # flag handled in src/main.mk, not a C preprocessor flag. USE_LINENOISE := 1 #### Extra arguments for linking the finished binary. Fossil needs | > > > > > > > | > | > | > | < < < < < < < < < < | 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 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # #TCC = gcc -O6 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage TCC = gcc -g -Os -Wall # To use the included miniz library # FOSSIL_ENABLE_MINIZ = 1 # TCC += -DFOSSIL_ENABLE_MINIZ # To add support for HTTPS TCC += -DFOSSIL_ENABLE_SSL # To enable legacy mv/rm support TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 #### We sometimes add the -static option here so that we can build a # static executable that will run in a chroot jail. #LIB = -static TCC += -DFOSSIL_DYNAMIC_BUILD=1 TCCFLAGS = $(CFLAGS) # We don't attempt to use libedit or libreadline in this simplified # build system (contrast auto.def and Makefile.in) so use the included # copy of linenoise. MinGW can't make use of this, but linenoise is # ifdef'd out elsewhere for that platform. Note that this is a make # flag handled in src/main.mk, not a C preprocessor flag. USE_LINENOISE := 1 #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library unless the miniz # library in the source tree is being used. There are no other # required dependencies. ZLIB_LIB.0 = -lz ZLIB_LIB.1 = ZLIB_LIB. = $(ZLIB_LIB.0) # If using zlib: LIB += $(ZLIB_LIB.$(FOSSIL_ENABLE_MINIZ)) $(LDFLAGS) # If using HTTPS: LIB += -lcrypto -lssl # Many platforms put cos() needed by src/piechart.c in libm, rather than # in libc. We cannot enable this by default because libm doesn't exist # everywhere. #LIB += -lm #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh # You should not need to change anything below this line ############################################################################### # # Automatic platform-specific options. HOST_OS_CMD = uname -s HOST_OS = $(HOST_OS_CMD:sh) LIB.SunOS= -lsocket -lnsl LIB += $(LIB.$(HOST_OS)) TCC.DragonFly += -DUSE_PREAD TCC.FreeBSD += -DUSE_PREAD TCC.NetBSD += -DUSE_PREAD TCC.OpenBSD += -DUSE_PREAD TCC += $(TCC.$(HOST_OS)) include $(SRCDIR)/main.mk |
Changes to Makefile.in.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src | < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src #### The directory into which object code files should be written. # Having a "./" prefix in the value of this variable breaks our use of the # "makeheaders" tool when running make on the MinGW platform, apparently # due to some command line argument manipulation performed automatically # by the shell. # |
︙ | ︙ | |||
42 43 44 45 46 47 48 | #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = @TCLSH@ CFLAGS = @CFLAGS@ | < | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = @TCLSH@ CFLAGS = @CFLAGS@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ BCCFLAGS = @CPPFLAGS@ $(CFLAGS) TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ USE_LINENOISE = @USE_LINENOISE@ USE_MMAN_H = @USE_MMAN_H@ USE_SEE = @USE_SEE@ FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ include $(SRCDIR)/main.mk distclean: clean -rm -f autoconfig.h config.log Makefile reconfig: @AUTOREMAKE@ # Automatically reconfigure whenever an autosetup file or one of the # make source files change. # # The "touch" is necessary to avoid a make loop due to a new upstream # feature in autosetup (GH 0a71e3c3b7) which rewrites *.in outputs only # if doing so will write different contents; otherwise, it leaves them # alone so the mtime doesn't change. This means that if you change one # our depdendencies besides Makefile.in, we'll reconfigure but Makefile # won't change, so this rule will remain out of date, so we'll reconfig # but Makefile won't change, so we'll reconfig but... endlessly. # # This is also why we repeat the reconfig target's command here instead # of delegating to it with "$(MAKE) reconfig": having children running # around interfering makes this failure mode even worse. Makefile: @srcdir@/Makefile.in $(SRCDIR)/main.mk @AUTODEPS@ @AUTOREMAKE@ touch @builddir@/Makefile |
Changes to Makefile.osx-jaguar.
︙ | ︙ | |||
36 37 38 39 40 41 42 | # BCC = cc BCCFLAGS = $(CFLAGS) #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # | | > | > | 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 | # BCC = cc BCCFLAGS = $(CFLAGS) #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # E = TCC = cc TCCFLAGS = $(CFLAGS) #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh # LIB = -lz LIB = compat/zlib/libz.a TCC += -g -O0 -DHAVE_AUTOCONFIG_H TCC += -Icompat/zlib TCC += -DSQLITE_WITHOUT_ZONEMALLOC TCC += -D_BSD_SOURCE=1 TCC += -DWITHOUT_ICONV TCC += -Dsocklen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 INSTALLDIR = $(DESTDIR)/usr/local/bin USE_SYSTEM_SQLITE = USE_LINENOISE = 1 # FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ FOSSIL_ENABLE_TCL = 0 FOSSIL_ENABLE_MINIZ = 0 include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Deleted README.md.
|
| < < < < < < < < < < < < < < < |
Changes to VERSION.
|
| | | 1 | 2.7 |
Added ajax/README.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | This is the README for how to set up the Fossil/JSON test web page under Apache on Unix systems. This is only intended only for Fossil/JSON developers/tinkerers: First, copy cgi-bin/fossil-json.cgi.example to cgi-bin/fossil-json.cgi. Edit it and correct the paths to the fossil binary and the repo you want to serve. Make it executable. MAKE SURE that the fossil repo you use is world-writable OR that your Web/CGI server is set up to run as the user ID of the owner of the fossil file. ALSO: the DIRECTORY CONTAINING the repo file must be writable by the CGI process. Next, set up an apache vhost entry. Mine looks like: <VirtualHost *:80> ServerAlias fjson ScriptAlias /cgi-bin/ /home/stephan/cvs/fossil/fossil-json/ajax/cgi-bin/ DocumentRoot /home/stephan/cvs/fossil/fossil-json/ajax </VirtualHost> Now add your preferred vhost name (fjson in the above example) to /etc/hosts: 127.0.0.1 ...other aliases... fjson Restart your Apache. Now visit: http://fjson/ that will show the test/demo page. If it doesn't, edit index.html and make sure that: WhAjaj.Connector.options.ajax.url = ...; points to your CGI script. In theory you can also do this over fossil standalone server mode, but i haven't yet tested that particular test page in that mode. |
Added ajax/cgi-bin/fossil-json.cgi.example.
> > | 1 2 | #!/path/to/fossil/binary repository: /path/to/repo.fsl |
Added ajax/i-test/rhino-shell.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | var FShell = { serverUrl: 'http://localhost:8080' //'http://fjson/cgi-bin/fossil-json.cgi' //'http://192.168.1.62:8080' //'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi' , verbose:false, prompt:"fossil shell > ", wiki:{}, consol:java.lang.System.console(), v:function(msg){ if(this.verbose){ print("VERBOSE: "+msg); } } }; (function bootstrap() { var srcdir = '../js/'; var includes = [srcdir+'json2.js', srcdir+'whajaj.js', srcdir+'fossil-ajaj.js' ]; for( var i in includes ) { load(includes[i]); } WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.rhino; FShell.fossil = new FossilAjaj({ asynchronous:false, /* rhino-based impl doesn't support async. */ timeout:10000, url:FShell.serverUrl }); print("Server: "+FShell.serverUrl); var cb = FShell.fossil.ajaj.callbacks; cb.beforeSend = function(req,opt){ if(!FShell.verbose) return; print("SENDING REQUEST: AJAJ options="+JSON.stringify(opt)); if(req) print("Request envelope="+WhAjaj.stringify(req)); }; cb.afterSend = function(req,opt){ //if(!FShell.verbose) return; //print("REQUEST RETURNED: opt="+JSON.stringify(opt)); //if(req) print("Request="+WhAjaj.stringify(req)); }; cb.onError = function(req,opt){ //if(!FShell.verbose) return; print("ERROR: "+WhAjaj.stringify(opt)); }; cb.onResponse = function(resp,req){ if(!FShell.verbose) return; if(resp && resp.resultCode){ print("Response contains error info: "+resp.resultCode+": "+resp.resultText); } print("GOT RESPONSE: "+(('string'===typeof resp) ? resp : WhAjaj.stringify(resp))); }; FShell.fossil.HAI({ onResponse:function(resp,opt){ assertResponseOK(resp); } }); })(); /** Throws an exception of cond is a falsy value. */ function assert(cond, descr){ descr = descr || "Undescribed condition."; if(!cond){ throw new Error("Assertion failed: "+descr); }else{ //print("Assertion OK: "+descr); } } /** Convenience form of FShell.fossil.sendCommand(command,payload,ajajOpt). */ function send(command,payload, ajajOpt){ FShell.fossil.sendCommand(command,payload,ajajOpt); } /** Asserts that resp is-a Object, resp.fossil is-a string, and !resp.resultCode. */ function assertResponseOK(resp){ assert('object' === typeof resp,'Response is-a object.'); assert( 'string' === typeof resp.fossil, 'Response contains fossil property.'); assert( !resp.resultCode, 'resp.resultCode='+resp.resultCode); } /** Asserts that resp is-a Object, resp.fossil is-a string, and resp.resultCode is a truthy value. If expectCode is set then it also asserts that (resp.resultCode=='FOSSIL-'+expectCode). */ function assertResponseError(resp,expectCode){ assert('object' === typeof resp,'Response is-a object.'); assert( 'string' === typeof resp.fossil, 'Response contains fossil property.'); assert( resp.resultCode, 'resp.resultCode='+resp.resultCode); if(expectCode){ assert( 'FOSSIL-'+expectCode == resp.resultCode, 'Expecting result code '+expectCode ); } } FShell.readline = (typeof readline === 'function') ? (readline) : (function() { importPackage(java.io); importPackage(java.lang); var stdin = new BufferedReader(new InputStreamReader(System['in'])); var self = this; return function(prompt) { if(prompt) print(prompt); var x = stdin.readLine(); return null===x ? x : String(x) /*convert to JS string!*/; }; }()); FShell.dispatchLine = function(line){ var av = line.split(' '); // FIXME: to shell-like tokenization. Too tired! var cmd = av[0]; var key, h; if('/' == cmd[0]) key = '/'; else key = this.commandAliases[cmd]; if(!key) key = cmd; h = this.commandHandlers[key]; if(!h){ print("Command not known: "+cmd +" ("+key+")"); }else if(!WhAjaj.isFunction(h)){ print("Not a function: "+key); } else{ print("Sending ["+key+"] command... "); try{h(av);} catch(e){ print("EXCEPTION: "+e); } } }; FShell.onResponseDefault = function(callback){ return function(resp,req){ assertResponseOK(resp); print("Payload: "+(resp.payload ? WhAjaj.stringify(resp.payload) : "none")); if(WhAjaj.isFunction(callback)){ callback(resp,req); } }; }; FShell.commandHandlers = { "?":function(args){ var k; print("Available commands...\n"); var o = FShell.commandHandlers; for(k in o){ if(! o.hasOwnProperty(k)) continue; print("\t"+k); } }, "/":function(args){ FShell.fossil.sendCommand('/json'+args[0],undefined,{ beforeSend:function(req,opt){ print("Sending to: "+opt.url); }, onResponse:FShell.onResponseDefault() }); }, "eval":function(args){ eval(args.join(' ')); }, "login":function(args){ FShell.fossil.login(args[1], args[2], { onResponse:FShell.onResponseDefault() }); }, "whoami":function(args){ FShell.fossil.whoami({ onResponse:FShell.onResponseDefault() }); }, "HAI":function(args){ FShell.fossil.HAI({ onResponse:FShell.onResponseDefault() }); } }; FShell.commandAliases = { "li":"login", "lo":"logout", "who":"whoami", "hi":"HAI", "tci":"/timeline/ci?limit=3" }; FShell.mainLoop = function(){ var line; var check = /\S/; //var isJavaNull = /java\.lang\.null/; //print(typeof java.lang['null']); while( null != (line=this.readline(this.prompt)) ){ if(null===line) break /*EOF*/; else if( "" === line ) continue; //print("Got line: "+line); else if(!check.test(line)) continue; print('typeof line = '+typeof line); this.dispatchLine(line); print(""); } print("Bye!"); }; FShell.mainLoop(); |
Added ajax/i-test/rhino-test.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | var TestApp = { serverUrl: 'http://localhost:8080' //'http://fjson/cgi-bin/fossil-json.cgi' //'http://192.168.1.62:8080' //'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi' , verbose:true, fossilBinary:'fossil', wiki:{} }; (function bootstrap() { var srcdir = '../js/'; var includes = [srcdir+'json2.js', srcdir+'whajaj.js', srcdir+'fossil-ajaj.js' ]; for( var i in includes ) { load(includes[i]); } WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.rhino; TestApp.fossil = new FossilAjaj({ asynchronous:false, /* rhino-based impl doesn't support async or timeout. */ timeout:0, url:TestApp.serverUrl, fossilBinary:TestApp.fossilBinary }); var cb = TestApp.fossil.ajaj.callbacks; cb.beforeSend = function(req,opt){ if(!TestApp.verbose) return; print("SENDING REQUEST: AJAJ options="+JSON.stringify(opt)); if(req) print("Request envelope="+WhAjaj.stringify(req)); }; cb.afterSend = function(req,opt){ //if(!TestApp.verbose) return; //print("REQUEST RETURNED: opt="+JSON.stringify(opt)); //if(req) print("Request="+WhAjaj.stringify(req)); }; cb.onError = function(req,opt){ if(!TestApp.verbose) return; print("ERROR: "+WhAjaj.stringify(opt)); }; cb.onResponse = function(resp,req){ if(!TestApp.verbose) return; print("GOT RESPONSE: "+(('string'===typeof resp) ? resp : WhAjaj.stringify(resp))); }; })(); /** Throws an exception of cond is a falsy value. */ function assert(cond, descr){ descr = descr || "Undescribed condition."; if(!cond){ print("Assertion FAILED: "+descr); throw new Error("Assertion failed: "+descr); // aarrgghh. Exceptions are of course swallowed by // the AJAX layer, to keep from killing a browser's // script environment. }else{ if(TestApp.verbose) print("Assertion OK: "+descr); } } /** Calls func() in a try/catch block and throws an exception if func() does NOT throw. */ function assertThrows(func, descr){ descr = descr || "Undescribed condition failed."; var ex; try{ func(); }catch(e){ ex = e; } if(!ex){ throw new Error("Function did not throw (as expected): "+descr); }else{ if(TestApp.verbose) print("Function threw (as expected): "+descr+": "+ex); } } /** Convenience form of TestApp.fossil.sendCommand(command,payload,ajajOpt). */ function send(command,payload, ajajOpt){ TestApp.fossil.sendCommand(command,payload,ajajOpt); } /** Asserts that resp is-a Object, resp.fossil is-a string, and !resp.resultCode. */ function assertResponseOK(resp){ assert('object' === typeof resp,'Response is-a object.'); assert( 'string' === typeof resp.fossil, 'Response contains fossil property.'); assert( undefined === resp.resultCode, 'resp.resultCode is not set'); } /** Asserts that resp is-a Object, resp.fossil is-a string, and resp.resultCode is a truthy value. If expectCode is set then it also asserts that (resp.resultCode=='FOSSIL-'+expectCode). */ function assertResponseError(resp,expectCode){ assert('object' === typeof resp,'Response is-a object.'); assert( 'string' === typeof resp.fossil, 'Response contains fossil property.'); assert( !!resp.resultCode, 'resp.resultCode='+resp.resultCode); if(expectCode){ assert( 'FOSSIL-'+expectCode == resp.resultCode, 'Expecting result code '+expectCode ); } } function testHAI(){ var rs; TestApp.fossil.HAI({ onResponse:function(resp,req){ rs = resp; } }); assertResponseOK(rs); TestApp.serverVersion = rs.fossil; assert( 'string' === typeof TestApp.serverVersion, 'server version = '+TestApp.serverVersion); } testHAI.description = 'Get server version info.'; function testIAmNobody(){ TestApp.fossil.whoami('/json/whoami'); assert('nobody' === TestApp.fossil.auth.name, 'User == nobody.' ); assert(!TestApp.fossil.auth.authToken, 'authToken is not set.' ); } testIAmNobody.description = 'Ensure that current user is "nobody".'; function testAnonymousLogin(){ TestApp.fossil.login(); assert('string' === typeof TestApp.fossil.auth.authToken, 'authToken = '+TestApp.fossil.auth.authToken); assert( 'string' === typeof TestApp.fossil.auth.name, 'User name = '+TestApp.fossil.auth.name); TestApp.fossil.userName = null; TestApp.fossil.whoami('/json/whoami'); assert( 'string' === typeof TestApp.fossil.auth.name, 'User name = '+TestApp.fossil.auth.name); } testAnonymousLogin.description = 'Perform anonymous login.'; function testAnonWiki(){ var rs; TestApp.fossil.sendCommand('/json/wiki/list',undefined,{ beforeSend:function(req,opt){ assert( req && (req.authToken==TestApp.fossil.auth.authToken), 'Request envelope contains expected authToken.' ); }, onResponse:function(resp,req){ rs = resp; } }); assertResponseOK(rs); assert( (typeof [] === typeof rs.payload) && rs.payload.length, "Wiki list seems to be okay."); TestApp.wiki.list = rs.payload; TestApp.fossil.sendCommand('/json/wiki/get',{ name:TestApp.wiki.list[0] },{ onResponse:function(resp,req){ rs = resp; } }); assertResponseOK(rs); assert(rs.payload.name == TestApp.wiki.list[0], "Fetched page name matches expectations."); print("Got first wiki page: "+WhAjaj.stringify(rs.payload)); } testAnonWiki.description = 'Fetch wiki list as anonymous user.'; function testFetchCheckinArtifact(){ var art = '18dd383e5e7684ece'; var rs; TestApp.fossil.sendCommand('/json/artifact',{ 'name': art }, { onResponse:function(resp,req){ rs = resp; } }); assertResponseOK(rs); assert(3 == rs.payload.parents.length, 'Got 3 parent artifacts.'); } testFetchCheckinArtifact.description = '/json/artifact/CHECKIN'; function testAnonLogout(){ var rs; TestApp.fossil.logout({ onResponse:function(resp,req){ rs = resp; } }); assertResponseOK(rs); print("Ensure that second logout attempt fails..."); TestApp.fossil.logout({ onResponse:function(resp,req){ rs = resp; } }); assertResponseError(rs); } testAnonLogout.description = 'Log out anonymous user.'; function testExternalProcess(){ var req = { command:"HAI", requestId:'testExternalProcess()' }; var args = [TestApp.fossilBinary, 'json', '--json-input', '-']; var p = java.lang.Runtime.getRuntime().exec(args); var outs = p.getOutputStream(); var osr = new java.io.OutputStreamWriter(outs); var osb = new java.io.BufferedWriter(osr); var json = JSON.stringify(req); osb.write(json,0, json.length); osb.close(); req = json = outs = osr = osb = undefined; var ins = p.getInputStream(); var isr = new java.io.InputStreamReader(ins); var br = new java.io.BufferedReader(isr); var line; while( null !== (line=br.readLine())){ print(line); } br.close(); isr.close(); ins.close(); p.waitFor(); } testExternalProcess.description = 'Run fossil as external process.'; function testExternalProcessHandler(){ var aj = TestApp.fossil.ajaj; var oldImpl = aj.sendImpl; aj.sendImpl = FossilAjaj.rhinoLocalBinarySendImpl; var rs; TestApp.fossil.sendCommand('/json/HAI',undefined,{ onResponse:function(resp,opt){ rs = resp; } }); aj.sendImpl = oldImpl; assertResponseOK(rs); print("Using local fossil binary via AJAX interface, we fetched: "+ WhAjaj.stringify(rs)); } testExternalProcessHandler.description = 'Try local fossil binary via AJAX interface.'; (function runAllTests(){ var testList = [ testHAI, testIAmNobody, testAnonymousLogin, testAnonWiki, testFetchCheckinArtifact, testAnonLogout, testExternalProcess, testExternalProcessHandler ]; var i, f; for( i = 0; i < testList.length; ++i ){ f = testList[i]; try{ print("Running test #"+(i+1)+": "+(f.description || "no description.")); f(); }catch(e){ print("Test #"+(i+1)+" failed: "+e); throw e; } } })(); print("Done! If you don't see an exception message in the last few lines, you win!"); |
Added ajax/index.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Fossil/JSON raw request sending</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script> <script type="text/javascript" src="js/whajaj.js"></script> <script type="text/javascript" src="js/fossil-ajaj.js"></script> <style type='text/css'> th { text-align: left; background-color: #ececec; } .dangerWillRobinson { background-color: yellow; } </style> <script type='text/javascript'> WhAjaj.Connector.options.ajax.url = /* Change this to your CGI/server root path: */ //'http://fjson/cgi-bin/fossil.cgi' //'/repos/fossil-sgb/json.cgi' '/cgi-bin/fossil-json.cgi' ; var TheApp = { response:null, sessionID:null, jqe:{}/*jqe==jQuery Elements*/, ajaxCount:0, cgi: new FossilAjaj() }; TheApp.startAjaxNotif = function() { ++this.ajaxCount; TheApp.jqe.responseContainer.removeClass('dangerWillRobinson'); this.jqe.ajaxNotification.attr( 'title', this.ajaxCount+" pending AJAX operation(s)..." ); if( 1 == this.ajaxCount ) this.jqe.ajaxNotification.fadeIn(); }; TheApp.endAjaxNotif = function() { --this.ajaxCount; this.jqe.ajaxNotification.attr( 'title', this.ajaxCount+" pending AJAX operation(s)..." ); if( 0 == this.ajaxCount ) this.jqe.ajaxNotification.fadeOut(); }; TheApp.responseContainsError = function(resp) { if( resp && resp.resultCode ) { //alert("Error response:\n"+JSON.stringify(resp,0,4)); TheApp.jqe.taResponse.val( "RESPONSE CONTAINS ERROR INFO:\n"+WhAjaj.stringify(resp) ); //TheApp.jqe.responseContainer.css({backgroundColor:'yellow'}); //TheApp.jqe.responseContainer.addClass('dangerWillRobinson'); TheApp.jqe.responseContainer.flash( '255,0,0', 1500 ); return true; } return false; }; TheApp.sendRequest = function() { var path = this.jqe.textPath.val(); var self = this; var data = this.jqe.taRequest.val(); var doPost = (data && data.length); var req; if( doPost ) try { req = JSON.parse(data); } catch(e) { TheApp.jqe.taResponse.val("Request is not valid JSON.\n"+e); return; } if( req ) { req.requestId = this.cgi.generateRequestId(); } var self = this; var opt = { url: WhAjaj.Connector.options.ajax.url + path, method: doPost ? 'POST' : 'GET' }; this.cgi.sendRequest( req, opt ); }; jQuery.fn.animateHighlight = function(highlightColor, duration) { var highlightBg = highlightColor || "#FFFF9C"; var animateMs = duration || 1500; var originalBg = this.css("backgroundColor"); this.stop().css("background-color", highlightBg).animate({backgroundColor: originalBg}, animateMs); }; jQuery.fn.flash = function( color, duration ) { var current = this.css( 'color' ); this.animate( { color: 'rgb(' + color + ')' }, duration / 2); this.animate( { color: current }, duration / 2 ); }; function myJsonPCallback(obj){ alert("JSONP callback got:\n"+WhAjaj.stringify(obj)); } jQuery(document).ready(function(){ var ids = [// list of HTML element IDs we use often. 'btnSend', 'ajaxNotification', 'currentAuthToken', 'responseContainer', 'taRequest', 'taRequestOpt', 'taResponse', 'textPath', 'timer' ]; var i, k; for( i = 0; i < ids.length; ++i ) { k = ids[i]; TheApp.jqe[k] = jQuery('#'+k); } TheApp.jqe.textPath. keyup(function(event){ if(event.keyCode == 13){ TheApp.sendRequest(); } }); TheApp.timer = { _tstart:0,_tend:0,duration:0, start:function(){ this._tstart = (new Date()).getTime(); }, end:function(){ this._tend = (new Date()).getTime(); return this.duration = this._tend - this._tstart; } }; var ajcb = TheApp.cgi.ajaj.callbacks; ajcb.beforeSend = function(req,opt) { TheApp.timer.start(); var val = req ? (('string'===typeof req) ? req : WhAjaj.stringify(req)) : ''; TheApp.jqe.taResponse.val(''); TheApp.jqe.taRequest.val( val ); TheApp.jqe.taRequestOpt.val( opt ? WhAjaj.stringify(opt) : '' ); TheApp.startAjaxNotif(); }; ajcb.afterSend = function(req,opt) { TheApp.timer.end(); TheApp.endAjaxNotif(); TheApp.jqe.timer.text( "(Round-trip time (incl. JS overhead): "+TheApp.timer.duration+'ms)' ); }; ajcb.onResponse = function(resp,req, opt) { var val; if(this.jsonp) return /*was already handled*/; try { val = WhAjaj.stringify(resp); } catch(e) { val = WhAjaj.stringify(e) } //alert("onResponse this:"+WhAjaj.stringify(this)); //alert("val="+val); // FIXME: this.url is hosed for login because of how i overload onResponse() if( opt.url ) TheApp.jqe.textPath.val(opt.url.replace(WhAjaj.Connector.options.ajax.url,'')); TheApp.jqe.taResponse.val( val ); }; ajcb.onError = function(req,opt) { TheApp.jqe.taResponse.val( "ERROR SENDING REQUEST:\n"+WhAjaj.stringify(opt) ); }; TheApp.cgi.onLogin = function(){ TheApp.jqe.taResponse.val( "Logged in:\n"+WhAjaj.stringify(this.auth)); TheApp.jqe.currentAuthToken.html("Logged in: "+WhAjaj.stringify(this.auth)); }; TheApp.cgi.onLogout = function(){ TheApp.jqe.taResponse.val( "Logged out!" ); TheApp.jqe.currentAuthToken.text("Not logged in"); }; TheApp.cgi.whoami(); jQuery('#headerArea').click(function(){ jQuery(this).slideUp('fast',function(){ jQuery(this).remove(); }); }); }); </script> </head> <body> <span id='ajaxNotification'></span> <div id='headerArea'> <h1>You know, for sending raw JSON requests to Fossil...</h1> If you're actually using this page, then you know what you're doing and don't need help text, hoverhelp, and a snazzy interface. <br><br> JSON API docs: <a href='https://docs.google.com/document/d/1fXViveNhDbiXgCuE7QDXQOKeFzf2qNUkBEgiUvoqFN4/edit'>https://docs.google.com/document/d/1fXViveNhDbiXgCuE7QDXQOKeFzf2qNUkBEgiUvoqFN4/edit</a> </div><!-- #headerArea --> See also: <a href='wiki-editor.html'>prototype wiki editor</a>. <h2>Request...</h2> Path: <input type='text' size='40' id='textPath' value='/json/HAI'/> <input type='button' value='Send...' id='btnSend' onclick='TheApp.sendRequest()' /><br/> If the POST textarea is not empty then it will be posted with the request. <hr/> <strong>Quick-posts:</strong><br/> <input type='button' value='HAI' onclick='TheApp.cgi.HAI()' /> <input type='button' value='HAI JSONP' onclick='TheApp.cgi.sendCommand("/json/HAI",undefined,{jsonp:"myJsonPCallback"});' /> <input type='button' value='version' onclick='TheApp.cgi.sendCommand("/json/version")' /> <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat?full=0")' /> <input type='button' value='whoami' onclick='TheApp.cgi.whoami()' /> <input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' /> <input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' /> <input type='button' value='g' onclick='TheApp.cgi.sendCommand("/json/g")' /> <br/> <input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' /> <input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' /> <input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' /> <input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' /> <input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' /> <br/> <input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' /> <input type='button' value='wiki/list verbose' onclick='TheApp.cgi.sendCommand("/json/wiki/list",{verbose:1})' /> <input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' /> <input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' /> <input type='button' value='wiki/diff' onclick='TheApp.cgi.sendCommand("/json/wiki/diff/e32ccdcda59e930c77c/e15992f475760cdf3a9")' /> <br/> <input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' /> <input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' /> <input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' /> <input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' /> <input type='button' value='tag/add' onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' /> <input type='button' value='tag/cancel' onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' /> <input type='button' value='tag/find' onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' /> <br/> <input type='button' value='diff' onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' /> <input type='button' value='diff/A/B' onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' /> <input type='button' value='query' onclick='TheApp.cgi.sendCommand("/json/query?format=o","SELECT * from user")' /> <input type='button' value='report list' onclick='TheApp.cgi.sendCommand("/json/report/list")' /> <input type='button' value='report get' onclick='TheApp.cgi.sendCommand("/json/report/get",2)' /> <input type='button' value='report run' onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' /> <input type='button' value='config/get' onclick='TheApp.cgi.sendCommand("/json/config/get")' /> <!-- not yet ready... <input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' /> --> <!-- <input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' /> <input type='button' value='get more' onclick='TheApp.cgi.getPages("HelloWorld/WhikiNews")' /> <input type='button' value='get client data' onclick='TheApp.cgi.getPageClientData("HelloWorld/whiki/WhikiCommands")' /> <input type='button' value='save client data' onclick='TheApp.cgi.savePageClientData({"HelloWorld":[1,3,5]})' /> --> <hr/> <b>Login:</b> <br/> <input type='button' value='Anon. PW' onclick='TheApp.cgi.sendCommand("/json/anonymousPassword")' /> <input type='button' value='Anon. PW+Login' onclick='TheApp.cgi.login()' /> <br/> name:<input type='text' id='textUser' value='json-demo' size='12'/> pw:<input type='password' id='textPassword' value='json-demo' size='12'/> <input type='button' value='login' onclick='TheApp.cgi.login(jQuery("#textUser").val(),jQuery("#textPassword").val(),{onResponse:TheApp.onLogin})' /> <input type='button' value='logout' onclick='TheApp.cgi.logout()' /> <br/> <span id='currentAuthToken' style='font-family:monospaced'></span> <br/> <hr/> <table> <tr> <th>POST data</th> <th>Request AJAJ options</th> </tr> <tr> <td width='50%' valign='top'> <textarea id='taRequest' rows='10' cols='50'></textarea> </td> <td width='50%' valign='top'> <textarea id='taRequestOpt' rows='10' cols='40' readonly></textarea> </td> </tr> <tr> <th colspan='2'>Response <span id='timer'></span></th> </tr> <tr> <td colspan='2' id='responseContainer' valign='top'> <textarea id='taResponse' rows='20' cols='80' readonly></textarea> </td> </tr> </table> <div></div> <div></div> <div></div> </body></html> |
Added ajax/js/fossil-ajaj.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | /** This file contains a WhAjaj extension for use with Fossil/JSON. Author: Stephan Beal (sgbeal@googlemail.com) License: Public Domain */ /** Constructor for a new Fossil AJAJ client. ajajOpt may be an optional object suitable for passing to the WhAjaj.Connector() constructor. On returning, this.ajaj is-a WhAjaj.Connector instance which can be used to send requests to the back-end (though the convenience functions of this class are the preferred way to do it). Clients are encouraged to use FossilAjaj.sendCommand() (and friends) instead of the underlying WhAjaj.Connector API, since this class' API contains Fossil-specific request-calling handling (e.g. of authentication info) whereas WhAjaj is more generic. */ function FossilAjaj(ajajOpt) { this.ajaj = new WhAjaj.Connector(ajajOpt); return this; } FossilAjaj.prototype.generateRequestId = function() { return this.ajaj.generateRequestId(); }; /** Proxy for this.ajaj.sendRequest(). */ FossilAjaj.prototype.sendRequest = function(req,opt) { return this.ajaj.sendRequest(req,opt); }; /** Sends a command to the fossil back-end. Command should be the path part of the URL, e.g. /json/stat, payload is a request-specific value type (may often be null/undefined). ajajOpt is an optional object holding WhAjaj.sendRequest()-compatible options. This function constructs a Fossil/JSON request envelope based on the given arguments and adds this.auth.authToken and a requestId to it. */ FossilAjaj.prototype.sendCommand = function(command, payload, ajajOpt) { var req; ajajOpt = ajajOpt || {}; if(payload || (this.auth && this.auth.authToken) || ajajOpt.jsonp) { req = { payload:payload, requestId:('function' === typeof this.generateRequestId) ? this.generateRequestId() : undefined, authToken:(this.auth ? this.auth.authToken : undefined), jsonp:('string' === typeof ajajOpt.jsonp) ? ajajOpt.jsonp : undefined }; } ajajOpt.method = req ? 'POST' : 'GET'; // just for debuggering: ajajOpt.method = 'POST'; if(!req) req={}; if(command) ajajOpt.url = this.ajaj.derivedOption('url',ajajOpt) + command; this.ajaj.sendRequest(req,ajajOpt); }; /** Sends a login request to the back-end. ajajOpt is an optional configuration object suitable for passing to sendCommand(). After the response returns, this.auth will be set to the response payload. If name === 'anonymous' (the default if none is passed in) then this function ignores the pw argument and must make two requests - the first one gets the captcha code and the second one submits it. ajajOpt.onResponse() (if set) is only called for the actual login response (the 2nd one), as opposed to being called for both requests. However, this.ajaj.callbacks.onResponse() _is_ called for both (because it happens at a lower level). If this object has an onLogin() function it is called (with no arguments) before the onResponse() handler of the login is called (that is the 2nd request for anonymous logins) and any exceptions it throws are ignored. */ FossilAjaj.prototype.login = function(name,pw,ajajOpt) { name = name || 'anonymous'; var self = this; var loginReq = { name:name, password:pw }; ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} ); var oldOnResponse = ajajOpt.onResponse; ajajOpt.onResponse = function(resp,req) { var thisOpt = this; //alert('login response:\n'+WhAjaj.stringify(resp)); if( resp && resp.payload ) { //self.userName = resp.payload.name; //self.capabilities = resp.payload.capabilities; self.auth = resp.payload; } if( WhAjaj.isFunction( self.onLogin ) ){ try{ self.onLogin(); } catch(e){} } if( WhAjaj.isFunction(oldOnResponse) ) { oldOnResponse.apply(thisOpt,[resp,req]); } }; function doLogin(){ //alert("Sending login request..."+WhAjaj.stringify(loginReq)); self.sendCommand('/json/login', loginReq, ajajOpt); } if( 'anonymous' === name ){ this.sendCommand('/json/anonymousPassword',undefined,{ onResponse:function(resp,req){ /* if( WhAjaj.isFunction(oldOnResponse) ){ oldOnResponse.apply(this, [resp,req]); }; */ if(resp && !resp.resultCode){ //alert("Got PW. Trying to log in..."+WhAjaj.stringify(resp)); loginReq.anonymousSeed = resp.payload.seed; loginReq.password = resp.payload.password; doLogin(); } } }); } else doLogin(); }; /** Logs out of fossil, invaliding this login token. ajajOpt is an optional configuration object suitable for passing to sendCommand(). If this object has an onLogout() function it is called (with no arguments) before the onResponse() handler is called. IFF the response succeeds then this.auth is unset. */ FossilAjaj.prototype.logout = function(ajajOpt) { var self = this; ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} ); var oldOnResponse = ajajOpt.onResponse; ajajOpt.onResponse = function(resp,req) { var thisOpt = this; self.auth = undefined; if( WhAjaj.isFunction( self.onLogout ) ){ try{ self.onLogout(); } catch(e){} } if( WhAjaj.isFunction(oldOnResponse) ) { oldOnResponse.apply(thisOpt,[resp,req]); } }; this.sendCommand('/json/logout', undefined, ajajOpt ); }; /** Sends a HAI request to the server. /json/HAI is an alias /json/version. ajajOpt is an optional configuration object suitable for passing to sendCommand(). */ FossilAjaj.prototype.HAI = function(ajajOpt) { this.sendCommand('/json/HAI', undefined, ajajOpt); }; /** Sends a /json/whoami request. Updates this.auth to contain the login info, removing them if the response does not contain that data. */ FossilAjaj.prototype.whoami = function(ajajOpt) { var self = this; ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} ); var oldOnResponse = ajajOpt.onResponse; ajajOpt.onResponse = function(resp,req) { var thisOpt = this; if( resp && resp.payload ){ if(!self.auth || (self.auth.authToken!==resp.payload.authToken)){ self.auth = resp.payload; if( WhAjaj.isFunction(self.onLogin) ){ self.onLogin(); } } } else { delete self.auth; } if( WhAjaj.isFunction(oldOnResponse) ) { oldOnResponse.apply(thisOpt,[resp,req]); } }; self.sendCommand('/json/whoami', undefined, ajajOpt); }; /** EXPERIMENTAL concrete WhAjaj.Connector.sendImpl() implementation which uses Rhino to connect to a local fossil binary for input and output. Its signature and semantics are as described for WhAjaj.Connector.prototype.sendImpl(), with a few exceptions and additions: - It does not support timeouts or asynchronous mode. - The args.fossilBinary property must point to the local fossil binary (it need not be a complete path if fossil is in the $PATH). This function throws (without calling any request callbacks) if args.fossilBinary is not set. fossilBinary may be set on WhAjaj.Connector.options.ajax, in the FossilAjaj constructor call, as the ajax options parameter to any of the FossilAjaj.sendCommand() family of functions, or by setting aFossilAjajInstance.ajaj.options.fossilBinary on a specific FossilAjaj instance. - It uses the args.url field to create the "command" property of the request, constructs a request envelope, spawns a fossil process in JSON mode, feeds it the request envelope, and returns the response envelope via the same mechanisms defined for the HTTP-based implementations. The interface is otherwise compatible with the "normal" FossilAjaj.sendCommand() front-end (it is, however, fossil-specific, and not back-end agnostic like the WhAjaj.sendImpl() interface intends). */ FossilAjaj.rhinoLocalBinarySendImpl = function(request,args){ var self = this; request = request || {}; if(!args.fossilBinary){ throw new Error("fossilBinary is not set on AJAX options!"); } var url = args.url.split('?')[0].split(/\/+/); if(url.length>1){ // 3x shift(): protocol, host, 'json' part of path request.command = (url.shift(),url.shift(),url.shift(), url.join('/')); } delete args.url; //print("rhinoLocalBinarySendImpl SENDING: "+WhAjaj.stringify(request)); var json; try{ var pargs = [args.fossilBinary, 'json', '--json-input', '-']; var p = java.lang.Runtime.getRuntime().exec(pargs); var outs = p.getOutputStream(); var osr = new java.io.OutputStreamWriter(outs); var osb = new java.io.BufferedWriter(osr); json = JSON.stringify(request); osb.write(json,0, json.length); osb.close(); var ins = p.getInputStream(); var isr = new java.io.InputStreamReader(ins); var br = new java.io.BufferedReader(isr); var line; json = []; while( null !== (line=br.readLine())){ json.push(line); } ins.close(); }catch(e){ args.errorMessage = e.toString(); WhAjaj.Connector.sendHelper.onSendError.apply( self, [request, args] ); return undefined; } json = json.join(''); //print("READ IN JSON: "+json); WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] ); }/*rhinoLocalBinary*/ |
Added ajax/js/json2.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | /* http://www.JSON.org/json2.js 2009-06-29 Public Domain. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. See http://www.JSON.org/js.html This file creates a global JSON object containing two methods: stringify and parse. JSON.stringify(value, replacer, space) value any JavaScript value, usually an object or array. replacer an optional parameter that determines how object values are stringified for objects. It can be a function or an array of strings. space an optional parameter that specifies the indentation of nested structures. If it is omitted, the text will be packed without extra whitespace. If it is a number, it will specify the number of spaces to indent at each level. If it is a string (such as '\t' or ' '), it contains the characters used to indent at each level. This method produces a JSON text from a JavaScript value. When an object value is found, if the object contains a toJSON method, its toJSON method will be called and the result will be stringified. A toJSON method does not serialize: it returns the value represented by the name/value pair that should be serialized, or undefined if nothing should be serialized. The toJSON method will be passed the key associated with the value, and this will be bound to the object holding the key. For example, this would serialize Dates as ISO strings. Date.prototype.toJSON = function (key) { function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } return this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z'; }; You can provide an optional replacer method. It will be passed the key and value of each member, with this bound to the containing object. The value that is returned from your method will be serialized. If your method returns undefined, then the member will be excluded from the serialization. If the replacer parameter is an array of strings, then it will be used to select the members to be serialized. It filters the results such that only members with keys listed in the replacer array are stringified. Values that do not have JSON representations, such as undefined or functions, will not be serialized. Such values in objects will be dropped; in arrays they will be replaced with null. You can use a replacer function to replace those with JSON values. JSON.stringify(undefined) returns undefined. The optional space parameter produces a stringification of the value that is filled with line breaks and indentation to make it easier to read. If the space parameter is a non-empty string, then that string will be used for indentation. If the space parameter is a number, then the indentation will be that many spaces. Example: text = JSON.stringify(['e', {pluribus: 'unum'}]); // text is '["e",{"pluribus":"unum"}]' text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' text = JSON.stringify([new Date()], function (key, value) { return this[key] instanceof Date ? 'Date(' + this[key] + ')' : value; }); // text is '["Date(---current time---)"]' JSON.parse(text, reviver) This method parses a JSON text to produce an object or array. It can throw a SyntaxError exception. The optional reviver parameter is a function that can filter and transform the results. It receives each of the keys and values, and its return value is used instead of the original value. If it returns what it received, then the structure is not modified. If it returns undefined then the member is deleted. Example: // Parse the text. Values that look like ISO date strings will // be converted to Date objects. myData = JSON.parse(text, function (key, value) { var a; if (typeof value === 'string') { a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); if (a) { return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6])); } } return value; }); myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { var d; if (typeof value === 'string' && value.slice(0, 5) === 'Date(' && value.slice(-1) === ')') { d = new Date(value.slice(5, -1)); if (d) { return d; } } return value; }); This is a reference implementation. You are free to copy, modify, or redistribute. This code should be minified before deployment. See http://javascript.crockford.com/jsmin.html USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO NOT CONTROL. */ /*jslint evil: true */ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length, parse, prototype, push, replace, slice, stringify, test, toJSON, toString, valueOf */ // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. var JSON = JSON || {}; (function () { function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { // table of character substitutions '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' }, rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { // Produce a string from holder[key]. var i, // The loop counter. k, // The member key. v, // The member value. length, mind = gap, partial, value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === 'function') { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case 'string': return quote(value); case 'number': // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce 'null'. The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is 'object', we might be dealing with an object or an array or // null. case 'object': // Due to a specification blunder in ECMAScript, typeof null is 'object', // so watch out for that case. if (!value) { return 'null'; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === '[object Array]') { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ''; indent = ''; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === 'string') { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } // Make a fake root object containing our value under the key of ''. // Return the result of stringifying the value. return str('', {'': value}); }; } // If the JSON object does not yet have a parse method, give it one. if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with '()' and 'new' // because they can cause invocation, and '=' because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we // replace all simple value tokens with ']' characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or ']' or // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. if (/^[\],:{}\s]*$/. test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The '{' operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval('(' + text + ')'); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return typeof reviver === 'function' ? walk({'': j}, '') : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError('JSON.parse'); }; } }()); |
Added ajax/js/whajaj.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 | /** This file provides a JS interface into the core functionality of JSON-centric back-ends. It sends GET or JSON POST requests to a back-end and expects JSON responses. The exact semantics of the underlying back-end and overlying front-end are not its concern, and it leaves the interpretation of the data up to the client/server insofar as possible. All functionality is part of a class named WhAjaj, and that class acts as namespace for this framework. Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) License: Public Domain This framework is directly derived from code originally found in http://code.google.com/p/jsonmessage, and later in http://whiki.wanderinghorse.net, where it contained quite a bit of application-specific logic. It was eventually (the 3rd time i needed it) split off into its own library to simplify inclusion into my many mini-projects. */ /** The WhAjaj function is primarily a namespace, and not intended to called or instantiated via the 'new' operator. */ function WhAjaj() { } /** Returns a millisecond Unix Epoch timestamp. */ WhAjaj.msTimestamp = function() { return (new Date()).getTime(); }; /** Returns a Unix Epoch timestamp (in seconds) in integer format. Reminder to self: (1.1 %1.2) evaluates to a floating-point value in JS, and thus this implementation is less than optimal. */ WhAjaj.unixTimestamp = function() { var ts = (new Date()).getTime(); return parseInt( ""+((ts / 1000) % ts) ); }; /** Returns true if v is-a Array instance. */ WhAjaj.isArray = function( v ) { return (v && (v instanceof Array) || (Object.prototype.toString.call(v) === "[object Array]") ); /* Reminders to self: typeof [] == "object" toString.call([]) == "[object Array]" ([]).toString() == empty */ }; /** Returns true if v is-a Object instance. */ WhAjaj.isObject = function( v ) { return v && (v instanceof Object) && ('[object Object]' === Object.prototype.toString.apply(v) ); }; /** Returns true if v is-a Function instance. */ WhAjaj.isFunction = function(obj) { return obj && ( (obj instanceof Function) || ('function' === typeof obj) || ("[object Function]" === Object.prototype.toString.call(obj)) ) ; }; /** Parses window.location.search-style string into an object containing key/value pairs of URL arguments (already urldecoded). If the str argument is not passed (arguments.length==0) then window.location.search.substring(1) is used by default. If neither str is passed in nor window exists then false is returned. On success it returns an Object containing the key/value pairs parsed from the string. Keys which have no value are treated has having the boolean true value. FIXME: for keys in the form "name[]", build an array of results, like PHP does. */ WhAjaj.processUrlArgs = function(str) { if( 0 === arguments.length ) { if( ('undefined' === typeof window) || !window.location || !window.location.search ) return false; else str = (''+window.location.search).substring(1); } if( ! str ) return false; str = (''+str).split(/#/,2)[0]; // remove #... to avoid it being added as part of the last value. var args = {}; var sp = str.split(/&+/); var rx = /^([^=]+)(=(.+))?/; var i, m; for( i in sp ) { m = rx.exec( sp[i] ); if( ! m ) continue; args[decodeURIComponent(m[1])] = (m[3] ? decodeURIComponent(m[3]) : true); } return args; }; /** A simple wrapper around JSON.stringify(), using my own personal preferred values for the 2nd and 3rd parameters. To globally set its indentation level, assign WhAjaj.stringify.indent to an integer value (0 for no intendation). This function is intended only for human-readable output, not generic over-the-wire JSON output (where JSON.stringify(val) will produce smaller results). */ WhAjaj.stringify = function(val) { if( ! arguments.callee.indent ) arguments.callee.indent = 4; return JSON.stringify(val,0,arguments.callee.indent); }; /** Each instance of this class holds state information for making AJAJ requests to a back-end system. While clients may use one "requester" object per connection attempt, for connections to the same back-end, using an instance configured for that back-end can simplify usage. This class is designed so that the actual connection-related details (i.e. _how_ it connects to the back-end) may be re-implemented to use a client's preferred connection mechanism (e.g. jQuery). The optional opt parameter may be an object with any (or all) of the properties documented for WhAjaj.Connector.options.ajax. Properties set here (or later via modification of the "options" property of this object) will be used in calls to WhAjaj.Connector.sendRequest(), and these override (normally) any options set in WhAjaj.Connector.options.ajax. Note that WhAjaj.Connector.sendRequest() _also_ takes an options object, and ones passed there will override, for purposes of that one request, any options passed in here or defined in WhAjaj.Connector.options.ajax. See WhAjaj.Connector.options.ajax and WhAjaj.Connector.prototype.sendRequest() for more details about the precedence of options. Sample usage: @code // Set up common connection-level options: var cgi = new WhAjaj.Connector({ url: '/cgi-bin/my.cgi', timeout:10000, onResponse(resp,req) { alert(JSON.stringify(resp,0.4)); }, onError(req,opt) { alert(opt.errorMessage); } }); // Any of those options may optionally be set globally in // WhAjaj.Connector.options.ajax (onError(), beforeSend(), and afterSend() // are often easiest/most useful to set globally). // Get list of pages... cgi.sendRequest( null, { onResponse(resp,req){ alert(WhAjaj.stringify(resp)); } }); @endcode For common request types, clients can add functions to this object which act as wrappers for backend-specific functionality. As a simple example: @code cgi.login = function(name,pw,ajajOpt) { this.sendRequest( {command:"json/login", name:name, password:pw }, ajajOpt ); }; @endcode TODOs: - Caching of page-load requests, with a configurable lifetime. - Use-cases like the above login() function are a tiny bit problematic to implement when each request has a different URL path (i know this from the whiki and fossil implementations). This is partly a side-effect of design descisions made back in the very first days of this code's life. i need to go through and see where i can bend those conventions a bit (where it won't break my other apps unduly). */ WhAjaj.Connector = function(opt) { if(WhAjaj.isObject(opt)) this.options = opt; //TODO?: this.$cache = {}; }; /** The core options used by WhAjaj.Connector instances for performing network operations. These options can (and some _should_) be changed by a client application. They can also be changed on specific instances of WhAjaj.Connector, but for most applications it is simpler to set them here and not have to bother with configuring each WhAjaj.Connector instance. Apps which use multiple back-ends at one time, however, will need to customize each instance for a given back-end. */ WhAjaj.Connector.options = { /** A (meaningless) prefix to apply to WhAjaj.Connector-generated request IDs. */ requestIdPrefix:'WhAjaj.Connector-', /** Default options for WhAjaj.Connector.sendRequest() connection parameters. This object holds only connection-related options and callbacks (all optional), and not options related to the required JSON structure of any given request. i.e. the page name used in a get-page request are not set here but are specified as part of the request object. These connection options are a "normalized form" of options often found in various AJAX libraries like jQuery, Prototype, dojo, etc. This approach allows us to swap out the real connection-related parts by writing a simple proxy which transforms our "normalized" form to the backend-specific form. For examples, see the various implementations stored in WhAjaj.Connector.sendImpls. The following callback options are, in practice, almost always set globally to some app-wide defaults: - onError() to report errors using a common mechanism. - beforeSend() to start a visual activity notification - afterSend() to disable the visual activity notification However, be aware that if any given WhAjaj.Connector instance is given its own before/afterSend callback then those will override these. Mixing shared/global and per-instance callbacks can potentially lead to confusing results if, e.g., the beforeSend() and afterSend() functions have side-effects but are not used with their proper before/after partner. TODO: rename this to 'ajaj' (the name is historical). The problem with renaming it is is that the word 'ajax' is pretty prevelant in the source tree, so i can't globally swap it out. */ ajax: { /** URL of the back-end server/CGI. */ url: '/some/path', /** Connection method. Some connection-related functions might override any client-defined setting. Must be one of 'GET' or 'POST'. For custom connection implementation, it may optionally be some implementation-specified value. Normally the API can derive this value automatically - if the request uses JSON data it is POSTed, else it is GETted. */ method:'GET', /** A hint whether to run the operation asynchronously or not. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. Interestingly, at least one popular AJAX toolkit does not document supporting _synchronous_ AJAX operations. All common browser-side implementations support async operation, but non-browser implementations might not. */ asynchronous:true, /** A HTTP authentication login name for the AJAX connection. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. */ loginName:undefined, /** An HTTP authentication login password for the AJAJ connection. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. */ loginPassword:undefined, /** A connection timeout, in milliseconds, for establishing an AJAJ connection. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. */ timeout:10000, /** If an AJAJ request receives JSON data from the back-end, that data is passed as a plain Object as the response parameter (exception: in jsonp mode it is passed a string (why???)). The initiating request object is passed as the second parameter, but clients can normally ignore it (only those which need a way to map specific requests to responses will need it). The 3rd parameter is the same as the 'this' object for the context of the callback, but is provided because the instance-level callbacks (set in (WhAjaj.Connector instance).callbacks, require it in some cases (because their 'this' is different!). Note that the response might contain error information which comes from the back-end. The difference between this error info and the info passed to the onError() callback is that this data indicates an application-level error, whereas onError() is used to report connection-level problems or when the backend produces non-JSON data (which, when not in jsonp mode, is unexpected and is as fatal to the request as a connection error). */ onResponse: function(response, request, opt){}, /** If an AJAX request fails to establish a connection or it receives non-JSON data from the back-end, this function is called (e.g. timeout error or host name not resolvable). It is passed the originating request and the "normalized" connection parameters used for that request. The connectOpt object "should" (or "might") have an "errorMessage" property which describes the nature of the problem. Clients will almost always want to replace the default implementation with something which integrates into their application. */ onError: function(request, connectOpt) { alert('AJAJ request failed:\n' +'Connection information:\n' +JSON.stringify(connectOpt,0,4) ); }, /** Called before each connection attempt is made. Clients can use this to, e.g., enable a visual "network activity notification" for the user. It is passed the original request object and the normalized connection parameters for the request. If this function changes opt, those changes _are_ applied to the subsequent request. If this function throws, neither the onError() nor afterSend() callbacks are triggered and WhAjaj.Connector.sendImpl() propagates the exception back to the caller. */ beforeSend: function(request,opt){}, /** Called after an AJAJ connection attempt completes, regardless of success or failure. Passed the same parameters as beforeSend() (see that function for details). Here's an example of setting up a visual notification on ajax operations using jQuery (but it's also easy to do without jQuery as well): @code function startAjaxNotif(req,opt) { var me = arguments.callee; var c = ++me.ajaxCount; me.element.text( c + " pending AJAX operation(s)..." ); if( 1 == c ) me.element.stop().fadeIn(); } startAjaxNotif.ajaxCount = 0. startAjaxNotif.element = jQuery('#whikiAjaxNotification'); function endAjaxNotif() { var c = --startAjaxNotif.ajaxCount; startAjaxNotif.element.text( c+" pending AJAX operation(s)..." ); if( 0 == c ) startAjaxNotif.element.stop().fadeOut(); } @endcode Set the beforeSend/afterSend properties to those functions to enable the notifications by default. */ afterSend: function(request,opt){}, /** If jsonp is a string then the WhAjaj-internal response handling code ASSUMES that the response contains a JSONP-style construct and eval()s it after afterSend() but before onResponse(). In this case, onResponse() will get a string value for the response instead of a response object parsed from JSON. */ jsonp:undefined, /** Don't use yet. Planned future option. */ propagateExceptions:false } }; /** WhAjaj.Connector.prototype.callbacks defines callbacks analog to the onXXX callbacks defined in WhAjaj.Connector.options.ajax, with two notable differences: 1) these callbacks, if set, are called in addition to any request-specific callback. The intention is to allow a framework to set "framework-level" callbacks which should be called independently of the request-specific callbacks (without interfering with them, e.g. requiring special re-forwarding features). 2) The 'this' object in these callbacks is the Connector instance associated with the callback, whereas the "other" onXXX form has its "ajax options" object as its this. When this API says that an onXXX callback will be called for a request, both the request's onXXX (if set) and this one (if set) will be called. */ WhAjaj.Connector.prototype.callbacks = {}; /** Instance-specific values for AJAJ-level properties (as opposed to application-level request properties). Options set here "override" those specified in WhAjaj.Connector.options.ajax and are "overridden" by options passed to sendRequest(). */ WhAjaj.Connector.prototype.options = {}; /** Tries to find the given key in any of the following, returning the first match found: opt, this.options, WhAjaj.Connector.options.ajax. Returns undefined if key is not found. */ WhAjaj.Connector.prototype.derivedOption = function(key,opt) { var v = opt ? opt[key] : undefined; if( undefined !== v ) return v; else v = this.options[key]; if( undefined !== v ) return v; else v = WhAjaj.Connector.options.ajax[key]; return v; }; /** Returns a unique string on each call containing a generic reandom request identifier string. This is not used by the core API but can be used by client code to generate unique IDs for each request (if needed). The exact format is unspecified and may change in the future. Request IDs can be used by clients to "match up" responses to specific requests if needed. In practice, however, they are seldom, if ever, needed. When passing several concurrent requests through the same response callback, it might be useful for some clients to be able to distinguish, possibly re-routing them through other handlers based on the originating request type. If this.options.requestIdPrefix or WhAjaj.Connector.options.requestIdPrefix is set then that text is prefixed to the returned string. */ WhAjaj.Connector.prototype.generateRequestId = function() { if( undefined === arguments.callee.sequence ) { arguments.callee.sequence = 0; } var pref = this.options.requestIdPrefix || WhAjaj.Connector.options.requestIdPrefix || ''; return pref + WhAjaj.msTimestamp() + '/'+(Math.round( Math.random() * 100000000) )+ ':'+(++arguments.callee.sequence); }; /** Copies (SHALLOWLY) all properties in opt to this.options. */ WhAjaj.Connector.prototype.addOptions = function(opt) { var k, v; for( k in opt ) { if( ! opt.hasOwnProperty(k) ) continue /* proactive Prototype kludge! */; this.options[k] = opt[k]; } return this.options; }; /** An internal helper object which holds several functions intended to simplify the creation of concrete communication channel implementations for WhAjaj.Connector.sendImpl(). These operations take care of some of the more error-prone parts of ensuring that onResponse(), onError(), etc. callbacks are called consistently using the same rules. */ WhAjaj.Connector.sendHelper = { /** opt is assumed to be a normalized set of WhAjaj.Connector.sendRequest() options. This function creates a url by concatenating opt.url and some form of opt.urlParam. If opt.urlParam is an object or string then it is appended to the url. An object is assumed to be a one-dimensional set of simple (urlencodable) key/value pairs, and not larger data structures. A string value is assumed to be a well-formed, urlencoded set of key/value pairs separated by '&' characters. The new/normalized URL is returned (opt is not modified). If opt.urlParam is not set then opt.url is returned (or an empty string if opt.url is itself a false value). TODO: if opt is-a Object and any key points to an array, build up a list of keys in the form "keyname[]". We could arguably encode sub-objects like "keyname[subkey]=...", but i don't know if that's conventions-compatible with other frameworks. */ normalizeURL: function(opt) { var u = opt.url || ''; if( opt.urlParam ) { var addQ = (u.indexOf('?') >= 0) ? false : true; var addA = addQ ? false : ((u.indexOf('&')>=0) ? true : false); var tail = ''; if( WhAjaj.isObject(opt.urlParam) ) { var li = [], k; for( k in opt.urlParam) { li.push( k+'='+encodeURIComponent( opt.urlParam[k] ) ); } tail = li.join('&'); } else if( 'string' === typeof opt.urlParam ) { tail = opt.urlParam; } u = u + (addQ ? '?' : '') + (addA ? '&' : '') + tail; } return u; }, /** Should be called by WhAjaj.Connector.sendImpl() implementations after a response has come back. This function takes care of most of ensuring that framework-level conventions involving WhAjaj.Connector.options.ajax properties are followed. The request argument must be the original request passed to the sendImpl() function. It may legally be null for GET requests. The opt object should be the normalized AJAX options used for the connection. The resp argument may be either a plain Object or a string (in which case it is assumed to be JSON). The 'this' object for this call MUST be a WhAjaj.Connector instance in order for callback processing to work properly. This function takes care of the following: - Calling opt.afterSend() - If resp is a string, de-JSON-izing it to an object. - Calling opt.onResponse() - Calling opt.onError() in several common (potential) error cases. - If resp is-a String and opt.jsonp then resp is assumed to be a JSONP-form construct and is eval()d BEFORE opt.onResponse() is called. It is arguable to eval() it first, but the logic integrates better with the non-jsonp handler. The sendImpl() should return immediately after calling this. The sendImpl() must call only one of onSendSuccess() or onSendError(). It must call one of them or it must implement its own response/error handling, which is not recommended because getting the documented semantics of the onError/onResponse/afterSend handling correct can be tedious. */ onSendSuccess:function(request,resp,opt) { var cb = this.callbacks || {}; if( WhAjaj.isFunction(cb.afterSend) ) { try {cb.afterSend( request, opt );} catch(e){} } if( WhAjaj.isFunction(opt.afterSend) ) { try {opt.afterSend( request, opt );} catch(e){} } function doErr(){ if( WhAjaj.isFunction(cb.onError) ) { try {cb.onError( request, opt );} catch(e){} } if( WhAjaj.isFunction(opt.onError) ) { try {opt.onError( request, opt );} catch(e){} } } if( ! resp ) { opt.errorMessage = "Sending of request succeeded but returned no data!"; doErr(); return false; } if( 'string' === typeof resp ) { try { resp = opt.jsonp ? eval(resp) : JSON.parse(resp); } catch(e) { opt.errorMessage = e.toString(); doErr(); return; } } try { if( WhAjaj.isFunction( cb.onResponse ) ) { cb.onResponse( resp, request, opt ); } if( WhAjaj.isFunction( opt.onResponse ) ) { opt.onResponse( resp, request, opt ); } return true; } catch(e) { opt.errorMessage = "Exception while handling inbound JSON response:\n" + e +"\nOriginal response data:\n"+JSON.stringify(resp,0,2) ; ; doErr(); return false; } }, /** Should be called by sendImpl() implementations after a response has failed to connect (e.g. could not resolve host or timeout reached). This function takes care of most of ensuring that framework-level conventions involving WhAjaj.Connector.options.ajax properties are followed. The request argument must be the original request passed to the sendImpl() function. It may legally be null for GET requests. The 'this' object for this call MUST be a WhAjaj.Connector instance in order for callback processing to work properly. The opt object should be the normalized AJAX options used for the connection. By convention, the caller of this function "should" set opt.errorMessage to contain a human-readable description of the error. The sendImpl() should return immediately after calling this. The return value from this function is unspecified. */ onSendError: function(request,opt) { var cb = this.callbacks || {}; if( WhAjaj.isFunction(cb.afterSend) ) { try {cb.afterSend( request, opt );} catch(e){} } if( WhAjaj.isFunction(opt.afterSend) ) { try {opt.afterSend( request, opt );} catch(e){} } if( WhAjaj.isFunction( cb.onError ) ) { try {cb.onError( request, opt );} catch(e) {/*ignore*/} } if( WhAjaj.isFunction( opt.onError ) ) { try {opt.onError( request, opt );} catch(e) {/*ignore*/} } } }; /** WhAjaj.Connector.sendImpls holds several concrete implementations of WhAjaj.Connector.prototype.sendImpl(). To use a specific implementation by default assign WhAjaj.Connector.prototype.sendImpl to one of these functions. The functions defined here require that the 'this' object be-a WhAjaj.Connector instance. Historical notes: a) We once had an implementation based on Prototype, but that library just pisses me off (they change base-most types' prototypes, introducing side-effects in client code which doesn't even use Prototype). The Prototype version at the time had a serious toJSON() bug which caused empty arrays to serialize as the string "[]", which broke a bunch of my code. (That has been fixed in the mean time, but i don't use Prototype.) b) We once had an implementation for the dojo library, If/when the time comes to add Prototype/dojo support, we simply need to port: http://code.google.com/p/jsonmessage/source/browse/trunk/lib/JSONMessage/JSONMessage.inc.js (search that file for "dojo" and "Prototype") to this tree. That code is this code's generic grandfather and they are still very similar, so a port is trivial. */ WhAjaj.Connector.sendImpls = { /** This is a concrete implementation of WhAjaj.Connector.prototype.sendImpl() which uses the environment's native XMLHttpRequest class to send whiki requests and fetch the responses. The only argument must be a connection properties object, as constructed by WhAjaj.Connector.normalizeAjaxParameters(). If window.firebug is set then window.firebug.watchXHR() is called to enable monitoring of the XMLHttpRequest object. This implementation honors the loginName and loginPassword connection parameters. Returns the XMLHttpRequest object. This implementation requires that the 'this' object be-a WhAjaj.Connector. This implementation uses setTimeout() to implement the timeout support, and thus the JS engine must provide that functionality. */ XMLHttpRequest: function(request, args) { var json = WhAjaj.isObject(request) ? JSON.stringify(request) : request; var xhr = new XMLHttpRequest(); var startTime = (new Date()).getTime(); var timeout = args.timeout || 10000/*arbitrary!*/; var hitTimeout = false; var done = false; var tmid /* setTimeout() ID */; var whself = this; function handleTimeout() { hitTimeout = true; if( ! done ) { var now = (new Date()).getTime(); try { xhr.abort(); } catch(e) {/*ignore*/} // see: http://www.w3.org/TR/XMLHttpRequest/#the-abort-method args.errorMessage = "Timeout of "+timeout+"ms reached after "+(now-startTime)+"ms during AJAX request."; WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); } return; } function onStateChange() { // reminder to self: apparently 'this' is-not-a XHR :/ if( hitTimeout ) { /* we're too late - the error was already triggered. */ return; } if( 4 == xhr.readyState ) { done = true; if( tmid ) { clearTimeout( tmid ); tmid = null; } if( (xhr.status >= 200) && (xhr.status < 300) ) { WhAjaj.Connector.sendHelper.onSendSuccess.apply( whself, [request, xhr.responseText, args] ); return; } else { if( undefined === args.errorMessage ) { args.errorMessage = "Error sending a '"+args.method+"' AJAX request to " +"["+args.url+"]: " +"Status text=["+xhr.statusText+"]" ; WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); } else { /*maybe it was was set by the timeout handler. */ } return; } } }; xhr.onreadystatechange = onStateChange; if( ('undefined'!==(typeof window)) && ('firebug' in window) && ('watchXHR' in window.firebug) ) { /* plug in to firebug lite's XHR monitor... */ window.firebug.watchXHR( xhr ); } try { //alert( JSON.stringify( args )); function xhrOpen() { if( ('loginName' in args) && args.loginName ) { xhr.open( args.method, args.url, args.asynchronous, args.loginName, args.loginPassword ); } else { xhr.open( args.method, args.url, args.asynchronous ); } } if( json && ('POST' === args.method.toUpperCase()) ) { xhrOpen(); xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8"); // Google Chrome warns that it refuses to set these // "unsafe" headers (his words, not mine): // xhr.setRequestHeader("Content-length", json.length); // xhr.setRequestHeader("Connection", "close"); xhr.send( json ); } else /* assume GET */ { xhrOpen(); xhr.send(null); } tmid = setTimeout( handleTimeout, timeout ); return xhr; } catch(e) { args.errorMessage = e.toString(); WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); return undefined; } }/*XMLHttpRequest()*/, /** This is a concrete implementation of WhAjaj.Connector.prototype.sendImpl() which uses the jQuery AJAX API to send requests and fetch the responses. The first argument may be either null/false, an Object containing toJSON-able data to post to the back-end, or such an object in JSON string form. The second argument must be a connection properties object, as constructed by WhAjaj.Connector.normalizeAjaxParameters(). If window.firebug is set then window.firebug.watchXHR() is called to enable monitoring of the XMLHttpRequest object. This implementation honors the loginName and loginPassword connection parameters. Returns the XMLHttpRequest object. This implementation requires that the 'this' object be-a WhAjaj.Connector. */ jQuery:function(request,args) { var data = request || undefined; var whself = this; if( data ) { if('string'!==typeof data) { try { data = JSON.stringify(data); } catch(e) { WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); return; } } } var ajopt = { url: args.url, data: data, type: args.method, async: args.asynchronous, password: (undefined !== args.loginPassword) ? args.loginPassword : undefined, username: (undefined !== args.loginName) ? args.loginName : undefined, contentType: 'application/json; charset=utf-8', error: function(xhr, textStatus, errorThrown) { //this === the options for this ajax request args.errorMessage = "Error sending a '"+ajopt.type+"' request to ["+ajopt.url+"]: " +"Status text=["+textStatus+"]" +(errorThrown ? ("Error=["+errorThrown+"]") : "") ; WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); }, success: function(data) { WhAjaj.Connector.sendHelper.onSendSuccess.apply( whself, [request, data, args] ); }, /* Set dataType=text instead of json to keep jQuery from doing our carefully written response handling for us. */ dataType: 'text' }; if( undefined !== args.timeout ) { ajopt.timeout = args.timeout; } try { return jQuery.ajax(ajopt); } catch(e) { args.errorMessage = e.toString(); WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); return undefined; } }/*jQuery()*/, /** This is a concrete implementation of WhAjaj.Connector.prototype.sendImpl() which uses the rhino Java API to send requests and fetch the responses. Limitations vis-a-vis the interface: - timeouts are not supported. - asynchronous mode is not supported because implementing it requires the ability to kill a running thread (which is deprecated in the Java API). TODOs: - add socket timeouts. - support HTTP proxy. The Java APIs support this, it just hasn't been added here yet. */ rhino:function(request,args) { var self = this; var data = request || undefined; if( data ) { if('string'!==typeof data) { try { data = JSON.stringify(data); } catch(e) { WhAjaj.Connector.sendHelper.onSendError.apply( self, [request, args] ); return; } } } var url; var con; var IO = new JavaImporter(java.io); var wr; var rd, ln, json = []; function setIncomingCookies(list){ if(!list || !list.length) return; if( !self.cookies ) self.cookies = {}; var k, v, i; for( i = 0; i < list.length; ++i ){ v = list[i].split('=',2); k = decodeURIComponent(v[0]) v = v[0] ? decodeURIComponent(v[0].split(';',2)[0]) : null; //print("RECEIVED COOKIE: "+k+"="+v); if(!v) { delete self.cookies[k]; continue; }else{ self.cookies[k] = v; } } }; function setOutboundCookies(conn){ if(!self.cookies) return; var k, v; for( k in self.cookies ){ if(!self.cookies.hasOwnProperty(k)) continue /*kludge for broken JS libs*/; v = self.cookies[k]; conn.addRequestProperty("Cookie", encodeURIComponent(k)+'='+encodeURIComponent(v)); //print("SENDING COOKIE: "+k+"="+v); } }; try{ url = new java.net.URL( args.url ) con = url.openConnection(/*FIXME: add proxy support!*/); con.setRequestProperty("Accept-Charset","utf-8"); setOutboundCookies(con); if(data){ con.setRequestProperty("Content-Type","application/json; charset=utf-8"); con.setDoOutput( true ); wr = new IO.OutputStreamWriter(con.getOutputStream()) wr.write(data); wr.flush(); wr.close(); wr = null; //print("POSTED: "+data); } rd = new IO.BufferedReader(new IO.InputStreamReader(con.getInputStream())); //var skippedHeaders = false; while ((line = rd.readLine()) !== null) { //print("LINE: "+line); //if(!line.length && !skippedHeaders){ // skippedHeaders = true; // json = []; // continue; //} json.push(line); } setIncomingCookies(con.getHeaderFields().get("Set-Cookie")); }catch(e){ args.errorMessage = e.toString(); WhAjaj.Connector.sendHelper.onSendError.apply( self, [request, args] ); return undefined; } try { if(wr) wr.close(); } catch(e) { /*ignore*/} try { if(rd) rd.close(); } catch(e) { /*ignore*/} json = json.join(''); //print("READ IN JSON: "+json); WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] ); }/*rhino*/ }; /** An internal function which takes an object containing properties for a WhAjaj.Connector network request. This function creates a new object containing a superset of the properties from: a) opt b) this.options c) WhAjaj.Connector.options.ajax in that order, using the first one it finds. All non-function properties are _deeply_ copied via JSON cloning in order to prevent accidental "cross-request pollenation" (been there, done that). Functions cannot be cloned and are simply copied by reference. This function throws if JSON-copying one of the options fails (e.g. due to cyclic data structures). Reminder to self: this function does not "normalize" opt.urlParam by encoding it into opt.url, mainly for historical reasons, but also because that behaviour was specifically undesirable in this code's genetic father. */ WhAjaj.Connector.prototype.normalizeAjaxParameters = function (opt) { var rc = {}; function merge(k,v) { if( rc.hasOwnProperty(k) ) return; else if( WhAjaj.isFunction(v) ) {} else if( WhAjaj.isObject(v) ) v = JSON.parse( JSON.stringify(v) ); rc[k]=v; } function cp(obj) { if( ! WhAjaj.isObject(obj) ) return; var k; for( k in obj ) { if( ! obj.hasOwnProperty(k) ) continue /* i will always hate the Prototype designers for this. */; merge(k, obj[k]); } } cp( opt ); cp( this.options ); cp( WhAjaj.Connector.options.ajax ); // no, not here: rc.url = WhAjaj.Connector.sendHelper.normalizeURL(rc); return rc; }; /** This is the generic interface for making calls to a back-end JSON-producing request handler. It is a simple wrapper around WhAjaj.Connector.prototype.sendImpl(), which just normalizes the connection options for sendImpl() and makes sure that opt.beforeSend() is (possibly) called. The request parameter must either be false/null/empty or a fully-populated JSON-able request object (which will be sent as unencoded application/json text), depending on the type of request being made. It is never semantically legal (in this API) for request to be a string/number/true/array value. As a rule, only POST requests use the request data. GET requests should encode their data in opt.url or opt.urlParam (see below). opt must contain the network-related parameters for the request. Paramters _not_ set in opt are pulled from this.options or WhAjaj.Connector.options.ajax (in that order, using the first value it finds). Thus the set of connection-level options used for the request are a superset of those various sources. The "normalized" (or "superimposed") opt object's URL may be modified before the request is sent, as follows: if opt.urlParam is a string then it is assumed to be properly URL-encoded parameters and is appended to the opt.url. If it is an Object then it is assumed to be a one-dimensional set of key/value pairs with simple values (numbers, strings, booleans, null, and NOT objects/arrays). The keys/values are URL-encoded and appended to the URL. The beforeSend() callback (see below) can modify the options object before the request attempt is made. The callbacks in the normalized opt object will be triggered as follows (if they are set to Function values): - beforeSend(request,opt) will be called before any network processing starts. If beforeSend() throws then no other callbacks are triggered and this function propagates the exception. This function is passed normalized connection options as its second parameter, and changes this function makes to that object _will_ be used for the pending connection attempt. - onError(request,opt) will be called if a connection to the back-end cannot be established. It will be passed the original request object (which might be null, depending on the request type) and the normalized options object. In the error case, the opt object passed to onError() "should" have a property called "errorMessage" which contains a description of the problem. - onError(request,opt) will also be called if connection succeeds but the response is not JSON data. - onResponse(response,request) will be called if the response returns JSON data. That data might hold an error response code - clients need to check for that. It is passed the response object (a plain object) and the original request object. - afterSend(request,opt) will be called directly after the AJAX request is finished, before onError() or onResonse() are called. Possible TODO: we explicitly do NOT pass the response to this function in order to keep the line between the responsibilities of the various callback clear (otherwise this could be used the same as onResponse()). In practice it would sometimes be useful have the response passed to this function, mainly for logging/debugging purposes. The return value from this function is meaningless because AJAX operations tend to take place asynchronously. */ WhAjaj.Connector.prototype.sendRequest = function(request,opt) { if( !WhAjaj.isFunction(this.sendImpl) ) { throw new Error("This object has no sendImpl() member function! I don't know how to send the request!"); } var ex = false; var av = Array.prototype.slice.apply( arguments, [0] ); /** FIXME: how to handle the error, vis-a-vis- the callbacks, if normalizeAjaxParameters() throws? It can throw if (de)JSON-izing fails. */ var norm = this.normalizeAjaxParameters( WhAjaj.isObject(opt) ? opt : {} ); norm.url = WhAjaj.Connector.sendHelper.normalizeURL(norm); if( ! request ) norm.method = 'GET'; var cb = this.callbacks || {}; if( this.callbacks && WhAjaj.isFunction(this.callbacks.beforeSend) ) { this.callbacks.beforeSend( request, norm ); } if( WhAjaj.isFunction(norm.beforeSend) ){ norm.beforeSend( request, norm ); } //alert( WhAjaj.stringify(request)+'\n'+WhAjaj.stringify(norm)); try { this.sendImpl( request, norm ); } catch(e) { ex = e; } if(ex) throw ex; }; /** sendImpl() holds a concrete back-end connection implementation. It can be replaced with a custom implementation if one follows the rules described throughout this API. See WhAjaj.Connector.sendImpls for the concrete implementations included with this API. */ //WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.XMLHttpRequest; //WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.rhino; //WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.jQuery; if( 'undefined' !== typeof jQuery ){ WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.jQuery; } else { WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.XMLHttpRequest; } |
Added ajax/wiki-editor.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Fossil/JSON Wiki Editor Prototype</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript" src="js/whajaj.js"></script> <script type="text/javascript" src="js/fossil-ajaj.js"></script> <style type='text/css'> th { text-align: left; background-color: #ececec; } .dangerWillRobinson { background-color: yellow; } .wikiPageLink { text-decoration: underline; } </style> <script type='text/javascript'> WhAjaj.Connector.options.ajax.url = /* Change this to your CGI/server root path: */ //'http://fjson/cgi-bin/fossil.cgi' //'/repos/fossil-sgb/json.cgi' '/cgi-bin/fossil-json.cgi' ; var TheApp = { response:null, sessionID:null, jqe:{}/*jqe==jQuery Elements*/, ajaxCount:0, cgi: new FossilAjaj(), pages:{} }; TheApp.startAjaxNotif = function() { ++this.ajaxCount; TheApp.jqe.responseContainer.removeClass('dangerWillRobinson'); this.jqe.ajaxNotification.attr( 'title', this.ajaxCount+" pending AJAX operation(s)..." ); if( 1 == this.ajaxCount ) this.jqe.ajaxNotification.fadeIn(); }; TheApp.endAjaxNotif = function() { --this.ajaxCount; this.jqe.ajaxNotification.attr( 'title', this.ajaxCount+" pending AJAX operation(s)..." ); if( 0 == this.ajaxCount ) this.jqe.ajaxNotification.fadeOut(); }; TheApp.responseContainsError = function(resp) { if( !resp || resp.resultCode ) { //alert("Error response:\n"+JSON.stringify(resp,0,4)); TheApp.jqe.taResponse.val( "RESPONSE CONTAINS ERROR INFO:\n"+WhAjaj.stringify(resp) ); //TheApp.jqe.responseContainer.css({backgroundColor:'yellow'}); //TheApp.jqe.responseContainer.addClass('dangerWillRobinson'); TheApp.jqe.responseContainer.flash( '255,0,0', 1500 ); return true; } return false; }; TheApp.sendRequest = function() { var path = this.jqe.textPath.val(); var self = this; var data = this.jqe.pageListArea.val(); var doPost = (data && data.length); var req; if( doPost ) try { req = JSON.parse(data); } catch(e) { TheApp.jqe.taResponse.val("Request is not valid JSON.\n"+e); return; } if( req ) { req.requestId = this.cgi.generateRequestId(); } var self = this; var opt = { url: WhAjaj.Connector.options.ajax.url + path, method: doPost ? 'POST' : 'GET' }; this.cgi.sendRequest( req, opt ); }; jQuery.fn.animateHighlight = function(highlightColor, duration) { var highlightBg = highlightColor || "#FFFF9C"; var animateMs = duration || 1500; var originalBg = this.css("backgroundColor"); this.stop().css("background-color", highlightBg).animate({backgroundColor: originalBg}, animateMs); }; jQuery.fn.flash = function( color, duration ) { var current = this.css( 'color' ); this.animate( { color: 'rgb(' + color + ')' }, duration / 2); this.animate( { color: current }, duration / 2 ); }; jQuery(document).ready(function(){ var ids = [ 'btnSend', 'ajaxNotification', 'currentAuthToken', 'responseContainer', 'spanPageName', 'pageListArea', 'taPageContent', 'taResponse', 'textPath', // list of HTML element IDs we use often. 'timer' ]; var i, k; for( i = 0; i < ids.length; ++i ) { k = ids[i]; TheApp.jqe[k] = jQuery('#'+k); } TheApp.jqe.textPath. keyup(function(event){ if(event.keyCode == 13){ TheApp.sendRequest(); } }); TheApp.timer = { _tstart:0,_tend:0,duration:0, start:function(){ this._tstart = (new Date()).getTime(); }, end:function(){ this._tend = (new Date()).getTime(); return this.duration = this._tend - this._tstart; } }; var ajcb = TheApp.cgi.ajaj.callbacks; ajcb.beforeSend = TheApp.beforeSend = function(req,opt) { TheApp.timer.start(); var val = req ? (('string'===typeof req) ? req : WhAjaj.stringify(req)) : ''; TheApp.jqe.taResponse.val(''); TheApp.startAjaxNotif(); }; ajcb.afterSend = TheApp.afterSend = function(req,opt) { TheApp.timer.end(); TheApp.endAjaxNotif(); TheApp.jqe.timer.text( "(Round-trip time: "+TheApp.timer.duration+'ms)' ); }; ajcb.onResponse = TheApp.onResponse = function(resp,req) { var val; try { val = WhAjaj.stringify(resp); } catch(e) { val = WhAjaj.stringify(e) } if(resp.resultCode){ alert("Response contains error info:\n"+val); } TheApp.jqe.taResponse.val( val ); }; ajcb.onError = function(req,opt) { TheApp.jqe.taResponse.val( "ERROR SENDING REQUEST:\n"+WhAjaj.stringify(opt) ); }; TheApp.jqe.taPageContent.blur(function(){ var p = TheApp.currentPage; if(! p ) return; p.content = TheApp.jqe.taPageContent.val(); }); TheApp.cgi.onLogin = function(){ TheApp.jqe.taResponse.val( "Logged in: "+WhAjaj.stringify(this.auth)); TheApp.jqe.currentAuthToken.text("Logged in: "+WhAjaj.stringify(this.auth)); }; TheApp.cgi.onLogout = function(){ TheApp.jqe.taResponse.val( "Logged out!" ); TheApp.jqe.currentAuthToken.text(""); }; TheApp.showPage = function(name){ function doShow(page){ TheApp.currentPage = page; TheApp.jqe.spanPageName.text('('+page.name+')'); TheApp.jqe.taPageContent.val(page.content); } var p = ('object' === typeof name) ? name : TheApp.pages[name]; if(('object' === typeof p) && p.content) { doShow(p); return; } TheApp.cgi.sendCommand('/json/wiki/get',{ name:name },{ onResponse:function(resp,req){ TheApp.onResponse(resp,req); if(resp.resultCode) return; var p = resp.payload; doShow( TheApp.pages[p.name] = p ); } }); }; TheApp.refreshPageListView = function(){ var list = (function(){ var k, v, li = []; for( k in TheApp.pages ){ if(!TheApp.pages.hasOwnProperty(k)) continue; li.push(k); } return li; })(); var i, p, a, tgt = TheApp.jqe.pageListArea; tgt.text(''); function makeLink(name){ var link = jQuery('<span></span>'); link.text(name); link.addClass('wikiPageLink'); link.click(function(e){ TheApp.showPage(name); e.preventDefault(); return false; }); return link; } list.sort(); for( i = 0; i < list.length; ++i ){ tgt.append(makeLink(list[i])); tgt.append('<br/>'); } }; TheApp.loadPageList = function(){ TheApp.cgi.sendCommand('/json/wiki/list',null,{ onResponse:function(resp,req){ TheApp.onResponse(resp,req); if(resp.resultCode) return; var i, v, p, ar = resp.payload; for( i = 0; i < ar.length; ++i ){ v = ar[i]; p = TheApp.pages[v]; if( !p ) TheApp.pages[v] = {name:v}; } TheApp.refreshPageListView(); } }); return false /*for click handlers*/; } TheApp.savePage = function(p){ p = p || TheApp.currentPage; if( 'object' !== typeof p ){ p = TheApp.pages[p]; } if('object' !== typeof p){ alert("savePage() argument is not a page object or known page name."); } TheApp.pages[p.name] = p; p.content = TheApp.jqe.taPageContent.val(); var req = { name:p.name, content:p.content }; if(! confirm("Really save wiki page ["+p.name+"]?") ) return; TheApp.cgi.sendCommand('/json/wiki/'+(p.isNew?'create':'save'),req,{ onResponse:function(resp,req){ TheApp.onResponse(resp,req); if(resp.resultCode) return; delete p.isNew; p.timestamp = resp.payload.timestamp; } }); }; TheApp.createNewPage = function(){ var name = prompt("New page name?"); if(!name) return; var p = { name:name, content:"New, empty page.", isNew:true }; TheApp.pages[name] = p; TheApp.refreshPageListView(); TheApp.showPage(p); /* if(! confirm("Really create new wiki page ["+name+"]?") ) return; TheApp.cgi.sendCommand('/json/wiki/create',req,{ onResponse:function(resp,req){ TheApp.onResponse(resp,req); if(resp.resultCode) return; TheApp.pages[p.name] = p; TheApp.refreshPageListView(); } }); */ }; TheApp.cgi.whoami(); }); </script> </head> <body> <span id='ajaxNotification'></span> <h1>PROTOTYPE JSON-based Fossil Wiki Editor</h1> See also: <a href='index.html'>main test page</a>. <br> <b>Login:</b> <br/> <input type='button' value='Anon. Login' onclick='TheApp.cgi.login()' /> or: name:<input type='text' id='textUser' value='json-demo' size='12'/> pw:<input type='password' id='textPassword' value='json-demo' size='12'/> <input type='button' value='login' onclick='TheApp.cgi.login(jQuery("#textUser").val(),jQuery("#textPassword").val(),{onResponse:TheApp.onLogin})' /> <input type='button' value='logout' onclick='TheApp.cgi.logout()' /> <br/> <span id='currentAuthToken' style='font-family:monospaced'></span> <hr/> <strong>Quick-posts:</strong><br/> <input type='button' value='HAI' onclick='TheApp.cgi.HAI()' /> <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat")' /> <input type='button' value='whoami' onclick='TheApp.cgi.whoami()' /> <input type='button' value='wiki/list' onclick='TheApp.loadPageList()' /> <!-- <input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci")' /> --> <!-- <input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' /> <input type='button' value='get more' onclick='TheApp.cgi.getPages("HelloWorld/WhikiNews")' /> <input type='button' value='get client data' onclick='TheApp.cgi.getPageClientData("HelloWorld/whiki/WhikiCommands")' /> <input type='button' value='save client data' onclick='TheApp.cgi.savePageClientData({"HelloWorld":[1,3,5]})' /> --> <hr/> <table> <tr> <th>Page List</th> <th>Content <span id='spanPageName'></span></th> </tr> <tr> <td width='25%' valign='top'> <input type='button' value='Create new...' onclick='TheApp.createNewPage()' /><br/> <div id='pageListArea'></div> </td> <td width='75%' valign='top'> <input type='button' value='Save' onclick='TheApp.savePage()' /><br/> <textarea id='taPageContent' rows='20' cols='60'></textarea> </td> </tr> <tr> <th colspan='2'>Response <span id='timer'></span></th> </tr> <tr> <td colspan='2' id='responseContainer'> <textarea id='taResponse' rows='20' cols='80' readonly></textarea> </td> </tr> </table> <div></div> <div></div> <div></div> </body></html> |
Added art/CollRev1.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="15,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.95,12.95;20.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="15,13"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="5"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="16.2733,14.064"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="16.2733,13.5215;18.7096,14.4615"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="16.2733,14.064"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="15,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.95,6.95;20.05,9.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="15,7"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="5"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="17.0039,8.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.0039,7.52147;17.979,8.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#File#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="17.0039,8.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="15,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.95,0.95;20.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="15,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="5"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="16.4942,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="16.4942,1.52147;18.4887,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Project#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="16.4942,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - ZigZagLine" version="1" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="17.5,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.45,8.92929;17.55,13"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="17.5,13"/> <dia:point val="17.5,13"/> <dia:point val="17.5,9"/> <dia:point val="17.5,9"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="17.5,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.45,2.92929;17.55,7"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="17.5,7"/> <dia:point val="17.5,7"/> <dia:point val="17.5,3"/> <dia:point val="17.5,3"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Box" version="0" id="O8"> <dia:attribute name="obj_pos"> <dia:point val="15,19"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.95,18.95;20.05,21.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="15,19"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="5"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O9"> <dia:attribute name="obj_pos"> <dia:point val="16.7775,20.064"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="16.7775,19.5215;18.2225,20.4615"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Meta#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="16.7775,20.064"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - PolyLine" version="0" id="O10"> <dia:attribute name="obj_pos"> <dia:point val="15,20"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="7.5,14.95;15.05,20.05"/> </dia:attribute> <dia:attribute name="poly_points"> <dia:point val="15,20"/> <dia:point val="8,20"/> <dia:point val="8,15"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O11"> <dia:attribute name="obj_pos"> <dia:point val="15,14"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="10.95,13.5;15.05,14.5"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="15,14"/> <dia:point val="11,14"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O12"> <dia:attribute name="obj_pos"> <dia:point val="20,20"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="19.95,1.5;27.05,20.05"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="20,20"/> <dia:point val="27,20"/> <dia:point val="27,2"/> <dia:point val="20,2"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="false"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O13"> <dia:attribute name="obj_pos"> <dia:point val="17.5,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17,14.95;18,19.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="17.5,15"/> <dia:point val="17.5,19"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - PolyLine" version="0" id="O14"> <dia:attribute name="obj_pos"> <dia:point val="8,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="7.95,1.5;15.05,13.05"/> </dia:attribute> <dia:attribute name="poly_points"> <dia:point val="8,13"/> <dia:point val="8,2"/> <dia:point val="15,2"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Box" version="0" id="O15"> <dia:attribute name="obj_pos"> <dia:point val="5,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,12.95;11.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,13"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O16"> <dia:attribute name="obj_pos"> <dia:point val="6.91375,14.0725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6.91375,13.53;9.08625,14.47"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Symbol#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6.91375,14.0725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Text" version="1" id="O17"> <dia:attribute name="obj_pos"> <dia:point val="18,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18,11.4575;21.06,12.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="18,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O18"> <dia:attribute name="obj_pos"> <dia:point val="18,6"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18,5.4575;21.06,6.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="18,6"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O19"> <dia:attribute name="obj_pos"> <dia:point val="18,16"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18,15.4575;19.03,16.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#has#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="18,16"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O20"> <dia:attribute name="obj_pos"> <dia:point val="21,20"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="21,19.4575;24.06,20.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="21,20"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O21"> <dia:attribute name="obj_pos"> <dia:point val="11,20"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="11,19.4575;14.06,20.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="11,20"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O22"> <dia:attribute name="obj_pos"> <dia:point val="12,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12,14.4575;15.06,15.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="12,15"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O23"> <dia:attribute name="obj_pos"> <dia:point val="9,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="9,11.4575;12.06,12.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="9,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O24"> <dia:attribute name="obj_pos"> <dia:point val="1,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1,12.4575;10.5175,13.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#(Line of Development / Branch)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="1,13"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:layer> </dia:diagram> |
Added art/CollRev2.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="13,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12.95,0.95;20.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="13,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="7"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="15.2818,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="15.2818,1.52147;17.7182,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="15.2818,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="13,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12.95,6.95;20.05,9.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="13,7"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="7"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="14.1456,8.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.1456,7.52147;18.8544,8.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision' (Child)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14.1456,8.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="2,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.95,1.95;9.05,4.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="2,2"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="7"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="5.00393,3.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.00393,2.52147;5.97901,3.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#File#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.00393,3.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Line" version="0" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="13,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.83023,6.5028;13.0606,8.06063"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="13,8"/> <dia:point val="9,7"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="13,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.83023,1.93937;13.0606,3.4972"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="13,2"/> <dia:point val="9,3"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O8"> <dia:attribute name="obj_pos"> <dia:point val="13,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.57833,1.92972;13.0703,7.35139"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="13,2"/> <dia:point val="9,7"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O9"> <dia:attribute name="obj_pos"> <dia:point val="13,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.57833,2.64861;13.0703,8.07028"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="13,8"/> <dia:point val="9,3"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Box" version="0" id="O10"> <dia:attribute name="obj_pos"> <dia:point val="2,6"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.95,5.95;9.05,8.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="2,6"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="7"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O11"> <dia:attribute name="obj_pos"> <dia:point val="3.53147,6.6725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="3.53147,6.13;7.45147,7.87"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Line of Development#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="3.53147,6.6725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Text" version="1" id="O12"> <dia:attribute name="obj_pos"> <dia:point val="18,6"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18,5.4575;20.0947,6.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># parent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="18,6"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O13"> <dia:attribute name="obj_pos"> <dia:point val="18,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.5,2.95;18.5,7.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="18,7"/> <dia:point val="18,3"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Text" version="1" id="O14"> <dia:attribute name="obj_pos"> <dia:point val="22,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="22,6.4575;28.4122,8.1975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#branch parent symbol (NULL)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="22,7"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O15"> <dia:attribute name="obj_pos"> <dia:point val="20,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="19.95,7.5;22.05,8.5"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="20,8"/> <dia:point val="22,8"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Polygon" version="0" id="O16"> <dia:attribute name="obj_pos"> <dia:point val="23,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="21.9293,6.87929;23.05,9.12071"/> </dia:attribute> <dia:attribute name="poly_points"> <dia:point val="23,7"/> <dia:point val="22,8"/> <dia:point val="23,9"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Text" version="1" id="O17"> <dia:attribute name="obj_pos"> <dia:point val="15,4"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="15,3.4575;16.57,4.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># child#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="15,4"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O18"> <dia:attribute name="obj_pos"> <dia:point val="15,3"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.5,2.95;15.5,7.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="15,3"/> <dia:point val="15,7"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> </dia:group> </dia:layer> </dia:diagram> |
Added art/CollRev3.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:object type="Standard - Text" version="1" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="7,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="7,14.6;7,15.8"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>##</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="7,15"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Box" version="0" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="13,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12.95,0.95;19.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="13,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="14.04,1.66397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.04,1.12147;17.96,2.86147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Line of Development#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14.04,1.66397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="3,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.95,0.95;9.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="3,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="4.04,1.66397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.04,1.12147;7.96,2.86147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Line' of Development#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="4.04,1.66397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="3,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.95,12.95;9.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="3,13"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="3.94,13.664"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="3.94,13.1215;8.06,14.8615"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision'' (Branch Start)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="3.94,13.664"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="13,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12.95,6.95;19.05,9.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="13,7"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O8"> <dia:attribute name="obj_pos"> <dia:point val="14.7733,8.0725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.7733,7.53;17.2096,8.47"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14.7733,8.0725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O9"> <dia:attribute name="obj_pos"> <dia:point val="23,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="22.95,12.95;29.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="23,13"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O10"> <dia:attribute name="obj_pos"> <dia:point val="25.5039,14.0725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="25.5039,13.53;26.479,14.47"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#File#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="25.5039,14.0725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O11"> <dia:attribute name="obj_pos"> <dia:point val="13,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12.95,12.95;19.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="13,13"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O12"> <dia:attribute name="obj_pos"> <dia:point val="14.6933,13.6725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.6933,13.13;17.2896,14.87"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision' (Child)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14.6933,13.6725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Line" version="0" id="O13"> <dia:attribute name="obj_pos"> <dia:point val="19,14"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18.95,13.5;23.05,14.5"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="19,14"/> <dia:point val="23,14"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O14"> <dia:attribute name="obj_pos"> <dia:point val="6,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.5,2.95;6.5,13.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="6,13"/> <dia:point val="6,3"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O15"> <dia:attribute name="obj_pos"> <dia:point val="18,9"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.5,8.95;18.5,13.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="18,9"/> <dia:point val="18,13"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O16"> <dia:attribute name="obj_pos"> <dia:point val="16,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="15.5,2.95;16.5,7.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="16,7"/> <dia:point val="16,3"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O17"> <dia:attribute name="obj_pos"> <dia:point val="14,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="13.5,8.95;14.5,13.05"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="14,13"/> <dia:point val="14,9"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O18"> <dia:attribute name="obj_pos"> <dia:point val="9,14"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.95,7.5;13.05,14.05"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="9,14"/> <dia:point val="11,14"/> <dia:point val="11,8"/> <dia:point val="13,8"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O19"> <dia:attribute name="obj_pos"> <dia:point val="6,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.95,14.95;26.5,17.05"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="6,15"/> <dia:point val="6,17"/> <dia:point val="26,17"/> <dia:point val="26,15"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="1"/> <dia:enum val="0"/> <dia:enum val="1"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="false"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O20"> <dia:attribute name="obj_pos"> <dia:point val="19,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18.95,7.95;26.5,13.05"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="19,8"/> <dia:point val="26,8"/> <dia:point val="26,13"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O21"> <dia:attribute name="obj_pos"> <dia:point val="6,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6,11.4575;8.2125,13.1975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># branch parent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O22"> <dia:attribute name="obj_pos"> <dia:point val="14,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14,11.4575;16.0947,12.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># parent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O23"> <dia:attribute name="obj_pos"> <dia:point val="18,10"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18,9.4575;19.57,10.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># child#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="18,10"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O24"> <dia:attribute name="obj_pos"> <dia:point val="19,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="19,6.52875;22.245,8.39875"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="19,7"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O25"> <dia:attribute name="obj_pos"> <dia:point val="6,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6,14.4575;9.245,16.1975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6,15"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O26"> <dia:attribute name="obj_pos"> <dia:point val="19,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="19,12.5288;22.245,14.3987"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="19,13"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O27"> <dia:attribute name="obj_pos"> <dia:point val="9,14"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="9,13.5288;11.0947,15.3987"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># parent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="9,14"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O28"> <dia:attribute name="obj_pos"> <dia:point val="3,14"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,1.5;3.05,14.05"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="3,14"/> <dia:point val="1,14"/> <dia:point val="1,2"/> <dia:point val="3,2"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="false"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O29"> <dia:attribute name="obj_pos"> <dia:point val="1,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1,11.4575;4.245,12.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># belongs to#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="1,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O30"> <dia:attribute name="obj_pos"> <dia:point val="10,2.12153"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="10,1.10403;12.205,2.86403"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#=/=#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="1.5"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="10,2.12153"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:layer> </dia:diagram> |
Added art/CollRev4.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="3,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.95,7.95;9.05,10.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="3,8"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="4.11647,8.66397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.11647,8.12147;7.86647,9.86147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision' (Child NTDB)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="4.11647,8.66397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,0.95;11.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="6.78184,1.6725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6.78184,1.13;9.21816,2.87"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision (NTDB)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6.78184,1.6725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="1,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,14.95;7.05,17.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,15"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="2.11647,15.664"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.11647,15.1215;5.86647,16.8615"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision'' (Child NTDB)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="2.11647,15.664"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="13,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="12.95,12.95;19.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="13,13"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="14.2915,13.664"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14.2915,13.1215;17.6915,14.8615"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Revision"" (non-NTDB)#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14.2915,13.664"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Line" version="0" id="O8"> <dia:attribute name="obj_pos"> <dia:point val="8,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="7.93501,2.76788;10.4828,8.06499"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="8,8"/> <dia:point val="10,3"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O9"> <dia:attribute name="obj_pos"> <dia:point val="6,3"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="3.51719,2.93501;6.06499,8.23212"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="6,3"/> <dia:point val="4,8"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O10"> <dia:attribute name="obj_pos"> <dia:point val="4,10"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.51719,9.93501;4.06499,15.2321"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="4,10"/> <dia:point val="2,15"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O11"> <dia:attribute name="obj_pos"> <dia:point val="6,15"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.93501,9.76788;8.48281,15.065"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="6,15"/> <dia:point val="8,10"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O12"> <dia:attribute name="obj_pos"> <dia:point val="16,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.70852,8.54107;16.0682,13.0682"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="16,13"/> <dia:point val="9,9"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O13"> <dia:attribute name="obj_pos"> <dia:point val="6,10"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.93178,9.93178;13.2915,14.4589"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="6,10"/> <dia:point val="13,14"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O14"> <dia:attribute name="obj_pos"> <dia:point val="6,14"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6,13.5288;8.27969,15.3987"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># parent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6,14"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O15"> <dia:attribute name="obj_pos"> <dia:point val="6,3"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6,2.4575;7.385,4.1975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># child#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6,3"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O16"> <dia:attribute name="obj_pos"> <dia:point val="4,10"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4,9.4575;5.385,11.1975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># child#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="4,10"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O17"> <dia:attribute name="obj_pos"> <dia:point val="15,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="15,11.5288;18.3897,13.3987"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># dbparent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="15,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O18"> <dia:attribute name="obj_pos"> <dia:point val="9,12"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="9,11.4575;11.865,12.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># dbchild#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="9,12"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O19"> <dia:attribute name="obj_pos"> <dia:point val="8,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8,6.4575;10.2797,8.1975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string># parent#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="8,7"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:layer> </dia:diagram> |
Added art/branching.odp.
cannot compute difference between binary files
Added art/concept1.dia.
cannot compute difference between binary files
Added art/concept2.dia.
cannot compute difference between binary files
Added art/delta1.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,0.95;5.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="2,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2,1.4575;4.12,2.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Header#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="2,2"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,0.95;9.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="5.53022,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.53022,1.4575;8.45272,2.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Segments#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.53022,2"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="9,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.95,0.95;13.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="9,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="10,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="10,1.4575;11.7893,2.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Trailer#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="10,2"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> </dia:layer> </dia:diagram> |
Added art/delta2.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="4,7"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="3.95,6.95;9.05,9.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="4,7"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="5"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="4.73538,8.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.73538,7.52147;8.24757,8.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Copy Range#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="4.73538,8.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="4,4"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="3.95,3.95;9.05,6.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="4,4"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="5"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="4.64772,5.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.64772,4.52147;8.33522,5.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Insert Literal#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="4.64772,5.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - ZigZagLine" version="1" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="2.5,3"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.45,2.95;4.05,5.5"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="2.5,3"/> <dia:point val="2.5,5"/> <dia:point val="4,5"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="2.5,3"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.45,2.95;4.05,8.5"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="2.5,3"/> <dia:point val="2.5,8"/> <dia:point val="4,8"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Box" version="0" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,0.95;2.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Box" version="0" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="2,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.95,0.95;3.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="2,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Box" version="0" id="O8"> <dia:attribute name="obj_pos"> <dia:point val="3,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.95,0.95;4.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="3,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Box" version="0" id="O9"> <dia:attribute name="obj_pos"> <dia:point val="7,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6.95,0.95;8.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="7,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O10"> <dia:attribute name="obj_pos"> <dia:point val="5,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5,1.52147;5.8775,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#***#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> </dia:layer> </dia:diagram> |
Added art/delta3.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,0.95;5.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="1.98659,2.0725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.98659,1.53;3.99635,2.47"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Length#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="1.98659,2.0725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,0.95;7.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="5.43272,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.43272,1.52147;6.55022,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#"@"#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.43272,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="7,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6.95,0.95;11.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="7,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="8.12625,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.12625,1.52147;9.87375,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Offset#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="8.12625,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="11,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="10.95,0.95;13.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="11,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="11.64,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="11.64,1.52147;12.36,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#","#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="11.64,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> </dia:layer> </dia:diagram> |
Added art/delta4.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,0.95;5.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="1.98659,2.0725"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.98659,1.53;3.99636,2.47"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Length#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="1.98659,2.0725"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="7,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6.95,0.95;11.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="7,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="8.18375,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="8.18375,1.52147;9.81625,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Bytes#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="8.18375,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,0.95;7.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="5.63375,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.63375,1.52147;6.36625,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#":"#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.63375,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> </dia:layer> </dia:diagram> |
Added art/delta5.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,0.95;7.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="5.62522,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.62522,1.52147;6.35772,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#";"#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.62522,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,0.95;5.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="1.47522,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1.47522,1.52147;4.50772,2.46147"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Checksum#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="1.47522,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> </dia:layer> </dia:diagram> |
Added art/delta6.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="0.95,0.95;5.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="1,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="2.39397,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2.39397,1.50441;3.60603,2.49559"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Size#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="2.39397,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,0.95;7.05,3.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,1"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="2"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="5.44022,2.06397"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.44022,1.50441;6.55978,2.49559"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#"\n"#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.44022,2.06397"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> </dia:layer> </dia:diagram> |
Added art/encode1.tex.
> > | 1 2 | \LARGE A = (\sum_{i=0}^{NHASH-1} z_i) \bmod 2^{16} |
Added art/encode10.dia.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | <?xml version="1.0" encoding="UTF-8"?> <dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> <dia:diagramdata> <dia:attribute name="background"> <dia:color val="#ffffff"/> </dia:attribute> <dia:attribute name="pagebreak"> <dia:color val="#000099"/> </dia:attribute> <dia:attribute name="paper"> <dia:composite type="paper"> <dia:attribute name="name"> <dia:string>#Letter#</dia:string> </dia:attribute> <dia:attribute name="tmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="bmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="lmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="rmargin"> <dia:real val="2.5399999618530273"/> </dia:attribute> <dia:attribute name="is_portrait"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="scaling"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="fitto"> <dia:boolean val="false"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="grid"> <dia:composite type="grid"> <dia:attribute name="width_x"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="width_y"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="visible_x"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="visible_y"> <dia:int val="1"/> </dia:attribute> <dia:composite type="color"/> </dia:composite> </dia:attribute> <dia:attribute name="color"> <dia:color val="#d8e5e5"/> </dia:attribute> <dia:attribute name="guides"> <dia:composite type="guides"> <dia:attribute name="hguides"/> <dia:attribute name="vguides"/> </dia:composite> </dia:attribute> </dia:diagramdata> <dia:layer name="Background" visible="true"> <dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O0"> <dia:attribute name="obj_pos"> <dia:point val="6,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.975,1.975;12.025,22.025"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="6,2"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="20"/> </dia:attribute> <dia:attribute name="border_width"> <dia:real val="0.050000000000000003"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> <dia:group> <dia:object type="Standard - Box" version="0" id="O1"> <dia:attribute name="obj_pos"> <dia:point val="6,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.975,7.975;12.025,9.025"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="6,8"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="1"/> </dia:attribute> <dia:attribute name="border_width"> <dia:real val="0.050000000000000003"/> </dia:attribute> <dia:attribute name="inner_color"> <dia:color val="#ffff00"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O2"> <dia:attribute name="obj_pos"> <dia:point val="5.95,8.4925"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.95,7.95;10.145,8.89"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Gap => Insert#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.95,8.4925"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O3"> <dia:attribute name="obj_pos"> <dia:point val="6,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.975,1.975;12.025,8.025"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="6,2"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="border_width"> <dia:real val="0.050000000000000003"/> </dia:attribute> <dia:attribute name="inner_color"> <dia:color val="#90ee90"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O4"> <dia:attribute name="obj_pos"> <dia:point val="5.975,2.53456"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.975,1.99206;8.91195,2.93206"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Processed#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.975,2.53456"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O5"> <dia:attribute name="obj_pos"> <dia:point val="6,9"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.975,8.975;12.025,18.025"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="6,9"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="9"/> </dia:attribute> <dia:attribute name="border_width"> <dia:real val="0.050000000000000003"/> </dia:attribute> <dia:attribute name="inner_color"> <dia:color val="#ffa500"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O6"> <dia:attribute name="obj_pos"> <dia:point val="5.975,9.53456"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="5.975,8.99206;11.4275,9.93206"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Common => Copy#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="5.975,9.53456"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O7"> <dia:attribute name="obj_pos"> <dia:point val="5,11"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,10.95;13.05,15.05"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="5,11"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="8"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="4"/> </dia:attribute> <dia:attribute name="inner_color"> <dia:color val="#bfbfbf"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O8"> <dia:attribute name="obj_pos"> <dia:point val="4.95,11.9675"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,10.95;9.26848,12.71"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Window#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="1.5"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="4.95,11.9675"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:group> <dia:group> <dia:object type="Standard - Box" version="0" id="O9"> <dia:attribute name="obj_pos"> <dia:point val="18,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.975,1.975;24.025,24.025"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="18,2"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="22"/> </dia:attribute> <dia:attribute name="border_width"> <dia:real val="0.050000000000000003"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> <dia:object type="Standard - Box" version="0" id="O10"> <dia:attribute name="obj_pos"> <dia:point val="18,5"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="17.975,4.975;24.025,14.025"/> </dia:attribute> <dia:attribute name="elem_corner"> <dia:point val="18,5"/> </dia:attribute> <dia:attribute name="elem_width"> <dia:real val="6"/> </dia:attribute> <dia:attribute name="elem_height"> <dia:real val="9"/> </dia:attribute> <dia:attribute name="border_width"> <dia:real val="0.050000000000000003"/> </dia:attribute> <dia:attribute name="inner_color"> <dia:color val="#ffa500"/> </dia:attribute> <dia:attribute name="show_background"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="corner_radius"> <dia:real val="1.1754943508222875e-38"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Text" version="1" id="O11"> <dia:attribute name="obj_pos"> <dia:point val="14,9"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="14,8.4575;16.8122,9.3975"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Signature#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="0.80000000000000004"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="14,9"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - ZigZagLine" version="1" id="O12"> <dia:attribute name="obj_pos"> <dia:point val="12,13"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="11.95,9;18.05,13.05"/> </dia:attribute> <dia:attribute name="orth_points"> <dia:point val="12,13"/> <dia:point val="15,13"/> <dia:point val="15,9.5"/> <dia:point val="18,9.5"/> </dia:attribute> <dia:attribute name="orth_orient"> <dia:enum val="0"/> <dia:enum val="1"/> <dia:enum val="0"/> </dia:attribute> <dia:attribute name="autorouting"> <dia:boolean val="true"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Text" version="1" id="O13"> <dia:attribute name="obj_pos"> <dia:point val="2,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="2,6.9825;4.6625,8.7425"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Base#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="1.5"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="2,8"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O14"> <dia:attribute name="obj_pos"> <dia:point val="5,8"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="4.95,7.5;6.05,8.5"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="5,8"/> <dia:point val="6,8"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> </dia:group> <dia:group> <dia:object type="Standard - Text" version="1" id="O15"> <dia:attribute name="obj_pos"> <dia:point val="1,11"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="1,9.9825;3.6725,11.7425"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Slide#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="1.5"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="1,11"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Line" version="0" id="O16"> <dia:attribute name="obj_pos"> <dia:point val="4,11"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="3.95,10.5;5.05,11.5"/> </dia:attribute> <dia:attribute name="conn_endpoints"> <dia:point val="4,11"/> <dia:point val="5,11"/> </dia:attribute> <dia:attribute name="numcp"> <dia:int val="1"/> </dia:attribute> <dia:attribute name="end_arrow"> <dia:enum val="22"/> </dia:attribute> <dia:attribute name="end_arrow_length"> <dia:real val="0.5"/> </dia:attribute> <dia:attribute name="end_arrow_width"> <dia:real val="0.5"/> </dia:attribute> </dia:object> </dia:group> <dia:object type="Standard - Text" version="1" id="O17"> <dia:attribute name="obj_pos"> <dia:point val="6,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="6,0.9825;9.38727,2.7425"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Target#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="1.5"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="6,2"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> <dia:object type="Standard - Text" version="1" id="O18"> <dia:attribute name="obj_pos"> <dia:point val="18,2"/> </dia:attribute> <dia:attribute name="obj_bb"> <dia:rectangle val="18,0.9825;21.3125,2.7425"/> </dia:attribute> <dia:attribute name="text"> <dia:composite type="text"> <dia:attribute name="string"> <dia:string>#Origin#</dia:string> </dia:attribute> <dia:attribute name="font"> <dia:font family="sans" style="0" name="Helvetica"/> </dia:attribute> <dia:attribute name="height"> <dia:real val="1.5"/> </dia:attribute> <dia:attribute name="pos"> <dia:point val="18,2"/> </dia:attribute> <dia:attribute name="color"> <dia:color val="#000000"/> </dia:attribute> <dia:attribute name="alignment"> <dia:enum val="0"/> </dia:attribute> </dia:composite> </dia:attribute> <dia:attribute name="valign"> <dia:enum val="3"/> </dia:attribute> </dia:object> </dia:group> </dia:layer> </dia:diagram> |
Added art/encode2.tex.
> | 1 | \LARGE B = (\sum_{i=0}^{NHASH-1} (NHASH-i)z_i) \bmod 2^{16} |
Added art/encode3.tex.
> | 1 | \LARGE V = 2^{16}B + A |
Added art/encode4.tex.
> | 1 | \LARGE z_0 |
Added art/encode5.tex.
> | 1 | \LARGE z_{new} |
Added art/encode6.tex.
> | 1 | \LARGE A_{new} = (A - z_0 + z_{new}) \bmod 2^{16} |
Added art/encode7.tex.
> | 1 | \LARGE B_{new} = (B - z_0 NHASH + A_{new}) \bmod 2^{16} |
Added art/encode8.tex.
> | 1 | \LARGE V_{new} = 2^{16}B_{new} + A_{new} |
Added art/encode9.tex.
> | 1 | \LARGE A_{new} |
Changes to auto.def.
1 2 | # System autoconfiguration. Try: ./configure --help | < < > < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | # System autoconfiguration. Try: ./configure --help use cc cc-lib options { with-openssl:path|auto|tree|none => {Look for OpenSSL in the given path, automatically, in the source tree, or none} with-miniz=0 => {Use miniz from the source tree} with-zlib:path|auto|tree => {Look for zlib in the given path, automatically, or in the source tree} with-exec-rel-paths=0 => {Enable relative paths for external diff/gdiff} with-legacy-mv-rm=1 => {Enable legacy behavior for mv/rm (skip checkout files)} with-th1-docs=0 => {Enable TH1 for embedded documentation pages} with-th1-hooks=0 => {Enable TH1 hooks for commands and web pages} with-tcl:path => {Enable Tcl integration, with Tcl in the specified path} with-tcl-stubs=0 => {Enable Tcl integration via stubs library mechanism} with-tcl-private-stubs=0 => {Enable Tcl integration via private stubs mechanism} with-mman=0 => {Enable use of POSIX memory APIs from "sys/mman.h"} with-see=0 => {Enable the SQLite Encryption Extension (SEE)} internal-sqlite=1 => {Don't use the internal SQLite, use the system one} static=0 => {Link a static executable} fusefs=1 => {Disable the Fuse Filesystem} fossil-debug=0 => {Build with fossil debugging enabled} no-opt=0 => {Build without optimization} json=0 => {Build with fossil JSON API enabled} } # sqlite wants these types if possible cc-with {-includes {stdint.h inttypes.h}} { cc-check-types uint32_t uint16_t int16_t uint8_t } # Use pread/pwrite system calls in place of seek + read/write if possible define USE_PREAD [cc-check-functions pread] # Find tclsh for the test suite. # # We can't use jimsh for this: the test suite uses features of Tcl that # Jim doesn't support, either statically or due to the way it's built by # autosetup. For example, Jim supports `file normalize`, but only if # you build it with HAVE_REALPATH, which won't ever be defined in this # context because autosetup doesn't try to discover platform-specific # details like that before it decides to build jimsh0. Besides which, # autosetup won't build jimsh0 at all if it can find tclsh itself. # Ironically, this means we may right now be running under either jimsh0 # or a version of tclsh that we find unsuitable below! cc-check-progs tclsh set hbtd /usr/local/Cellar/tcl-tk if {[string equal false [get-define TCLSH]]} { msg-result "WARNING: 'make test' will not run here." } else { set v [exec /bin/sh -c "echo 'puts \$tcl_version' | tclsh"] if {[expr $v >= 8.6]} { msg-result "Found Tclsh version $v in the PATH." define TCLSH tclsh } elseif {[file isdirectory $hbtd]} { # This is a macOS system with the Homebrew version of Tcl/Tk # installed. Select the newest version. It won't normally be # in the PATH to avoid shadowing /usr/bin/tclsh, and even if it # were in the PATH, it's bad practice to put /usr/local/bin (the |
︙ | ︙ | |||
106 107 108 109 110 111 112 113 114 | } } define EXTRA_CFLAGS "-Wall" define EXTRA_LDFLAGS "" define USE_SYSTEM_SQLITE 0 define USE_LINENOISE 0 define USE_MMAN_H 0 define USE_SEE 0 | > < < < < < < < < < | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | } } define EXTRA_CFLAGS "-Wall" define EXTRA_LDFLAGS "" define USE_SYSTEM_SQLITE 0 define USE_LINENOISE 0 define FOSSIL_ENABLE_MINIZ 0 define USE_MMAN_H 0 define USE_SEE 0 # This procedure is a customized version of "cc-check-function-in-lib", # that does not modify the LIBS variable. Its use prevents prematurely # pulling in libraries that will be added later anyhow (e.g. "-ldl"). proc check-function-in-lib {function libs {otherlibs {}}} { if {[string length $otherlibs]} { msg-checking "Checking for $function in $libs with $otherlibs..." |
︙ | ︙ | |||
155 156 157 158 159 160 161 | } else { msg-result "no" } return $found } if {![opt-bool internal-sqlite]} { | | | | > > > > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < > > > > > > | 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 | } else { msg-result "no" } return $found } if {![opt-bool internal-sqlite]} { proc find_internal_sqlite {} { # On some systems (slackware), libsqlite3 requires -ldl to link. So # search for the system SQLite once with -ldl, and once without. If # the library can only be found with $extralibs set to -ldl, then # the code below will append -ldl to LIBS. # foreach extralibs {{} {-ldl}} { # Locate the system SQLite by searching for sqlite3_open(). Then check # if sqlite3_create_window_function can be found as well. If we can find open() but # not create_window_function(), then the system SQLite is too old to link against # fossil. # if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} { if {![check-function-in-lib sqlite3_create_window_function sqlite3 $extralibs]} { user-error "system sqlite3 too old (require >= 3.25.0)" } # Success. Update symbols and return. # define USE_SYSTEM_SQLITE 1 define-append LIBS -lsqlite3 define-append LIBS $extralibs return } } user-error "system sqlite3 not found" } find_internal_sqlite } proc is_mingw {} { return [string match *mingw* [get-define host]] } if {[is_mingw]} { define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE define-append LIBS -lkernel32 -lws2_32 } else { # # NOTE: All platforms except MinGW should use the linenoise # package. It is currently unsupported on Win32. # define USE_LINENOISE 1 } if {[string match *-solaris* [get-define host]]} { define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__} } if {[opt-bool fossil-debug]} { define CFLAGS {-g -O0 -Wall} define-append CFLAGS -DFOSSIL_DEBUG msg-result "Debugging support enabled" } if {[opt-bool no-opt]} { define CFLAGS {-g -O0 -Wall} msg-result "Builting without compiler optimization" } if {[opt-bool with-mman]} { define-append EXTRA_CFLAGS -DUSE_MMAN_H define USE_MMAN_H 1 msg-result "Enabling \"sys/mman.h\" support" } if {[opt-bool with-see]} { define-append EXTRA_CFLAGS -DUSE_SEE define USE_SEE 1 msg-result "Enabling encryption support" } if {[opt-bool json]} { # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON # is required in the CFLAGS because json*.c # have #ifdef guards around the whole file without # reading config.h first. define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON define FOSSIL_ENABLE_JSON msg-result "JSON support enabled" } if {[opt-bool with-legacy-mv-rm]} { define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_LEGACY_MV_RM=1 define FOSSIL_ENABLE_LEGACY_MV_RM msg-result "Legacy mv/rm support enabled" } if {[opt-bool with-exec-rel-paths]} { define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_EXEC_REL_PATHS define FOSSIL_ENABLE_EXEC_REL_PATHS msg-result "Relative paths in external diff/gdiff enabled" } |
︙ | ︙ | |||
316 317 318 319 320 321 322 | define FOSSIL_DYNAMIC_BUILD } # Check for libraries that need to be sorted out early cc-check-function-in-lib iconv iconv # Helper for OpenSSL checking | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | define FOSSIL_DYNAMIC_BUILD } # Check for libraries that need to be sorted out early cc-check-function-in-lib iconv iconv # Helper for OpenSSL checking proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto}}} { msg-checking "Checking for $msg..." set rc 0 if {[is_mingw]} { lappend libs -lgdi32 -lwsock32 -lcrypt32 } if {[info exists ::zlib_lib]} { lappend libs $::zlib_lib |
︙ | ︙ | |||
350 351 352 353 354 355 356 | return 1 } else { msg-result "no" return 0 } } | > > > > | | | | | | < < | | | | | | | < < | < < < < < < < < < | < < < | < < < < < < < < < < < < < < | | | < > > | < | > > > > | | < | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | return 1 } else { msg-result "no" return 0 } } if {[opt-bool with-miniz]} { define FOSSIL_ENABLE_MINIZ 1 msg-result "Using miniz for compression" } else { # Check for zlib, using the given location if specified set zlibpath [opt-val with-zlib] if {$zlibpath eq "tree"} { set zlibdir [file dirname $autosetup(dir)]/compat/zlib if {![file isdirectory $zlibdir]} { user-error "The zlib in source tree directory does not exist" } cc-with [list -cflags "-I$zlibdir -L$zlibdir"] define-append EXTRA_CFLAGS -I$zlibdir define-append LIBS $zlibdir/libz.a set ::zlib_lib $zlibdir/libz.a msg-result "Using zlib in source tree" } else { if {$zlibpath ni {auto ""}} { cc-with [list -cflags "-I$zlibpath -L$zlibpath"] define-append EXTRA_CFLAGS -I$zlibpath define-append EXTRA_LDFLAGS -L$zlibpath msg-result "Using zlib from $zlibpath" } if {![cc-check-includes zlib.h] || ![check-function-in-lib inflateEnd z]} { user-error "zlib not found please install it or specify the location with --with-zlib" } set ::zlib_lib -lz } } set ssldirs [opt-val with-openssl] if {$ssldirs ne "none"} { if {[opt-bool with-miniz]} { user-error "The --with-miniz option is incompatible with OpenSSL" } set found 0 if {$ssldirs eq "tree"} { set ssldir [file dirname $autosetup(dir)]/compat/openssl if {![file isdirectory $ssldir]} { user-error "The OpenSSL in source tree directory does not exist" } set msg "ssl in $ssldir" set cflags "-I$ssldir/include" set ldflags "-L$ssldir" set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a" set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs] } else { if {$ssldirs in {auto ""}} { catch { set cflags [exec pkg-config openssl --cflags-only-I] set ldflags [exec pkg-config openssl --libs-only-L] set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"] } msg if {!$found} { set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl \ /usr/pkg /usr/local /usr /usr/local/opt/openssl" } } if {!$found} { foreach dir $ssldirs { if {$dir eq ""} { set msg "system ssl" set cflags "" |
︙ | ︙ | |||
453 454 455 456 457 458 459 | } } } if {$found} { define FOSSIL_ENABLE_SSL define-append EXTRA_CFLAGS $cflags define-append EXTRA_LDFLAGS $ldflags | < < | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | } } } if {$found} { define FOSSIL_ENABLE_SSL define-append EXTRA_CFLAGS $cflags define-append EXTRA_LDFLAGS $ldflags if {[info exists ssllibs]} { define-append LIBS $ssllibs } else { define-append LIBS -lssl -lcrypto } if {[info exists ::zlib_lib]} { define-append LIBS $::zlib_lib |
︙ | ︙ | |||
483 484 485 486 487 488 489 | } } else { if {[info exists ::zlib_lib]} { define-append LIBS $::zlib_lib } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | } } else { if {[info exists ::zlib_lib]} { define-append LIBS $::zlib_lib } } set tclpath [opt-val with-tcl] if {$tclpath ne ""} { set tclprivatestubs [opt-bool with-tcl-private-stubs] # Note parse-tclconfig-sh is in autosetup/local.tcl if {$tclpath eq "1"} { set tcldir [file dirname $autosetup(dir)]/compat/tcl-8.6 if {$tclprivatestubs} { |
︙ | ︙ | |||
655 656 657 658 659 660 661 | } set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL) msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)" if {!$tclprivatestubs} { define-append LIBS $libs } define-append EXTRA_CFLAGS $cflags | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | } set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL) msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)" if {!$tclprivatestubs} { define-append LIBS $libs } define-append EXTRA_CFLAGS $cflags if {[info exists zlibpath] && $zlibpath eq "tree"} { # # NOTE: When using zlib in the source tree, prevent Tcl from # pulling in the system one. # set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \ $tclconfig(TCL_LD_FLAGS)] } # # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be # be checked for near the bottom of this file. # set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \ $tclconfig(TCL_LD_FLAGS)] define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) define FOSSIL_ENABLE_TCL } # Network functions require libraries on some systems cc-check-function-in-lib gethostbyname nsl if {![cc-check-function-in-lib socket {socket network}]} { # Last resort, may be Windows if {[is_mingw]} { define-append LIBS -lwsock32 } |
︙ | ︙ | |||
734 735 736 737 738 739 740 | # Other nonstandard function checks cc-check-functions utime cc-check-functions usleep cc-check-functions strchrnul cc-check-functions pledge cc-check-functions backtrace | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | # Other nonstandard function checks cc-check-functions utime cc-check-functions usleep cc-check-functions strchrnul cc-check-functions pledge cc-check-functions backtrace # Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE if {![cc-check-functions getloadavg]} { define FOSSIL_OMIT_LOAD_AVERAGE 1 msg-result "Load average support unavailable" } # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars if {![cc-check-functions getpassphrase]} { # Haiku needs this cc-check-function-in-lib getpass bsd } cc-check-function-in-lib sin m # Check for the FuseFS library if {[opt-bool fusefs]} { if {[cc-check-function-in-lib fuse_mount fuse]} { define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS define FOSSIL_HAVE_FUSEFS 1 define-append LIBS -lfuse msg-result "FuseFS support enabled" } } # Finally, append -ldl to make sure it's the last in the list. # The library order matters in case of static linking. if {[check-function-in-lib dlopen dl]} { # Some platforms (*BSD) have the dl functions already in libc and no libdl. # In such case we can link directly without -ldl. define-append LIBS [get-define lib_dlopen] } make-template Makefile.in make-config-header autoconfig.h -auto {USE_* FOSSIL_*} |
Changes to autosetup/README.autosetup.
|
| < < < < < < < < < < | | 1 | This is autosetup v0.6.6. See http://msteveb.github.com/autosetup/ |
Changes to autosetup/autosetup.
1 2 3 4 5 | #!/bin/sh # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # vim:se syntax=tcl: # \ | | < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/bin/sh # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # vim:se syntax=tcl: # \ dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@" set autosetup(version) 0.6.6 # Can be set to 1 to debug early-init problems set autosetup(debug) 0 ################################################################## # # Main flow of control, option handling # proc main {argv} { global autosetup define |
︙ | ︙ | |||
71 72 73 74 75 76 77 | set autosetup(argv) $argv set autosetup(cmdline) {} # options is a list of known options set autosetup(options) {} # optset is a dictionary of option values set by the user based on getopt set autosetup(optset) {} | | < < < < < | < < < < < < < < < < < < | | > | | > | | < < < < < < | | | | | | < < < < < | 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 | set autosetup(argv) $argv set autosetup(cmdline) {} # options is a list of known options set autosetup(options) {} # optset is a dictionary of option values set by the user based on getopt set autosetup(optset) {} # optdefault is a dictionary of default values for options set autosetup(optdefault) {} set autosetup(optionhelp) {} set autosetup(showhelp) 0 # Parse options use getopt # At the is point we don't know what is a valid option # We simply parse anything that looks like an option set autosetup(getopt) [getopt argv] #"=Core Options:" options-add { help:=local => "display help and options. Optionally specify a module name, such as --help=system" version => "display the version of autosetup" ref:=text manual:=text reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'" debug => "display debugging output as autosetup runs" install:=. => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)" force init:=help => "create initial auto.def, etc. Use --init=help for known types" # Undocumented options option-checking=1 nopager quiet timing conf: } if {[opt-bool version]} { puts $autosetup(version) exit 0 } # autosetup --conf=alternate-auto.def if {[opt-val conf] ne ""} { set autosetup(autodef) [opt-val conf] } # Debugging output (set this early) incr autosetup(debug) [opt-bool debug] incr autosetup(force) [opt-bool force] incr autosetup(msg-quiet) [opt-bool quiet] incr autosetup(msg-timing) [opt-bool timing] # If the local module exists, source it now to allow for # project-local customisations if {[file exists $autosetup(libdir)/local.tcl]} { use local } # Now any auto-load modules foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] { automf_load source $file } if {[opt-val help] ne ""} { incr autosetup(showhelp) use help autosetup_help [opt-val help] } if {[opt-val {manual ref reference}] ne ""} { use help autosetup_reference [opt-val {manual ref reference}] } # Allow combining --install and --init set earlyexit 0 if {[opt-val install] ne ""} { use install autosetup_install [opt-val install] incr earlyexit } if {[opt-val init] ne ""} { use init autosetup_init [opt-val init] incr earlyexit } if {$earlyexit} { exit 0 } if {![file exists $autosetup(autodef)]} { # Check for invalid option first options {} user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)" } |
︙ | ︙ | |||
210 211 212 213 214 215 216 | } define AUTOREMAKE [file-normalize $autosetup(exe)] define-append AUTOREMAKE [get-define CONFIGURE_OPTS] # Log how we were invoked configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]" | < | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | } define AUTOREMAKE [file-normalize $autosetup(exe)] define-append AUTOREMAKE [get-define CONFIGURE_OPTS] # Log how we were invoked configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]" # Note that auto.def is *not* loaded in the global scope source $autosetup(autodef) # Could warn here if options {} was not specified show-notices |
︙ | ︙ | |||
236 237 238 239 240 241 242 | # @opt-bool ?-nodefault? option ... # # Check each of the named, boolean options and if any have been explicitly enabled # or disabled by the user, return 1 or 0 accordingly. # # If the option was specified more than once, the last value wins. | | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | # @opt-bool ?-nodefault? option ... # # Check each of the named, boolean options and if any have been explicitly enabled # or disabled by the user, return 1 or 0 accordingly. # # If the option was specified more than once, the last value wins. # e.g. With --enable-foo --disable-foo, [opt-bool foo] will return 0 # # If no value was specified by the user, returns the default value for the # first option. If -nodefault is given, this behaviour changes and # -1 is returned instead. # proc opt-bool {args} { set nodefault 0 if {[lindex $args 0] eq "-nodefault"} { set nodefault 1 set args [lrange $args 1 end] |
︙ | ︙ | |||
263 264 265 266 267 268 269 | if {$nodefault} { return -1 } # Default value is the default for the first option return [dict get $::autosetup(optdefault) [lindex $args 0]] } | | | > < > < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | if {$nodefault} { return -1 } # Default value is the default for the first option return [dict get $::autosetup(optdefault) [lindex $args 0]] } # @opt-val option-list ?default=""? # # Returns a list containing all the values given for the non-boolean options in 'option-list'. # There will be one entry in the list for each option given by the user, including if the # same option was used multiple times. # If only a single value is required, use something like: # ## lindex [opt-val $names] end # # If no options were set, $default is returned (exactly, not as a list). # proc opt-val {names {default ""}} { option-check-names {*}$names foreach opt $names { if {[dict exists $::autosetup(optset) $opt]} { lappend result {*}[dict get $::autosetup(optset) $opt] } } if {[info exists result]} { return $result } return $default } proc option-check-names {args} { foreach o $args { if {$o ni $::autosetup(options)} { autosetup-error "Request for undeclared option --$o" } } } |
︙ | ︙ | |||
391 392 393 394 395 396 397 | set opt [lindex $opts $i] if {[string match =* $opt]} { # This is a special heading lappend autosetup(optionhelp) $opt "" set header {} continue } | < < < < < < < < | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | set opt [lindex $opts $i] if {[string match =* $opt]} { # This is a special heading lappend autosetup(optionhelp) $opt "" set header {} continue } #puts "i=$i, opt=$opt" regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value if {$name in $autosetup(options)} { autosetup-error "Option $name already specified" } #puts "$opt => $name $colon $equal $value" # Find the corresponding value in the user options # and set the default if necessary if {[string match "-*" $opt]} { # This is a documentation-only option, like "-C <dir>" set opthelp $opt } elseif {$colon eq ""} { # Boolean option lappend autosetup(options) $name if {$value eq "1"} { set opthelp "--disable-$name" } else { set opthelp "--$name" } # Set the default if {$value eq ""} { set value 0 } dict set autosetup(optdefault) $name $value if {[dict exists $autosetup(getopt) $name]} { # The option was specified by the user. Look at the last value. lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue if {$type eq "str"} { # Can we convert the value to a boolean? if {$setvalue in {1 enabled yes}} { |
︙ | ︙ | |||
449 450 451 452 453 454 455 | dict set autosetup(optset) $name $setvalue #puts "Found boolean option --$name=$setvalue" } } else { # String option. lappend autosetup(options) $name | < < < < < < < < < < < < < < < < < < < < < > | < < < | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | dict set autosetup(optset) $name $setvalue #puts "Found boolean option --$name=$setvalue" } } else { # String option. lappend autosetup(options) $name if {$equal eq "="} { # String option with optional value set opthelp "--$name?=$value?" } else { # String option with required value set opthelp "--$name=$value" } dict set autosetup(optdefault) $name $value # Get the values specified by the user if {[dict exists $autosetup(getopt) $name]} { set listvalue {} foreach pair [dict get $autosetup(getopt) $name] { lassign $pair type setvalue if {$type eq "bool" && $setvalue} { if {$equal ne "="} { user-error "Option --$name requires a value" } # If given as a boolean, use the default value set setvalue $value } lappend listvalue $setvalue } #puts "Found string option --$name=$listvalue" dict set autosetup(optset) $name $listvalue } } # Now create the help for this option if appropriate if {[lindex $opts $i+1] eq "=>"} { set desc [lindex $opts $i+2] #string match \n* $desc if {$header ne ""} { lappend autosetup(optionhelp) $header "" set header "" } # A multi-line description lappend autosetup(optionhelp) $opthelp $desc |
︙ | ︙ | |||
592 593 594 595 596 597 598 | puts $desc } else { options-wrap-desc [string trim $desc] $cols " " $indent [expr $max + 2] } } } | | | < | | | | < < < | | | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | puts $desc } else { options-wrap-desc [string trim $desc] $cols " " $indent [expr $max + 2] } } } # @options options-spec # # Specifies configuration-time options which may be selected by the user # and checked with opt-val and opt-bool. The format of options-spec follows. # # A boolean option is of the form: # ## name[=0|1] => "Description of this boolean option" # # The default is name=0, meaning that the option is disabled by default. # If name=1 is used to make the option enabled by default, the description should reflect # that with text like "Disable support for ...". # # An argument option (one which takes a parameter) is of the form: # ## name:[=]value => "Description of this option" # # If the name:value form is used, the value must be provided with the option (as --name=myvalue). # If the name:=value form is used, the value is optional and the given value is used as the default # if it is not provided. # # Undocumented options are also supported by omitting the "=> description. # These options are not displayed with --help and can be useful for internal options or as aliases. # # For example, --disable-lfs is an alias for --disable=largefile: # ## lfs=1 largefile=1 => "Disable large file support" # proc options {optlist} { # Allow options as a list or args options-add $optlist "Local Options:" |
︙ | ︙ | |||
643 644 645 646 647 648 649 | if {$o ni $::autosetup(options)} { user-error "Unknown option --$o" } } } } | < < < < < < < < < < < | > | | | | | | | | | < < < < | < < < < < | < < < < < < < < < < < < | | | | | | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 | if {$o ni $::autosetup(options)} { user-error "Unknown option --$o" } } } } proc config_guess {} { if {[file-isexec $::autosetup(dir)/config.guess]} { exec-with-stderr sh $::autosetup(dir)/config.guess if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} { user-error $alias } return $alias } else { configlog "No config.guess, so using uname" string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r] } } proc config_sub {alias} { if {[file-isexec $::autosetup(dir)/config.sub]} { if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} { user-error $alias } } return $alias } # @define name ?value=1? # # Defines the named variable to the given value. # These (name, value) pairs represent the results of the configuration check # and are available to be checked, modified and substituted. # proc define {name {value 1}} { set ::define($name) $value #dputs "$name <= $value" } # @undefine name # # Undefine the named variable # proc undefine {name} { unset -nocomplain ::define($name) #dputs "$name <= <undef>" } # @define-append name value ... # # Appends the given value(s) to the given 'defined' variable. # If the variable is not defined or empty, it is set to $value. # Otherwise the value is appended, separated by a space. # Any extra values are similarly appended. # If any value is already contained in the variable (as a substring) it is omitted. # proc define-append {name args} { if {[get-define $name ""] ne ""} { # Make a token attempt to avoid duplicates foreach arg $args { if {[string first $arg $::define($name)] == -1} { append ::define($name) " " $arg } } } else { set ::define($name) [join $args] } #dputs "$name += [join $args] => $::define($name)" } # @get-define name ?default=0? # # Returns the current value of the 'defined' variable, or $default # if not set. # proc get-define {name {default 0}} { if {[info exists ::define($name)]} { #dputs "$name => $::define($name)" return $::define($name) } #dputs "$name => $default" return $default } # @is-defined name # # Returns 1 if the given variable is defined. # proc is-defined {name} { info exists ::define($name) } # @all-defines # # Returns a dictionary (name value list) of all defined variables. # # This is suitable for use with 'dict', 'array set' or 'foreach' # and allows for arbitrary processing of the defined variables. # proc all-defines {} { array get ::define } # @get-env name default # # If $name was specified on the command line, return it. # If $name was set in the environment, return it. # Otherwise return $default. # proc get-env {name default} { if {[dict exists $::autosetup(cmdline) $name]} { return [dict get $::autosetup(cmdline) $name] } getenv $name $default } # @env-is-set name # # Returns 1 if the $name was specified on the command line or in the environment. # Note that an empty environment variable is not considered to be set. # proc env-is-set {name} { if {[dict exists $::autosetup(cmdline) $name]} { return 1 } if {[getenv $name ""] ne ""} { return 1 } return 0 } # @readfile filename ?default=""? # # Return the contents of the file, without the trailing newline. # If the file doesn't exist or can't be read, returns $default. # proc readfile {filename {default_value ""}} { set result $default_value catch { set f [open $filename] set result [read -nonewline $f] close $f } return $result } # @writefile filename value # # Creates the given file containing $value. # Does not add an extra newline. # proc writefile {filename value} { set f [open $filename w] puts -nonewline $f $value close $f } |
︙ | ︙ | |||
841 842 843 844 845 846 847 | set args {} foreach arg $argv { lappend args [quote-if-needed $arg] } join $args } | | > | > > > | < | | < | < < | | < > > | < | < < | < < < | < | < < | | > > > | > > > > > | > > > | 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | set args {} foreach arg $argv { lappend args [quote-if-needed $arg] } join $args } # @suffix suf list # # Takes a list and returns a new list with $suf appended # to each element # ## suffix .c {a b c} => {a.c b.c c.c} # proc suffix {suf list} { set result {} foreach p $list { lappend result $p$suf } return $result } # @prefix pre list # # Takes a list and returns a new list with $pre prepended # to each element # ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c} # proc prefix {pre list} { set result {} foreach p $list { lappend result $pre$p } return $result } # @find-executable name # # Searches the path for an executable with the given name. # Note that the name may include some parameters, e.g. "cc -mbig-endian", # in which case the parameters are ignored. # Returns 1 if found, or 0 if not. # proc find-executable {name} { # Ignore any parameters set name [lindex $name 0] if {$name eq ""} { # The empty string is never a valid executable return 0 } foreach p [split-path] { dputs "Looking for $name in $p" set exec [file join $p $name] if {[file-isexec $exec]} { dputs "Found $name -> $exec" return 1 } } return 0 } # @find-an-executable ?-required? name ... # # Given a list of possible executable names, # searches for one of these on the path. # |
︙ | ︙ | |||
925 926 927 928 929 930 931 | } } return "" } # @configlog msg # | | | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | } } return "" } # @configlog msg # # Writes the given message to the configuration log, config.log # proc configlog {msg} { if {![info exists ::autosetup(logfh)]} { set ::autosetup(logfh) [open config.log w] } puts $::autosetup(logfh) $msg } |
︙ | ︙ | |||
961 962 963 964 965 966 967 | set ::autosetup(msg-checking) 0 show-notices } } # @msg-quiet command ... # | | | | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | set ::autosetup(msg-checking) 0 show-notices } } # @msg-quiet command ... # # msg-quiet evaluates it's arguments as a command with output # from msg-checking and msg-result suppressed. # # This is useful if a check needs to run a subcheck which isn't # of interest to the user. proc msg-quiet {args} { incr ::autosetup(msg-quiet) set rc [uplevel 1 $args] incr ::autosetup(msg-quiet) -1 |
︙ | ︙ | |||
1002 1003 1004 1005 1006 1007 1008 | # # Usage errors such as wrong command line options # @user-error msg # # Indicate incorrect usage to the user, including if required components # or features are not found. | | | 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 | # # Usage errors such as wrong command line options # @user-error msg # # Indicate incorrect usage to the user, including if required components # or features are not found. # autosetup exits with a non-zero return code. # proc user-error {msg} { show-notices puts stderr "Error: $msg" puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options" exit 1 } |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | proc maybe-show-timestamp {} { if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} { puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]] } } | < < < < < < < < < < < | 886 887 888 889 890 891 892 893 894 895 896 897 898 899 | proc maybe-show-timestamp {} { if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} { puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]] } } proc autosetup_version {} { return "autosetup v$::autosetup(version)" } ################################################################## # # Directory/path handling |
︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 | # or 'autosetup/X/init.tcl' # # The latter form is useful for a complex module which requires additional # support file. In this form, '$::usedir' is set to the module directory # when it is loaded. # proc use {args} { | < < < < < < | | | | | < < | | | < < < < < < < < < < < < < < < < < < < | | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | # or 'autosetup/X/init.tcl' # # The latter form is useful for a complex module which requires additional # support file. In this form, '$::usedir' is set to the module directory # when it is loaded. # proc use {args} { foreach m $args { if {[info exists ::libmodule($m)]} { continue } set ::libmodule($m) 1 if {[info exists ::modsource($m)]} { automf_load eval $::modsource($m) } else { set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl] set found 0 foreach source $sources { if {[file exists $source]} { incr found break } } if {$found} { # For the convenience of the "use" source, point to the directory # it is being loaded from set ::usedir [file dirname $source] automf_load source $source autosetup_add_dep $source } else { autosetup-error "use: No such module: $m" } } } } # Load module source in the global scope by executing the given command proc automf_load {args} { if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} { autosetup-full-error [error-dump $msg $opts $::autosetup(debug)] } } # Initial settings set autosetup(exe) $::argv0 set autosetup(istcl) 1 set autosetup(start) [clock millis] set autosetup(installed) 0 set autosetup(msg-checking) 0 set autosetup(msg-quiet) 0 # Embedded modules are inserted below here set autosetup(installed) 1 # ----- module asciidoc-formatting ----- set modsource(asciidoc-formatting) { # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module which provides text formatting # asciidoc format use formatting |
︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 | } set defn [string trim [join $args \n]] regsub -all "\n\n" $defn "\n ::\n" defn puts $defn } } | | | | | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 | } set defn [string trim [join $args \n]] regsub -all "\n\n" $defn "\n ::\n" defn puts $defn } } # ----- module formatting ----- set modsource(formatting) { # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module which provides common text formatting # This is designed for documenation which looks like: # code {...} # or # code { # ... # ... # } # In the second case, we need to work out the indenting |
︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 | } # Return the result return $lines } } | | | | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 | } # Return the result return $lines } } # ----- module getopt ----- set modsource(getopt) { # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Simple getopt module # Parse everything out of the argv list which looks like an option # Everything which doesn't look like an option, or is after --, is left unchanged |
︙ | ︙ | |||
1396 1397 1398 1399 1400 1401 1402 | break } if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} { # --name=value dict lappend opts $name [list str $value] } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} { | | | | | 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 | break } if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} { # --name=value dict lappend opts $name [list str $value] } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} { if {$prefix in {enable- with- ""}} { set value 1 } else { set value 0 } dict lappend opts $name [list bool $value] } else { lappend nargv $arg } } #puts "getopt: argv=[join $argv] => [join $nargv]" #array set getopt $opts #parray getopt set argv $nargv return $opts } } # ----- module help ----- set modsource(help) { # Copyright (c) 2010 WorkWare Systems http://workware.net.au/ # All rights reserved # Module which provides usage, help and the command reference proc autosetup_help {what} { use_pager |
︙ | ︙ | |||
1451 1452 1453 1454 1455 1456 1457 | } else { options-show } } exit 0 } | < < < < < < < < < < < < < < < < < < | 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | } else { options-show } } exit 0 } # If not already paged and stdout is a tty, pipe the output through the pager # This is done by reinvoking autosetup with --nopager added proc use_pager {} { if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} { if {[catch { exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr } msg opts] == 1} { |
︙ | ︙ | |||
1521 1522 1523 1524 1525 1526 1527 | exit 0 } proc autosetup_output_block {type lines} { if {[llength $lines]} { switch $type { | < < < < < < | 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 | exit 0 } proc autosetup_output_block {type lines} { if {[llength $lines]} { switch $type { code { codelines $lines } p { p [join $lines] } list { |
︙ | ︙ | |||
1548 1549 1550 1551 1552 1553 1554 | } # Generate a command reference from inline documentation proc automf_command_reference {} { lappend files $::autosetup(prog) lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]] | < < < < < | | < | | < < < < < < < < < | | | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 | } # Generate a command reference from inline documentation proc automf_command_reference {} { lappend files $::autosetup(prog) lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]] section "Core Commands" set type p set lines {} set cmd {} foreach file $files { set f [open $file] while {![eof $f]} { set line [gets $f] # Find lines starting with "# @*" and continuing through the remaining comment lines if {![regexp {^# @(.*)} $line -> cmd]} { continue } # Synopsis or command? if {$cmd eq "synopsis:"} { section "Module: [file rootname [file tail $file]]" } else { subsection $cmd } set lines {} set type p # Now the description while {![eof $f]} { |
︙ | ︙ | |||
1607 1608 1609 1610 1611 1612 1613 | set t p } #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd" if {$t ne $type || $cmd eq ""} { # Finish the current block | | | < < < < < < < < < | | | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | set t p } #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd" if {$t ne $type || $cmd eq ""} { # Finish the current block autosetup_output_block $type $lines set lines {} set type $t } if {$cmd ne ""} { lappend lines $cmd } } autosetup_output_block $type $lines } close $f } } } # ----- module init ----- set modsource(init) { # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module to help create auto.def and configure proc autosetup_init {type} { set help 0 |
︙ | ︙ | |||
1691 1692 1693 1694 1695 1696 1697 | } else { puts "I don't see $filename, so I will create it." } writefile $filename $contents } } | | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < < | | | < < | < < < | | | | < | | < < < < < | < < | < < < < < < | | < | | < < < < | < | < < < < < < | | < < < < | > > | < < < < < | < | | | | < | < | < < < < < | < < | < | | < < < < < < | < < < < < < < < < < | < | < < < | < | < < < | < < | | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 | } else { puts "I don't see $filename, so I will create it." } writefile $filename $contents } } # ----- module install ----- set modsource(install) { # Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module which can install autosetup proc autosetup_install {dir} { if {[catch { cd $dir file mkdir autosetup set f [open autosetup/autosetup w] set publicmodules [glob $::autosetup(libdir)/*.auto] # First the main script, but only up until "CUT HERE" set in [open $::autosetup(dir)/autosetup] while {[gets $in buf] >= 0} { if {$buf ne "##-- CUT HERE --##"} { puts $f $buf continue } # Insert the static modules here # i.e. those which don't contain @synopsis: puts $f "set autosetup(installed) 1" foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] { set buf [readfile $file] if {[string match "*\n# @synopsis:*" $buf]} { lappend publicmodules $file continue } set modname [file rootname [file tail $file]] puts $f "# ----- module $modname -----" puts $f "\nset modsource($modname) \{" puts $f $buf puts $f "\}\n" } } close $in close $f exec chmod 755 autosetup/autosetup # Install public modules foreach file $publicmodules { autosetup_install_file $file autosetup } # Install support files foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} { autosetup_install_file $::autosetup(dir)/$file autosetup } exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh writefile autosetup/README.autosetup \ "This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n" } error]} { user-error "Failed to install autosetup: $error" } puts "Installed [autosetup_version] to autosetup/" # Now create 'configure' if necessary autosetup_create_configure } proc autosetup_create_configure {} { if {[file exists configure]} { if {!$::autosetup(force)} { # Could this be an autosetup configure? if {![string match "*\nWRAPPER=*" [readfile configure]]} { puts "I see configure, but not created by autosetup, so I won't overwrite it." puts "Remove it or use --force to overwrite." return } } else { puts "I will overwrite the existing configure because you used --force." } } else { puts "I don't see configure, so I will create it." } writefile configure \ {#!/bin/sh dir="`dirname "$0"`/autosetup" WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" } catch {exec chmod 755 configure} } # Append the contents of $file to filehandle $f proc autosetup_install_append {f file} { set in [open $file] puts $f [read $in] close $in } proc autosetup_install_file {file dir} { if {![file exists $file]} { error "Missing installation file '$file'" } writefile [file join $dir [file tail $file]] [readfile $file]\n } if {$::autosetup(installed)} { user-error "autosetup can only be installed from development source, not from installed copy" } } # ----- module markdown-formatting ----- set modsource(markdown-formatting) { # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module which provides text formatting # markdown format (kramdown syntax) use formatting |
︙ | ︙ | |||
1987 1988 1989 1990 1991 1992 1993 | puts -nonewline ": " regsub -all "\n\n" $defn "\n: " defn } puts "$defn" } } | | | | 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 | puts -nonewline ": " regsub -all "\n\n" $defn "\n: " defn } puts "$defn" } } # ----- module misc ----- set modsource(misc) { # Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module containing misc procs useful to modules # Largely for platform compatibility set autosetup(istcl) [info exists ::tcl_library] |
︙ | ︙ | |||
2165 2166 2167 2168 2169 2170 2171 | # Remove the trailing newline string trim $result } } } | | | | | < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | < | | | < | | | | | | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 | # Remove the trailing newline string trim $result } } } # ----- module text-formatting ----- set modsource(text-formatting) { # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module which provides text formatting use formatting proc wordwrap {text length {firstprefix ""} {nextprefix ""}} { set len 0 set space $firstprefix foreach word [split $text] { set word [string trim $word] if {$word == ""} { continue } if {$len && [string length $space$word] + $len >= $length} { puts "" set len 0 set space $nextprefix } incr len [string length $space$word] # Use man-page conventions for highlighting 'quoted' and *quoted* # single words. # Use x^Hx for *bold* and _^Hx for 'underline'. # # less and more will both understand this. # Pipe through 'col -b' to remove them. if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} { regsub -all . $bareword "_\b&" word append word $dot } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} { regsub -all . $bareword "&\b&" word append word $dot } puts -nonewline $space$word set space " " } if {$len} { puts "" } } proc title {text} { underline [string trim $text] = nl } proc p {text} { wordwrap $text 80 nl } proc codelines {lines} { foreach line $lines { puts " $line" } nl } proc nl {} { puts "" } proc underline {text char} { regexp "^(\[ \t\]*)(.*)" $text -> indent words puts $text puts $indent[string repeat $char [string length $words]] } proc section {text} { underline "[string trim $text]" - nl } proc subsection {text} { underline "$text" ~ nl } proc bullet {text} { wordwrap $text 76 " * " " " } proc indent {text} { wordwrap $text 76 " " " " } proc defn {first args} { if {$first ne ""} { underline " $first" ~ } foreach p $args { if {$p ne ""} { indent $p } } } } # ----- module wiki-formatting ----- set modsource(wiki-formatting) { # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Module which provides text formatting # wiki.tcl.tk format output use formatting |
︙ | ︙ | |||
2447 2448 2449 2450 2451 2452 2453 | # Entry/Exit # if {$autosetup(debug)} { main $argv } if {[catch {main $argv} msg opts] == 1} { show-notices | | | 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 | # Entry/Exit # if {$autosetup(debug)} { main $argv } if {[catch {main $argv} msg opts] == 1} { show-notices autosetup-full-error [error-dump $msg $opts $::autosetup(debug)] if {!$autosetup(debug)} { puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace" } exit 1 } |
Deleted autosetup/autosetup-config.guess.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted autosetup/autosetup-config.sub.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted autosetup/autosetup-find-tclsh.
|
| < < < < < < < < < < < < < < < < < |
Deleted autosetup/autosetup-test-tclsh.
|
| < < < < < < < < < < < < < < < < < < < < |
Changes to autosetup/cc-db.tcl.
1 2 3 4 5 | # Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'cc-db' module provides a knowledge based of system idiosyncrasies # In general, this module can always be included use cc module-options {} # openbsd needs sys/types.h to detect some system headers cc-include-needs sys/socket.h sys/types.h |
︙ | ︙ |
Changes to autosetup/cc-lib.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # Provides a library of common tests on top of the 'cc' module. use cc module-options {} # @cc-check-lfs # | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # Provides a library of common tests on top of the 'cc' module. use cc module-options {} # @cc-check-lfs # # The equivalent of the AC_SYS_LARGEFILE macro # # defines 'HAVE_LFS' if LFS is available, # and defines '_FILE_OFFSET_BITS=64' if necessary # # Returns 1 if 'LFS' is available or 0 otherwise # proc cc-check-lfs {} { cc-check-includes sys/types.h |
︙ | ︙ | |||
33 34 35 36 37 38 39 | } define-feature lfs $lfs return $lfs } # @cc-check-endian # | | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | } define-feature lfs $lfs return $lfs } # @cc-check-endian # # The equivalent of the AC_C_BIGENDIAN macro # # defines 'HAVE_BIG_ENDIAN' if endian is known to be big, # or 'HAVE_LITTLE_ENDIAN' if endian is known to be little. # # Returns 1 if determined, or 0 if not. # proc cc-check-endian {} { cc-check-includes sys/types.h sys/param.h |
︙ | ︙ | |||
78 79 80 81 82 83 84 | # @cc-check-flags flag ?...? # # Checks whether the given C/C++ compiler flags can be used. Defines feature # names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and # appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'. proc cc-check-flags {args} { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | # @cc-check-flags flag ?...? # # Checks whether the given C/C++ compiler flags can be used. Defines feature # names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and # appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'. proc cc-check-flags {args} { set result 1 array set opts [cc-get-settings] switch -exact -- $opts(-lang) { c++ { set lang C++ set prefix CXXFLAG } c { set lang C set prefix CFLAG } default { autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)" } } foreach flag $args { msg-checking "Checking whether the $lang compiler accepts $flag..." if {[cctest -cflags $flag]} { msg-result yes define-feature $prefix$flag cc-with [list -cflags [list $flag]] define-append ${prefix}S $flag } else { msg-result no set result 0 } } return $result } # @cc-check-standards ver ?...? # # Checks whether the C/C++ compiler accepts one of the specified '-std=$ver' # options, and appends the first working one to '-cflags' and 'CFLAGS' or # 'CXXFLAGS'. proc cc-check-standards {args} { array set opts [cc-get-settings] foreach std $args { if {[cc-check-flags -std=$std]} { return $std } } return "" } # Checks whether $keyword is usable as alignof proc cctest_alignof {keyword} { msg-checking "Checking for $keyword..." if {[cctest -code [subst -nobackslashes { printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x')); }]]} then { msg-result ok define-feature $keyword } else { msg-result "not found" } } # @cc-check-c11 # # Checks for several C11/C++11 extensions and their alternatives. Currently # checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'. proc cc-check-c11 {} { msg-checking "Checking for _Static_assert..." if {[cctest -code { _Static_assert(1, "static assertions are available"); }]} then { msg-result ok define-feature _Static_assert } else { msg-result "not found" } cctest_alignof _Alignof cctest_alignof __alignof__ cctest_alignof __alignof } # @cc-check-alloca # # The equivalent of the AC_FUNC_ALLOCA macro # # Checks for the existence of alloca # defines HAVE_ALLOCA and returns 1 if it exists proc cc-check-alloca {} { cc-check-some-feature alloca { cctest -includes alloca.h -code { alloca (2 * sizeof (int)); } } } # @cc-signal-return-type # # The equivalent of the AC_TYPE_SIGNAL macro # # defines RETSIGTYPE to int or void proc cc-signal-return-type {} { msg-checking "Checking return type of signal handlers..." cc-with {-includes {sys/types.h signal.h}} { if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} { set type int } else { set type void } define RETSIGTYPE $type msg-result $type } } |
Changes to autosetup/cc-shared.tcl.
1 2 3 4 5 6 7 8 9 10 11 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'cc-shared' module provides support for shared libraries and shared objects. # It defines the following variables: # ## SH_CFLAGS Flags to use compiling sources destined for a shared library ## SH_LDFLAGS Flags to use linking (creating) a shared library ## SH_SOPREFIX Prefix to use to set the soname when creating a shared library | < < | | < < < | > > > > | | 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 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'cc-shared' module provides support for shared libraries and shared objects. # It defines the following variables: # ## SH_CFLAGS Flags to use compiling sources destined for a shared library ## SH_LDFLAGS Flags to use linking (creating) a shared library ## SH_SOPREFIX Prefix to use to set the soname when creating a shared library ## SH_SOEXT Extension for shared libs ## SH_SOEXTVER Format for versioned shared libs - %s = version ## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object ## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed ## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved ## SH_LINKFLAGS Flags to use linking an executable which will load shared objects ## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries ## STRIPLIBFLAGS Arguments to strip a dynamic library module-options {} # Defaults: gcc on unix define SHOBJ_CFLAGS -fpic define SHOBJ_LDFLAGS -shared define SH_CFLAGS -fpic define SH_LDFLAGS -shared define SH_LINKFLAGS -rdynamic define SH_SOEXT .so define SH_SOEXTVER .so.%s define SH_SOPREFIX -Wl,-soname, define LD_LIBRARY_PATH LD_LIBRARY_PATH define STRIPLIBFLAGS --strip-unneeded # Note: This is a helpful reference for identifying the toolchain # http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers switch -glob -- [get-define host] { *-*-darwin* { define SHOBJ_CFLAGS "-dynamic -fno-common" define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup" define SHOBJ_LDFLAGS_R -bundle define SH_CFLAGS -dynamic define SH_LDFLAGS -dynamiclib define SH_LINKFLAGS "" define SH_SOEXT .dylib define SH_SOEXTVER .%s.dylib define SH_SOPREFIX -Wl,-install_name, define LD_LIBRARY_PATH DYLD_LIBRARY_PATH define STRIPLIBFLAGS -x } *-*-ming* - *-*-cygwin - *-*-msys { define SHOBJ_CFLAGS "" define SHOBJ_LDFLAGS -shared define SH_CFLAGS "" define SH_LDFLAGS -shared define SH_LINKFLAGS "" define SH_SOEXT .dll define SH_SOEXTVER .dll define SH_SOPREFIX "" define LD_LIBRARY_PATH PATH } sparc* { if {[msg-quiet cc-check-decls __SUNPRO_C]} { msg-result "Found sun stdio compiler" # sun stdio compiler # XXX: These haven't been fully tested. define SHOBJ_CFLAGS -KPIC define SHOBJ_LDFLAGS "-G" define SH_CFLAGS -KPIC define SH_LINKFLAGS -Wl,-export-dynamic define SH_SOPREFIX -Wl,-h, } else { # sparc has a very small GOT table limit, so use -fPIC define SH_CFLAGS -fPIC define SHOBJ_CFLAGS -fPIC } } *-*-solaris* { if {[msg-quiet cc-check-decls __SUNPRO_C]} { msg-result "Found sun stdio compiler" # sun stdio compiler # XXX: These haven't been fully tested. define SHOBJ_CFLAGS -KPIC define SHOBJ_LDFLAGS "-G" define SH_CFLAGS -KPIC define SH_LINKFLAGS -Wl,-export-dynamic define SH_SOPREFIX -Wl,-h, } } |
︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 | define SHOBJ_LDFLAGS -shared define SH_CFLAGS "" define SH_LDFLAGS -shared define SH_LINKFLAGS "" define SH_SOPREFIX "" define LD_LIBRARY_PATH LIBRARY_PATH } } if {![is-defined SHOBJ_LDFLAGS_R]} { define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS] } | > > > > > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | define SHOBJ_LDFLAGS -shared define SH_CFLAGS "" define SH_LDFLAGS -shared define SH_LINKFLAGS "" define SH_SOPREFIX "" define LD_LIBRARY_PATH LIBRARY_PATH } microblaze* { # Microblaze generally needs -fPIC rather than -fpic define SHOBJ_CFLAGS -fPIC define SH_CFLAGS -fPIC } } if {![is-defined SHOBJ_LDFLAGS_R]} { define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS] } |
Changes to autosetup/cc.tcl.
1 2 3 4 5 6 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'cc' module supports checking various 'features' of the C or C++ | | | < > > > > > | 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 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'cc' module supports checking various 'features' of the C or C++ # compiler/linker environment. Common commands are cc-check-includes, # cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template. # # The following environment variables are used if set: # ## CC - C compiler ## CXX - C++ compiler ## CCACHE - Set to "none" to disable automatic use of ccache ## CFLAGS - Additional C compiler flags ## CXXFLAGS - Additional C++ compiler flags ## LDFLAGS - Additional compiler flags during linking ## LIBS - Additional libraries to use (for all tests) ## CROSS - Tool prefix for cross compilation # # The following variables are defined from the corresponding # environment variables if set. # ## CPPFLAGS ## LINKFLAGS ## CC_FOR_BUILD ## LD use system module-options {} # Note that the return code is not meaningful proc cc-check-something {name code} { uplevel 1 $code } # Checks for the existence of the given function by linking # proc cctest_function {function} { cctest -link 1 -declare "extern void $function\(void);" -code "$function\();" } |
︙ | ︙ | |||
62 63 64 65 66 67 68 | proc cctest_decl {name} { cctest -code "#ifndef $name\n(void)$name;\n#endif" } # @cc-check-sizeof type ... # # Checks the size of the given types (between 1 and 32, inclusive). | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | proc cctest_decl {name} { cctest -code "#ifndef $name\n(void)$name;\n#endif" } # @cc-check-sizeof type ... # # Checks the size of the given types (between 1 and 32, inclusive). # Defines a variable with the size determined, or "unknown" otherwise. # e.g. for type 'long long', defines SIZEOF_LONG_LONG. # Returns the size of the last type. # proc cc-check-sizeof {args} { foreach type $args { msg-checking "Checking for sizeof $type..." set size unknown # Try the most common sizes first |
︙ | ︙ | |||
103 104 105 106 107 108 109 | } } return $ret } # @cc-check-includes includes ... # | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | } } return $ret } # @cc-check-includes includes ... # # Checks that the given include files can be used proc cc-check-includes {args} { cc-check-some-feature $args { set with {} if {[dict exists $::autosetup(cc-include-deps) $each]} { set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]] msg-quiet cc-check-includes {*}$deps foreach i $deps { |
︙ | ︙ | |||
128 129 130 131 132 133 134 | cctest -includes $each } } } # @cc-include-needs include required ... # | | | | | | | | | | | | | | | 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 | cctest -includes $each } } } # @cc-include-needs include required ... # # Ensures that when checking for 'include', a check is first # made for each 'required' file, and if found, it is #included proc cc-include-needs {file args} { foreach depfile $args { dict set ::autosetup(cc-include-deps) $file $depfile 1 } } # @cc-check-types type ... # # Checks that the types exist. proc cc-check-types {args} { cc-check-some-feature $args { cctest_type $each } } # @cc-check-defines define ... # # Checks that the given preprocessor symbol is defined proc cc-check-defines {args} { cc-check-some-feature $args { cctest_define $each } } # @cc-check-decls name ... # # Checks that each given name is either a preprocessor symbol or rvalue # such as an enum. Note that the define used is HAVE_DECL_xxx # rather than HAVE_xxx proc cc-check-decls {args} { set ret 1 foreach name $args { msg-checking "Checking for $name..." set r [cctest_decl $name] define-feature "decl $name" $r if {$r} { msg-result "ok" } else { msg-result "not found" set ret 0 } } return $ret } # @cc-check-functions function ... # # Checks that the given functions exist (can be linked) proc cc-check-functions {args} { cc-check-some-feature $args { cctest_function $each } } # @cc-check-members type.member ... # # Checks that the given type/structure members exist. # A structure member is of the form "struct stat.st_mtime" proc cc-check-members {args} { cc-check-some-feature $args { cctest_member $each } } # @cc-check-function-in-lib function libs ?otherlibs? # # Checks that the given function can be found in one of the libs. # # First checks for no library required, then checks each of the libraries # in turn. # # If the function is found, the feature is defined and lib_$function is defined # to -l$lib where the function was found, or "" if no library required. # In addition, -l$lib is prepended to the LIBS define. # # If additional libraries may be needed for linking, they should be specified # as $extralibs as "-lotherlib1 -lotherlib2". # These libraries are not automatically added to LIBS. # # Returns 1 if found or 0 if not. # proc cc-check-function-in-lib {function libs {otherlibs {}}} { msg-checking "Checking libs for $function..." set found 0 cc-with [list -libs $otherlibs] { if {[cctest_function $function]} { msg-result "none needed" define lib_$function "" |
︙ | ︙ | |||
234 235 236 237 238 239 240 | incr found break } } } } } | < | > > | | | | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | incr found break } } } } } if {$found} { define [feature-define-name $function] } else { msg-result "no" } return $found } # @cc-check-tools tool ... # # Checks for existence of the given compiler tools, taking # into account any cross compilation prefix. # # For example, when checking for "ar", first AR is checked on the command # line and then in the environment. If not found, "${host}-ar" or # simply "ar" is assumed depending upon whether cross compiling. # The path is searched for this executable, and if found AR is defined # to the executable name. # Note that even when cross compiling, the simple "ar" is used as a fallback, # but a warning is generated. This is necessary for some toolchains. # # It is an error if the executable is not found. # proc cc-check-tools {args} { foreach tool $args { set TOOL [string toupper $tool] |
︙ | ︙ | |||
277 278 279 280 281 282 283 | } } # @cc-check-progs prog ... # # Checks for existence of the given executables on the path. # | | | | < < < < < < < < < < < < < < < < < < < < < < < | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | } } # @cc-check-progs prog ... # # Checks for existence of the given executables on the path. # # For example, when checking for "grep", the path is searched for # the executable, 'grep', and if found GREP is defined as "grep". # # If the executable is not found, the variable is defined as false. # Returns 1 if all programs were found, or 0 otherwise. # proc cc-check-progs {args} { set failed 0 foreach prog $args { set PROG [string toupper $prog] msg-checking "Checking for $prog..." if {![find-executable $prog]} { msg-result no define $PROG false incr failed } else { msg-result ok define $PROG $prog } } expr {!$failed} } # Adds the given settings to $::autosetup(ccsettings) and # returns the old settings. # proc cc-add-settings {settings} { |
︙ | ︙ | |||
342 343 344 345 346 347 348 | array set new $prev foreach {name value} $settings { switch -exact -- $name { -cflags - -includes { # These are given as lists | | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | array set new $prev foreach {name value} $settings { switch -exact -- $name { -cflags - -includes { # These are given as lists lappend new($name) {*}$value } -declare { lappend new($name) $value } -libs { # Note that new libraries are added before previous libraries set new($name) [list {*}$value {*}$new($name)] } -link - -lang - -nooutput { set new($name) $value } -source - -sourcefile - -code { # XXX: These probably are only valid directly from cctest set new($name) $value |
︙ | ︙ | |||
389 390 391 392 393 394 395 | set prev [cc-get-settings] cc-store-settings [dict merge $prev $args] return $prev } # @cc-with settings ?{ script }? # | | | | | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | set prev [cc-get-settings] cc-store-settings [dict merge $prev $args] return $prev } # @cc-with settings ?{ script }? # # Sets the given 'cctest' settings and then runs the tests in 'script'. # Note that settings such as -lang replace the current setting, while # those such as -includes are appended to the existing setting. # # If no script is given, the settings become the default for the remainder # of the auto.def file. # ## cc-with {-lang c++} { ## # This will check with the C++ compiler ## cc-check-types bool ## cc-with {-includes signal.h} { ## # This will check with the C++ compiler, signal.h and any existing includes. ## ... ## } ## # back to just the C++ compiler ## } # # The -libs setting is special in that newer values are added *before* earlier ones. # ## cc-with {-libs {-lc -lm}} { ## cc-with {-libs -ldl} { ## cctest -libs -lsocket ... ## # libs will be in this order: -lsocket -ldl -lc -lm ## } ## } |
︙ | ︙ | |||
431 432 433 434 435 436 437 | return -code [dict get $info -code] $result } return $result } } # @cctest ?settings? | | | | > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | return -code [dict get $info -code] $result } return $result } } # @cctest ?settings? # # Low level C compiler checker. Compiles and or links a small C program # according to the arguments and returns 1 if OK, or 0 if not. # # Supported settings are: # ## -cflags cflags A list of flags to pass to the compiler ## -includes list A list of includes, e.g. {stdlib.h stdio.h} ## -declare code Code to declare before main() ## -link 1 Don't just compile, link too ## -lang c|c++ Use the C (default) or C++ compiler ## -libs liblist List of libraries to link, e.g. {-ldl -lm} ## -code code Code to compile in the body of main() ## -source code Compile a complete program. Ignore -includes, -declare and -code ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file] ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error # # Unless -source or -sourcefile is specified, the C program looks like: # ## #include <firstinclude> /* same for remaining includes in the list */ ## ## declare-code /* any code in -declare, verbatim */ ## ## int main(void) { ## code /* any code in -code, verbatim */ ## return 0; ## } # # Any failures are recorded in 'config.log' # proc cctest {args} { set src conftest__.c set tmp conftest__ # Easiest way to merge in the settings cc-with $args { array set opts [cc-get-settings] } |
︙ | ︙ | |||
503 504 505 506 507 508 509 | } # Build the command line set cmdline {} lappend cmdline {*}[get-define CCACHE] switch -exact -- $opts(-lang) { c++ { | < < | 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | } # Build the command line set cmdline {} lappend cmdline {*}[get-define CCACHE] switch -exact -- $opts(-lang) { c++ { lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS] } c { lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS] } default { autosetup-error "cctest called with unknown language: $opts(-lang)" } } |
︙ | ︙ | |||
571 572 573 574 575 576 577 | set ::cc_cache($cmdline,$lines) $ok return $ok } # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*? # | | | | | | | | | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | set ::cc_cache($cmdline,$lines) $ok return $ok } # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*? # # Deprecated - see make-config-header proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} { user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead" make-config-header $file -auto $autopatterns -bare $barepatterns } # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ... # # Examines all defined variables which match the given patterns # and writes an include file, $file, which defines each of these. # Variables which match '-auto' are output as follows: # - defines which have the value "0" are ignored. # - defines which have integer values are defined as the integer value. # - any other value is defined as a string, e.g. "value" # Variables which match '-bare' are defined as-is. # Variables which match '-str' are defined as a string, e.g. "value" # Variables which match '-none' are omitted. # # Note that order is important. The first pattern which matches is selected # Default behaviour is: # # -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none * # # If the file would be unchanged, it is not written. proc make-config-header {file args} { set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]] file mkdir [file dirname $file] set lines {} lappend lines "#ifndef $guard" |
︙ | ︙ | |||
695 696 697 698 699 700 701 | if {[get-define CC] eq ""} { user-error "Could not find a C compiler. Tried: [join $try ", "]" } define CCACHE [find-an-executable [get-env CCACHE ccache]] | < < < < < < < < < | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | if {[get-define CC] eq ""} { user-error "Could not find a C compiler. Tried: [join $try ", "]" } define CCACHE [find-an-executable [get-env CCACHE ccache]] # Initial cctest settings cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0} set autosetup(cc-include-deps) {} msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]" if {[get-define CXX] ne "false"} { msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]" |
︙ | ︙ |
Added autosetup/config.guess.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 | #! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-11-04' # 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 3 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, see <http://www.gnu.org/licenses/>. # # 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 Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches to <config-patches@gnu.org>. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2014 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 ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # 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 case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include <features.h> #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # 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 tuples: *-*-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 ;; sh5el) machine=sh5le-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 -q __ELF__ 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 ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; 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 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; 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 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; 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 ;; 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 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; 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 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # 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 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include <stdio.h> /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; 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 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; 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 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include <sys/systemcfg.h> main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi 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 ;; *:AIX:*:[4567]) 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/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include <stdlib.h> #include <unistd.h> int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include <unistd.h> int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; 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 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; 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 ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; 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 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; 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 -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; 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-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; 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 ;; 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 ;; 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 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; 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 ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. 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 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` echo ${UNAME_MACHINE}-pc-isc$UNAME_REL elif /bin/uname -X 2>/dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; 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 i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; 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 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' 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; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *: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 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says <Richard.M.Bartel@ccMail.Census.GOV> echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes <hewes@openmarket.com>. # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; 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 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *: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 ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *: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 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 <<EOF $0: unable to guess system type This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD and http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD If the version you run ($0) is already up to date, please send the following data and any information you think might be pertinent to <config-patches@gnu.org> in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: |
Added autosetup/config.sub.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 | #! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-12-03' # 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 3 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, see <http://www.gnu.org/licenses/>. # # 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 Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to <config-patches@gnu.org>. # # 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. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) Copyright 1992-2014 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 ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # 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 ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -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 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -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/'` ;; -sco5v6*) # 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*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -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 \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-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*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-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*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 ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; 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 ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) 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 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; 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 ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) 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. -auroraux) os=-auroraux ;; -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* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # 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* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -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 score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; 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 ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: |
Added autosetup/find-tclsh.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/bin/sh # Looks for a suitable tclsh or jimsh in the PATH # If not found, builds a bootstrap jimsh from source d=`dirname "$0"` { "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0 PATH="$PATH:$d"; export PATH for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do { $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0 done echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0" for cc in ${CC_FOR_BUILD:-cc} gcc; do { $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue "$d/jimsh0" "$d/test-tclsh" && exit 0 done echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc." echo false |
Changes to autosetup/jimsh0.c.
1 2 3 4 5 6 7 8 9 | /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */ #define JIM_TCL_COMPAT #define JIM_ANSIC #define JIM_REGEXP #define HAVE_NO_AUTOCONF #define _JIMAUTOCONF_H #define TCL_LIBRARY "." #define jim_ext_bootstrap #define jim_ext_aio | > > | 1 2 3 4 5 6 7 8 9 10 11 | /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */ #define _GNU_SOURCE #define JIM_TCL_COMPAT #define JIM_REFERENCES #define JIM_ANSIC #define JIM_REGEXP #define HAVE_NO_AUTOCONF #define _JIMAUTOCONF_H #define TCL_LIBRARY "." #define jim_ext_bootstrap #define jim_ext_aio |
︙ | ︙ | |||
27 28 29 30 31 32 33 | #define TCL_PLATFORM_PLATFORM "windows" #define TCL_PLATFORM_PATH_SEPARATOR ";" #define HAVE_MKDIR_ONE_ARG #define HAVE_SYSTEM #define HAVE_SYS_TIME_H #define HAVE_DIRENT_H #define HAVE_UNISTD_H | < < < < < < < < < < < < < < < | | 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 | #define TCL_PLATFORM_PLATFORM "windows" #define TCL_PLATFORM_PATH_SEPARATOR ";" #define HAVE_MKDIR_ONE_ARG #define HAVE_SYSTEM #define HAVE_SYS_TIME_H #define HAVE_DIRENT_H #define HAVE_UNISTD_H #else #define TCL_PLATFORM_OS "unknown" #define TCL_PLATFORM_PLATFORM "unix" #define TCL_PLATFORM_PATH_SEPARATOR ":" #define HAVE_VFORK #define HAVE_WAITPID #define HAVE_ISATTY #define HAVE_MKSTEMP #define HAVE_LINK #define HAVE_SYS_TIME_H #define HAVE_DIRENT_H #define HAVE_UNISTD_H #endif #define JIM_VERSION 76 #ifndef JIM_WIN32COMPAT_H #define JIM_WIN32COMPAT_H #ifdef __cplusplus extern "C" { |
︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #define LLONG_MIN (-LLONG_MAX - 1I64) #endif #define JIM_WIDE_MIN LLONG_MIN #define JIM_WIDE_MAX LLONG_MAX #define JIM_WIDE_MODIFIER "I64d" #define strcasecmp _stricmp #define strtoull _strtoui64 #include <io.h> struct timeval { long tv_sec; long tv_usec; }; int gettimeofday(struct timeval *tv, void *unused); #define HAVE_OPENDIR struct dirent { char *d_name; }; typedef struct DIR { | > | | | > > > > > | | 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 | #define LLONG_MIN (-LLONG_MAX - 1I64) #endif #define JIM_WIDE_MIN LLONG_MIN #define JIM_WIDE_MAX LLONG_MAX #define JIM_WIDE_MODIFIER "I64d" #define strcasecmp _stricmp #define strtoull _strtoui64 #define snprintf _snprintf #include <io.h> struct timeval { long tv_sec; long tv_usec; }; int gettimeofday(struct timeval *tv, void *unused); #define HAVE_OPENDIR struct dirent { char *d_name; }; typedef struct DIR { long handle; struct _finddata_t info; struct dirent result; char *name; } DIR; DIR *opendir(const char *name); int closedir(DIR *dir); struct dirent *readdir(DIR *dir); #elif defined(__MINGW32__) #include <stdlib.h> #define strtod __strtod #endif #endif #ifdef __cplusplus } #endif #endif #ifndef UTF8_UTIL_H |
︙ | ︙ | |||
151 152 153 154 155 156 157 | int utf8_fromunicode(char *p, unsigned uc); #ifndef JIM_UTF8 #include <ctype.h> | | < < | | | | 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 | int utf8_fromunicode(char *p, unsigned uc); #ifndef JIM_UTF8 #include <ctype.h> #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B)) #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) #define utf8_getchars(CP, C) (*(CP) = (C), 1) #define utf8_upper(C) toupper(C) #define utf8_title(C) toupper(C) #define utf8_lower(C) tolower(C) #define utf8_index(C, I) (I) #define utf8_charlen(C) 1 #define utf8_prev_len(S, L) 1 #else #endif #ifdef __cplusplus } #endif #endif #ifndef __JIM__H #define __JIM__H #ifdef __cplusplus extern "C" { #endif #include <time.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #ifndef HAVE_NO_AUTOCONF #endif |
︙ | ︙ | |||
231 232 233 234 235 236 237 | #define JIM_BREAK 3 #define JIM_CONTINUE 4 #define JIM_SIGNAL 5 #define JIM_EXIT 6 #define JIM_EVAL 7 | | | | | | | | | | | | | | | 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 256 | #define JIM_BREAK 3 #define JIM_CONTINUE 4 #define JIM_SIGNAL 5 #define JIM_EXIT 6 #define JIM_EVAL 7 #define JIM_MAX_CALLFRAME_DEPTH 1000 #define JIM_MAX_EVAL_DEPTH 2000 #define JIM_PRIV_FLAG_SHIFT 20 #define JIM_NONE 0 #define JIM_ERRMSG 1 #define JIM_ENUM_ABBREV 2 #define JIM_UNSHARED 4 #define JIM_MUSTEXIST 8 #define JIM_SUBST_NOVAR 1 #define JIM_SUBST_NOCMD 2 #define JIM_SUBST_NOESC 4 #define JIM_SUBST_FLAG 128 #define JIM_CASESENS 0 #define JIM_NOCASE 1 #define JIM_PATH_LEN 1024 #define JIM_NOTUSED(V) ((void) V) |
︙ | ︙ | |||
346 347 348 349 350 351 352 | #define Jim_GetHashEntryVal(he) ((he)->u.val) #define Jim_GetHashTableCollisions(ht) ((ht)->collisions) #define Jim_GetHashTableSize(ht) ((ht)->size) #define Jim_GetHashTableUsed(ht) ((ht)->used) typedef struct Jim_Obj { | | | | | | | | | | | | < < < < < < | | | | | | | | | | | | | > > > > > | | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | #define Jim_GetHashEntryVal(he) ((he)->u.val) #define Jim_GetHashTableCollisions(ht) ((ht)->collisions) #define Jim_GetHashTableSize(ht) ((ht)->size) #define Jim_GetHashTableUsed(ht) ((ht)->used) typedef struct Jim_Obj { char *bytes; const struct Jim_ObjType *typePtr; int refCount; int length; union { jim_wide wideValue; int intValue; double doubleValue; void *ptr; struct { void *ptr1; void *ptr2; } twoPtrValue; struct { struct Jim_Var *varPtr; unsigned long callFrameId; int global; } varValue; struct { struct Jim_Obj *nsObj; struct Jim_Cmd *cmdPtr; unsigned long procEpoch; } cmdValue; struct { struct Jim_Obj **ele; int len; int maxLen; } listValue; struct { int maxLength; int charLength; } strValue; struct { unsigned long id; struct Jim_Reference *refPtr; } refValue; struct { struct Jim_Obj *fileNameObj; int lineNumber; } sourceValue; struct { struct Jim_Obj *varNameObjPtr; struct Jim_Obj *indexObjPtr; } dictSubstValue; struct { void *compre; unsigned flags; } regexpValue; struct { int line; int argc; } scriptLineValue; } internalRep; struct Jim_Obj *prevObjPtr; struct Jim_Obj *nextObjPtr; } Jim_Obj; #define Jim_IncrRefCount(objPtr) \ ++(objPtr)->refCount #define Jim_DecrRefCount(interp, objPtr) \ if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr) |
︙ | ︙ | |||
450 451 452 453 454 455 456 | typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp, struct Jim_Obj *objPtr); typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp, struct Jim_Obj *srcPtr, Jim_Obj *dupPtr); typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr); typedef struct Jim_ObjType { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp, struct Jim_Obj *objPtr); typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp, struct Jim_Obj *srcPtr, Jim_Obj *dupPtr); typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr); typedef struct Jim_ObjType { const char *name; Jim_FreeInternalRepProc *freeIntRepProc; Jim_DupInternalRepProc *dupIntRepProc; Jim_UpdateStringProc *updateStringProc; int flags; } Jim_ObjType; #define JIM_TYPE_NONE 0 #define JIM_TYPE_REFERENCES 1 typedef struct Jim_CallFrame { unsigned long id; int level; struct Jim_HashTable vars; struct Jim_HashTable *staticVars; struct Jim_CallFrame *parent; Jim_Obj *const *argv; int argc; Jim_Obj *procArgsObjPtr; Jim_Obj *procBodyObjPtr; struct Jim_CallFrame *next; Jim_Obj *nsObj; Jim_Obj *fileNameObj; int line; Jim_Stack *localCommands; struct Jim_Obj *tailcallObj; struct Jim_Cmd *tailcallCmd; } Jim_CallFrame; typedef struct Jim_Var { Jim_Obj *objPtr; struct Jim_CallFrame *linkFramePtr; } Jim_Var; typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc, Jim_Obj *const *argv); typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData); typedef struct Jim_Cmd { int inUse; int isproc; struct Jim_Cmd *prevCmd; union { struct { Jim_CmdProc *cmdProc; Jim_DelCmdProc *delProc; void *privData; } native; struct { Jim_Obj *argListObjPtr; Jim_Obj *bodyObjPtr; Jim_HashTable *staticVars; int argListLen; int reqArity; int optArity; int argsPos; int upcall; struct Jim_ProcArg { Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; } *arglist; Jim_Obj *nsObj; } proc; } u; } Jim_Cmd; typedef struct Jim_PrngState { unsigned char sbox[256]; unsigned int i, j; } Jim_PrngState; typedef struct Jim_Interp { Jim_Obj *result; int errorLine; Jim_Obj *errorFileNameObj; int addStackTrace; int maxCallFrameDepth; int maxEvalDepth; int evalDepth; int returnCode; int returnLevel; int exitCode; long id; int signal_level; jim_wide sigmask; int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); Jim_CallFrame *framePtr; Jim_CallFrame *topFramePtr; struct Jim_HashTable commands; unsigned long procEpoch; /* Incremented every time the result of procedures names lookup caching may no longer be valid. */ unsigned long callFrameEpoch; /* Incremented every time a new callframe is created. This id is used for the 'ID' field contained in the Jim_CallFrame structure. */ int local; Jim_Obj *liveList; Jim_Obj *freeList; Jim_Obj *currentScriptObj; Jim_Obj *nullScriptObj; Jim_Obj *emptyObj; Jim_Obj *trueObj; Jim_Obj *falseObj; unsigned long referenceNextId; struct Jim_HashTable references; unsigned long lastCollectId; /* reference max Id of the last GC execution. It's set to -1 while the collection is running as sentinel to avoid to recursive calls via the [collect] command inside finalizers. */ time_t lastCollectTime; Jim_Obj *stackTrace; Jim_Obj *errorProc; Jim_Obj *unknown; int unknown_called; int errorFlag; void *cmdPrivData; /* Used to pass the private data pointer to a command. It is set to what the user specified via Jim_CreateCommand(). */ struct Jim_CallFrame *freeFramesList; struct Jim_HashTable assocData; Jim_PrngState *prngState; struct Jim_HashTable packages; Jim_Stack *loadHandles; } Jim_Interp; #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++ #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l)) #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval)) #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b) |
︙ | ︙ | |||
631 632 633 634 635 636 637 | JIM_EXPORT void Jim_Free (void *ptr); JIM_EXPORT char * Jim_StrDup (const char *s); JIM_EXPORT char *Jim_StrDupLen(const char *s, int l); JIM_EXPORT char **Jim_GetEnviron(void); JIM_EXPORT void Jim_SetEnviron(char **env); | | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | JIM_EXPORT void Jim_Free (void *ptr); JIM_EXPORT char * Jim_StrDup (const char *s); JIM_EXPORT char *Jim_StrDupLen(const char *s, int l); JIM_EXPORT char **Jim_GetEnviron(void); JIM_EXPORT void Jim_SetEnviron(char **env); JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *template); JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script); JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script); |
︙ | ︙ | |||
824 825 826 827 828 829 830 | JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags); JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len); JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr); | | < < | < < | < < < < | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags); JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len); JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr); JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj); JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr); JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr); JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr); JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr); JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr, jim_wide *widePtr); JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr); #define Jim_NewWideObj Jim_NewIntObj JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp, |
︙ | ︙ | |||
868 869 870 871 872 873 874 | JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue); JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg); JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr, const char * const *tablePtr, int *indexPtr, const char *name, int flags); | < < | 850 851 852 853 854 855 856 857 858 859 860 861 862 863 | JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue); JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg); JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr, const char * const *tablePtr, int *indexPtr, const char *name, int flags); JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr); JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len); typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data); |
︙ | ︙ | |||
896 897 898 899 900 901 902 | JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp); JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp); JIM_EXPORT void Jim_HistoryLoad(const char *filename); JIM_EXPORT void Jim_HistorySave(const char *filename); | | < | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp); JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp); JIM_EXPORT void Jim_HistoryLoad(const char *filename); JIM_EXPORT void Jim_HistorySave(const char *filename); JIM_EXPORT char *Jim_HistoryGetline(const char *prompt); JIM_EXPORT void Jim_HistoryAdd(const char *line); JIM_EXPORT void Jim_HistoryShow(void); JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); JIM_EXPORT int Jim_IsBigEndian(void); |
︙ | ︙ | |||
923 924 925 926 927 928 929 | JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr); JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); #ifdef __cplusplus } #endif | | | | | | | | | | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr); JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); #ifdef __cplusplus } #endif #endif #ifndef JIM_SUBCMD_H #define JIM_SUBCMD_H #ifdef __cplusplus extern "C" { #endif #define JIM_MODFLAG_HIDDEN 0x0001 #define JIM_MODFLAG_FULLARGV 0x0002 typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv); typedef struct { const char *cmd; const char *args; jim_subcmd_function *function; short minargs; short maxargs; unsigned short flags; } jim_subcmd_type; const jim_subcmd_type * Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv); int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv); |
︙ | ︙ | |||
979 980 981 982 983 984 985 | typedef struct { int rm_so; int rm_eo; } regmatch_t; typedef struct regexp { | | | | | | | | | | | | | | | | | | | | | | | | | | | 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | typedef struct { int rm_so; int rm_eo; } regmatch_t; typedef struct regexp { int re_nsub; int cflags; int err; int regstart; int reganch; int regmust; int regmlen; int *program; const char *regparse; int p; int proglen; int eflags; const char *start; const char *reginput; const char *regbol; regmatch_t *pmatch; int nmatch; } regexp; typedef regexp regex_t; #define REG_EXTENDED 0 #define REG_NEWLINE 1 #define REG_ICASE 2 #define REG_NOTBOL 16 enum { REG_NOERROR, REG_NOMATCH, REG_BADPAT, REG_ERR_NULL_ARGUMENT, REG_ERR_UNKNOWN, REG_ERR_TOO_BIG, REG_ERR_NOMEM, REG_ERR_TOO_MANY_PAREN, REG_ERR_UNMATCHED_PAREN, REG_ERR_UNMATCHED_BRACES, |
︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 1054 | size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); void regfree(regex_t *preg); #ifdef __cplusplus } #endif #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | | | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 | size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); void regfree(regex_t *preg); #ifdef __cplusplus } #endif #endif int Jim_bootstrapInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG)) return JIM_ERR; return Jim_EvalSource(interp, "bootstrap.tcl", 1, "\n" "\n" "proc package {cmd pkg} {\n" " if {$cmd eq \"require\"} {\n" " foreach path $::auto_path {\n" " if {[file exists $path/$pkg.tcl]} {\n" " uplevel #0 [list source $path/$pkg.tcl]\n" " return\n" " }\n" " }\n" " }\n" "}\n" ); } |
︙ | ︙ | |||
1196 1197 1198 1199 1200 1201 1202 | " return \"\"\n" "}\n" "\n" "if {$tcl_platform(platform) eq \"windows\"} {\n" " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n" "}\n" "\n" | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | " return \"\"\n" "}\n" "\n" "if {$tcl_platform(platform) eq \"windows\"} {\n" " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n" "}\n" "\n" "_jimsh_init\n" ); } int Jim_globInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG)) return JIM_ERR; |
︙ | ︙ | |||
1444 1445 1446 1447 1448 1449 1450 | { if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG)) return JIM_ERR; return Jim_EvalSource(interp, "stdlib.tcl", 1, "\n" "\n" | < < < < < < < | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | { if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG)) return JIM_ERR; return Jim_EvalSource(interp, "stdlib.tcl", 1, "\n" "\n" "\n" "proc lambda {arglist args} {\n" " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n" "}\n" "\n" "proc lambda.finalizer {name val} {\n" " rename $name {}\n" |
︙ | ︙ | |||
1511 1512 1513 1514 1515 1516 1517 | " lappend lines $line\n" " }\n" " }\n" " join $lines \\n\n" "}\n" "\n" "\n" | < < < < < < < | 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 | " lappend lines $line\n" " }\n" " }\n" " join $lines \\n\n" "}\n" "\n" "\n" "\n" "proc errorInfo {msg {stacktrace \"\"}} {\n" " if {$stacktrace eq \"\"} {\n" "\n" " set stacktrace [info stacktrace]\n" "\n" " lappend stacktrace {*}[stacktrace 1]\n" |
︙ | ︙ | |||
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 | "\n" "proc {info nameofexecutable} {} {\n" " if {[exists ::jim::exe]} {\n" " return $::jim::exe\n" " }\n" "}\n" "\n" "\n" "proc {dict update} {&varName args script} {\n" " set keys {}\n" " foreach {n v} $args {\n" " upvar $v var_$v\n" " if {[dict exists $varName $n]} {\n" " set var_$v [dict get $varName $n]\n" | > > > > > > > > > > > > > > > > > > > > > | 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 | "\n" "proc {info nameofexecutable} {} {\n" " if {[exists ::jim::exe]} {\n" " return $::jim::exe\n" " }\n" "}\n" "\n" "\n" "proc {dict with} {&dictVar {args key} script} {\n" " set keys {}\n" " foreach {n v} [dict get $dictVar {*}$key] {\n" " upvar $n var_$n\n" " set var_$n $v\n" " lappend keys $n\n" " }\n" " catch {uplevel 1 $script} msg opts\n" " if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n" " foreach n $keys {\n" " if {[info exists var_$n]} {\n" " dict set dictVar {*}$key $n [set var_$n]\n" " } else {\n" " dict unset dictVar {*}$key $n\n" " }\n" " }\n" " }\n" " return {*}$opts $msg\n" "}\n" "\n" "\n" "proc {dict update} {&varName args script} {\n" " set keys {}\n" " foreach {n v} $args {\n" " upvar $v var_$v\n" " if {[dict exists $varName $n]} {\n" " set var_$v [dict get $varName $n]\n" |
︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 | " dict unset varName $n\n" " }\n" " }\n" " }\n" " return {*}$opts $msg\n" "}\n" "\n" "proc {dict replace} {dictionary {args {key value}}} {\n" " if {[llength ${key value}] % 2} {\n" " tailcall {dict replace}\n" " }\n" " tailcall dict merge $dictionary ${key value}\n" "}\n" "\n" | > > > > > > > > > > > > > | 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 | " dict unset varName $n\n" " }\n" " }\n" " }\n" " return {*}$opts $msg\n" "}\n" "\n" "\n" "\n" "proc {dict merge} {dict args} {\n" " foreach d $args {\n" "\n" " dict size $d\n" " foreach {k v} $d {\n" " dict set dict $k $v\n" " }\n" " }\n" " return $dict\n" "}\n" "\n" "proc {dict replace} {dictionary {args {key value}}} {\n" " if {[llength ${key value}] % 2} {\n" " tailcall {dict replace}\n" " }\n" " tailcall dict merge $dictionary ${key value}\n" "}\n" "\n" |
︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | "proc {dict remove} {dictionary {args key}} {\n" " foreach k $key {\n" " dict unset dictionary $k\n" " }\n" " return $dictionary\n" "}\n" "\n" "\n" "proc {dict for} {vars dictionary script} {\n" " if {[llength $vars] != 2} {\n" " return -code error \"must have exactly two variable names\"\n" " }\n" " dict size $dictionary\n" " tailcall foreach $vars $dictionary $script\n" | > > > > > | 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | "proc {dict remove} {dictionary {args key}} {\n" " foreach k $key {\n" " dict unset dictionary $k\n" " }\n" " return $dictionary\n" "}\n" "\n" "\n" "proc {dict values} {dictionary {pattern *}} {\n" " dict keys [lreverse $dictionary] $pattern\n" "}\n" "\n" "\n" "proc {dict for} {vars dictionary script} {\n" " if {[llength $vars] != 2} {\n" " return -code error \"must have exactly two variable names\"\n" " }\n" " dict size $dictionary\n" " tailcall foreach $vars $dictionary $script\n" |
︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 | "\n" "\n" "proc fileevent {args} {\n" " tailcall {*}$args\n" "}\n" "\n" "\n" "\n" "proc parray {arrayname {pattern *} {puts puts}} {\n" " upvar $arrayname a\n" "\n" " set max 0\n" " foreach name [array names a $pattern]] {\n" " if {[string length $name] > $max} {\n" | > | 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 | "\n" "\n" "proc fileevent {args} {\n" " tailcall {*}$args\n" "}\n" "\n" "\n" "\n" "\n" "proc parray {arrayname {pattern *} {puts puts}} {\n" " upvar $arrayname a\n" "\n" " set max 0\n" " foreach name [array names a $pattern]] {\n" " if {[string length $name] > $max} {\n" |
︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 | " catch {$in close}\n" " }\n" "}\n" "\n" "\n" "\n" "proc popen {cmd {mode r}} {\n" | | < < < < | < < < < < < < < < < < | | 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 | " catch {$in close}\n" " }\n" "}\n" "\n" "\n" "\n" "proc popen {cmd {mode r}} {\n" " lassign [socket pipe] r w\n" " try {\n" " if {[string match \"w*\" $mode]} {\n" " lappend cmd <@$r &\n" " set pids [exec {*}$cmd]\n" " $r close\n" " set f $w\n" " } else {\n" " lappend cmd >@$w &\n" " set pids [exec {*}$cmd]\n" " $w close\n" " set f $r\n" " }\n" " lambda {cmd args} {f pids} {\n" " if {$cmd eq \"pid\"} {\n" " return $pids\n" " }\n" " if {$cmd eq \"close\"} {\n" " $f close\n" "\n" " foreach p $pids { os.wait $p }\n" " return\n" " }\n" " tailcall $f $cmd {*}$args\n" " }\n" " } on error {error opts} {\n" " $r close\n" " $w close\n" " error $error\n" |
︙ | ︙ | |||
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 | " return -code error \"can not find channel named \\\"$channelId\\\"\"\n" " }\n" " if {[catch {$channelId pid} pids]} {\n" " return \"\"\n" " }\n" " return $pids\n" "}\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" | > > > > | 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 | " return -code error \"can not find channel named \\\"$channelId\\\"\"\n" " }\n" " if {[catch {$channelId pid} pids]} {\n" " return \"\"\n" " }\n" " return $pids\n" "}\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" |
︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 | " }\n" " file delete $path\n" "}\n" ); } | < < < < < < < < < < | | < | < < < | | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 | " }\n" " file delete $path\n" "}\n" ); } #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #include <sys/stat.h> #endif #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H) #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #ifdef HAVE_SYS_UN_H #include <sys/un.h> #endif #else #define JIM_ANSIC #endif #if defined(JIM_SSL) #include <openssl/ssl.h> #include <openssl/err.h> #endif #define AIO_CMD_LEN 32 #define AIO_BUF_LEN 256 #ifndef HAVE_FTELLO #define ftello ftell #endif #ifndef HAVE_FSEEKO #define fseeko fseek #endif #define AIO_KEEPOPEN 1 #if defined(JIM_IPV6) #define IPV6 1 #else #define IPV6 0 #ifndef PF_INET6 #define PF_INET6 0 #endif #endif #define JimCheckStreamError(interp, af) af->fops->error(af) struct AioFile; typedef struct { int (*writer)(struct AioFile *af, const char *buf, int len); int (*reader)(struct AioFile *af, char *buf, int len); const char *(*getline)(struct AioFile *af, char *buf, int len); int (*error)(const struct AioFile *af); const char *(*strerror)(struct AioFile *af); int (*verify)(struct AioFile *af); } JimAioFopsType; typedef struct AioFile { FILE *fp; Jim_Obj *filename; int type; int openFlags; int fd; Jim_Obj *rEvent; Jim_Obj *wEvent; Jim_Obj *eEvent; int addr_family; void *ssl; const JimAioFopsType *fops; |
︙ | ︙ | |||
2007 2008 2009 2010 2011 2012 2013 | static int stdio_error(const AioFile *af) { if (!ferror(af->fp)) { return JIM_OK; } clearerr(af->fp); | | | | 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 | static int stdio_error(const AioFile *af) { if (!ferror(af->fp)) { return JIM_OK; } clearerr(af->fp); if (feof(af->fp) || errno == EAGAIN || errno == EINTR) { return JIM_OK; } #ifdef ECONNRESET if (errno == ECONNRESET) { return JIM_OK; } #endif #ifdef ECONNABORTED if (errno != ECONNABORTED) { return JIM_OK; } #endif return JIM_ERR; } static const char *stdio_strerror(struct AioFile *af) |
︙ | ︙ | |||
2064 2065 2066 2067 2068 2069 2070 | Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af)); } else { Jim_SetResultString(interp, JimAioErrorString(af), -1); } } | < < < < < < < < < | | > | | 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 | Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af)); } else { Jim_SetResultString(interp, JimAioErrorString(af), -1); } } static void JimAioDelProc(Jim_Interp *interp, void *privData) { AioFile *af = privData; JIM_NOTUSED(interp); Jim_DecrRefCount(interp, af->filename); #ifdef jim_ext_eventloop Jim_DeleteFileHandler(interp, af->fp, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION); #endif #if defined(JIM_SSL) if (af->ssl != NULL) { SSL_free(af->ssl); } #endif if (!(af->openFlags & AIO_KEEPOPEN)) { fclose(af->fp); } Jim_Free(af); } static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); char buf[AIO_BUF_LEN]; Jim_Obj *objPtr; int nonewline = 0; jim_wide neededLen = -1; if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) { nonewline = 1; argv++; argc--; } if (argc == 1) { |
︙ | ︙ | |||
2143 2144 2145 2146 2147 2148 2149 | if (neededLen != -1) { neededLen -= retval; } } if (retval != readlen) break; } | | | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | if (neededLen != -1) { neededLen -= retval; } } if (retval != readlen) break; } if (JimCheckStreamError(interp, af)) { Jim_FreeNewObj(interp, objPtr); return JIM_ERR; } if (nonewline) { int len; const char *s = Jim_GetString(objPtr, &len); |
︙ | ︙ | |||
2165 2166 2167 2168 2169 2170 2171 | return JIM_OK; } AioFile *Jim_AioFile(Jim_Interp *interp, Jim_Obj *command) { Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG); | | < < < < < < < < < < | 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 | return JIM_OK; } AioFile *Jim_AioFile(Jim_Interp *interp, Jim_Obj *command) { Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG); if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) { return (AioFile *) cmdPtr->u.native.privData; } Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command); return NULL; } FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command) { AioFile *af; af = Jim_AioFile(interp, command); if (af == NULL) { return NULL; } return af->fp; } static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); jim_wide count = 0; jim_wide maxlen = JIM_WIDE_MAX; AioFile *outf = Jim_AioFile(interp, argv[0]); |
︙ | ︙ | |||
2256 2257 2258 2259 2260 2261 2262 | if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') { Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1); } else { len = strlen(buf); if (len && (buf[len - 1] == '\n')) { | | | | | 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 | if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') { Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1); } else { len = strlen(buf); if (len && (buf[len - 1] == '\n')) { len--; } Jim_AppendString(interp, objPtr, buf, len); break; } } if (JimCheckStreamError(interp, af)) { Jim_FreeNewObj(interp, objPtr); return JIM_ERR; } if (argc) { if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) { Jim_FreeNewObj(interp, objPtr); return JIM_ERR; } len = Jim_Length(objPtr); if (len == 0 && feof(af->fp)) { len = -1; } Jim_SetResultInt(interp, len); } else { Jim_SetResult(interp, objPtr); } |
︙ | ︙ | |||
2353 2354 2355 2356 2357 2358 2359 | Jim_SetResultInt(interp, feof(af->fp)); return JIM_OK; } static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc == 3) { | | | 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 | Jim_SetResultInt(interp, feof(af->fp)); return JIM_OK; } static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc == 3) { #if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN) static const char * const options[] = { "r", "w", NULL }; enum { OPT_R, OPT_W, }; int option; AioFile *af = Jim_CmdPrivData(interp); if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { return JIM_ERR; |
︙ | ︙ | |||
2444 2445 2446 2447 2448 2449 2450 | (void)fcntl(af->fd, F_SETFL, fmode); } Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0); return JIM_OK; } #endif | < | 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 | (void)fcntl(af->fd, F_SETFL, fmode); } Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0); return JIM_OK; } #endif #ifdef HAVE_FSYNC static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); fflush(af->fp); fsync(af->fd); |
︙ | ︙ | |||
2511 2512 2513 2514 2515 2516 2517 | return Jim_EvalObjBackground(interp, *objPtrPtr); } static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj, int argc, Jim_Obj * const *argv) { if (argc == 0) { | | | | | | | | | 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 | return Jim_EvalObjBackground(interp, *objPtrPtr); } static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj, int argc, Jim_Obj * const *argv) { if (argc == 0) { if (*scriptHandlerObj) { Jim_SetResult(interp, *scriptHandlerObj); } return JIM_OK; } if (*scriptHandlerObj) { Jim_DeleteFileHandler(interp, af->fp, mask); } if (Jim_Length(argv[0]) == 0) { return JIM_OK; } Jim_IncrRefCount(argv[0]); *scriptHandlerObj = argv[0]; Jim_CreateFileHandler(interp, af->fp, mask, JimAioFileEventHandler, scriptHandlerObj, JimAioFileEventFinalizer); return JIM_OK; } static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
2562 2563 2564 2565 2566 2567 2568 | AioFile *af = Jim_CmdPrivData(interp); return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv); } #endif | < < | | < < < < < < < | | | | | | | | | | | | | | | | 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 | AioFile *af = Jim_CmdPrivData(interp); return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv); } #endif static const jim_subcmd_type aio_command_table[] = { { "read", "?-nonewline? ?len?", aio_cmd_read, 0, 2, }, { "copyto", "handle ?size?", aio_cmd_copy, 1, 2, }, { "gets", "?var?", aio_cmd_gets, 0, 1, }, { "puts", "?-nonewline? str", aio_cmd_puts, 1, 2, }, { "isatty", NULL, aio_cmd_isatty, 0, 0, }, { "flush", NULL, aio_cmd_flush, 0, 0, }, { "eof", NULL, aio_cmd_eof, 0, 0, }, { "close", "?r(ead)|w(rite)?", aio_cmd_close, 0, 1, JIM_MODFLAG_FULLARGV, }, { "seek", "offset ?start|current|end", aio_cmd_seek, 1, 2, }, { "tell", NULL, aio_cmd_tell, 0, 0, }, { "filename", NULL, aio_cmd_filename, 0, 0, }, #ifdef O_NDELAY { "ndelay", "?0|1?", aio_cmd_ndelay, 0, 1, }, #endif #ifdef HAVE_FSYNC { "sync", NULL, aio_cmd_sync, 0, 0, }, #endif { "buffering", "none|line|full", aio_cmd_buffering, 1, 1, }, #ifdef jim_ext_eventloop { "readable", "?readable-script?", aio_cmd_readable, 0, 1, }, { "writable", "?writable-script?", aio_cmd_writable, 0, 1, }, { "onexception", "?exception-script?", aio_cmd_onexception, 0, 1, }, #endif { NULL } }; static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
2722 2723 2724 2725 2726 2727 2728 | mode = (argc == 3) ? Jim_String(argv[2]) : "r"; #ifdef jim_ext_tclcompat { const char *filename = Jim_String(argv[1]); | | | 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 | mode = (argc == 3) ? Jim_String(argv[2]) : "r"; #ifdef jim_ext_tclcompat { const char *filename = Jim_String(argv[1]); if (*filename == '|') { Jim_Obj *evalObj[3]; evalObj[0] = Jim_NewStringObj(interp, "::popen", -1); evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1); evalObj[2] = Jim_NewStringObj(interp, mode, -1); |
︙ | ︙ | |||
2759 2760 2761 2762 2763 2764 2765 2766 | if (!filename) { filename = Jim_NewStringObj(interp, buf, -1); } Jim_IncrRefCount(filename); if (fh == NULL) { if (fd >= 0) { | > < < > | | < < < > | > | | | > | > > | > > > > | > | > > > > > > > | > > > | > > | | > > | | > | > | < > > > | | < < < | | 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 | if (!filename) { filename = Jim_NewStringObj(interp, buf, -1); } Jim_IncrRefCount(filename); if (fh == NULL) { #if !defined(JIM_ANSIC) if (fd >= 0) { fh = fdopen(fd, mode); } else #endif fh = fopen(Jim_String(filename), mode); if (fh == NULL) { JimAioSetError(interp, filename); #if !defined(JIM_ANSIC) if (fd >= 0) { close(fd); } #endif Jim_DecrRefCount(interp, filename); return NULL; } } af = Jim_Alloc(sizeof(*af)); memset(af, 0, sizeof(*af)); af->fp = fh; af->fd = fileno(fh); af->filename = filename; #ifdef FD_CLOEXEC if ((openFlags & AIO_KEEPOPEN) == 0) { (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC); } #endif af->openFlags = openFlags; af->addr_family = family; af->fops = &stdio_fops; af->ssl = NULL; Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc); Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, Jim_NewStringObj(interp, buf, -1))); return af; } #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H)) static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename, const char *hdlfmt, int family, const char *mode[2]) { if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0])) { Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1])) { Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); Jim_SetResult(interp, objPtr); return JIM_OK; } } close(p[0]); close(p[1]); JimAioSetError(interp, NULL); return JIM_ERR; } #endif int Jim_MakeTempFile(Jim_Interp *interp, const char *template) { #ifdef HAVE_MKSTEMP int fd; mode_t mask; Jim_Obj *filenameObj; if (template == NULL) { const char *tmpdir = getenv("TMPDIR"); if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) { tmpdir = "/tmp/"; } filenameObj = Jim_NewStringObj(interp, tmpdir, -1); if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') { Jim_AppendString(interp, filenameObj, "/", 1); } Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1); } else { filenameObj = Jim_NewStringObj(interp, template, -1); } #if defined(S_IRWXG) && defined(S_IRWXO) mask = umask(S_IXUSR | S_IRWXG | S_IRWXO); #else mask = umask(S_IXUSR); #endif fd = mkstemp(filenameObj->bytes); umask(mask); if (fd < 0) { JimAioSetError(interp, filenameObj); Jim_FreeNewObj(interp, filenameObj); return -1; } Jim_SetResult(interp, filenameObj); return fd; #else Jim_SetResultString(interp, "platform has no tempfile support", -1); return -1; #endif } int Jim_aioInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG)) return JIM_ERR; #if defined(JIM_SSL) Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL); #endif Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL); #ifndef JIM_ANSIC Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL); #endif JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r"); JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w"); JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w"); return JIM_OK; } |
︙ | ︙ | |||
2947 2948 2949 2950 2951 2952 2953 | #if defined(JIM_REGEXP) #else #include <regex.h> #endif static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { | | | | | | | | | | | | 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 | #if defined(JIM_REGEXP) #else #include <regex.h> #endif static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { regfree(objPtr->internalRep.regexpValue.compre); Jim_Free(objPtr->internalRep.regexpValue.compre); } static const Jim_ObjType regexpObjType = { "regexp", FreeRegexpInternalRep, NULL, NULL, JIM_TYPE_NONE }; static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags) { regex_t *compre; const char *pattern; int ret; if (objPtr->typePtr == ®expObjType && objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) { return objPtr->internalRep.regexpValue.compre; } pattern = Jim_String(objPtr); compre = Jim_Alloc(sizeof(regex_t)); if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) { char buf[100]; regerror(ret, compre, buf, sizeof(buf)); Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf); regfree(compre); Jim_Free(compre); return NULL; } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = ®expObjType; objPtr->internalRep.regexpValue.flags = flags; objPtr->internalRep.regexpValue.compre = compre; return compre; } int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int opt_indices = 0; |
︙ | ︙ | |||
3135 3136 3137 3138 3139 3140 3141 | if (match == REG_NOMATCH) { goto done; } num_matches++; if (opt_all && !opt_inline) { | | | 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 | if (match == REG_NOMATCH) { goto done; } num_matches++; if (opt_all && !opt_inline) { goto try_next_match; } j = 0; for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) { Jim_Obj *resultObj; |
︙ | ︙ | |||
3175 3176 3177 3178 3179 3180 3181 | } } if (opt_inline) { Jim_ListAppendElement(interp, resultListObj, resultObj); } else { | | | 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 | } } if (opt_inline) { Jim_ListAppendElement(interp, resultListObj, resultObj); } else { result = Jim_SetVariable(interp, argv[i], resultObj); if (result != JIM_OK) { Jim_FreeObj(interp, resultObj); break; } } |
︙ | ︙ | |||
3302 3303 3304 3305 3306 3307 3308 | } pattern = Jim_String(argv[i]); source_str = Jim_GetString(argv[i + 1], &source_len); replace_str = Jim_GetString(argv[i + 2], &replace_len); varname = argv[i + 3]; | | | | 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 | } pattern = Jim_String(argv[i]); source_str = Jim_GetString(argv[i + 1], &source_len); replace_str = Jim_GetString(argv[i + 2], &replace_len); varname = argv[i + 3]; resultObj = Jim_NewStringObj(interp, "", 0); if (offset) { if (offset < 0) { offset += source_len + 1; } if (offset > source_len) { offset = source_len; } else if (offset < 0) { offset = 0; } } Jim_AppendString(interp, resultObj, source_str, offset); n = source_len - offset; p = source_str + offset; do { int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags); |
︙ | ︙ | |||
3376 3377 3378 3379 3380 3381 3382 | pmatch[idx].rm_eo - pmatch[idx].rm_so); } } p += pmatch[0].rm_eo; n -= pmatch[0].rm_eo; | | | | | | | 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 | pmatch[idx].rm_eo - pmatch[idx].rm_so); } } p += pmatch[0].rm_eo; n -= pmatch[0].rm_eo; if (!opt_all || n == 0) { break; } if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') { break; } if (pattern[0] == '\0' && n) { Jim_AppendString(interp, resultObj, p, 1); p++; n--; } regexec_flags |= REG_NOTBOL; } while (n); Jim_AppendString(interp, resultObj, p, -1); if (argc - i == 4) { result = Jim_SetVariable(interp, varname, resultObj); if (result == JIM_OK) { Jim_SetResultInt(interp, num_matches); } else { |
︙ | ︙ | |||
3454 3455 3456 3457 3458 3459 3460 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif # ifndef MAXPATHLEN # define MAXPATHLEN JIM_PATH_LEN # endif | | < < < < < < < | 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif # ifndef MAXPATHLEN # define MAXPATHLEN JIM_PATH_LEN # endif #if defined(__MINGW32__) || defined(_MSC_VER) #define ISWINDOWS 1 #else #define ISWINDOWS 0 #endif static const char *JimGetFileType(int mode) { if (S_ISREG(mode)) { return "file"; } else if (S_ISDIR(mode)) { |
︙ | ︙ | |||
3512 3513 3514 3515 3516 3517 3518 | { Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1)); Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); } static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb) { | | < < < | < | < < | < < | < < < > > > > > > | | | 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 | { Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1)); Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); } static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb) { Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); AppendStatElement(interp, listObj, "dev", sb->st_dev); AppendStatElement(interp, listObj, "ino", sb->st_ino); AppendStatElement(interp, listObj, "mode", sb->st_mode); AppendStatElement(interp, listObj, "nlink", sb->st_nlink); AppendStatElement(interp, listObj, "uid", sb->st_uid); AppendStatElement(interp, listObj, "gid", sb->st_gid); AppendStatElement(interp, listObj, "size", sb->st_size); AppendStatElement(interp, listObj, "atime", sb->st_atime); AppendStatElement(interp, listObj, "mtime", sb->st_mtime); AppendStatElement(interp, listObj, "ctime", sb->st_ctime); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1)); if (varName) { Jim_Obj *objPtr = Jim_GetVariable(interp, varName, JIM_NONE); if (objPtr) { if (Jim_DictSize(interp, objPtr) < 0) { Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName); Jim_FreeNewObj(interp, listObj); return JIM_ERR; } if (Jim_IsShared(objPtr)) objPtr = Jim_DuplicateObj(interp, objPtr); Jim_ListAppendList(interp, objPtr, listObj); Jim_DictSize(interp, objPtr); Jim_InvalidateStringRep(objPtr); Jim_FreeNewObj(interp, listObj); listObj = objPtr; } Jim_SetVariable(interp, varName, listObj); } Jim_SetResult(interp, listObj); return JIM_OK; } static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *path = Jim_String(argv[0]); const char *p = strrchr(path, '/'); if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') { Jim_SetResultString(interp, "..", -1); } else if (!p) { Jim_SetResultString(interp, ".", -1); } else if (p == path) { Jim_SetResultString(interp, "/", -1); } else if (ISWINDOWS && p[-1] == ':') { Jim_SetResultString(interp, path, p - path + 1); } else { Jim_SetResultString(interp, path, p - path); } return JIM_OK; } |
︙ | ︙ | |||
3658 3659 3660 3661 3662 3663 3664 | { int i; char *newname = Jim_Alloc(MAXPATHLEN + 1); char *last = newname; *newname = 0; | | | | | | | | | | 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 | { int i; char *newname = Jim_Alloc(MAXPATHLEN + 1); char *last = newname; *newname = 0; for (i = 0; i < argc; i++) { int len; const char *part = Jim_GetString(argv[i], &len); if (*part == '/') { last = newname; } else if (ISWINDOWS && strchr(part, ':')) { last = newname; } else if (part[0] == '.') { if (part[1] == '/') { part += 2; len -= 2; } else if (part[1] == 0 && last != newname) { continue; } } if (last != newname && last[-1] != '/') { *last++ = '/'; } if (len) { if (last + len - newname >= MAXPATHLEN) { Jim_Free(newname); Jim_SetResultString(interp, "Path too long", -1); return JIM_ERR; } memcpy(last, part, len); last += len; } if (last > newname + 1 && last[-1] == '/') { if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) { *--last = 0; } } } *last = 0; Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname)); return JIM_OK; } static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode) |
︙ | ︙ | |||
3737 3738 3739 3740 3741 3742 3743 | } static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #ifdef X_OK return file_access(interp, argv[0], X_OK); #else | | | 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 | } static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #ifdef X_OK return file_access(interp, argv[0], X_OK); #else Jim_SetResultBool(interp, 1); return JIM_OK; #endif } static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
3762 3763 3764 3765 3766 3767 3768 | } while (argc--) { const char *path = Jim_String(argv[0]); if (unlink(path) == -1 && errno != ENOENT) { if (rmdir(path) == -1) { | | | 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 | } while (argc--) { const char *path = Jim_String(argv[0]); if (unlink(path) == -1 && errno != ENOENT) { if (rmdir(path) == -1) { if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) { Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path, strerror(errno)); return JIM_ERR; } } } |
︙ | ︙ | |||
3785 3786 3787 3788 3789 3790 3791 | #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755) #endif static int mkdir_all(char *path) { int ok = 1; | | | | | | | | 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 | #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755) #endif static int mkdir_all(char *path) { int ok = 1; goto first; while (ok--) { { char *slash = strrchr(path, '/'); if (slash && slash != path) { *slash = 0; if (mkdir_all(path) != 0) { return -1; } *slash = '/'; } } first: if (MKDIR_DEFAULT(path) == 0) { return 0; } if (errno == ENOENT) { continue; } if (errno == EEXIST) { struct stat sb; if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { return 0; } errno = EEXIST; } break; } return -1; } static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
3844 3845 3846 3847 3848 3849 3850 | argv++; } return JIM_OK; } static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { | | | 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 | argv++; } return JIM_OK; } static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL); if (fd < 0) { return JIM_ERR; } close(fd); return JIM_OK; |
︙ | ︙ | |||
3962 3963 3964 3965 3966 3967 3968 | if (file_stat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } Jim_SetResultInt(interp, sb.st_atime); return JIM_OK; } | < < < < < < < < < < < < < < < < < < < > | > > | > > > > | > > > > > > > < < < < < < < < < < < < < < < < < < < < | 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 | if (file_stat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } Jim_SetResultInt(interp, sb.st_atime); return JIM_OK; } static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct stat sb; if (argc == 2) { #ifdef HAVE_UTIMES jim_wide newtime; struct timeval times[2]; if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) { return JIM_ERR; } times[1].tv_sec = times[0].tv_sec = newtime; times[1].tv_usec = times[0].tv_usec = 0; if (utimes(Jim_String(argv[0]), times) != 0) { Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno)); return JIM_ERR; } #else Jim_SetResultString(interp, "Not implemented", -1); return JIM_ERR; #endif } if (file_stat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } Jim_SetResultInt(interp, sb.st_mtime); return JIM_OK; } static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return Jim_EvalPrefix(interp, "file copy", argc, argv); } static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
4133 4134 4135 4136 4137 4138 4139 | static const jim_subcmd_type file_command_table[] = { { "atime", "name", file_cmd_atime, 1, 1, | | | < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 | static const jim_subcmd_type file_command_table[] = { { "atime", "name", file_cmd_atime, 1, 1, }, { "mtime", "name ?time?", file_cmd_mtime, 1, 2, }, { "copy", "?-force? source dest", file_cmd_copy, 2, 3, }, { "dirname", "name", file_cmd_dirname, 1, 1, }, { "rootname", "name", file_cmd_rootname, 1, 1, }, { "extension", "name", file_cmd_extension, 1, 1, }, { "tail", "name", file_cmd_tail, 1, 1, }, { "normalize", "name", file_cmd_normalize, 1, 1, }, { "join", "name ?name ...?", file_cmd_join, 1, -1, }, { "readable", "name", file_cmd_readable, 1, 1, }, { "writable", "name", file_cmd_writable, 1, 1, }, { "executable", "name", file_cmd_executable, 1, 1, }, { "exists", "name", file_cmd_exists, 1, 1, }, { "delete", "?-force|--? name ...", file_cmd_delete, 1, -1, }, { "mkdir", "dir ...", file_cmd_mkdir, 1, -1, }, { "tempfile", "?template?", file_cmd_tempfile, 0, 1, }, { "rename", "?-force? source dest", file_cmd_rename, 2, 3, }, #if defined(HAVE_LINK) && defined(HAVE_SYMLINK) { "link", "?-symbolic|-hard? newname target", file_cmd_link, 2, 3, }, #endif #if defined(HAVE_READLINK) { "readlink", "name", file_cmd_readlink, 1, 1, }, #endif { "size", "name", file_cmd_size, 1, 1, }, { "stat", "name ?var?", file_cmd_stat, 1, 2, }, { "lstat", "name ?var?", file_cmd_lstat, 1, 2, }, { "type", "name", file_cmd_type, 1, 1, }, #ifdef HAVE_GETEUID { "owned", "name", file_cmd_owned, 1, 1, }, #endif { "isdirectory", "name", file_cmd_isdirectory, 1, 1, }, { "isfile", "name", file_cmd_isfile, 1, 1, }, { NULL } }; static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
︙ | ︙ | |||
4359 4360 4361 4362 4363 4364 4365 | if (getcwd(cwd, MAXPATHLEN) == NULL) { Jim_SetResultString(interp, "Failed to get pwd", -1); Jim_Free(cwd); return JIM_ERR; } else if (ISWINDOWS) { | | | 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 | if (getcwd(cwd, MAXPATHLEN) == NULL) { Jim_SetResultString(interp, "Failed to get pwd", -1); Jim_Free(cwd); return JIM_ERR; } else if (ISWINDOWS) { char *p = cwd; while ((p = strchr(p, '\\')) != NULL) { *p++ = '/'; } } Jim_SetResultString(interp, cwd, -1); |
︙ | ︙ | |||
4383 4384 4385 4386 4387 4388 4389 | Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL); Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL); Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL); return JIM_OK; } | < < < | | | 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 | Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL); Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL); Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL); return JIM_OK; } #include <string.h> #include <ctype.h> #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__) static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp); int i, j; int rc; for (i = 1; i < argc; i++) { int len; const char *arg = Jim_GetString(argv[i], &len); if (i > 1) { Jim_AppendString(interp, cmdlineObj, " ", 1); } if (strpbrk(arg, "\\\" ") == NULL) { Jim_AppendString(interp, cmdlineObj, arg, len); continue; } Jim_AppendString(interp, cmdlineObj, "\"", 1); for (j = 0; j < len; j++) { if (arg[j] == '\\' || arg[j] == '"') { |
︙ | ︙ | |||
4449 4450 4451 4452 4453 4454 4455 | return JIM_OK; } #else #include <errno.h> #include <signal.h> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | > > > > | | | | > > < | > > > | > > > > | | | 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 | return JIM_OK; } #else #include <errno.h> #include <signal.h> #if defined(__MINGW32__) #ifndef STRICT #define STRICT #endif #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <fcntl.h> typedef HANDLE fdtype; typedef HANDLE pidtype; #define JIM_BAD_FD INVALID_HANDLE_VALUE #define JIM_BAD_PID INVALID_HANDLE_VALUE #define JimCloseFd CloseHandle #define WIFEXITED(STATUS) 1 #define WEXITSTATUS(STATUS) (STATUS) #define WIFSIGNALED(STATUS) 0 #define WTERMSIG(STATUS) 0 #define WNOHANG 1 static fdtype JimFileno(FILE *fh); static pidtype JimWaitPid(pidtype pid, int *status, int nohang); static fdtype JimDupFd(fdtype infd); static fdtype JimOpenForRead(const char *filename); static FILE *JimFdOpenForRead(fdtype fd); static int JimPipe(fdtype pipefd[2]); static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId); static int JimErrno(void); #else #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> #include <sys/stat.h> typedef int fdtype; typedef int pidtype; #define JimPipe pipe #define JimErrno() errno #define JIM_BAD_FD -1 #define JIM_BAD_PID -1 #define JimFileno fileno #define JimReadFd read #define JimCloseFd close #define JimWaitPid waitpid #define JimDupFd dup #define JimFdOpenForRead(FD) fdopen((FD), "r") #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0) #ifndef HAVE_EXECVPE #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV) #endif #endif static const char *JimStrError(void); static char **JimSaveEnv(char **env); static void JimRestoreEnv(char **env); static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr); static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr); static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj); static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents, int len); static fdtype JimOpenForWrite(const char *filename, int append); static int JimRewindFd(fdtype fd); static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg) { Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError()); } static const char *JimStrError(void) { return strerror(JimErrno()); } static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr) { int len; const char *s = Jim_GetString(objPtr, &len); if (len > 0 && s[len - 1] == '\n') { objPtr->length--; objPtr->bytes[objPtr->length] = '\0'; } } static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj) { char buf[256]; FILE *fh = JimFdOpenForRead(fd); int ret = 0; if (fh == NULL) { return -1; } while (1) { |
︙ | ︙ | |||
4513 4514 4515 4516 4517 4518 4519 | int n; char **envptr; char *envdata; Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE); if (!objPtr) { | | | | | 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 | int n; char **envptr; char *envdata; Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE); if (!objPtr) { return Jim_GetEnviron(); } num = Jim_ListLength(interp, objPtr); if (num % 2) { num--; } size = Jim_Length(objPtr) + 2; envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); envdata = (char *)&envptr[num / 2 + 1]; |
︙ | ︙ | |||
4556 4557 4558 4559 4560 4561 4562 | static void JimFreeEnv(char **env, char **original_environ) { if (env != original_environ) { Jim_Free(env); } } | > > > > > > > > > > > > > > > | | > | < < > | | | < < < | < < < | < < < < | | | | < | | | < < | | < < < < < < < < < < < < < < < < < < < | | < | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > | | > > > > > > > > > > > > > > > > > > > > > < < < < < > | > > | | | | | < < < < < | < < | | < | < | < | < | | < < | | < < | < | < < | | | | | | | | | | | | < < < | > > | | | | | 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 | static void JimFreeEnv(char **env, char **original_environ) { if (env != original_environ) { Jim_Free(env); } } #ifndef jim_ext_signal const char *Jim_SignalId(int sig) { static char buf[10]; snprintf(buf, sizeof(buf), "%d", sig); return buf; } const char *Jim_SignalName(int sig) { return Jim_SignalId(sig); } #endif static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj) { Jim_Obj *errorCode; if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) { return JIM_OK; } errorCode = Jim_NewListObj(interp, NULL, 0); if (WIFEXITED(waitStatus)) { Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus))); } else { const char *type; const char *action; if (WIFSIGNALED(waitStatus)) { type = "CHILDKILLED"; action = "killed"; } else { type = "CHILDSUSP"; action = "suspended"; } Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1)); if (errStrObj) { Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL); } Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1)); Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1)); } Jim_SetGlobalVariableStr(interp, "errorCode", errorCode); return JIM_ERR; } struct WaitInfo { pidtype pid; int status; int flags; }; struct WaitInfoTable { struct WaitInfo *info; int size; int used; }; #define WI_DETACHED 2 #define WAIT_TABLE_GROW_BY 4 static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData) { struct WaitInfoTable *table = privData; Jim_Free(table->info); Jim_Free(table); } static struct WaitInfoTable *JimAllocWaitInfoTable(void) { struct WaitInfoTable *table = Jim_Alloc(sizeof(*table)); table->info = NULL; table->size = table->used = 0; return table; } static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { fdtype outputId; fdtype errorId; pidtype *pidPtr; int numPids, result; int child_siginfo = 1; Jim_Obj *childErrObj; Jim_Obj *errStrObj; if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { Jim_Obj *listObj; int i; argc--; numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL); if (numPids < 0) { return JIM_ERR; } listObj = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < numPids; i++) { Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i])); } Jim_SetResult(interp, listObj); JimDetachPids(interp, numPids, pidPtr); Jim_Free(pidPtr); return JIM_OK; } numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId); if (numPids < 0) { return JIM_ERR; } result = JIM_OK; errStrObj = Jim_NewStringObj(interp, "", 0); if (outputId != JIM_BAD_FD) { if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) { result = JIM_ERR; Jim_SetResultErrno(interp, "error reading from output pipe"); } } childErrObj = Jim_NewStringObj(interp, "", 0); Jim_IncrRefCount(childErrObj); if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) { result = JIM_ERR; } if (errorId != JIM_BAD_FD) { int ret; JimRewindFd(errorId); ret = JimAppendStreamToString(interp, errorId, errStrObj); if (ret < 0) { Jim_SetResultErrno(interp, "error reading from error pipe"); result = JIM_ERR; } else if (ret > 0) { child_siginfo = 0; } } if (child_siginfo) { Jim_AppendObj(interp, errStrObj, childErrObj); } Jim_DecrRefCount(interp, childErrObj); Jim_RemoveTrailingNewline(errStrObj); Jim_SetResult(interp, errStrObj); return result; } static void JimReapDetachedPids(struct WaitInfoTable *table) { struct WaitInfo *waitPtr; int count; int dest; if (!table) { return; } waitPtr = table->info; dest = 0; for (count = table->used; count > 0; waitPtr++, count--) { if (waitPtr->flags & WI_DETACHED) { int status; pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG); if (pid == waitPtr->pid) { table->used--; continue; } } if (waitPtr != &table->info[dest]) { table->info[dest] = *waitPtr; } dest++; } } static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr) { int i; for (i = 0; i < table->used; i++) { if (pid == table->info[i].pid) { JimWaitPid(pid, statusPtr, 0); if (i != table->used - 1) { table->info[i] = table->info[table->used - 1]; } table->used--; return pid; } } return JIM_BAD_PID; } static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr) { int j; struct WaitInfoTable *table = Jim_CmdPrivData(interp); for (j = 0; j < numPids; j++) { int i; for (i = 0; i < table->used; i++) { if (pidPtr[j] == table->info[i].pid) { table->info[i].flags |= WI_DETACHED; break; } } } } static FILE *JimGetAioFilehandle(Jim_Interp *interp, const char *name) { FILE *fh; Jim_Obj *fhObj; fhObj = Jim_NewStringObj(interp, name, -1); Jim_IncrRefCount(fhObj); fh = Jim_AioFilehandle(interp, fhObj); Jim_DecrRefCount(interp, fhObj); return fh; } static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr) { pidtype *pidPtr = NULL; /* Points to malloc-ed array holding all * the pids of child processes. */ int numPids = 0; /* Actual number of processes that exist * at *pidPtr right now. */ int cmdCount; /* Count of number of distinct commands * found in argc/argv. */ const char *input = NULL; /* Describes input for pipeline, depending * on "inputFile". NULL means take input * from stdin/pipe. */ int input_len = 0; #define FILE_NAME 0 #define FILE_APPEND 1 #define FILE_HANDLE 2 #define FILE_TEXT 3 int inputFile = FILE_NAME; /* 1 means input is name of input file. * 2 means input is filehandle name. * 0 means input holds actual * text to be input to command. */ int outputFile = FILE_NAME; /* 0 means output is the name of output file. * 1 means output is the name of output file, and append. * 2 means output is filehandle name. * All this is ignored if output is NULL */ int errorFile = FILE_NAME; /* 0 means error is the name of error file. * 1 means error is the name of error file, and append. * 2 means error is filehandle name. * All this is ignored if error is NULL */ const char *output = NULL; /* Holds name of output file to pipe to, * or NULL if output goes to stdout/pipe. */ const char *error = NULL; /* Holds name of stderr file to pipe to, * or NULL if stderr goes to stderr/pipe. */ fdtype inputId = JIM_BAD_FD; fdtype outputId = JIM_BAD_FD; fdtype errorId = JIM_BAD_FD; fdtype lastOutputId = JIM_BAD_FD; fdtype pipeIds[2]; int firstArg, lastArg; /* Indexes of first and last arguments in * current command. */ int lastBar; int i; pidtype pid; char **save_environ; struct WaitInfoTable *table = Jim_CmdPrivData(interp); char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1)); int arg_count = 0; JimReapDetachedPids(table); if (inPipePtr != NULL) { *inPipePtr = JIM_BAD_FD; } if (outPipePtr != NULL) { *outPipePtr = JIM_BAD_FD; } if (errFilePtr != NULL) { *errFilePtr = JIM_BAD_FD; } pipeIds[0] = pipeIds[1] = JIM_BAD_FD; cmdCount = 1; lastBar = -1; for (i = 0; i < argc; i++) { const char *arg = Jim_String(argv[i]); if (arg[0] == '<') { |
︙ | ︙ | |||
4978 4979 4980 4981 4982 4983 4984 | output = arg + 1; if (*output == '>') { outputFile = FILE_APPEND; output++; } if (*output == '&') { | | | 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 | output = arg + 1; if (*output == '>') { outputFile = FILE_APPEND; output++; } if (*output == '&') { output++; dup_error = 1; } if (*output == '@') { outputFile = FILE_HANDLE; output++; } |
︙ | ︙ | |||
5019 5020 5021 5022 5023 5024 5025 | if (i == lastBar + 1 || i == argc - 1) { Jim_SetResultString(interp, "illegal use of | or |& in command", -1); goto badargs; } lastBar = i; cmdCount++; } | | | | | < < < < | | | < | | | | | | | | | | > | | | | | | | | | | | | | | > | | | | | | | | | < < | | > | < < < < < < < | | | | < < < | | < < < | < < < < < | < < | | < < < < < < < | < < | | < | < < < | < < < | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 | if (i == lastBar + 1 || i == argc - 1) { Jim_SetResultString(interp, "illegal use of | or |& in command", -1); goto badargs; } lastBar = i; cmdCount++; } arg_array[arg_count++] = (char *)arg; continue; } if (i >= argc) { Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg); goto badargs; } } if (arg_count == 0) { Jim_SetResultString(interp, "didn't specify command to execute", -1); badargs: Jim_Free(arg_array); return -1; } save_environ = JimSaveEnv(JimBuildEnv(interp)); if (input != NULL) { if (inputFile == FILE_TEXT) { inputId = JimCreateTemp(interp, input, input_len); if (inputId == JIM_BAD_FD) { goto error; } } else if (inputFile == FILE_HANDLE) { FILE *fh = JimGetAioFilehandle(interp, input); if (fh == NULL) { goto error; } inputId = JimDupFd(JimFileno(fh)); } else { inputId = JimOpenForRead(input); if (inputId == JIM_BAD_FD) { Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError()); goto error; } } } else if (inPipePtr != NULL) { if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create input pipe for command"); goto error; } inputId = pipeIds[0]; *inPipePtr = pipeIds[1]; pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } if (output != NULL) { if (outputFile == FILE_HANDLE) { FILE *fh = JimGetAioFilehandle(interp, output); if (fh == NULL) { goto error; } fflush(fh); lastOutputId = JimDupFd(JimFileno(fh)); } else { lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND); if (lastOutputId == JIM_BAD_FD) { Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError()); goto error; } } } else if (outPipePtr != NULL) { if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create output pipe"); goto error; } lastOutputId = pipeIds[1]; *outPipePtr = pipeIds[0]; pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } if (error != NULL) { if (errorFile == FILE_HANDLE) { if (strcmp(error, "1") == 0) { if (lastOutputId != JIM_BAD_FD) { errorId = JimDupFd(lastOutputId); } else { error = "stdout"; } } if (errorId == JIM_BAD_FD) { FILE *fh = JimGetAioFilehandle(interp, error); if (fh == NULL) { goto error; } fflush(fh); errorId = JimDupFd(JimFileno(fh)); } } else { errorId = JimOpenForWrite(error, errorFile == FILE_APPEND); if (errorId == JIM_BAD_FD) { Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError()); goto error; } } } else if (errFilePtr != NULL) { errorId = JimCreateTemp(interp, NULL, 0); if (errorId == JIM_BAD_FD) { goto error; } *errFilePtr = JimDupFd(errorId); } pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr)); for (i = 0; i < numPids; i++) { pidPtr[i] = JIM_BAD_PID; } for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) { int pipe_dup_err = 0; fdtype origErrorId = errorId; for (lastArg = firstArg; lastArg < arg_count; lastArg++) { if (arg_array[lastArg][0] == '|') { if (arg_array[lastArg][1] == '&') { pipe_dup_err = 1; } break; } } arg_array[lastArg] = NULL; if (lastArg == arg_count) { outputId = lastOutputId; } else { if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create pipe"); goto error; } outputId = pipeIds[1]; } if (pipe_dup_err) { errorId = outputId; } #ifdef __MINGW32__ pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId); if (pid == JIM_BAD_PID) { Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]); goto error; } #else pid = vfork(); if (pid < 0) { Jim_SetResultErrno(interp, "couldn't fork child process"); goto error; } if (pid == 0) { if (inputId != -1) dup2(inputId, 0); if (outputId != -1) dup2(outputId, 1); if (errorId != -1) dup2(errorId, 2); for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) { close(i); } (void)signal(SIGPIPE, SIG_DFL); execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron()); fprintf(stderr, "couldn't exec \"%s\"\n", arg_array[firstArg]); _exit(127); } #endif if (table->used == table->size) { table->size += WAIT_TABLE_GROW_BY; table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info)); } table->info[table->used].pid = pid; table->info[table->used].flags = 0; table->used++; pidPtr[numPids] = pid; errorId = origErrorId; if (inputId != JIM_BAD_FD) { JimCloseFd(inputId); } if (outputId != JIM_BAD_FD) { JimCloseFd(outputId); } inputId = pipeIds[0]; pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } *pidArrayPtr = pidPtr; cleanup: if (inputId != JIM_BAD_FD) { JimCloseFd(inputId); } if (lastOutputId != JIM_BAD_FD) { JimCloseFd(lastOutputId); } if (errorId != JIM_BAD_FD) { JimCloseFd(errorId); } Jim_Free(arg_array); JimRestoreEnv(save_environ); return numPids; error: if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) { JimCloseFd(*inPipePtr); *inPipePtr = JIM_BAD_FD; } if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) { JimCloseFd(*outPipePtr); *outPipePtr = JIM_BAD_FD; } if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) { JimCloseFd(*errFilePtr); *errFilePtr = JIM_BAD_FD; } if (pipeIds[0] != JIM_BAD_FD) { JimCloseFd(pipeIds[0]); } if (pipeIds[1] != JIM_BAD_FD) { JimCloseFd(pipeIds[1]); } if (pidPtr != NULL) { for (i = 0; i < numPids; i++) { if (pidPtr[i] != JIM_BAD_PID) { JimDetachPids(interp, 1, &pidPtr[i]); } } Jim_Free(pidPtr); } numPids = -1; goto cleanup; } static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj) { struct WaitInfoTable *table = Jim_CmdPrivData(interp); int result = JIM_OK; int i; for (i = 0; i < numPids; i++) { int waitStatus = 0; if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) { if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus, errStrObj) != JIM_OK) { result = JIM_ERR; } } } Jim_Free(pidPtr); return result; } int Jim_execInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG)) return JIM_ERR; #ifdef SIGPIPE (void)signal(SIGPIPE, SIG_IGN); #endif Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable); return JIM_OK; } #if defined(__MINGW32__) static SECURITY_ATTRIBUTES *JimStdSecAttrs(void) { static SECURITY_ATTRIBUTES secAtts; secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); secAtts.lpSecurityDescriptor = NULL; secAtts.bInheritHandle = TRUE; return &secAtts; } static int JimErrno(void) { switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: return ENOENT; case ERROR_PATH_NOT_FOUND: return ENOENT; case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; case ERROR_ACCESS_DENIED: return EACCES; case ERROR_INVALID_HANDLE: return EBADF; case ERROR_BAD_ENVIRONMENT: return E2BIG; case ERROR_BAD_FORMAT: return ENOEXEC; case ERROR_INVALID_ACCESS: return EACCES; case ERROR_INVALID_DRIVE: return ENOENT; case ERROR_CURRENT_DIRECTORY: return EACCES; case ERROR_NOT_SAME_DEVICE: return EXDEV; case ERROR_NO_MORE_FILES: return ENOENT; case ERROR_WRITE_PROTECT: return EROFS; case ERROR_BAD_UNIT: return ENXIO; case ERROR_NOT_READY: return EBUSY; case ERROR_BAD_COMMAND: return EIO; case ERROR_CRC: return EIO; case ERROR_BAD_LENGTH: return EIO; case ERROR_SEEK: return EIO; case ERROR_WRITE_FAULT: return EIO; case ERROR_READ_FAULT: return EIO; case ERROR_GEN_FAILURE: return EIO; case ERROR_SHARING_VIOLATION: return EACCES; case ERROR_LOCK_VIOLATION: return EACCES; case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE; case ERROR_HANDLE_DISK_FULL: return ENOSPC; case ERROR_NOT_SUPPORTED: return ENODEV; case ERROR_REM_NOT_LIST: return EBUSY; case ERROR_DUP_NAME: return EEXIST; case ERROR_BAD_NETPATH: return ENOENT; case ERROR_NETWORK_BUSY: return EBUSY; case ERROR_DEV_NOT_EXIST: return ENODEV; case ERROR_TOO_MANY_CMDS: return EAGAIN; case ERROR_ADAP_HDW_ERR: return EIO; case ERROR_BAD_NET_RESP: return EIO; case ERROR_UNEXP_NET_ERR: return EIO; case ERROR_NETNAME_DELETED: return ENOENT; case ERROR_NETWORK_ACCESS_DENIED: return EACCES; case ERROR_BAD_DEV_TYPE: return ENODEV; case ERROR_BAD_NET_NAME: return ENOENT; case ERROR_TOO_MANY_NAMES: return ENFILE; case ERROR_TOO_MANY_SESS: return EIO; case ERROR_SHARING_PAUSED: return EAGAIN; case ERROR_REDIR_PAUSED: return EAGAIN; case ERROR_FILE_EXISTS: return EEXIST; case ERROR_CANNOT_MAKE: return ENOSPC; case ERROR_OUT_OF_STRUCTURES: return ENFILE; case ERROR_ALREADY_ASSIGNED: return EEXIST; case ERROR_INVALID_PASSWORD: return EPERM; case ERROR_NET_WRITE_FAULT: return EIO; case ERROR_NO_PROC_SLOTS: return EAGAIN; case ERROR_DISK_CHANGE: return EXDEV; case ERROR_BROKEN_PIPE: return EPIPE; case ERROR_OPEN_FAILED: return ENOENT; case ERROR_DISK_FULL: return ENOSPC; case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE; case ERROR_INVALID_TARGET_HANDLE: return EBADF; case ERROR_INVALID_NAME: return ENOENT; case ERROR_PROC_NOT_FOUND: return ESRCH; case ERROR_WAIT_NO_CHILDREN: return ECHILD; case ERROR_CHILD_NOT_COMPLETE: return ECHILD; case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; case ERROR_SEEK_ON_DEVICE: return ESPIPE; case ERROR_BUSY_DRIVE: return EAGAIN; case ERROR_DIR_NOT_EMPTY: return EEXIST; case ERROR_NOT_LOCKED: return EACCES; case ERROR_BAD_PATHNAME: return ENOENT; case ERROR_LOCK_FAILED: return EACCES; case ERROR_ALREADY_EXISTS: return EEXIST; case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG; case ERROR_BAD_PIPE: return EPIPE; case ERROR_PIPE_BUSY: return EAGAIN; case ERROR_PIPE_NOT_CONNECTED: return EPIPE; case ERROR_DIRECTORY: return ENOTDIR; } return EINVAL; } static int JimPipe(fdtype pipefd[2]) { if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) { return 0; } return -1; } static fdtype JimDupFd(fdtype infd) { fdtype dupfd; pidtype pid = GetCurrentProcess(); if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) { return dupfd; } return JIM_BAD_FD; } static int JimRewindFd(fdtype fd) { return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0; } #if 0 static int JimReadFd(fdtype fd, char *buffer, size_t len) { DWORD num; if (ReadFile(fd, buffer, len, &num, NULL)) { return num; } if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) { return 0; } return -1; } #endif static FILE *JimFdOpenForRead(fdtype fd) { return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r"); } static fdtype JimFileno(FILE *fh) { return (fdtype)_get_osfhandle(_fileno(fh)); } static fdtype JimOpenForRead(const char *filename) { return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, JimStdSecAttrs(), OPEN_EXISTING, 0, NULL); } static fdtype JimOpenForWrite(const char *filename, int append) { return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL); } static FILE *JimFdOpenForWrite(fdtype fd) { return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w"); } static pidtype JimWaitPid(pidtype pid, int *status, int nohang) { DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE); if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) { return JIM_BAD_PID; } GetExitCodeProcess(pid, &ret); *status = ret; CloseHandle(pid); return pid; } static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents, int len) { char name[MAX_PATH]; HANDLE handle; if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) { return JIM_BAD_FD; } handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(), CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); if (handle == INVALID_HANDLE_VALUE) { goto error; } if (contents != NULL) { FILE *fh = JimFdOpenForWrite(JimDupFd(handle)); if (fh == NULL) { goto error; } if (fwrite(contents, len, 1, fh) != 1) { fclose(fh); goto error; } fseek(fh, 0, SEEK_SET); fclose(fh); } return handle; error: Jim_SetResultErrno(interp, "failed to create temp file"); CloseHandle(handle); DeleteFile(name); return JIM_BAD_FD; } static int JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH]) { int i; static char extensions[][5] = {".exe", "", ".bat"}; |
︙ | ︙ | |||
5404 5405 5406 5407 5408 5409 5410 | } static void JimRestoreEnv(char **env) { JimFreeEnv(env, Jim_GetEnviron()); } | < < < < < | 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 | } static void JimRestoreEnv(char **env) { JimFreeEnv(env, Jim_GetEnviron()); } static Jim_Obj * JimWinBuildCommandLine(Jim_Interp *interp, char **argv) { char *start, *special; int quote, i; Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0); |
︙ | ︙ | |||
5482 5483 5484 5485 5486 5487 5488 | Jim_AppendString(interp, strObj, "\"", 1); } } return strObj; } static pidtype | | | < | > | | > | | > | | | > | | | > | < < < | > | > > > | | > | < < < < < < < < < < < | | | | > > > > > | > | > > | > > > > > > > > > | > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | < | | > | < > | > < < | | < < < < < < < < < < < < < < | < | < < < | < < < < | | | | 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 | Jim_AppendString(interp, strObj, "\"", 1); } } return strObj; } static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId) { STARTUPINFO startInfo; PROCESS_INFORMATION procInfo; HANDLE hProcess, h; char execPath[MAX_PATH]; pidtype pid = JIM_BAD_PID; Jim_Obj *cmdLineObj; if (JimWinFindExecutable(argv[0], execPath) < 0) { return JIM_BAD_PID; } argv[0] = execPath; hProcess = GetCurrentProcess(); cmdLineObj = JimWinBuildCommandLine(interp, argv); ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESTDHANDLES; startInfo.hStdInput = INVALID_HANDLE_VALUE; startInfo.hStdOutput= INVALID_HANDLE_VALUE; startInfo.hStdError = INVALID_HANDLE_VALUE; if (inputId == JIM_BAD_FD) { if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) { CloseHandle(h); } } else { DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdInput == JIM_BAD_FD) { goto end; } if (outputId == JIM_BAD_FD) { startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0, JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } else { DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdOutput == JIM_BAD_FD) { goto end; } if (errorId == JIM_BAD_FD) { startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0, JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdError == JIM_BAD_FD) { goto end; } if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE, 0, env, NULL, &startInfo, &procInfo)) { goto end; } WaitForInputIdle(procInfo.hProcess, 5000); CloseHandle(procInfo.hThread); pid = procInfo.hProcess; end: Jim_FreeNewObj(interp, cmdLineObj); if (startInfo.hStdInput != JIM_BAD_FD) { CloseHandle(startInfo.hStdInput); } if (startInfo.hStdOutput != JIM_BAD_FD) { CloseHandle(startInfo.hStdOutput); } if (startInfo.hStdError != JIM_BAD_FD) { CloseHandle(startInfo.hStdError); } return pid; } #else static int JimOpenForWrite(const char *filename, int append) { return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666); } static int JimRewindFd(int fd) { return lseek(fd, 0L, SEEK_SET); } static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len) { int fd = Jim_MakeTempFile(interp, NULL); if (fd != JIM_BAD_FD) { unlink(Jim_String(Jim_GetResult(interp))); if (contents) { if (write(fd, contents, len) != len) { Jim_SetResultErrno(interp, "couldn't write temp file"); close(fd); return -1; } lseek(fd, 0L, SEEK_SET); } } return fd; } static char **JimSaveEnv(char **env) { char **saveenv = Jim_GetEnviron(); Jim_SetEnviron(env); return saveenv; } static void JimRestoreEnv(char **env) { JimFreeEnv(Jim_GetEnviron(), env); Jim_SetEnviron(env); } #endif #endif #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif #include <stdlib.h> #include <string.h> #include <stdio.h> #include <time.h> #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { char buf[100]; time_t t; long seconds; const char *format = "%a %b %d %H:%M:%S %Z %Y"; if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) { return -1; } if (argc == 3) { format = Jim_String(argv[2]); } if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) { return JIM_ERR; } t = seconds; if (strftime(buf, sizeof(buf), format, localtime(&t)) == 0) { Jim_SetResultString(interp, "format string too long", -1); return JIM_ERR; } Jim_SetResultString(interp, buf, -1); return JIM_OK; } #ifdef HAVE_STRPTIME static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { char *pt; struct tm tm; time_t now = time(0); if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) { return -1; } localtime_r(&now, &tm); pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm); if (pt == 0 || *pt != 0) { Jim_SetResultString(interp, "Failed to parse time according to format", -1); return JIM_ERR; } Jim_SetResultInt(interp, mktime(&tm)); return JIM_OK; } #endif static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 | Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000); return JIM_OK; } static const jim_subcmd_type clock_command_table[] = { { "clicks", NULL, clock_cmd_micros, 0, 0, | > > > > > > > | < < < < < < < | | > > > > > > > | < > | < < < < < < < | 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 | Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000); return JIM_OK; } static const jim_subcmd_type clock_command_table[] = { { "seconds", NULL, clock_cmd_seconds, 0, 0, }, { "clicks", NULL, clock_cmd_micros, 0, 0, }, { "microseconds", NULL, clock_cmd_micros, 0, 0, }, { "milliseconds", NULL, clock_cmd_millis, 0, 0, }, { "format", "seconds ?-format format?", clock_cmd_format, 1, 3, }, #ifdef HAVE_STRPTIME { "scan", "str -format format", clock_cmd_scan, 3, 3, }, #endif { NULL } }; int Jim_clockInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG)) return JIM_ERR; |
︙ | ︙ | |||
5823 5824 5825 5826 5827 5828 5829 | #include <string.h> #include <stdio.h> #include <errno.h> static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { | | | < | | > | | | | < < | | | < < | | 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 | #include <string.h> #include <stdio.h> #include <errno.h> static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0); return JIM_OK; } static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); Jim_Obj *patternObj; if (!objPtr) { return JIM_OK; } patternObj = (argc == 1) ? NULL : argv[1]; if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) { if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) { Jim_SetResult(interp, objPtr); return JIM_OK; } } return Jim_DictValues(interp, objPtr, patternObj); } static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); if (!objPtr) { return JIM_OK; } return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]); } static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; int len; Jim_Obj *resultObj; Jim_Obj *objPtr; Jim_Obj **dictValuesObj; if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) { Jim_UnsetVariable(interp, argv[0], JIM_NONE); return JIM_OK; } objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); if (objPtr == NULL) { return JIM_OK; } if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) { return JIM_ERR; } resultObj = Jim_NewDictObj(interp, NULL, 0); for (i = 0; i < len; i += 2) { if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) { Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]); } } Jim_Free(dictValuesObj); Jim_SetVariable(interp, argv[0], resultObj); return JIM_OK; } static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; int len = 0; objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); if (objPtr) { len = Jim_DictSize(interp, objPtr); if (len < 0) { return JIM_ERR; } } Jim_SetResultInt(interp, len); return JIM_OK; } |
︙ | ︙ | |||
5950 5951 5952 5953 5954 5955 5956 | if (len % 2) { Jim_SetResultString(interp, "list must have an even number of elements", -1); return JIM_ERR; } dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); if (!dictObj) { | | | 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 | if (len % 2) { Jim_SetResultString(interp, "list must have an even number of elements", -1); return JIM_ERR; } dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); if (!dictObj) { return Jim_SetVariable(interp, argv[0], listObj); } else if (Jim_DictSize(interp, dictObj) < 0) { return JIM_ERR; } if (Jim_IsShared(dictObj)) { |
︙ | ︙ | |||
5979 5980 5981 5982 5983 5984 5985 | static const jim_subcmd_type array_command_table[] = { { "exists", "arrayName", array_cmd_exists, 1, 1, | | | | | | | | | 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 | static const jim_subcmd_type array_command_table[] = { { "exists", "arrayName", array_cmd_exists, 1, 1, }, { "get", "arrayName ?pattern?", array_cmd_get, 1, 2, }, { "names", "arrayName ?pattern?", array_cmd_names, 1, 2, }, { "set", "arrayName list", array_cmd_set, 2, 2, }, { "size", "arrayName", array_cmd_size, 1, 1, }, { "stat", "arrayName", array_cmd_stat, 1, 1, }, { "unset", "arrayName ?pattern?", array_cmd_unset, 1, 2, }, { NULL } }; int Jim_arrayInit(Jim_Interp *interp) { |
︙ | ︙ | |||
6061 6062 6063 6064 6065 6066 6067 | Jim_execInit(interp); Jim_clockInit(interp); Jim_arrayInit(interp); Jim_stdlibInit(interp); Jim_tclcompatInit(interp); return JIM_OK; } | | < < < | 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 | Jim_execInit(interp); Jim_clockInit(interp); Jim_arrayInit(interp); Jim_stdlibInit(interp); Jim_tclcompatInit(interp); return JIM_OK; } #define JIM_OPTIMIZATION #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> |
︙ | ︙ | |||
6133 6134 6135 6136 6137 6138 6139 | #ifdef JIM_DEBUG_PANIC static void JimPanicDump(int fail_condition, const char *fmt, ...); #define JimPanic(X) JimPanicDump X #else #define JimPanic(X) #endif | < < < < < < | 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 | #ifdef JIM_DEBUG_PANIC static void JimPanicDump(int fail_condition, const char *fmt, ...); #define JimPanic(X) JimPanicDump X #else #define JimPanic(X) #endif static char JimEmptyStringRep[] = ""; static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action); static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr, int flags); static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands); |
︙ | ︙ | |||
6195 6196 6197 6198 6199 6200 6201 | if (flags & JIM_CHARSET_SCAN) { if (*pattern == '^') { not++; pattern++; } | | | | | | | | 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 | if (flags & JIM_CHARSET_SCAN) { if (*pattern == '^') { not++; pattern++; } if (*pattern == ']') { goto first; } } while (*pattern && *pattern != ']') { if (pattern[0] == '\\') { first: pattern += utf8_tounicode_case(pattern, &pchar, nocase); } else { int start; int end; pattern += utf8_tounicode_case(pattern, &start, nocase); if (pattern[0] == '-' && pattern[1]) { pattern += utf8_tounicode(pattern, &pchar); pattern += utf8_tounicode_case(pattern, &end, nocase); if ((c >= start && c <= end) || (c >= end && c <= start)) { match = 1; } continue; } pchar = start; } |
︙ | ︙ | |||
6252 6253 6254 6255 6256 6257 6258 | switch (pattern[0]) { case '*': while (pattern[1] == '*') { pattern++; } pattern++; if (!pattern[0]) { | | | | | | | | 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 | switch (pattern[0]) { case '*': while (pattern[1] == '*') { pattern++; } pattern++; if (!pattern[0]) { return 1; } while (*string) { if (JimGlobMatch(pattern, string, nocase)) return 1; string += utf8_tounicode(string, &c); } return 0; case '?': string += utf8_tounicode(string, &c); break; case '[': { string += utf8_tounicode(string, &c); pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0); if (!pattern) { return 0; } if (!*pattern) { continue; } break; } case '\\': if (pattern[1]) { pattern++; } default: string += utf8_tounicode_case(string, &c, nocase); utf8_tounicode_case(pattern, &pchar, nocase); if (pchar != c) { return 0; } break; |
︙ | ︙ | |||
6332 6333 6334 6335 6336 6337 6338 | return JimSign(c1 - c2); } maxchars--; } if (!maxchars) { return 0; } | | | 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 | return JimSign(c1 - c2); } maxchars--; } if (!maxchars) { return 0; } if (*s1) { return 1; } if (*s2) { return -1; } return 0; |
︙ | ︙ | |||
6373 6374 6375 6376 6377 6378 6379 | static int JimStringLast(const char *s1, int l1, const char *s2, int l2) { const char *p; if (!l1 || !l2 || l1 > l2) return -1; | | | 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 | static int JimStringLast(const char *s1, int l1, const char *s2, int l2) { const char *p; if (!l1 || !l2 || l1 > l2) return -1; for (p = s2 + l2 - 1; p != s2 - 1; p--) { if (*p == *s1 && memcmp(s1, p, l1) == 0) { return p - s2; } } return -1; } |
︙ | ︙ | |||
6432 6433 6434 6435 6436 6437 6438 | if (str[i] == '+') { i++; } *sign = 1; } if (str[i] != '0') { | | | | | | | | | 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 | if (str[i] == '+') { i++; } *sign = 1; } if (str[i] != '0') { return 0; } switch (str[i + 1]) { case 'x': case 'X': *base = 16; break; case 'o': case 'O': *base = 8; break; case 'b': case 'B': *base = 2; break; default: return 0; } i += 2; if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { return i; } *base = 10; return 0; } static long jim_strtol(const char *str, char **endptr) { int sign; int base; int i = JimNumberBase(str, &base, &sign); if (base != 10) { long value = strtol(str + i, endptr, base); if (endptr == NULL || *endptr != str + i) { return value * sign; } } return strtol(str, endptr, 10); } static jim_wide jim_strtoull(const char *str, char **endptr) { #ifdef HAVE_LONG_LONG int sign; int base; int i = JimNumberBase(str, &base, &sign); if (base != 10) { jim_wide value = strtoull(str + i, endptr, base); if (endptr == NULL || *endptr != str + i) { return value * sign; } } return strtoull(str, endptr, 10); #else return (unsigned long)jim_strtol(str, endptr); #endif } int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) |
︙ | ︙ | |||
6511 6512 6513 6514 6515 6516 6517 | return JimCheckConversion(str, endptr); } int Jim_StringToDouble(const char *str, double *doublePtr) { char *endptr; | | | | < < < < < < | < | < < < < | < < < | 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 | return JimCheckConversion(str, endptr); } int Jim_StringToDouble(const char *str, double *doublePtr) { char *endptr; errno = 0; *doublePtr = strtod(str, &endptr); return JimCheckConversion(str, endptr); } static jim_wide JimPowWide(jim_wide b, jim_wide e) { jim_wide i, res = 1; if ((b == 0 && e != 0) || (e < 0)) return 0; for (i = 0; i < e; i++) { res *= b; } return res; } #ifdef JIM_DEBUG_PANIC static void JimPanicDump(int condition, const char *fmt, ...) { |
︙ | ︙ | |||
6606 6607 6608 6609 6610 6611 6612 | } char *Jim_StrDupLen(const char *s, int l) { char *copy = Jim_Alloc(l + 1); memcpy(copy, s, l + 1); | | | 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 | } char *Jim_StrDupLen(const char *s, int l) { char *copy = Jim_Alloc(l + 1); memcpy(copy, s, l + 1); copy[l] = 0; return copy; } static jim_wide JimClock(void) { |
︙ | ︙ | |||
6695 6696 6697 6698 6699 6700 6701 | minimal = JIM_HT_INITIAL_SIZE; Jim_ExpandHashTable(ht, minimal); } void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) { | | | | | | | | | | 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 | minimal = JIM_HT_INITIAL_SIZE; Jim_ExpandHashTable(ht, minimal); } void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) { Jim_HashTable n; unsigned int realsize = JimHashTableNextPower(size), i; if (size <= ht->used) return; Jim_InitHashTable(&n, ht->type, ht->privdata); n.size = realsize; n.sizemask = realsize - 1; n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *)); n.uniq = ht->uniq; memset(n.table, 0, realsize * sizeof(Jim_HashEntry *)); n.used = ht->used; for (i = 0; ht->used > 0; i++) { Jim_HashEntry *he, *nextHe; if (ht->table[i] == NULL) continue; he = ht->table[i]; while (he) { unsigned int h; nextHe = he->next; h = Jim_HashKey(ht, he->key) & n.sizemask; he->next = n.table[h]; n.table[h] = he; ht->used--; he = nextHe; } } assert(ht->used == 0); Jim_Free(ht->table); *ht = n; } int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val) { Jim_HashEntry *entry; entry = JimInsertHashEntry(ht, key, 0); if (entry == NULL) return JIM_ERR; Jim_SetHashKey(ht, entry, key); Jim_SetHashVal(ht, entry, val); return JIM_OK; } int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val) |
︙ | ︙ | |||
6775 6776 6777 6778 6779 6780 6781 | else { Jim_FreeEntryVal(ht, entry); Jim_SetHashVal(ht, entry, val); } existed = 1; } else { | | | 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 | else { Jim_FreeEntryVal(ht, entry); Jim_SetHashVal(ht, entry, val); } existed = 1; } else { Jim_SetHashKey(ht, entry, key); Jim_SetHashVal(ht, entry, val); existed = 0; } return existed; } |
︙ | ︙ | |||
6798 6799 6800 6801 6802 6803 6804 | return JIM_ERR; h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; prevHe = NULL; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) { | | | | | | | | 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 | return JIM_ERR; h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; prevHe = NULL; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) { if (prevHe) prevHe->next = he->next; else ht->table[h] = he->next; Jim_FreeEntryKey(ht, he); Jim_FreeEntryVal(ht, he); Jim_Free(he); ht->used--; return JIM_OK; } prevHe = he; he = he->next; } return JIM_ERR; } int Jim_FreeHashTable(Jim_HashTable *ht) { unsigned int i; for (i = 0; ht->used > 0; i++) { Jim_HashEntry *he, *nextHe; if ((he = ht->table[i]) == NULL) continue; while (he) { nextHe = he->next; Jim_FreeEntryKey(ht, he); Jim_FreeEntryVal(ht, he); Jim_Free(he); ht->used--; he = nextHe; } } Jim_Free(ht->table); JimResetHashTable(ht); return JIM_OK; } Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key) { Jim_HashEntry *he; unsigned int h; |
︙ | ︙ | |||
6916 6917 6918 6919 6920 6921 6922 | } static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace) { unsigned int h; Jim_HashEntry *he; | | | | | | 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 | } static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace) { unsigned int h; Jim_HashEntry *he; JimExpandHashTableIfNeeded(ht); h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) return replace ? he : NULL; he = he->next; } he = Jim_Alloc(sizeof(*he)); he->next = ht->table[h]; ht->table[h] = he; ht->used++; he->key = NULL; return he; |
︙ | ︙ | |||
6962 6963 6964 6965 6966 6967 6968 | static void JimStringCopyHTKeyDestructor(void *privdata, void *key) { Jim_Free(key); } static const Jim_HashTableType JimPackageHashTableType = { | | | | | | | | | | | | | | 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 | static void JimStringCopyHTKeyDestructor(void *privdata, void *key) { Jim_Free(key); } static const Jim_HashTableType JimPackageHashTableType = { JimStringCopyHTHashFunction, JimStringCopyHTDup, NULL, JimStringCopyHTKeyCompare, JimStringCopyHTKeyDestructor, NULL }; typedef struct AssocDataValue { Jim_InterpDeleteProc *delProc; void *data; } AssocDataValue; static void JimAssocDataHashTableValueDestructor(void *privdata, void *data) { AssocDataValue *assocPtr = (AssocDataValue *) data; if (assocPtr->delProc != NULL) assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data); Jim_Free(data); } static const Jim_HashTableType JimAssocDataHashTableType = { JimStringCopyHTHashFunction, JimStringCopyHTDup, NULL, JimStringCopyHTKeyCompare, JimStringCopyHTKeyDestructor, JimAssocDataHashTableValueDestructor }; void Jim_InitStack(Jim_Stack *stack) { stack->len = 0; stack->maxlen = 0; stack->vector = NULL; |
︙ | ︙ | |||
7048 7049 7050 7051 7052 7053 7054 | for (i = 0; i < stack->len; i++) freeFunc(stack->vector[i]); } | | | | | | | | | | | | < | < < < < | | | | | | | | | | | | | 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 | for (i = 0; i < stack->len; i++) freeFunc(stack->vector[i]); } #define JIM_TT_NONE 0 #define JIM_TT_STR 1 #define JIM_TT_ESC 2 #define JIM_TT_VAR 3 #define JIM_TT_DICTSUGAR 4 #define JIM_TT_CMD 5 #define JIM_TT_SEP 6 #define JIM_TT_EOL 7 #define JIM_TT_EOF 8 #define JIM_TT_LINE 9 #define JIM_TT_WORD 10 #define JIM_TT_SUBEXPR_START 11 #define JIM_TT_SUBEXPR_END 12 #define JIM_TT_SUBEXPR_COMMA 13 #define JIM_TT_EXPR_INT 14 #define JIM_TT_EXPR_DOUBLE 15 #define JIM_TT_EXPRSUGAR 16 #define JIM_TT_EXPR_OP 20 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF) struct JimParseMissing { int ch; int line; }; struct JimParserCtx { const char *p; int len; int linenr; const char *tstart; const char *tend; int tline; int tt; int eof; int inquote; int comment; struct JimParseMissing missing; }; static int JimParseScript(struct JimParserCtx *pc); static int JimParseSep(struct JimParserCtx *pc); static int JimParseEol(struct JimParserCtx *pc); static int JimParseCmd(struct JimParserCtx *pc); static int JimParseQuote(struct JimParserCtx *pc); |
︙ | ︙ | |||
7132 7133 7134 7135 7136 7137 7138 | pc->comment = 1; pc->missing.ch = ' '; pc->missing.line = linenr; } static int JimParseScript(struct JimParserCtx *pc) { | | | 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 | pc->comment = 1; pc->missing.ch = ' '; pc->missing.line = linenr; } static int JimParseScript(struct JimParserCtx *pc) { while (1) { if (!pc->len) { pc->tstart = pc->p; pc->tend = pc->p - 1; pc->tline = pc->linenr; pc->tt = JIM_TT_EOL; pc->eof = 1; return JIM_OK; |
︙ | ︙ | |||
7168 7169 7170 7171 7172 7173 7174 | return JimParseStr(pc); case '[': pc->comment = 0; return JimParseCmd(pc); case '$': pc->comment = 0; if (JimParseVar(pc) == JIM_ERR) { | | | 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 | return JimParseStr(pc); case '[': pc->comment = 0; return JimParseCmd(pc); case '$': pc->comment = 0; if (JimParseVar(pc) == JIM_ERR) { pc->tstart = pc->tend = pc->p++; pc->len--; pc->tt = JIM_TT_ESC; } return JIM_OK; case '#': if (pc->comment) { |
︙ | ︙ | |||
7229 7230 7231 7232 7233 7234 7235 | } static void JimParseSubBrace(struct JimParserCtx *pc) { int level = 1; | | | 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 | } static void JimParseSubBrace(struct JimParserCtx *pc) { int level = 1; pc->p++; pc->len--; while (pc->len) { switch (*pc->p) { case '\\': if (pc->len > 1) { if (*++pc->p == '\n') { |
︙ | ︙ | |||
7273 7274 7275 7276 7277 7278 7279 | } static int JimParseSubQuote(struct JimParserCtx *pc) { int tt = JIM_TT_STR; int line = pc->tline; | | | 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 | } static int JimParseSubQuote(struct JimParserCtx *pc) { int tt = JIM_TT_STR; int line = pc->tline; pc->p++; pc->len--; while (pc->len) { switch (*pc->p) { case '\\': if (pc->len > 1) { if (*++pc->p == '\n') { |
︙ | ︙ | |||
7322 7323 7324 7325 7326 7327 7328 | static void JimParseSubCmd(struct JimParserCtx *pc) { int level = 1; int startofword = 1; int line = pc->tline; | | | 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 | static void JimParseSubCmd(struct JimParserCtx *pc) { int level = 1; int startofword = 1; int line = pc->tline; pc->p++; pc->len--; while (pc->len) { switch (*pc->p) { case '\\': if (pc->len > 1) { if (*++pc->p == '\n') { |
︙ | ︙ | |||
7402 7403 7404 7405 7406 7407 7408 | pc->tline = pc->linenr; pc->tt = JimParseSubQuote(pc); return JIM_OK; } static int JimParseVar(struct JimParserCtx *pc) { | | | | 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 | pc->tline = pc->linenr; pc->tt = JimParseSubQuote(pc); return JIM_OK; } static int JimParseVar(struct JimParserCtx *pc) { pc->p++; pc->len--; #ifdef EXPRSUGAR_BRACKET if (*pc->p == '[') { JimParseCmd(pc); pc->tt = JIM_TT_EXPRSUGAR; return JIM_OK; } #endif pc->tstart = pc->p; |
︙ | ︙ | |||
7438 7439 7440 7441 7442 7443 7444 | if (pc->len) { pc->p++; pc->len--; } } else { while (1) { | | | | 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 | if (pc->len) { pc->p++; pc->len--; } } else { while (1) { if (pc->p[0] == ':' && pc->p[1] == ':') { while (*pc->p == ':') { pc->p++; pc->len--; } continue; } if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) { pc->p++; pc->len--; continue; } break; } if (*pc->p == '(') { int count = 1; const char *paren = NULL; pc->tt = JIM_TT_DICTSUGAR; while (count && pc->len) { |
︙ | ︙ | |||
7480 7481 7482 7483 7484 7485 7486 | } } if (count == 0) { pc->p++; pc->len--; } else if (paren) { | | | 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 | } } if (count == 0) { pc->p++; pc->len--; } else if (paren) { paren++; pc->len += (pc->p - paren); pc->p = paren; } #ifndef EXPRSUGAR_BRACKET if (*pc->tstart == '(') { pc->tt = JIM_TT_EXPRSUGAR; |
︙ | ︙ | |||
7505 7506 7507 7508 7509 7510 7511 | return JIM_OK; } static int JimParseStr(struct JimParserCtx *pc) { if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL || pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) { | | | | 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 | return JIM_OK; } static int JimParseStr(struct JimParserCtx *pc) { if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL || pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) { if (*pc->p == '{') { return JimParseBrace(pc); } if (*pc->p == '"') { pc->inquote = 1; pc->p++; pc->len--; pc->missing.line = pc->tline; } } pc->tstart = pc->p; pc->tline = pc->linenr; while (1) { if (pc->len == 0) { |
︙ | ︙ | |||
7543 7544 7545 7546 7547 7548 7549 | if (*(pc->p + 1) == '\n') { pc->linenr++; } pc->p++; pc->len--; } else if (pc->len == 1) { | | | | | | | 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 | if (*(pc->p + 1) == '\n') { pc->linenr++; } pc->p++; pc->len--; } else if (pc->len == 1) { pc->missing.ch = '\\'; } break; case '(': if (pc->len > 1 && pc->p[1] != '$') { break; } case ')': if (*pc->p == '(' || pc->tt == JIM_TT_VAR) { if (pc->p == pc->tstart) { pc->p++; pc->len--; } pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; } |
︙ | ︙ | |||
7601 7602 7603 7604 7605 7606 7607 | return JIM_OK; } break; } pc->p++; pc->len--; } | | | 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 | return JIM_OK; } break; } pc->p++; pc->len--; } return JIM_OK; } static int JimParseComment(struct JimParserCtx *pc) { while (*pc->p) { if (*pc->p == '\\') { pc->p++; |
︙ | ︙ | |||
7712 7713 7714 7715 7716 7717 7718 | for (k = 0; k < maxchars; k++) { int c = xdigitval(s[i + k + 1]); if (c == -1) { break; } val = (val << 4) | c; } | | | | | | | | | 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 | for (k = 0; k < maxchars; k++) { int c = xdigitval(s[i + k + 1]); if (c == -1) { break; } val = (val << 4) | c; } if (s[i] == '{') { if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') { i--; k = 0; } else { k++; } } if (k) { if (s[i] == 'x') { *p++ = val; } else { p += utf8_fromunicode(p, val); } i += k; break; } *p++ = s[i]; } break; case 'v': *p++ = 0xb; i++; break; case '\0': *p++ = '\\'; i++; break; case '\n': *p++ = ' '; do { i++; } while (s[i + 1] == ' ' || s[i + 1] == '\t'); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int val = 0; int c = odigitval(s[i + 1]); val = c; c = odigitval(s[i + 2]); if (c == -1) { |
︙ | ︙ | |||
7810 7811 7812 7813 7814 7815 7816 | { const char *start, *end; char *token; int len; start = pc->tstart; end = pc->tend; | < | > > > > | | | | | | | | | > | 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 | { const char *start, *end; char *token; int len; start = pc->tstart; end = pc->tend; if (start > end) { len = 0; token = Jim_Alloc(1); token[0] = '\0'; } else { len = (end - start) + 1; token = Jim_Alloc(len + 1); if (pc->tt != JIM_TT_ESC) { memcpy(token, start, len); token[len] = '\0'; } else { len = JimEscape(token, start, len); } } return Jim_NewStringObjNoAlloc(interp, token, len); } static int JimParseListSep(struct JimParserCtx *pc); static int JimParseListStr(struct JimParserCtx *pc); |
︙ | ︙ | |||
7888 7889 7890 7891 7892 7893 7894 | pc->tt = JIM_TT_STR; while (pc->len) { switch (*pc->p) { case '\\': pc->tt = JIM_TT_ESC; if (--pc->len == 0) { | | | 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 | pc->tt = JIM_TT_STR; while (pc->len) { switch (*pc->p) { case '\\': pc->tt = JIM_TT_ESC; if (--pc->len == 0) { pc->tend = pc->p; return JIM_OK; } pc->p++; break; case '\n': pc->linenr++; |
︙ | ︙ | |||
7924 7925 7926 7927 7928 7929 7930 | while (pc->len) { if (isspace(UCHAR(*pc->p))) { pc->tend = pc->p - 1; return JIM_OK; } if (*pc->p == '\\') { if (--pc->len == 0) { | | | | | | | | | | | | 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 | while (pc->len) { if (isspace(UCHAR(*pc->p))) { pc->tend = pc->p - 1; return JIM_OK; } if (*pc->p == '\\') { if (--pc->len == 0) { pc->tend = pc->p; return JIM_OK; } pc->tt = JIM_TT_ESC; pc->p++; } pc->p++; pc->len--; } pc->tend = pc->p - 1; return JIM_OK; } Jim_Obj *Jim_NewObj(Jim_Interp *interp) { Jim_Obj *objPtr; if (interp->freeList != NULL) { objPtr = interp->freeList; interp->freeList = objPtr->nextObjPtr; } else { objPtr = Jim_Alloc(sizeof(*objPtr)); } objPtr->refCount = 0; objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->liveList; if (interp->liveList) interp->liveList->prevObjPtr = objPtr; interp->liveList = objPtr; return objPtr; } void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr) { JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr, objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>")); Jim_FreeIntRep(interp, objPtr); if (objPtr->bytes != NULL) { if (objPtr->bytes != JimEmptyStringRep) Jim_Free(objPtr->bytes); } if (objPtr->prevObjPtr) objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr; if (objPtr->nextObjPtr) objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr; if (interp->liveList == objPtr) interp->liveList = objPtr->nextObjPtr; #ifdef JIM_DISABLE_OBJECT_POOL Jim_Free(objPtr); #else objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->freeList; if (interp->freeList) interp->freeList->prevObjPtr = objPtr; interp->freeList = objPtr; objPtr->refCount = -1; #endif |
︙ | ︙ | |||
8017 8018 8019 8020 8021 8022 8023 | Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *dupPtr; dupPtr = Jim_NewObj(interp); if (objPtr->bytes == NULL) { | | > | | | | | > | | > > | | 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 | Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *dupPtr; dupPtr = Jim_NewObj(interp); if (objPtr->bytes == NULL) { dupPtr->bytes = NULL; } else if (objPtr->length == 0) { dupPtr->bytes = JimEmptyStringRep; dupPtr->length = 0; dupPtr->typePtr = NULL; return dupPtr; } else { dupPtr->bytes = Jim_Alloc(objPtr->length + 1); dupPtr->length = objPtr->length; memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1); } dupPtr->typePtr = objPtr->typePtr; if (objPtr->typePtr != NULL) { if (objPtr->typePtr->dupIntRepProc == NULL) { dupPtr->internalRep = objPtr->internalRep; } else { objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr); } } return dupPtr; } const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr) { if (objPtr->bytes == NULL) { JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } if (lenPtr) *lenPtr = objPtr->length; return objPtr->bytes; } int Jim_Length(Jim_Obj *objPtr) { if (objPtr->bytes == NULL) { JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } return objPtr->length; } const char *Jim_String(Jim_Obj *objPtr) { if (objPtr->bytes == NULL) { JimPanic((objPtr->typePtr == NULL, "UpdateStringProc called against typeless value.")); JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } return objPtr->bytes; } static void JimSetStringBytes(Jim_Obj *objPtr, const char *str) { objPtr->bytes = Jim_StrDup(str); |
︙ | ︙ | |||
8096 8097 8098 8099 8100 8101 8102 | "dict-substitution", FreeDictSubstInternalRep, DupDictSubstInternalRep, NULL, JIM_TYPE_NONE, }; | < < < < < < < < < < < | < | | | > | | | 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 | "dict-substitution", FreeDictSubstInternalRep, DupDictSubstInternalRep, NULL, JIM_TYPE_NONE, }; static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); } static const Jim_ObjType interpolatedObjType = { "interpolated", FreeInterpolatedInternalRep, NULL, NULL, JIM_TYPE_NONE, }; static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static const Jim_ObjType stringObjType = { "string", NULL, |
︙ | ︙ | |||
8142 8143 8144 8145 8146 8147 8148 | dupPtr->internalRep.strValue.maxLength = srcPtr->length; dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength; } static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &stringObjType) { | | | | | | | 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 | dupPtr->internalRep.strValue.maxLength = srcPtr->length; dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength; } static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &stringObjType) { if (objPtr->bytes == NULL) { JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &stringObjType; objPtr->internalRep.strValue.maxLength = objPtr->length; objPtr->internalRep.strValue.charLength = -1; } return JIM_OK; } int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr) { |
︙ | ︙ | |||
8178 8179 8180 8181 8182 8183 8184 | } Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); | | | | > > | | | | 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 | } Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); if (len == -1) len = strlen(s); if (len == 0) { objPtr->bytes = JimEmptyStringRep; } else { objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, s, len); objPtr->bytes[len] = '\0'; } objPtr->length = len; objPtr->typePtr = NULL; return objPtr; } Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen) { #ifdef JIM_UTF8 int bytelen = utf8_index(s, charlen); Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen); objPtr->typePtr = &stringObjType; objPtr->internalRep.strValue.maxLength = bytelen; objPtr->internalRep.strValue.charLength = charlen; return objPtr; #else return Jim_NewStringObj(interp, s, charlen); |
︙ | ︙ | |||
8235 8236 8237 8238 8239 8240 8241 | if (len == -1) len = strlen(str); needlen = objPtr->length + len; if (objPtr->internalRep.strValue.maxLength < needlen || objPtr->internalRep.strValue.maxLength == 0) { needlen *= 2; | | | | 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 | if (len == -1) len = strlen(str); needlen = objPtr->length + len; if (objPtr->internalRep.strValue.maxLength < needlen || objPtr->internalRep.strValue.maxLength == 0) { needlen *= 2; if (needlen < 7) { needlen = 7; } if (objPtr->bytes == JimEmptyStringRep) { objPtr->bytes = Jim_Alloc(needlen + 1); } else { objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1); } objPtr->internalRep.strValue.maxLength = needlen; } memcpy(objPtr->bytes + objPtr->length, str, len); objPtr->bytes[objPtr->length + len] = '\0'; if (objPtr->internalRep.strValue.charLength >= 0) { objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len); } objPtr->length += len; } void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len) { |
︙ | ︙ | |||
8313 8314 8315 8316 8317 8318 8319 | int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) { int l1, l2; const char *s1 = Jim_GetString(firstObjPtr, &l1); const char *s2 = Jim_GetString(secondObjPtr, &l2); if (nocase) { | | | 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 | int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) { int l1, l2; const char *s1 = Jim_GetString(firstObjPtr, &l1); const char *s2 = Jim_GetString(secondObjPtr, &l2); if (nocase) { return JimStringCompareLen(s1, s2, -1, nocase); } return JimStringCompare(s1, l1, s2, l2); } int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) { |
︙ | ︙ | |||
8415 8416 8417 8418 8419 8420 8421 | return NULL; } if (first == 0 && rangeLen == len) { return strObjPtr; } if (len == bytelen) { | | | 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 | return NULL; } if (first == 0 && rangeLen == len) { return strObjPtr; } if (len == bytelen) { return Jim_NewStringObj(interp, str + first, rangeLen); } return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen); #else return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr); #endif } |
︙ | ︙ | |||
8444 8445 8446 8447 8448 8449 8450 | if (last < first) { return strObjPtr; } str = Jim_String(strObjPtr); | | | | > > > > > > > > | | 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 | if (last < first) { return strObjPtr; } str = Jim_String(strObjPtr); objPtr = Jim_NewStringObjUtf8(interp, str, first); if (newStrObj) { Jim_AppendObj(interp, objPtr, newStrObj); } Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1); return objPtr; } static void JimStrCopyUpperLower(char *dest, const char *str, int uc) { while (*str) { int c; str += utf8_tounicode(str, &c); dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c)); } *dest = 0; } static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr) { char *buf; int len; const char *str; SetStringFromAny(interp, strObjPtr); str = Jim_GetString(strObjPtr, &len); #ifdef JIM_UTF8 len *= 2; #endif buf = Jim_Alloc(len + 1); JimStrCopyUpperLower(buf, str, 0); return Jim_NewStringObjNoAlloc(interp, buf, -1); } static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr) { char *buf; const char *str; int len; if (strObjPtr->typePtr != &stringObjType) { SetStringFromAny(interp, strObjPtr); } str = Jim_GetString(strObjPtr, &len); #ifdef JIM_UTF8 len *= 2; #endif buf = Jim_Alloc(len + 1); JimStrCopyUpperLower(buf, str, 1); return Jim_NewStringObjNoAlloc(interp, buf, -1); } static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr) { char *buf, *p; int len; int c; const char *str; str = Jim_GetString(strObjPtr, &len); if (len == 0) { return strObjPtr; } #ifdef JIM_UTF8 len *= 2; #endif buf = p = Jim_Alloc(len + 1); str += utf8_tounicode(str, &c); p += utf8_getchars(p, utf8_title(c)); |
︙ | ︙ | |||
8547 8548 8549 8550 8551 8552 8553 | static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen) { while (len) { int c; int n = utf8_tounicode(str, &c); if (utf8_memchr(trimchars, trimlen, c) == NULL) { | | | 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 | static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen) { while (len) { int c; int n = utf8_tounicode(str, &c); if (utf8_memchr(trimchars, trimlen, c) == NULL) { break; } str += n; len -= n; } return str; } |
︙ | ︙ | |||
8618 8619 8620 8621 8622 8623 8624 | SetStringFromAny(interp, strObjPtr); len = Jim_Length(strObjPtr); nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen); if (nontrim == NULL) { | | | | | | | | | 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 | SetStringFromAny(interp, strObjPtr); len = Jim_Length(strObjPtr); nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen); if (nontrim == NULL) { return Jim_NewEmptyStringObj(interp); } if (nontrim == strObjPtr->bytes + len) { return strObjPtr; } if (Jim_IsShared(strObjPtr)) { strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes)); } else { strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0; strObjPtr->length = (nontrim - strObjPtr->bytes); } return strObjPtr; } static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) { Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr); strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr); if (objPtr != strObjPtr && objPtr->refCount == 0) { Jim_FreeNewObj(interp, objPtr); } return strObjPtr; } |
︙ | ︙ | |||
8670 8671 8672 8673 8674 8675 8676 | #endif static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict) { static const char * const strclassnames[] = { "integer", "alpha", "alnum", "ascii", "digit", "double", "lower", "upper", "space", "xdigit", | | | | 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 | #endif static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict) { static const char * const strclassnames[] = { "integer", "alpha", "alnum", "ascii", "digit", "double", "lower", "upper", "space", "xdigit", "control", "print", "graph", "punct", NULL }; enum { STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT, STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT, STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT }; int strclass; int len; int i; const char *str; int (*isclassfunc)(int c) = NULL; |
︙ | ︙ | |||
8709 8710 8711 8712 8713 8714 8715 | case STR_IS_DOUBLE: { double d; Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE); return JIM_OK; } | < < < < < < < | | 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 | case STR_IS_DOUBLE: { double d; Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE); return JIM_OK; } case STR_IS_ALPHA: isclassfunc = isalpha; break; case STR_IS_ALNUM: isclassfunc = isalnum; break; case STR_IS_ASCII: isclassfunc = jim_isascii; break; case STR_IS_DIGIT: isclassfunc = isdigit; break; case STR_IS_LOWER: isclassfunc = islower; break; case STR_IS_UPPER: isclassfunc = isupper; break; case STR_IS_SPACE: isclassfunc = isspace; break; case STR_IS_XDIGIT: isclassfunc = isxdigit; break; case STR_IS_CONTROL: isclassfunc = iscntrl; break; case STR_IS_PRINT: isclassfunc = isprint; break; case STR_IS_GRAPH: isclassfunc = isgraph; break; case STR_IS_PUNCT: isclassfunc = ispunct; break; default: return JIM_ERR; } for (i = 0; i < len; i++) { if (!isclassfunc(str[i])) { Jim_SetResultBool(interp, 0); return JIM_OK; } } Jim_SetResultBool(interp, 1); return JIM_OK; } |
︙ | ︙ | |||
8758 8759 8760 8761 8762 8763 8764 | int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str) { if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) { return 1; } else { | > > | | | 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 | int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str) { if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) { return 1; } else { const char *objStr = Jim_String(objPtr); if (strcmp(str, objStr) != 0) return 0; if (objPtr->typePtr != &comparedStringObjType) { Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &comparedStringObjType; } objPtr->internalRep.ptr = (char *)str; return 1; } } static int qsortCompareStringPointers(const void *a, const void *b) { char *const *sa = (char *const *)a; |
︙ | ︙ | |||
8858 8859 8860 8861 8862 8863 8864 | { Jim_Obj *objPtr; int type; } ScriptToken; typedef struct ScriptObj { | | | | | | | | | 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 | { Jim_Obj *objPtr; int type; } ScriptToken; typedef struct ScriptObj { ScriptToken *token; Jim_Obj *fileNameObj; int len; int substFlags; int inUse; /* Used to share a ScriptObj. Currently only used by Jim_EvalObj() as protection against shimmering of the currently evaluated object. */ int firstline; int linenr; int missing; } ScriptObj; static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static int JimParseCheckMissing(Jim_Interp *interp, int ch); static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr); void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) |
︙ | ︙ | |||
8899 8900 8901 8902 8903 8904 8905 | JIM_NOTUSED(srcPtr); dupPtr->typePtr = NULL; } typedef struct { | | | | | | | | | | | 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 | JIM_NOTUSED(srcPtr); dupPtr->typePtr = NULL; } typedef struct { const char *token; int len; int type; int line; } ParseToken; typedef struct { ParseToken *list; int size; int count; ParseToken static_list[20]; } ParseTokenList; static void ScriptTokenListInit(ParseTokenList *tokenlist) { tokenlist->list = tokenlist->static_list; tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken); tokenlist->count = 0; |
︙ | ︙ | |||
8934 8935 8936 8937 8938 8939 8940 | static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type, int line) { ParseToken *t; if (tokenlist->count == tokenlist->size) { | | | | | | < < | < < | | < < < | | | | | | | | | | | | | | | 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 | static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type, int line) { ParseToken *t; if (tokenlist->count == tokenlist->size) { tokenlist->size *= 2; if (tokenlist->list != tokenlist->static_list) { tokenlist->list = Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list)); } else { tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list)); memcpy(tokenlist->list, tokenlist->static_list, tokenlist->count * sizeof(*tokenlist->list)); } } t = &tokenlist->list[tokenlist->count++]; t->token = token; t->len = len; t->type = type; t->line = line; } static int JimCountWordTokens(ParseToken *t) { int expand = 1; int count = 0; if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) { if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) { expand = -1; t++; } } while (!TOKEN_IS_SEP(t->type)) { t++; count++; } return count * expand; } static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t) { Jim_Obj *objPtr; if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) { int len = t->len; char *str = Jim_Alloc(len + 1); len = JimEscape(str, t->token, len); objPtr = Jim_NewStringObjNoAlloc(interp, str, len); } else { objPtr = Jim_NewStringObj(interp, t->token, t->len); } return objPtr; } static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, ParseTokenList *tokenlist) { int i; struct ScriptToken *token; int lineargs = 0; ScriptToken *linefirst; int count; int linenr; #ifdef DEBUG_SHOW_SCRIPT_TOKENS printf("==== Tokens ====\n"); for (i = 0; i < tokenlist->count; i++) { printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type), tokenlist->list[i].len, tokenlist->list[i].token); } #endif count = tokenlist->count; for (i = 0; i < tokenlist->count; i++) { if (tokenlist->list[i].type == JIM_TT_EOL) { count++; } } linenr = script->firstline = tokenlist->list[0].line; token = script->token = Jim_Alloc(sizeof(ScriptToken) * count); linefirst = token++; for (i = 0; i < tokenlist->count; ) { int wordtokens; while (tokenlist->list[i].type == JIM_TT_SEP) { i++; } wordtokens = JimCountWordTokens(tokenlist->list + i); if (wordtokens == 0) { if (lineargs) { linefirst->type = JIM_TT_LINE; linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr); Jim_IncrRefCount(linefirst->objPtr); lineargs = 0; linefirst = token++; } i++; continue; } else if (wordtokens != 1) { token->type = JIM_TT_WORD; token->objPtr = Jim_NewIntObj(interp, wordtokens); Jim_IncrRefCount(token->objPtr); token++; if (wordtokens < 0) { i++; wordtokens = -wordtokens - 1; lineargs--; } } if (lineargs == 0) { linenr = tokenlist->list[i].line; } lineargs++; while (wordtokens--) { const ParseToken *t = &tokenlist->list[i++]; token->type = t->type; token->objPtr = JimMakeScriptObj(interp, t); Jim_IncrRefCount(token->objPtr); |
︙ | ︙ | |||
9117 9118 9119 9120 9121 9122 9123 | int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr) { ScriptObj *script = JimGetScript(interp, scriptObj); if (stateCharPtr) { *stateCharPtr = script->missing; } | | < < < | 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 | int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr) { ScriptObj *script = JimGetScript(interp, scriptObj); if (stateCharPtr) { *stateCharPtr = script->missing; } return (script->missing == ' '); } static int JimParseCheckMissing(Jim_Interp *interp, int ch) { const char *msg; switch (ch) { case '\\': case ' ': return JIM_OK; case '[': msg = "unmatched \"[\""; break; case '{': msg = "missing close-brace"; break; case '"': default: msg = "missing quote"; break; } Jim_SetResultString(interp, msg, -1); |
︙ | ︙ | |||
9159 9160 9161 9162 9163 9164 9165 | struct ScriptToken *token; token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count); for (i = 0; i < tokenlist->count; i++) { const ParseToken *t = &tokenlist->list[i]; | | | | | | | | | | 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 | struct ScriptToken *token; token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count); for (i = 0; i < tokenlist->count; i++) { const ParseToken *t = &tokenlist->list[i]; token->type = t->type; token->objPtr = JimMakeScriptObj(interp, t); Jim_IncrRefCount(token->objPtr); token++; } script->len = i; } static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int scriptTextLen; const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); struct JimParserCtx parser; struct ScriptObj *script; ParseTokenList tokenlist; int line = 1; if (objPtr->typePtr == &sourceObjType) { line = objPtr->internalRep.sourceValue.lineNumber; } ScriptTokenListInit(&tokenlist); JimParserInit(&parser, scriptText, scriptTextLen, line); while (!parser.eof) { JimParseScript(&parser); ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0); script = Jim_Alloc(sizeof(*script)); memset(script, 0, sizeof(*script)); script->inUse = 1; if (objPtr->typePtr == &sourceObjType) { script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; } else { script->fileNameObj = interp->emptyObj; } Jim_IncrRefCount(script->fileNameObj); script->missing = parser.missing.ch; script->linenr = parser.missing.line; ScriptObjAddTokens(interp, script, &tokenlist); ScriptTokenListFree(&tokenlist); Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; } static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script); static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr == interp->emptyObj) { objPtr = interp->nullScriptObj; } if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { JimSetScriptFromAny(interp, objPtr); } |
︙ | ︙ | |||
9265 9266 9267 9268 9269 9270 9271 | Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); if (cmdPtr->u.proc.staticVars) { Jim_FreeHashTable(cmdPtr->u.proc.staticVars); Jim_Free(cmdPtr->u.proc.staticVars); } } else { | | | > | | | | | | | | | | | | | | | 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 | Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); if (cmdPtr->u.proc.staticVars) { Jim_FreeHashTable(cmdPtr->u.proc.staticVars); Jim_Free(cmdPtr->u.proc.staticVars); } } else { if (cmdPtr->u.native.delProc) { cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData); } } if (cmdPtr->prevCmd) { JimDecrCmdRefCount(interp, cmdPtr->prevCmd); } Jim_Free(cmdPtr); } } static void JimVariablesHTValDestructor(void *interp, void *val) { Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr); Jim_Free(val); } static const Jim_HashTableType JimVariablesHashTableType = { JimStringCopyHTHashFunction, JimStringCopyHTDup, NULL, JimStringCopyHTKeyCompare, JimStringCopyHTKeyDestructor, JimVariablesHTValDestructor }; static void JimCommandsHT_ValDestructor(void *interp, void *val) { JimDecrCmdRefCount(interp, val); } static const Jim_HashTableType JimCommandsHashTableType = { JimStringCopyHTHashFunction, JimStringCopyHTDup, NULL, JimStringCopyHTKeyCompare, JimStringCopyHTKeyDestructor, JimCommandsHT_ValDestructor }; #ifdef jim_ext_namespace static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj) { const char *name = Jim_String(nsObj); if (name[0] == ':' && name[1] == ':') { while (*++name == ':') { } nsObj = Jim_NewStringObj(interp, name, -1); } else if (Jim_Length(interp->framePtr->nsObj)) { nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj); Jim_AppendStrings(interp, nsObj, "::", name, NULL); } return nsObj; } Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr) |
︙ | ︙ | |||
9348 9349 9350 9351 9352 9353 9354 | } static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr = interp->emptyObj; if (name[0] == ':' && name[1] == ':') { | | | | | | | | 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 | } static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr = interp->emptyObj; if (name[0] == ':' && name[1] == ':') { while (*++name == ':') { } } else if (Jim_Length(interp->framePtr->nsObj)) { objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj); Jim_AppendStrings(interp, objPtr, "::", name, NULL); name = Jim_String(objPtr); } Jim_IncrRefCount(objPtr); *objPtrPtr = objPtr; return name; } #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ)) #else #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME)) #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY) Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr) { return nameObjPtr; } #endif static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd) { Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name); if (he) { Jim_InterpIncrProcEpoch(interp); } if (he && interp->local) { cmd->prevCmd = Jim_GetHashEntryVal(he); Jim_SetHashVal(&interp->commands, he, cmd); } else { if (he) { Jim_DeleteHashEntry(&interp->commands, name); } Jim_AddHashEntry(&interp->commands, name, cmd); } return JIM_OK; } int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr, Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc) { Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr)); memset(cmdPtr, 0, sizeof(*cmdPtr)); cmdPtr->inUse = 1; cmdPtr->u.native.delProc = delProc; cmdPtr->u.native.cmdProc = cmdProc; cmdPtr->u.native.privData = privData; JimCreateCommand(interp, cmdNameStr, cmdPtr); |
︙ | ︙ | |||
9435 9436 9437 9438 9439 9440 9441 | Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp); for (i = 0; i < len; i++) { Jim_Obj *objPtr, *initObjPtr, *nameObjPtr; Jim_Var *varPtr; int subLen; objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i); | | | 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 | Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp); for (i = 0; i < len; i++) { Jim_Obj *objPtr, *initObjPtr, *nameObjPtr; Jim_Var *varPtr; int subLen; objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i); subLen = Jim_ListLength(interp, objPtr); if (subLen == 1 || subLen == 2) { nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0); if (subLen == 1) { initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); if (initObjPtr == NULL) { Jim_SetResultFormatted(interp, |
︙ | ︙ | |||
9481 9482 9483 9484 9485 9486 9487 | return JIM_OK; } static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname) { #ifdef jim_ext_namespace if (cmdPtr->isproc) { | | | | | | | | | | | 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 | return JIM_OK; } static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname) { #ifdef jim_ext_namespace if (cmdPtr->isproc) { const char *pt = strrchr(cmdname, ':'); if (pt && pt != cmdname && pt[-1] == ':') { Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1); Jim_IncrRefCount(cmdPtr->u.proc.nsObj); if (Jim_FindHashEntry(&interp->commands, pt + 1)) { Jim_InterpIncrProcEpoch(interp); } } } #endif } static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj) { Jim_Cmd *cmdPtr; int argListLen; int i; argListLen = Jim_ListLength(interp, argListObjPtr); cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen); memset(cmdPtr, 0, sizeof(*cmdPtr)); cmdPtr->inUse = 1; cmdPtr->isproc = 1; cmdPtr->u.proc.argListObjPtr = argListObjPtr; cmdPtr->u.proc.argListLen = argListLen; cmdPtr->u.proc.bodyObjPtr = bodyObjPtr; cmdPtr->u.proc.argsPos = -1; cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1); cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj; Jim_IncrRefCount(argListObjPtr); Jim_IncrRefCount(bodyObjPtr); Jim_IncrRefCount(cmdPtr->u.proc.nsObj); if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) { goto err; } for (i = 0; i < argListLen; i++) { Jim_Obj *argPtr; Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; int len; argPtr = Jim_ListGetIndex(interp, argListObjPtr, i); len = Jim_ListLength(interp, argPtr); if (len == 0) { Jim_SetResultString(interp, "argument with no name", -1); err: JimDecrCmdRefCount(interp, cmdPtr); return NULL; } if (len > 2) { Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr); goto err; } if (len == 2) { nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0); defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1); } else { nameObjPtr = argPtr; defaultObjPtr = NULL; } if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) { if (cmdPtr->u.proc.argsPos >= 0) { |
︙ | ︙ | |||
9619 9620 9621 9622 9623 9624 9625 | if (newName[0] == 0) { return Jim_DeleteCommand(interp, oldName); } fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj); fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj); | | | | | | 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 | if (newName[0] == 0) { return Jim_DeleteCommand(interp, oldName); } fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj); fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj); he = Jim_FindHashEntry(&interp->commands, fqold); if (he == NULL) { Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName); } else if (Jim_FindHashEntry(&interp->commands, fqnew)) { Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName); } else { cmdPtr = Jim_GetHashEntryVal(he); JimIncrCmdRefCount(cmdPtr); JimUpdateProcNamespace(interp, cmdPtr, fqnew); Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr); Jim_DeleteHashEntry(&interp->commands, fqold); Jim_InterpIncrProcEpoch(interp); ret = JIM_OK; } JimFreeQualifiedName(interp, qualifiedOldNameObj); JimFreeQualifiedName(interp, qualifiedNewNameObj); |
︙ | ︙ | |||
9680 9681 9682 9683 9684 9685 9686 | if (objPtr->typePtr != &commandObjType || objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch #ifdef jim_ext_namespace || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj) #endif ) { | | | | | | | | | | | | | | | | | | | 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 | if (objPtr->typePtr != &commandObjType || objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch #ifdef jim_ext_namespace || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj) #endif ) { const char *name = Jim_String(objPtr); Jim_HashEntry *he; if (name[0] == ':' && name[1] == ':') { while (*++name == ':') { } } #ifdef jim_ext_namespace else if (Jim_Length(interp->framePtr->nsObj)) { Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj); Jim_AppendStrings(interp, nameObj, "::", name, NULL); he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj)); Jim_FreeNewObj(interp, nameObj); if (he) { goto found; } } #endif he = Jim_FindHashEntry(&interp->commands, name); if (he == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr); } return NULL; } #ifdef jim_ext_namespace found: #endif cmd = Jim_GetHashEntryVal(he); Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &commandObjType; objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; objPtr->internalRep.cmdValue.cmdPtr = cmd; objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj; Jim_IncrRefCount(interp->framePtr->nsObj); } else { cmd = objPtr->internalRep.cmdValue.cmdPtr; } while (cmd->u.proc.upcall) { cmd = cmd->prevCmd; } return cmd; } #define JIM_DICT_SUGAR 100 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static const Jim_ObjType variableObjType = { "variable", NULL, NULL, NULL, JIM_TYPE_REFERENCES, }; static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr) { if (nameObjPtr->typePtr != &variableObjType) { int len; const char *str = Jim_GetString(nameObjPtr, &len); if (memchr(str, '\0', len)) { Jim_SetResultFormatted(interp, "%s name contains embedded null", type); return JIM_ERR; } } return JIM_OK; } static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { const char *varName; Jim_CallFrame *framePtr; Jim_HashEntry *he; int global; int len; if (objPtr->typePtr == &variableObjType) { framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr; if (objPtr->internalRep.varValue.callFrameId == framePtr->id) { return JIM_OK; } } else if (objPtr->typePtr == &dictSubstObjType) { return JIM_DICT_SUGAR; } else if (JimValidName(interp, "variable", objPtr) != JIM_OK) { return JIM_ERR; } varName = Jim_GetString(objPtr, &len); if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) { return JIM_DICT_SUGAR; } if (varName[0] == ':' && varName[1] == ':') { while (*++varName == ':') { } global = 1; framePtr = interp->topFramePtr; } else { global = 0; framePtr = interp->framePtr; } he = Jim_FindHashEntry(&framePtr->vars, varName); if (he == NULL) { if (!global && framePtr->staticVars) { he = Jim_FindHashEntry(framePtr->staticVars, varName); } if (he == NULL) { return JIM_ERR; } } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &variableObjType; objPtr->internalRep.varValue.callFrameId = framePtr->id; objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he); objPtr->internalRep.varValue.global = global; return JIM_OK; } static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr); static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags); static Jim_Var *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) { const char *name; Jim_CallFrame *framePtr; int global; Jim_Var *var = Jim_Alloc(sizeof(*var)); var->objPtr = valObjPtr; Jim_IncrRefCount(valObjPtr); var->linkFramePtr = NULL; name = Jim_String(nameObjPtr); if (name[0] == ':' && name[1] == ':') { while (*++name == ':') { } framePtr = interp->topFramePtr; global = 1; } else { framePtr = interp->framePtr; global = 0; } Jim_AddHashEntry(&framePtr->vars, name, var); Jim_FreeIntRep(interp, nameObjPtr); nameObjPtr->typePtr = &variableObjType; nameObjPtr->internalRep.varValue.callFrameId = framePtr->id; nameObjPtr->internalRep.varValue.varPtr = var; nameObjPtr->internalRep.varValue.global = global; return var; |
︙ | ︙ | |||
9891 9892 9893 9894 9895 9896 9897 | case JIM_OK: var = nameObjPtr->internalRep.varValue.varPtr; if (var->linkFramePtr == NULL) { Jim_IncrRefCount(valObjPtr); Jim_DecrRefCount(interp, var->objPtr); var->objPtr = valObjPtr; } | | | 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 | case JIM_OK: var = nameObjPtr->internalRep.varValue.varPtr; if (var->linkFramePtr == NULL) { Jim_IncrRefCount(valObjPtr); Jim_DecrRefCount(interp, var->objPtr); var->objPtr = valObjPtr; } else { Jim_CallFrame *savedCallFrame; savedCallFrame = interp->framePtr; interp->framePtr = var->linkFramePtr; err = Jim_SetVariable(interp, var->objPtr, valObjPtr); interp->framePtr = savedCallFrame; if (err != JIM_OK) |
︙ | ︙ | |||
9931 9932 9933 9934 9935 9936 9937 | result = Jim_SetVariableStr(interp, name, objPtr); interp->framePtr = savedFramePtr; return result; } int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val) { | | > > | > | | | | | | | 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 | result = Jim_SetVariableStr(interp, name, objPtr); interp->framePtr = savedFramePtr; return result; } int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val) { Jim_Obj *nameObjPtr, *valObjPtr; int result; nameObjPtr = Jim_NewStringObj(interp, name, -1); valObjPtr = Jim_NewStringObj(interp, val, -1); Jim_IncrRefCount(nameObjPtr); Jim_IncrRefCount(valObjPtr); result = Jim_SetVariable(interp, nameObjPtr, valObjPtr); Jim_DecrRefCount(interp, nameObjPtr); Jim_DecrRefCount(interp, valObjPtr); return result; } int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame) { const char *varName; const char *targetName; Jim_CallFrame *framePtr; Jim_Var *varPtr; switch (SetVariableFromAny(interp, nameObjPtr)) { case JIM_DICT_SUGAR: Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr); return JIM_ERR; case JIM_OK: varPtr = nameObjPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr == NULL) { Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr); return JIM_ERR; } varPtr->linkFramePtr = NULL; break; } varName = Jim_String(nameObjPtr); if (varName[0] == ':' && varName[1] == ':') { while (*++varName == ':') { } framePtr = interp->topFramePtr; } else { framePtr = interp->framePtr; } targetName = Jim_String(targetNameObjPtr); |
︙ | ︙ | |||
10000 10001 10002 10003 10004 10005 10006 | Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable", nameObjPtr); Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_ERR; } | | | | | | | | | 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 | Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable", nameObjPtr); Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_ERR; } if (framePtr == targetCallFrame) { Jim_Obj *objPtr = targetNameObjPtr; while (1) { if (strcmp(Jim_String(objPtr), varName) == 0) { Jim_SetResultString(interp, "can't upvar from variable to itself", -1); Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_ERR; } if (SetVariableFromAny(interp, objPtr) != JIM_OK) break; varPtr = objPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr != targetCallFrame) break; objPtr = varPtr->objPtr; } } Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr); nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame; Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_OK; } Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { switch (SetVariableFromAny(interp, nameObjPtr)) { case JIM_OK:{ Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr == NULL) { return varPtr->objPtr; } else { Jim_Obj *objPtr; Jim_CallFrame *savedCallFrame = interp->framePtr; interp->framePtr = varPtr->linkFramePtr; objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags); interp->framePtr = savedCallFrame; if (objPtr) { return objPtr; } } } break; case JIM_DICT_SUGAR: return JimDictSugarGet(interp, nameObjPtr, flags); } if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr); } return NULL; } |
︙ | ︙ | |||
10109 10110 10111 10112 10113 10114 10115 | { Jim_Var *varPtr; int retval; Jim_CallFrame *framePtr; retval = SetVariableFromAny(interp, nameObjPtr); if (retval == JIM_DICT_SUGAR) { | | | | | 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 | { Jim_Var *varPtr; int retval; Jim_CallFrame *framePtr; retval = SetVariableFromAny(interp, nameObjPtr); if (retval == JIM_DICT_SUGAR) { return JimDictSugarSet(interp, nameObjPtr, NULL); } else if (retval == JIM_OK) { varPtr = nameObjPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr) { framePtr = interp->framePtr; interp->framePtr = varPtr->linkFramePtr; retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE); interp->framePtr = framePtr; } else { const char *name = Jim_String(nameObjPtr); if (nameObjPtr->internalRep.varValue.global) { name += 2; framePtr = interp->topFramePtr; } else { framePtr = interp->framePtr; } retval = Jim_DeleteHashEntry(&framePtr->vars, name); if (retval == JIM_OK) { framePtr->id = interp->callFrameEpoch++; } } } if (retval != JIM_OK && (flags & JIM_ERRMSG)) { Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr); } |
︙ | ︙ | |||
10167 10168 10169 10170 10171 10172 10173 | p++; keyLen = (str + len) - p; if (str[len - 1] == ')') { keyLen--; } | | | | | | 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 | p++; keyLen = (str + len) - p; if (str[len - 1] == ')') { keyLen--; } keyObjPtr = Jim_NewStringObj(interp, p, keyLen); Jim_IncrRefCount(varObjPtr); Jim_IncrRefCount(keyObjPtr); *varPtrPtr = varObjPtr; *keyPtrPtr = keyObjPtr; } static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr) { int err; SetDictSubstFromAny(interp, objPtr); err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST); if (err == JIM_OK) { Jim_SetEmptyResult(interp); } else { if (!valObjPtr) { if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) { Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array", objPtr); return err; } } Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array", (valObjPtr ? "set" : "unset"), objPtr); } return err; } static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr, |
︙ | ︙ | |||
10224 10225 10226 10227 10228 10229 10230 | ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); if (ret != JIM_OK) { Jim_SetResultFormatted(interp, "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr, ret < 0 ? "variable isn't" : "no such element in"); } else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) { | | | 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 | ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); if (ret != JIM_OK) { Jim_SetResultFormatted(interp, "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr, ret < 0 ? "variable isn't" : "no such element in"); } else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) { Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr)); } return resObjPtr; } |
︙ | ︙ | |||
10249 10250 10251 10252 10253 10254 10255 | void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr); Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); } | | > | < | | > | | 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 | void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr); Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); } void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); dupPtr->internalRep.dictSubstValue.varNameObjPtr = srcPtr->internalRep.dictSubstValue.varNameObjPtr; dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr; dupPtr->typePtr = &dictSubstObjType; } static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &dictSubstObjType) { Jim_Obj *varObjPtr, *keyObjPtr; if (objPtr->typePtr == &interpolatedObjType) { varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr; keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr; Jim_IncrRefCount(varObjPtr); Jim_IncrRefCount(keyObjPtr); } |
︙ | ︙ | |||
10307 10308 10309 10310 10311 10312 10313 | Jim_DecrRefCount(interp, substKeyObjPtr); return resObjPtr; } static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr) { | > > | | > > | 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 | Jim_DecrRefCount(interp, substKeyObjPtr); return resObjPtr; } static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *resultObjPtr; if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) { resultObjPtr->refCount--; return resultObjPtr; } return NULL; } static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj) { |
︙ | ︙ | |||
10350 10351 10352 10353 10354 10355 10356 | Jim_IncrRefCount(nsObj); return cf; } static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands) { | | | | < | > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 | Jim_IncrRefCount(nsObj); return cf; } static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands) { if (localCommands) { Jim_Obj *cmdNameObj; while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) { Jim_HashEntry *he; Jim_Obj *fqObjName; Jim_HashTable *ht = &interp->commands; const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName); he = Jim_FindHashEntry(ht, fqname); if (he) { Jim_Cmd *cmd = Jim_GetHashEntryVal(he); if (cmd->prevCmd) { Jim_Cmd *prevCmd = cmd->prevCmd; cmd->prevCmd = NULL; JimDecrCmdRefCount(interp, cmd); Jim_SetHashVal(ht, he, prevCmd); } else { Jim_DeleteHashEntry(ht, fqname); Jim_InterpIncrProcEpoch(interp); } } Jim_DecrRefCount(interp, cmdNameObj); JimFreeQualifiedName(interp, fqObjName); } Jim_FreeStack(localCommands); Jim_Free(localCommands); } return JIM_OK; } #define JIM_FCF_FULL 0 #define JIM_FCF_REUSE 1 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action) { JimDeleteLocalProcs(interp, cf->localCommands); if (cf->procArgsObjPtr) Jim_DecrRefCount(interp, cf->procArgsObjPtr); if (cf->procBodyObjPtr) |
︙ | ︙ | |||
10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 | cf->vars.used = 0; } cf->next = interp->freeFramesList; interp->freeFramesList = cf; } int Jim_IsBigEndian(void) { union { unsigned short s; unsigned char c[2]; } uval = {0x0102}; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 | cf->vars.used = 0; } cf->next = interp->freeFramesList; interp->freeFramesList = cf; } #ifdef JIM_REFERENCES static void JimReferencesHTValDestructor(void *interp, void *val) { Jim_Reference *refPtr = (void *)val; Jim_DecrRefCount(interp, refPtr->objPtr); if (refPtr->finalizerCmdNamePtr != NULL) { Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr); } Jim_Free(val); } static unsigned int JimReferencesHTHashFunction(const void *key) { const unsigned long *widePtr = key; unsigned int intValue = (unsigned int)*widePtr; return Jim_IntHashFunction(intValue); } static void *JimReferencesHTKeyDup(void *privdata, const void *key) { void *copy = Jim_Alloc(sizeof(unsigned long)); JIM_NOTUSED(privdata); memcpy(copy, key, sizeof(unsigned long)); return copy; } static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2) { JIM_NOTUSED(privdata); return memcmp(key1, key2, sizeof(unsigned long)) == 0; } static void JimReferencesHTKeyDestructor(void *privdata, void *key) { JIM_NOTUSED(privdata); Jim_Free(key); } static const Jim_HashTableType JimReferencesHashTableType = { JimReferencesHTHashFunction, JimReferencesHTKeyDup, NULL, JimReferencesHTKeyCompare, JimReferencesHTKeyDestructor, JimReferencesHTValDestructor }; #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN) static int JimFormatReference(char *buf, Jim_Reference *refPtr, unsigned long id) { const char *fmt = "<reference.<%s>.%020lu>"; sprintf(buf, fmt, refPtr->tag, id); return JIM_REFERENCE_SPACE; } static void UpdateStringOfReference(struct Jim_Obj *objPtr); static const Jim_ObjType referenceObjType = { "reference", NULL, NULL, UpdateStringOfReference, JIM_TYPE_REFERENCES, }; static void UpdateStringOfReference(struct Jim_Obj *objPtr) { char buf[JIM_REFERENCE_SPACE + 1]; JimFormatReference(buf, objPtr->internalRep.refValue.refPtr, objPtr->internalRep.refValue.id); JimSetStringBytes(objPtr, buf); } static int isrefchar(int c) { return (c == '_' || isalnum(c)); } static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { unsigned long value; int i, len; const char *str, *start, *end; char refId[21]; Jim_Reference *refPtr; Jim_HashEntry *he; char *endptr; str = Jim_GetString(objPtr, &len); if (len < JIM_REFERENCE_SPACE) goto badformat; start = str; end = str + len - 1; while (*start == ' ') start++; while (*end == ' ' && end > start) end--; if (end - start + 1 != JIM_REFERENCE_SPACE) goto badformat; if (memcmp(start, "<reference.<", 12) != 0) goto badformat; if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>') goto badformat; for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) { if (!isrefchar(start[12 + i])) goto badformat; } memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20); refId[20] = '\0'; value = strtoul(refId, &endptr, 10); if (JimCheckConversion(refId, endptr) != JIM_OK) goto badformat; he = Jim_FindHashEntry(&interp->references, &value); if (he == NULL) { Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr); return JIM_ERR; } refPtr = Jim_GetHashEntryVal(he); Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &referenceObjType; objPtr->internalRep.refValue.id = value; objPtr->internalRep.refValue.refPtr = refPtr; return JIM_OK; badformat: Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr); return JIM_ERR; } Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr) { struct Jim_Reference *refPtr; unsigned long id; Jim_Obj *refObjPtr; const char *tag; int tagLen, i; Jim_CollectIfNeeded(interp); refPtr = Jim_Alloc(sizeof(*refPtr)); refPtr->objPtr = objPtr; Jim_IncrRefCount(objPtr); refPtr->finalizerCmdNamePtr = cmdNamePtr; if (cmdNamePtr) Jim_IncrRefCount(cmdNamePtr); id = interp->referenceNextId++; Jim_AddHashEntry(&interp->references, &id, refPtr); refObjPtr = Jim_NewObj(interp); refObjPtr->typePtr = &referenceObjType; refObjPtr->bytes = NULL; refObjPtr->internalRep.refValue.id = id; refObjPtr->internalRep.refValue.refPtr = refPtr; interp->referenceNextId++; tag = Jim_GetString(tagPtr, &tagLen); if (tagLen > JIM_REFERENCE_TAGLEN) tagLen = JIM_REFERENCE_TAGLEN; for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) { if (i < tagLen && isrefchar(tag[i])) refPtr->tag[i] = tag[i]; else refPtr->tag[i] = '_'; } refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0'; return refObjPtr; } Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR) return NULL; return objPtr->internalRep.refValue.refPtr; } int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr) { Jim_Reference *refPtr; if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL) return JIM_ERR; Jim_IncrRefCount(cmdNamePtr); if (refPtr->finalizerCmdNamePtr) Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr); refPtr->finalizerCmdNamePtr = cmdNamePtr; return JIM_OK; } int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr) { Jim_Reference *refPtr; if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL) return JIM_ERR; *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr; return JIM_OK; } static const Jim_HashTableType JimRefMarkHashTableType = { JimReferencesHTHashFunction, JimReferencesHTKeyDup, NULL, JimReferencesHTKeyCompare, JimReferencesHTKeyDestructor, NULL }; int Jim_Collect(Jim_Interp *interp) { int collected = 0; return collected; } #define JIM_COLLECT_ID_PERIOD 5000 #define JIM_COLLECT_TIME_PERIOD 300 void Jim_CollectIfNeeded(Jim_Interp *interp) { unsigned long elapsedId; int elapsedTime; elapsedId = interp->referenceNextId - interp->lastCollectId; elapsedTime = time(NULL) - interp->lastCollectTime; if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) { Jim_Collect(interp); } } #endif int Jim_IsBigEndian(void) { union { unsigned short s; unsigned char c[2]; } uval = {0x0102}; |
︙ | ︙ | |||
10524 10525 10526 10527 10528 10529 10530 | Jim_IncrRefCount(i->unknown); Jim_IncrRefCount(i->currentScriptObj); Jim_IncrRefCount(i->nullScriptObj); Jim_IncrRefCount(i->errorProc); Jim_IncrRefCount(i->trueObj); Jim_IncrRefCount(i->falseObj); | | | 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 | Jim_IncrRefCount(i->unknown); Jim_IncrRefCount(i->currentScriptObj); Jim_IncrRefCount(i->nullScriptObj); Jim_IncrRefCount(i->errorProc); Jim_IncrRefCount(i->trueObj); Jim_IncrRefCount(i->falseObj); Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY); Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0"); Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim"); Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS); Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM); Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR); |
︙ | ︙ | |||
10546 10547 10548 10549 10550 10551 10552 | void Jim_FreeInterp(Jim_Interp *i) { Jim_CallFrame *cf, *cfx; Jim_Obj *objPtr, *nextObjPtr; | | < < | 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 | void Jim_FreeInterp(Jim_Interp *i) { Jim_CallFrame *cf, *cfx; Jim_Obj *objPtr, *nextObjPtr; for (cf = i->framePtr; cf; cf = cfx) { cfx = cf->parent; JimFreeCallFrame(i, cf, JIM_FCF_FULL); } Jim_DecrRefCount(i, i->emptyObj); Jim_DecrRefCount(i, i->trueObj); Jim_DecrRefCount(i, i->falseObj); |
︙ | ︙ | |||
10580 10581 10582 10583 10584 10585 10586 | if (i->liveList != NULL) { objPtr = i->liveList; printf("\n-------------------------------------\n"); printf("Objects still in the free list:\n"); while (objPtr) { const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string"; | < | 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 | if (i->liveList != NULL) { objPtr = i->liveList; printf("\n-------------------------------------\n"); printf("Objects still in the free list:\n"); while (objPtr) { const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string"; if (objPtr->bytes && strlen(objPtr->bytes) > 20) { printf("%p (%d) %-10s: '%.20s...'\n", (void *)objPtr, objPtr->refCount, type, objPtr->bytes); } else { printf("%p (%d) %-10s: '%s'\n", |
︙ | ︙ | |||
10602 10603 10604 10605 10606 10607 10608 | objPtr = objPtr->nextObjPtr; } printf("-------------------------------------\n\n"); JimPanic((1, "Live list non empty freeing the interpreter! Leak?")); } #endif | | | | | 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 | objPtr = objPtr->nextObjPtr; } printf("-------------------------------------\n\n"); JimPanic((1, "Live list non empty freeing the interpreter! Leak?")); } #endif objPtr = i->freeList; while (objPtr) { nextObjPtr = objPtr->nextObjPtr; Jim_Free(objPtr); objPtr = nextObjPtr; } for (cf = i->freeFramesList; cf; cf = cfx) { cfx = cf->next; if (cf->vars.table) Jim_FreeHashTable(&cf->vars); Jim_Free(cf); } Jim_Free(i); } Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) { long level; const char *str; |
︙ | ︙ | |||
10643 10644 10645 10646 10647 10648 10649 | } } else { if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) { level = -1; } else { | | | | | | | 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 | } } else { if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) { level = -1; } else { level = interp->framePtr->level - level; } } } else { str = "1"; level = interp->framePtr->level - 1; } if (level == 0) { return interp->topFramePtr; } if (level > 0) { for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { if (framePtr->level == level) { return framePtr; } } } Jim_SetResultFormatted(interp, "bad level \"%s\"", str); return NULL; } static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr) { long level; Jim_CallFrame *framePtr; if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) { if (level <= 0) { level = interp->framePtr->level + level; } if (level == 0) { return interp->topFramePtr; } for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { if (framePtr->level == level) { return framePtr; } } } |
︙ | ︙ | |||
10707 10708 10709 10710 10711 10712 10713 | Jim_IncrRefCount(interp->stackTrace); } static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) { int len; | | | | | | | | 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 | Jim_IncrRefCount(interp->stackTrace); } static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) { int len; Jim_IncrRefCount(stackTraceObj); Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = stackTraceObj; interp->errorFlag = 1; len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) { interp->addStackTrace = 1; } } } static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, Jim_Obj *fileNameObj, int linenr) { if (strcmp(procname, "unknown") == 0) { procname = ""; } if (!*procname && !Jim_Length(fileNameObj)) { return; } if (Jim_IsShared(interp->stackTrace)) { Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace); Jim_IncrRefCount(interp->stackTrace); } if (!*procname && Jim_Length(fileNameObj)) { int len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3); if (Jim_Length(objPtr)) { objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2); if (Jim_Length(objPtr) == 0) { ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0); ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0); return; } } } } |
︙ | ︙ | |||
10855 10856 10857 10858 10859 10860 10861 | static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { jim_wide wideValue; const char *str; if (objPtr->typePtr == &coercedDoubleObjType) { | | | | | | 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 | static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { jim_wide wideValue; const char *str; if (objPtr->typePtr == &coercedDoubleObjType) { objPtr->typePtr = &intObjType; return JIM_OK; } str = Jim_String(objPtr); if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr); } return JIM_ERR; } if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) { Jim_SetResultString(interp, "Integer value too big to be represented", -1); return JIM_ERR; } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &intObjType; objPtr->internalRep.wideValue = wideValue; return JIM_OK; } #ifdef JIM_OPTIMIZATION |
︙ | ︙ | |||
10972 10973 10974 10975 10976 10977 10978 | return; } { char buf[JIM_DOUBLE_SPACE + 1]; int i; int len = sprintf(buf, "%.12g", value); | | | | 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 | return; } { char buf[JIM_DOUBLE_SPACE + 1]; int i; int len = sprintf(buf, "%.12g", value); for (i = 0; i < len; i++) { if (buf[i] == '.' || buf[i] == 'e') { #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX) char *e = strchr(buf, 'e'); if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') { e += 2; memmove(e, e + 1, len - (e - buf)); } #endif break; } } |
︙ | ︙ | |||
11001 11002 11003 11004 11005 11006 11007 11008 | static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { double doubleValue; jim_wide wideValue; const char *str; #ifdef HAVE_LONG_LONG | > > | | > < < | | | | 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 | static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { double doubleValue; jim_wide wideValue; const char *str; str = Jim_String(objPtr); #ifdef HAVE_LONG_LONG #define MIN_INT_IN_DOUBLE -(1LL << 53) #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1) if (objPtr->typePtr == &intObjType && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) { objPtr->typePtr = &coercedDoubleObjType; return JIM_OK; } else #endif if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) { Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &coercedDoubleObjType; objPtr->internalRep.wideValue = wideValue; return JIM_OK; } else { if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) { Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr); return JIM_ERR; } Jim_FreeIntRep(interp, objPtr); } objPtr->typePtr = &doubleObjType; objPtr->internalRep.doubleValue = doubleValue; return JIM_OK; } |
︙ | ︙ | |||
11067 11068 11069 11070 11071 11072 11073 | objPtr = Jim_NewObj(interp); objPtr->typePtr = &doubleObjType; objPtr->bytes = NULL; objPtr->internalRep.doubleValue = doubleValue; return objPtr; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 | objPtr = Jim_NewObj(interp); objPtr->typePtr = &doubleObjType; objPtr->bytes = NULL; objPtr->internalRep.doubleValue = doubleValue; return objPtr; } static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec); static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr); static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfList(struct Jim_Obj *objPtr); static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); |
︙ | ︙ | |||
11157 11158 11159 11160 11161 11162 11163 | #define JIM_ELESTR_SIMPLE 0 #define JIM_ELESTR_BRACE 1 #define JIM_ELESTR_QUOTE 2 static unsigned char ListElementQuotingType(const char *s, int len) { int i, level, blevel, trySimple = 1; | | | 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 | #define JIM_ELESTR_SIMPLE 0 #define JIM_ELESTR_BRACE 1 #define JIM_ELESTR_QUOTE 2 static unsigned char ListElementQuotingType(const char *s, int len) { int i, level, blevel, trySimple = 1; if (len == 0) return JIM_ELESTR_BRACE; if (s[0] == '"' || s[0] == '{') { trySimple = 0; goto testbrace; } for (i = 0; i < len; i++) { |
︙ | ︙ | |||
11179 11180 11181 11182 11183 11184 11185 | case '\\': case '\r': case '\n': case '\t': case '\f': case '\v': trySimple = 0; | | | | 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 | case '\\': case '\r': case '\n': case '\t': case '\f': case '\v': trySimple = 0; case '{': case '}': goto testbrace; } } return JIM_ELESTR_SIMPLE; testbrace: if (s[len - 1] == '\\') return JIM_ELESTR_QUOTE; level = 0; blevel = 0; for (i = 0; i < len; i++) { switch (s[i]) { case '{': |
︙ | ︙ | |||
11308 11309 11310 11311 11312 11313 11314 | { #define STATIC_QUOTING_LEN 32 int i, bufLen, realLength; const char *strRep; char *p; unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN]; | | | | | | | 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 | { #define STATIC_QUOTING_LEN 32 int i, bufLen, realLength; const char *strRep; char *p; unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN]; if (objc > STATIC_QUOTING_LEN) { quotingType = Jim_Alloc(objc); } else { quotingType = staticQuoting; } bufLen = 0; for (i = 0; i < objc; i++) { int len; strRep = Jim_GetString(objv[i], &len); quotingType[i] = ListElementQuotingType(strRep, len); switch (quotingType[i]) { case JIM_ELESTR_SIMPLE: if (i != 0 || strRep[0] != '#') { bufLen += len; break; } quotingType[i] = JIM_ELESTR_BRACE; case JIM_ELESTR_BRACE: bufLen += len + 2; break; case JIM_ELESTR_QUOTE: bufLen += len * 2; break; } bufLen++; } bufLen++; p = objPtr->bytes = Jim_Alloc(bufLen + 1); realLength = 0; for (i = 0; i < objc; i++) { int len, qlen; strRep = Jim_GetString(objv[i], &len); |
︙ | ︙ | |||
11372 11373 11374 11375 11376 11377 11378 | realLength++; } qlen = BackslashQuoteString(strRep, len, p); p += qlen; realLength += qlen; break; } | | | | 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 | realLength++; } qlen = BackslashQuoteString(strRep, len, p); p += qlen; realLength += qlen; break; } if (i + 1 != objc) { *p++ = ' '; realLength++; } } *p = '\0'; objPtr->length = realLength; if (quotingType != staticQuoting) { Jim_Free(quotingType); } } |
︙ | ︙ | |||
11413 11414 11415 11416 11417 11418 11419 | int i; listObjPtrPtr = JimDictPairs(objPtr, &len); for (i = 0; i < len; i++) { Jim_IncrRefCount(listObjPtrPtr[i]); } | | | | | | 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 | int i; listObjPtrPtr = JimDictPairs(objPtr, &len); for (i = 0; i < len; i++) { Jim_IncrRefCount(listObjPtrPtr[i]); } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &listObjType; objPtr->internalRep.listValue.len = len; objPtr->internalRep.listValue.maxLen = len; objPtr->internalRep.listValue.ele = listObjPtrPtr; return JIM_OK; } if (objPtr->typePtr == &sourceObjType) { fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; linenr = objPtr->internalRep.sourceValue.lineNumber; } else { fileNameObj = interp->emptyObj; linenr = 1; } Jim_IncrRefCount(fileNameObj); str = Jim_GetString(objPtr, &strLen); Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &listObjType; objPtr->internalRep.listValue.len = 0; objPtr->internalRep.listValue.maxLen = 0; objPtr->internalRep.listValue.ele = NULL; if (strLen) { JimParserInit(&parser, str, strLen, linenr); while (!parser.eof) { Jim_Obj *elementPtr; JimParseList(&parser); if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) |
︙ | ︙ | |||
11577 11578 11579 11580 11581 11582 11583 | static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { Jim_Obj *compare_script; int rc; jim_wide ret = 0; | | | 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 | static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { Jim_Obj *compare_script; int rc; jim_wide ret = 0; compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command); Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj); Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj); rc = Jim_EvalObj(sort_info->interp, compare_script); if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) { |
︙ | ︙ | |||
11599 11600 11601 11602 11603 11604 11605 | { int src; int dst = 0; Jim_Obj **ele = listObjPtr->internalRep.listValue.ele; for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) { if (comp(&ele[dst], &ele[src]) == 0) { | | | | < < < | | | < | | 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 | { int src; int dst = 0; Jim_Obj **ele = listObjPtr->internalRep.listValue.ele; for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) { if (comp(&ele[dst], &ele[src]) == 0) { Jim_DecrRefCount(sort_info->interp, ele[dst]); } else { dst++; } ele[dst] = ele[src]; } ele[++dst] = ele[src]; listObjPtr->internalRep.listValue.len = dst; } static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info) { struct lsort_info *prev_info; typedef int (qsort_comparator) (const void *, const void *); int (*fn) (Jim_Obj **, Jim_Obj **); Jim_Obj **vector; int len; int rc; JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object")); SetListFromAny(interp, listObjPtr); prev_info = sort_info; sort_info = info; vector = listObjPtr->internalRep.listValue.ele; len = listObjPtr->internalRep.listValue.len; switch (info->type) { case JIM_LSORT_ASCII: |
︙ | ︙ | |||
11656 11657 11658 11659 11660 11661 11662 | case JIM_LSORT_REAL: fn = ListSortReal; break; case JIM_LSORT_COMMAND: fn = ListSortCommand; break; default: | | | | | 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 | case JIM_LSORT_REAL: fn = ListSortReal; break; case JIM_LSORT_COMMAND: fn = ListSortCommand; break; default: fn = NULL; JimPanic((1, "ListSort called with invalid sort type")); return -1; } if (info->indexed) { info->subfn = fn; fn = ListSortIndexHelper; } if ((rc = setjmp(info->jmpbuf)) == 0) { qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn); |
︙ | ︙ | |||
11690 11691 11692 11693 11694 11695 11696 | int currentLen = listPtr->internalRep.listValue.len; int requiredLen = currentLen + elemc; int i; Jim_Obj **point; if (requiredLen > listPtr->internalRep.listValue.maxLen) { if (requiredLen < 2) { | | | 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 | int currentLen = listPtr->internalRep.listValue.len; int requiredLen = currentLen + elemc; int i; Jim_Obj **point; if (requiredLen > listPtr->internalRep.listValue.maxLen) { if (requiredLen < 2) { requiredLen = 4; } else { requiredLen *= 2; } listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele, |
︙ | ︙ | |||
11876 11877 11878 11879 11880 11881 11882 | Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < objc; i++) ListAppendList(objPtr, objv[i]); return objPtr; } else { | | | | | | | | 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 | Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < objc; i++) ListAppendList(objPtr, objv[i]); return objPtr; } else { int len = 0, objLen; char *bytes, *p; for (i = 0; i < objc; i++) { len += Jim_Length(objv[i]); } if (objc) len += objc - 1; p = bytes = Jim_Alloc(len + 1); for (i = 0; i < objc; i++) { const char *s = Jim_GetString(objv[i], &objLen); while (objLen && isspace(UCHAR(*s))) { s++; objLen--; len--; } while (objLen && isspace(UCHAR(s[objLen - 1]))) { if (objLen > 1 && s[objLen - 2] == '\\') { break; } objLen--; len--; } memcpy(p, s, objLen); |
︙ | ︙ | |||
11930 11931 11932 11933 11934 11935 11936 | { int first, last; int len, rangeLen; if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) return NULL; | | | 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 | { int first, last; int len, rangeLen; if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) return NULL; len = Jim_ListLength(interp, listObjPtr); first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, &first, &last, &rangeLen); if (first == 0 && last == len) { return listObjPtr; } return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen); |
︙ | ︙ | |||
11970 11971 11972 11973 11974 11975 11976 | static void JimObjectHTKeyValDestructor(void *interp, void *val) { Jim_DecrRefCount(interp, (Jim_Obj *)val); } static const Jim_HashTableType JimDictHashTableType = { | | | | | | | | 12028 12029 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 | static void JimObjectHTKeyValDestructor(void *interp, void *val) { Jim_DecrRefCount(interp, (Jim_Obj *)val); } static const Jim_HashTableType JimDictHashTableType = { JimObjectHTHashFunction, JimObjectHTKeyValDup, JimObjectHTKeyValDup, JimObjectHTKeyCompare, JimObjectHTKeyValDestructor, JimObjectHTKeyValDestructor }; static const Jim_ObjType dictObjType = { "dict", FreeDictInternalRep, DupDictInternalRep, UpdateStringOfDict, |
︙ | ︙ | |||
12000 12001 12002 12003 12004 12005 12006 | void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { Jim_HashTable *ht, *dupHt; Jim_HashTableIterator htiter; Jim_HashEntry *he; | | | | | | | | | 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133 12134 12135 12136 12137 12138 12139 12140 12141 | void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { Jim_HashTable *ht, *dupHt; Jim_HashTableIterator htiter; Jim_HashEntry *he; ht = srcPtr->internalRep.ptr; dupHt = Jim_Alloc(sizeof(*dupHt)); Jim_InitHashTable(dupHt, &JimDictHashTableType, interp); if (ht->size != 0) Jim_ExpandHashTable(dupHt, ht->size); JimInitHashTableIterator(ht, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { Jim_AddHashEntry(dupHt, he->key, he->u.val); } dupPtr->internalRep.ptr = dupHt; dupPtr->typePtr = &dictObjType; } static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len) { Jim_HashTable *ht; Jim_HashTableIterator htiter; Jim_HashEntry *he; Jim_Obj **objv; int i; ht = dictPtr->internalRep.ptr; objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); JimInitHashTableIterator(ht, &htiter); i = 0; while ((he = Jim_NextHashEntry(&htiter)) != NULL) { objv[i++] = Jim_GetHashEntryKey(he); objv[i++] = Jim_GetHashEntryVal(he); } *len = i; return objv; } static void UpdateStringOfDict(struct Jim_Obj *objPtr) { int len; Jim_Obj **objv = JimDictPairs(objPtr, &len); JimMakeListStringRep(objPtr, objv, len); Jim_Free(objv); } static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int listlen; if (objPtr->typePtr == &dictObjType) { return JIM_OK; } if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) { Jim_String(objPtr); } listlen = Jim_ListLength(interp, objPtr); if (listlen % 2) { Jim_SetResultString(interp, "missing value to go with key", -1); return JIM_ERR; } else { Jim_HashTable *ht; int i; ht = Jim_Alloc(sizeof(*ht)); Jim_InitHashTable(ht, &JimDictHashTableType, interp); for (i = 0; i < listlen; i += 2) { |
︙ | ︙ | |||
12098 12099 12100 12101 12102 12103 12104 | static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { Jim_HashTable *ht = objPtr->internalRep.ptr; | | | 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 | static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { Jim_HashTable *ht = objPtr->internalRep.ptr; if (valueObjPtr == NULL) { return Jim_DeleteHashEntry(ht, keyObjPtr); } Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr); return JIM_OK; } int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, |
︙ | ︙ | |||
12149 12150 12151 12152 12153 12154 12155 | ht = dictPtr->internalRep.ptr; if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr); } return JIM_ERR; } | < | | < | 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 | ht = dictPtr->internalRep.ptr; if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr); } return JIM_ERR; } *objPtrPtr = he->u.val; return JIM_OK; } int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len) { if (SetDictFromAny(interp, dictPtr) != JIM_OK) { return JIM_ERR; |
︙ | ︙ | |||
12200 12201 12202 12203 12204 12205 12206 | { Jim_Obj *varObjPtr, *objPtr, *dictObjPtr; int shared, i; varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags); if (objPtr == NULL) { if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) { | | | | | | | 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 | { Jim_Obj *varObjPtr, *objPtr, *dictObjPtr; int shared, i; varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags); if (objPtr == NULL) { if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) { return JIM_ERR; } varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0); if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) { Jim_FreeNewObj(interp, varObjPtr); return JIM_ERR; } } if ((shared = Jim_IsShared(objPtr))) varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr); for (i = 0; i < keyc; i++) { dictObjPtr = objPtr; if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) { goto err; } if (i == keyc - 1) { if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) { if (newObjPtr || (flags & JIM_MUSTEXIST)) { goto err; } } break; } Jim_InvalidateStringRep(dictObjPtr); if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr, newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) { if (Jim_IsShared(objPtr)) { objPtr = Jim_DuplicateObj(interp, objPtr); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } else { if (newObjPtr == NULL) { goto err; } objPtr = Jim_NewDictObj(interp, NULL, 0); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } Jim_InvalidateStringRep(objPtr); Jim_InvalidateStringRep(varObjPtr); if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) { goto err; } Jim_SetResult(interp, varObjPtr); return JIM_OK; |
︙ | ︙ | |||
12283 12284 12285 12286 12287 12288 12289 | } else { char buf[JIM_INTEGER_SPACE + 1]; if (objPtr->internalRep.intValue >= 0) { sprintf(buf, "%d", objPtr->internalRep.intValue); } else { | | | | | | | | | | 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 | } else { char buf[JIM_INTEGER_SPACE + 1]; if (objPtr->internalRep.intValue >= 0) { sprintf(buf, "%d", objPtr->internalRep.intValue); } else { sprintf(buf, "end%d", objPtr->internalRep.intValue + 1); } JimSetStringBytes(objPtr, buf); } } static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int idx, end = 0; const char *str; char *endptr; str = Jim_String(objPtr); if (strncmp(str, "end", 3) == 0) { end = 1; str += 3; idx = 0; } else { idx = jim_strtol(str, &endptr); if (endptr == str) { goto badindex; } str = endptr; } if (*str == '+' || *str == '-') { int sign = (*str == '+' ? 1 : -1); idx += sign * jim_strtol(++str, &endptr); if (str == endptr || *endptr) { goto badindex; } str = endptr; } while (isspace(UCHAR(*str))) { str++; } if (*str) { goto badindex; } if (end) { if (idx > 0) { idx = INT_MAX; } else { idx--; } } else if (idx < 0) { idx = -INT_MAX; } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &indexObjType; objPtr->internalRep.intValue = idx; return JIM_OK; badindex: Jim_SetResultFormatted(interp, "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr); return JIM_ERR; } int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr) { if (objPtr->typePtr == &intObjType) { jim_wide val = JimWideValue(objPtr); if (val < 0) *indexPtr = -INT_MAX; else if (val > INT_MAX) *indexPtr = INT_MAX; |
︙ | ︙ | |||
12390 12391 12392 12393 12394 12395 12396 | "continue", "signal", "exit", "eval", NULL }; | | | 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 | "continue", "signal", "exit", "eval", NULL }; #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes)) static const Jim_ObjType returnCodeObjType = { "return-code", NULL, NULL, NULL, JIM_TYPE_NONE, |
︙ | ︙ | |||
12415 12416 12417 12418 12419 12420 12421 | } static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int returnCode; jim_wide wideValue; | | | | > | | < | | > > | > > > > | > > > > > | > > > > | > > > | | | | | > | | < < < | < < | | > | | | | | > > > > | | | > > > | | > < < < < < | | 12471 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499 12500 12501 12502 12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575 12576 12577 12578 12579 12580 12581 12582 12583 12584 12585 12586 12587 12588 12589 12590 12591 12592 12593 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 12617 12618 12619 12620 12621 12622 12623 12624 12625 12626 12627 12628 12629 12630 12631 12632 12633 12634 12635 12636 12637 12638 12639 12640 | } static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int returnCode; jim_wide wideValue; if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR) returnCode = (int)wideValue; else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) { Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr); return JIM_ERR; } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &returnCodeObjType; objPtr->internalRep.intValue = returnCode; return JIM_OK; } int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr) { if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; *intPtr = objPtr->internalRep.intValue; return JIM_OK; } static int JimParseExprOperator(struct JimParserCtx *pc); static int JimParseExprNumber(struct JimParserCtx *pc); static int JimParseExprIrrational(struct JimParserCtx *pc); enum { JIM_EXPROP_MUL = JIM_TT_EXPR_OP, JIM_EXPROP_DIV, JIM_EXPROP_MOD, JIM_EXPROP_SUB, JIM_EXPROP_ADD, JIM_EXPROP_LSHIFT, JIM_EXPROP_RSHIFT, JIM_EXPROP_ROTL, JIM_EXPROP_ROTR, JIM_EXPROP_LT, JIM_EXPROP_GT, JIM_EXPROP_LTE, JIM_EXPROP_GTE, JIM_EXPROP_NUMEQ, JIM_EXPROP_NUMNE, JIM_EXPROP_BITAND, JIM_EXPROP_BITXOR, JIM_EXPROP_BITOR, JIM_EXPROP_LOGICAND, JIM_EXPROP_LOGICAND_LEFT, JIM_EXPROP_LOGICAND_RIGHT, JIM_EXPROP_LOGICOR, JIM_EXPROP_LOGICOR_LEFT, JIM_EXPROP_LOGICOR_RIGHT, JIM_EXPROP_TERNARY, JIM_EXPROP_TERNARY_LEFT, JIM_EXPROP_TERNARY_RIGHT, JIM_EXPROP_COLON, JIM_EXPROP_COLON_LEFT, JIM_EXPROP_COLON_RIGHT, JIM_EXPROP_POW, JIM_EXPROP_STREQ, JIM_EXPROP_STRNE, JIM_EXPROP_STRIN, JIM_EXPROP_STRNI, JIM_EXPROP_NOT, JIM_EXPROP_BITNOT, JIM_EXPROP_UNARYMINUS, JIM_EXPROP_UNARYPLUS, JIM_EXPROP_FUNC_FIRST, JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST, JIM_EXPROP_FUNC_WIDE, JIM_EXPROP_FUNC_ABS, JIM_EXPROP_FUNC_DOUBLE, JIM_EXPROP_FUNC_ROUND, JIM_EXPROP_FUNC_RAND, JIM_EXPROP_FUNC_SRAND, JIM_EXPROP_FUNC_SIN, JIM_EXPROP_FUNC_COS, JIM_EXPROP_FUNC_TAN, JIM_EXPROP_FUNC_ASIN, JIM_EXPROP_FUNC_ACOS, JIM_EXPROP_FUNC_ATAN, JIM_EXPROP_FUNC_SINH, JIM_EXPROP_FUNC_COSH, JIM_EXPROP_FUNC_TANH, JIM_EXPROP_FUNC_CEIL, JIM_EXPROP_FUNC_FLOOR, JIM_EXPROP_FUNC_EXP, JIM_EXPROP_FUNC_LOG, JIM_EXPROP_FUNC_LOG10, JIM_EXPROP_FUNC_SQRT, JIM_EXPROP_FUNC_POW, }; struct JimExprState { Jim_Obj **stack; int stacklen; int opcode; int skip; }; typedef struct Jim_ExprOperator { const char *name; int (*funcop) (Jim_Interp *interp, struct JimExprState * e); unsigned char precedence; unsigned char arity; unsigned char lazy; unsigned char namelen; } Jim_ExprOperator; static void ExprPush(struct JimExprState *e, Jim_Obj *obj) { Jim_IncrRefCount(obj); e->stack[e->stacklen++] = obj; } static Jim_Obj *ExprPop(struct JimExprState *e) { return e->stack[--e->stacklen]; } static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e) { int intresult = 1; int rc = JIM_OK; Jim_Obj *A = ExprPop(e); double dA, dC = 0; jim_wide wA, wC = 0; if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_FUNC_INT: case JIM_EXPROP_FUNC_WIDE: case JIM_EXPROP_FUNC_ROUND: case JIM_EXPROP_UNARYPLUS: wC = wA; break; case JIM_EXPROP_FUNC_DOUBLE: |
︙ | ︙ | |||
12577 12578 12579 12580 12581 12582 12583 | wC = !wA; break; default: abort(); } } else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) { | | < < < < | | | < | < | < < | < | | | | | | | | < | | < < < | | 12651 12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 12681 12682 12683 12684 12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708 12709 12710 12711 12712 12713 12714 12715 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 | wC = !wA; break; default: abort(); } } else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_FUNC_INT: case JIM_EXPROP_FUNC_WIDE: wC = dA; break; case JIM_EXPROP_FUNC_ROUND: wC = dA < 0 ? (dA - 0.5) : (dA + 0.5); break; case JIM_EXPROP_FUNC_DOUBLE: case JIM_EXPROP_UNARYPLUS: dC = dA; intresult = 0; break; case JIM_EXPROP_FUNC_ABS: dC = dA >= 0 ? dA : -dA; intresult = 0; break; case JIM_EXPROP_UNARYMINUS: dC = -dA; intresult = 0; break; case JIM_EXPROP_NOT: wC = !dA; break; default: abort(); } } if (rc == JIM_OK) { if (intresult) { ExprPush(e, Jim_NewIntObj(interp, wC)); } else { ExprPush(e, Jim_NewDoubleObj(interp, dC)); } } Jim_DecrRefCount(interp, A); return rc; } static double JimRandDouble(Jim_Interp *interp) { unsigned long x; JimRandomBytes(interp, &x, sizeof(x)); return (double)x / (unsigned long)~0; } static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *A = ExprPop(e); jim_wide wA; int rc = Jim_GetWide(interp, A, &wA); if (rc == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_BITNOT: ExprPush(e, Jim_NewIntObj(interp, ~wA)); break; case JIM_EXPROP_FUNC_SRAND: JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA)); ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp))); break; default: abort(); } } Jim_DecrRefCount(interp, A); return rc; } static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e) { JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()")); ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp))); return JIM_OK; } #ifdef JIM_MATH_FUNCTIONS static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e) { int rc; Jim_Obj *A = ExprPop(e); double dA, dC; rc = Jim_GetDouble(interp, A, &dA); if (rc == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_FUNC_SIN: dC = sin(dA); break; case JIM_EXPROP_FUNC_COS: dC = cos(dA); break; case JIM_EXPROP_FUNC_TAN: |
︙ | ︙ | |||
12733 12734 12735 12736 12737 12738 12739 | break; case JIM_EXPROP_FUNC_SQRT: dC = sqrt(dA); break; default: abort(); } | | | < < | | < < < < < < < | | | | 12794 12795 12796 12797 12798 12799 12800 12801 12802 12803 12804 12805 12806 12807 12808 12809 12810 12811 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 | break; case JIM_EXPROP_FUNC_SQRT: dC = sqrt(dA); break; default: abort(); } ExprPush(e, Jim_NewDoubleObj(interp, dC)); } Jim_DecrRefCount(interp, A); return rc; } #endif static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); jim_wide wA, wB; int rc = JIM_ERR; if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) { jim_wide wC; rc = JIM_OK; switch (e->opcode) { case JIM_EXPROP_LSHIFT: wC = wA << wB; break; case JIM_EXPROP_RSHIFT: wC = wA >> wB; break; case JIM_EXPROP_BITAND: |
︙ | ︙ | |||
12805 12806 12807 12808 12809 12810 12811 | if (negative) { wC = -wC; } } break; case JIM_EXPROP_ROTL: case JIM_EXPROP_ROTR:{ | | | | > | | > < < < < < | < < > | | < < < < < | | | | < < > | | | | | < < < < < < < < < < < | < < | | | > > > > > > > < | < | < < < | < < > | | | | | > | > | > | > | > | > > > | | | | | | | | > | > > | > > > > > > > | > < < < < < < < < | | < < | < < | < | < | < | | | | < < < < < | | | > > | > > > > > | > > | > > > > > > > > > > > | > > | | > > > | > | | > | > > > | > | | > | > > | | > > > > > > > > > > | > | > | | | | < | | | > > > > | | > > > > > > > > > > > > > > > | > > > > > | > | | > | > > > | | | | > | > | > > > > | | > > | > | > | | | | 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 12980 12981 12982 12983 12984 12985 12986 12987 12988 12989 12990 12991 12992 12993 12994 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 13020 13021 13022 13023 13024 13025 13026 13027 13028 13029 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039 13040 13041 13042 13043 13044 13045 13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169 13170 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182 13183 13184 13185 13186 13187 13188 13189 13190 13191 13192 13193 13194 13195 13196 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240 13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 | if (negative) { wC = -wC; } } break; case JIM_EXPROP_ROTL: case JIM_EXPROP_ROTR:{ unsigned long uA = (unsigned long)wA; unsigned long uB = (unsigned long)wB; const unsigned int S = sizeof(unsigned long) * 8; uB %= S; if (e->opcode == JIM_EXPROP_ROTR) { uB = S - uB; } wC = (unsigned long)(uA << uB) | (uA >> (S - uB)); break; } default: abort(); } ExprPush(e, Jim_NewIntObj(interp, wC)); } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return rc; } static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) { int intresult = 1; int rc = JIM_OK; double dA, dB, dC = 0; jim_wide wA, wB, wC = 0; Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); if ((A->typePtr != &doubleObjType || A->bytes) && (B->typePtr != &doubleObjType || B->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_POW: case JIM_EXPROP_FUNC_POW: wC = JimPowWide(wA, wB); break; case JIM_EXPROP_ADD: wC = wA + wB; break; case JIM_EXPROP_SUB: wC = wA - wB; break; case JIM_EXPROP_MUL: wC = wA * wB; break; case JIM_EXPROP_DIV: if (wB == 0) { Jim_SetResultString(interp, "Division by zero", -1); rc = JIM_ERR; } else { if (wB < 0) { wB = -wB; wA = -wA; } wC = wA / wB; if (wA % wB < 0) { wC--; } } break; case JIM_EXPROP_LT: wC = wA < wB; break; case JIM_EXPROP_GT: wC = wA > wB; break; case JIM_EXPROP_LTE: wC = wA <= wB; break; case JIM_EXPROP_GTE: wC = wA >= wB; break; case JIM_EXPROP_NUMEQ: wC = wA == wB; break; case JIM_EXPROP_NUMNE: wC = wA != wB; break; default: abort(); } } else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) { intresult = 0; switch (e->opcode) { case JIM_EXPROP_POW: case JIM_EXPROP_FUNC_POW: #ifdef JIM_MATH_FUNCTIONS dC = pow(dA, dB); #else Jim_SetResultString(interp, "unsupported", -1); rc = JIM_ERR; #endif break; case JIM_EXPROP_ADD: dC = dA + dB; break; case JIM_EXPROP_SUB: dC = dA - dB; break; case JIM_EXPROP_MUL: dC = dA * dB; break; case JIM_EXPROP_DIV: if (dB == 0) { #ifdef INFINITY dC = dA < 0 ? -INFINITY : INFINITY; #else dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL); #endif } else { dC = dA / dB; } break; case JIM_EXPROP_LT: wC = dA < dB; intresult = 1; break; case JIM_EXPROP_GT: wC = dA > dB; intresult = 1; break; case JIM_EXPROP_LTE: wC = dA <= dB; intresult = 1; break; case JIM_EXPROP_GTE: wC = dA >= dB; intresult = 1; break; case JIM_EXPROP_NUMEQ: wC = dA == dB; intresult = 1; break; case JIM_EXPROP_NUMNE: wC = dA != dB; intresult = 1; break; default: abort(); } } else { int i = Jim_StringCompareObj(interp, A, B, 0); switch (e->opcode) { case JIM_EXPROP_LT: wC = i < 0; break; case JIM_EXPROP_GT: wC = i > 0; break; case JIM_EXPROP_LTE: wC = i <= 0; break; case JIM_EXPROP_GTE: wC = i >= 0; break; case JIM_EXPROP_NUMEQ: wC = i == 0; break; case JIM_EXPROP_NUMNE: wC = i != 0; break; default: rc = JIM_ERR; break; } } if (rc == JIM_OK) { if (intresult) { ExprPush(e, Jim_NewIntObj(interp, wC)); } else { ExprPush(e, Jim_NewDoubleObj(interp, dC)); } } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return rc; } static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj) { int listlen; int i; listlen = Jim_ListLength(interp, listObjPtr); for (i = 0; i < listlen; i++) { if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) { return 1; } } return 0; } static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); jim_wide wC; switch (e->opcode) { case JIM_EXPROP_STREQ: case JIM_EXPROP_STRNE: wC = Jim_StringEqObj(A, B); if (e->opcode == JIM_EXPROP_STRNE) { wC = !wC; } break; case JIM_EXPROP_STRIN: wC = JimSearchList(interp, B, A); break; case JIM_EXPROP_STRNI: wC = !JimSearchList(interp, B, A); break; default: abort(); } ExprPush(e, Jim_NewIntObj(interp, wC)); Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return JIM_OK; } static int ExprBool(Jim_Interp *interp, Jim_Obj *obj) { long l; double d; if (Jim_GetLong(interp, obj, &l) == JIM_OK) { return l != 0; } if (Jim_GetDouble(interp, obj, &d) == JIM_OK) { return d != 0; } return -1; } static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *A = ExprPop(e); int rc = JIM_OK; switch (ExprBool(interp, A)) { case 0: e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: break; case -1: rc = JIM_ERR; } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, skip); return rc; } static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *A = ExprPop(e); int rc = JIM_OK; switch (ExprBool(interp, A)) { case 0: break; case 1: e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 1)); break; case -1: rc = JIM_ERR; break; } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, skip); return rc; } static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *A = ExprPop(e); int rc = JIM_OK; switch (ExprBool(interp, A)) { case 0: ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: ExprPush(e, Jim_NewIntObj(interp, 1)); break; case -1: rc = JIM_ERR; break; } Jim_DecrRefCount(interp, A); return rc; } static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *A = ExprPop(e); int rc = JIM_OK; ExprPush(e, A); switch (ExprBool(interp, A)) { case 0: e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: break; case -1: rc = JIM_ERR; break; } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, skip); return rc; } static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); if (ExprBool(interp, A)) { e->skip = JimWideValue(skip); ExprPush(e, B); } Jim_DecrRefCount(interp, skip); Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return JIM_OK; } static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e) { return JIM_OK; } enum { LAZY_NONE, LAZY_OP, LAZY_LEFT, LAZY_RIGHT }; #define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1} #define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1} static const struct Jim_ExprOperator Jim_ExprOperators[] = { OPRINIT("*", 110, 2, JimExprOpBin), OPRINIT("/", 110, 2, JimExprOpBin), OPRINIT("%", 110, 2, JimExprOpIntBin), OPRINIT("-", 100, 2, JimExprOpBin), |
︙ | ︙ | |||
13181 13182 13183 13184 13185 13186 13187 | OPRINIT("==", 70, 2, JimExprOpBin), OPRINIT("!=", 70, 2, JimExprOpBin), OPRINIT("&", 50, 2, JimExprOpIntBin), OPRINIT("^", 49, 2, JimExprOpIntBin), OPRINIT("|", 48, 2, JimExprOpIntBin), | > | > > > | > | | > > > > > | | | | | | | | | | | | | | | | | | < | | | | | | | | | | < < | | | | 13294 13295 13296 13297 13298 13299 13300 13301 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 13312 13313 13314 13315 13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 13337 13338 13339 13340 13341 13342 13343 13344 13345 13346 13347 13348 13349 13350 13351 13352 13353 13354 13355 13356 13357 13358 13359 13360 13361 13362 13363 13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375 13376 13377 13378 13379 13380 13381 13382 13383 | OPRINIT("==", 70, 2, JimExprOpBin), OPRINIT("!=", 70, 2, JimExprOpBin), OPRINIT("&", 50, 2, JimExprOpIntBin), OPRINIT("^", 49, 2, JimExprOpIntBin), OPRINIT("|", 48, 2, JimExprOpIntBin), OPRINIT_LAZY("&&", 10, 2, NULL, LAZY_OP), OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT), OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT), OPRINIT_LAZY("||", 9, 2, NULL, LAZY_OP), OPRINIT_LAZY(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT), OPRINIT_LAZY(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT), OPRINIT_LAZY("?", 5, 2, JimExprOpNull, LAZY_OP), OPRINIT_LAZY(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT), OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), OPRINIT_LAZY(":", 5, 2, JimExprOpNull, LAZY_OP), OPRINIT_LAZY(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT), OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), OPRINIT("**", 250, 2, JimExprOpBin), OPRINIT("eq", 60, 2, JimExprOpStrBin), OPRINIT("ne", 60, 2, JimExprOpStrBin), OPRINIT("in", 55, 2, JimExprOpStrBin), OPRINIT("ni", 55, 2, JimExprOpStrBin), OPRINIT("!", 150, 1, JimExprOpNumUnary), OPRINIT("~", 150, 1, JimExprOpIntUnary), OPRINIT(NULL, 150, 1, JimExprOpNumUnary), OPRINIT(NULL, 150, 1, JimExprOpNumUnary), OPRINIT("int", 200, 1, JimExprOpNumUnary), OPRINIT("wide", 200, 1, JimExprOpNumUnary), OPRINIT("abs", 200, 1, JimExprOpNumUnary), OPRINIT("double", 200, 1, JimExprOpNumUnary), OPRINIT("round", 200, 1, JimExprOpNumUnary), OPRINIT("rand", 200, 0, JimExprOpNone), OPRINIT("srand", 200, 1, JimExprOpIntUnary), #ifdef JIM_MATH_FUNCTIONS OPRINIT("sin", 200, 1, JimExprOpDoubleUnary), OPRINIT("cos", 200, 1, JimExprOpDoubleUnary), OPRINIT("tan", 200, 1, JimExprOpDoubleUnary), OPRINIT("asin", 200, 1, JimExprOpDoubleUnary), OPRINIT("acos", 200, 1, JimExprOpDoubleUnary), OPRINIT("atan", 200, 1, JimExprOpDoubleUnary), OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary), OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary), OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary), OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary), OPRINIT("floor", 200, 1, JimExprOpDoubleUnary), OPRINIT("exp", 200, 1, JimExprOpDoubleUnary), OPRINIT("log", 200, 1, JimExprOpDoubleUnary), OPRINIT("log10", 200, 1, JimExprOpDoubleUnary), OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary), OPRINIT("pow", 200, 2, JimExprOpBin), #endif }; #undef OPRINIT #undef OPRINIT_LAZY #define JIM_EXPR_OPERATORS_NUM \ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator)) static int JimParseExpression(struct JimParserCtx *pc) { while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) { if (*pc->p == '\n') { pc->linenr++; } pc->p++; pc->len--; } pc->tline = pc->linenr; pc->tstart = pc->p; if (pc->len == 0) { pc->tend = pc->p; pc->tt = JIM_TT_EOL; pc->eof = 1; |
︙ | ︙ | |||
13279 13280 13281 13282 13283 13284 13285 | break; case '[': return JimParseCmd(pc); case '$': if (JimParseVar(pc) == JIM_ERR) return JimParseExprOperator(pc); else { | | | 13399 13400 13401 13402 13403 13404 13405 13406 13407 13408 13409 13410 13411 13412 13413 | break; case '[': return JimParseCmd(pc); case '$': if (JimParseVar(pc) == JIM_ERR) return JimParseExprOperator(pc); else { if (pc->tt == JIM_TT_EXPRSUGAR) { return JIM_ERR; } return JIM_OK; } break; case '0': |
︙ | ︙ | |||
13308 13309 13310 13311 13312 13313 13314 | return JimParseBrace(pc); case 'N': case 'I': case 'n': case 'i': if (JimParseExprIrrational(pc) == JIM_ERR) | < < < < < < < < | | | | | 13428 13429 13430 13431 13432 13433 13434 13435 13436 13437 13438 13439 13440 13441 13442 13443 13444 13445 13446 13447 13448 13449 13450 13451 13452 13453 13454 13455 13456 13457 13458 13459 13460 13461 13462 13463 13464 13465 | return JimParseBrace(pc); case 'N': case 'I': case 'n': case 'i': if (JimParseExprIrrational(pc) == JIM_ERR) return JimParseExprOperator(pc); break; default: return JimParseExprOperator(pc); break; } return JIM_OK; } static int JimParseExprNumber(struct JimParserCtx *pc) { char *end; pc->tt = JIM_TT_EXPR_INT; jim_strtoull(pc->p, (char **)&pc->p); if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) { if (strtod(pc->tstart, &end)) { } if (end == pc->tstart) return JIM_ERR; if (end > pc->p) { pc->tt = JIM_TT_EXPR_DOUBLE; pc->p = end; } } pc->tend = pc->p - 1; pc->len -= (pc->p - pc->tstart); return JIM_OK; |
︙ | ︙ | |||
13368 13369 13370 13371 13372 13373 13374 | pc->tt = JIM_TT_EXPR_DOUBLE; return JIM_OK; } } return JIM_ERR; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | | | | | | | | | > > > > > > > > > | < < < < < < | 13480 13481 13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494 13495 13496 13497 13498 13499 13500 13501 13502 13503 13504 13505 13506 13507 13508 13509 13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 13523 13524 13525 13526 13527 13528 13529 13530 13531 13532 13533 13534 13535 13536 13537 13538 13539 13540 13541 13542 13543 13544 13545 13546 13547 13548 13549 13550 13551 13552 13553 13554 | pc->tt = JIM_TT_EXPR_DOUBLE; return JIM_OK; } } return JIM_ERR; } static int JimParseExprOperator(struct JimParserCtx *pc) { int i; int bestIdx = -1, bestLen = 0; for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) { const char * const opname = Jim_ExprOperators[i].name; const int oplen = Jim_ExprOperators[i].namelen; if (opname == NULL || opname[0] != pc->p[0]) { continue; } if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) { bestIdx = i + JIM_TT_EXPR_OP; bestLen = oplen; } } if (bestIdx == -1) { return JIM_ERR; } if (bestIdx >= JIM_EXPROP_FUNC_FIRST) { const char *p = pc->p + bestLen; int len = pc->len - bestLen; while (len && isspace(UCHAR(*p))) { len--; p++; } if (*p != '(') { return JIM_ERR; } } pc->tend = pc->p + bestLen - 1; pc->p += bestLen; pc->len -= bestLen; pc->tt = bestIdx; return JIM_OK; } static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode) { static Jim_ExprOperator dummy_op; if (opcode < JIM_TT_EXPR_OP) { return &dummy_op; } return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP]; } const char *jim_tt_name(int type) { static const char * const tt_names[JIM_TT_EXPR_OP] = { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT", "DBL", "$()" }; if (type < JIM_TT_EXPR_OP) { return tt_names[type]; } else { const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type); static char buf[20]; if (op->name) { return op->name; } |
︙ | ︙ | |||
13481 13482 13483 13484 13485 13486 13487 | FreeExprInternalRep, DupExprInternalRep, NULL, JIM_TYPE_REFERENCES, }; | | | < | | | | > | < | | < | < < < < < | | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > | < < < < | < < < < | < < < < < < < < < | < | | < < < < < | < < < < < < < | < | < < < < | < < < < < < < < < | < < < < < < < < < | | < < < < < < < < < < < < < | < < < < < < | < < < | < < < < | < < < < < | | | < < | < < < | < < | < < < < < < | | < < | < < < < < < < < | < | < < < | | < < < < | < < < < < < < < < < < < < < | | < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < | < < | | < < < < | | < < < < < < < < < < | < < < < < < | < < < < | < | | | | > > | > > | > > > | | > > > | | | < > | > > | > > | < | > | > | > | > > > > | > > > | | < > > > > | | > | | | | > | > | < | | > > > | > | | | | > | | > | > | | < > > | < | < | < < < | > > > > > > > > > > | | | < > | | > | > > > | > > > | > > > | > > > | > | < < < < < | < | < | | | | > | 13566 13567 13568 13569 13570 13571 13572 13573 13574 13575 13576 13577 13578 13579 13580 13581 13582 13583 13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 13594 13595 13596 13597 13598 13599 13600 13601 13602 13603 13604 13605 13606 13607 13608 13609 13610 13611 13612 13613 13614 13615 13616 13617 13618 13619 13620 13621 13622 13623 13624 13625 13626 13627 13628 13629 13630 13631 13632 13633 13634 13635 13636 13637 13638 13639 13640 13641 13642 13643 13644 13645 13646 13647 13648 13649 13650 13651 13652 13653 13654 13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689 13690 13691 13692 13693 13694 13695 13696 13697 13698 13699 13700 13701 13702 13703 13704 13705 13706 13707 13708 13709 13710 13711 13712 13713 13714 13715 13716 13717 13718 13719 13720 13721 13722 13723 13724 13725 13726 13727 13728 13729 13730 13731 13732 13733 13734 13735 13736 13737 13738 13739 13740 13741 13742 13743 13744 13745 13746 13747 13748 13749 13750 13751 13752 13753 13754 13755 13756 13757 13758 13759 13760 13761 13762 13763 13764 13765 13766 13767 13768 13769 13770 13771 13772 13773 13774 13775 13776 13777 13778 13779 13780 13781 13782 13783 13784 13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816 13817 13818 13819 13820 13821 13822 13823 13824 13825 13826 13827 13828 13829 13830 13831 13832 13833 13834 13835 13836 13837 13838 13839 13840 13841 13842 13843 13844 13845 13846 13847 13848 13849 13850 13851 13852 13853 13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 13864 13865 13866 13867 13868 13869 13870 13871 13872 13873 13874 13875 13876 13877 13878 13879 13880 13881 13882 13883 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896 13897 13898 13899 13900 13901 13902 13903 13904 13905 13906 13907 13908 13909 13910 13911 13912 13913 13914 13915 13916 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952 13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966 13967 13968 13969 13970 13971 13972 13973 13974 13975 13976 13977 13978 13979 13980 13981 13982 13983 13984 13985 13986 13987 13988 13989 13990 13991 13992 13993 13994 13995 13996 13997 13998 13999 14000 14001 14002 14003 14004 14005 14006 14007 14008 14009 14010 14011 14012 14013 14014 14015 14016 14017 14018 14019 14020 14021 | FreeExprInternalRep, DupExprInternalRep, NULL, JIM_TYPE_REFERENCES, }; typedef struct ExprByteCode { ScriptToken *token; int len; int inUse; } ExprByteCode; static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr) { int i; for (i = 0; i < expr->len; i++) { Jim_DecrRefCount(interp, expr->token[i].objPtr); } Jim_Free(expr->token); Jim_Free(expr); } static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { ExprByteCode *expr = (void *)objPtr->internalRep.ptr; if (expr) { if (--expr->inUse != 0) { return; } ExprFreeByteCode(interp, expr); } } static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); JIM_NOTUSED(srcPtr); dupPtr->typePtr = NULL; } static int ExprCheckCorrectness(ExprByteCode * expr) { int i; int stacklen = 0; int ternary = 0; for (i = 0; i < expr->len; i++) { ScriptToken *t = &expr->token[i]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); stacklen -= op->arity; if (stacklen < 0) { break; } if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) { ternary++; } else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) { ternary--; } stacklen++; } if (stacklen != 1 || ternary != 0) { return JIM_ERR; } return JIM_OK; } static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t) { int i; int leftindex, arity, offset; leftindex = expr->len - 1; arity = 1; while (arity) { ScriptToken *tt = &expr->token[leftindex]; if (tt->type >= JIM_TT_EXPR_OP) { arity += JimExprOperatorInfoByOpcode(tt->type)->arity; } arity--; if (--leftindex < 0) { return JIM_ERR; } } leftindex++; memmove(&expr->token[leftindex + 2], &expr->token[leftindex], sizeof(*expr->token) * (expr->len - leftindex)); expr->len += 2; offset = (expr->len - leftindex) - 1; expr->token[leftindex + 1].type = t->type + 1; expr->token[leftindex + 1].objPtr = interp->emptyObj; expr->token[leftindex].type = JIM_TT_EXPR_INT; expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset); expr->token[expr->len].objPtr = interp->emptyObj; expr->token[expr->len].type = t->type + 2; expr->len++; for (i = leftindex - 1; i > 0; i--) { const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(expr->token[i].type); if (op->lazy == LAZY_LEFT) { if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) { JimWideValue(expr->token[i - 1].objPtr) += 2; } } } return JIM_OK; } static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t) { struct ScriptToken *token = &expr->token[expr->len]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); if (op->lazy == LAZY_OP) { if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) { Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name); return JIM_ERR; } } else { token->objPtr = interp->emptyObj; token->type = t->type; expr->len++; } return JIM_OK; } static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index) { int ternary_count = 1; right_index--; while (right_index > 1) { if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) { ternary_count--; } else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) { ternary_count++; } else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) { return right_index; } right_index--; } return -1; } static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index) { int i = right_index - 1; int ternary_count = 1; while (i > 1) { if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) { if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) { *prev_right_index = i - 2; *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index); return 1; } } else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) { if (ternary_count == 0) { return 0; } ternary_count++; } i--; } return 0; } static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr) { int i; for (i = expr->len - 1; i > 1; i--) { int prev_right_index; int prev_left_index; int j; ScriptToken tmp; if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) { continue; } if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) { continue; } tmp = expr->token[prev_right_index]; for (j = prev_right_index; j < i; j++) { expr->token[j] = expr->token[j + 1]; } expr->token[i] = tmp; JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index); i++; } } static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj) { Jim_Stack stack; ExprByteCode *expr; int ok = 1; int i; int prevtt = JIM_TT_NONE; int have_ternary = 0; int count = tokenlist->count - 1; expr = Jim_Alloc(sizeof(*expr)); expr->inUse = 1; expr->len = 0; Jim_InitStack(&stack); for (i = 0; i < tokenlist->count; i++) { ParseToken *t = &tokenlist->list[i]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); if (op->lazy == LAZY_OP) { count += 2; if (t->type == JIM_EXPROP_TERNARY) { have_ternary = 1; } } } expr->token = Jim_Alloc(sizeof(ScriptToken) * count); for (i = 0; i < tokenlist->count && ok; i++) { ParseToken *t = &tokenlist->list[i]; struct ScriptToken *token = &expr->token[expr->len]; if (t->type == JIM_TT_EOL) { break; } switch (t->type) { case JIM_TT_STR: case JIM_TT_ESC: case JIM_TT_VAR: case JIM_TT_DICTSUGAR: case JIM_TT_EXPRSUGAR: case JIM_TT_CMD: token->type = t->type; strexpr: token->objPtr = Jim_NewStringObj(interp, t->token, t->len); if (t->type == JIM_TT_CMD) { JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line); } expr->len++; break; case JIM_TT_EXPR_INT: case JIM_TT_EXPR_DOUBLE: { char *endptr; if (t->type == JIM_TT_EXPR_INT) { token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr)); } else { token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr)); } if (endptr != t->token + t->len) { Jim_FreeNewObj(interp, token->objPtr); token->type = JIM_TT_STR; goto strexpr; } token->type = t->type; expr->len++; } break; case JIM_TT_SUBEXPR_START: Jim_StackPush(&stack, t); prevtt = JIM_TT_NONE; continue; case JIM_TT_SUBEXPR_COMMA: continue; case JIM_TT_SUBEXPR_END: ok = 0; while (Jim_StackLen(&stack)) { ParseToken *tt = Jim_StackPop(&stack); if (tt->type == JIM_TT_SUBEXPR_START) { ok = 1; break; } if (ExprAddOperator(interp, expr, tt) != JIM_OK) { goto err; } } if (!ok) { Jim_SetResultString(interp, "Unexpected close parenthesis", -1); goto err; } break; default:{ const struct Jim_ExprOperator *op; ParseToken *tt; if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) { if (t->type == JIM_EXPROP_SUB) { t->type = JIM_EXPROP_UNARYMINUS; } else if (t->type == JIM_EXPROP_ADD) { t->type = JIM_EXPROP_UNARYPLUS; } } op = JimExprOperatorInfoByOpcode(t->type); while ((tt = Jim_StackPeek(&stack)) != NULL) { const struct Jim_ExprOperator *tt_op = JimExprOperatorInfoByOpcode(tt->type); if (op->arity != 1 && tt_op->precedence >= op->precedence) { if (ExprAddOperator(interp, expr, tt) != JIM_OK) { ok = 0; goto err; } Jim_StackPop(&stack); } else { break; } } Jim_StackPush(&stack, t); break; } } prevtt = t->type; } while (Jim_StackLen(&stack)) { ParseToken *tt = Jim_StackPop(&stack); if (tt->type == JIM_TT_SUBEXPR_START) { ok = 0; Jim_SetResultString(interp, "Missing close parenthesis", -1); goto err; } if (ExprAddOperator(interp, expr, tt) != JIM_OK) { ok = 0; goto err; } } if (have_ternary) { ExprTernaryReorderExpression(interp, expr); } err: Jim_FreeStack(&stack); for (i = 0; i < expr->len; i++) { Jim_IncrRefCount(expr->token[i].objPtr); } if (!ok) { ExprFreeByteCode(interp, expr); return NULL; } return expr; } static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int exprTextLen; const char *exprText; struct JimParserCtx parser; struct ExprByteCode *expr; ParseTokenList tokenlist; int line; Jim_Obj *fileNameObj; int rc = JIM_ERR; if (objPtr->typePtr == &sourceObjType) { fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; line = objPtr->internalRep.sourceValue.lineNumber; } else { fileNameObj = interp->emptyObj; line = 1; } Jim_IncrRefCount(fileNameObj); exprText = Jim_GetString(objPtr, &exprTextLen); ScriptTokenListInit(&tokenlist); JimParserInit(&parser, exprText, exprTextLen, line); while (!parser.eof) { if (JimParseExpression(&parser) != JIM_OK) { ScriptTokenListFree(&tokenlist); invalidexpr: Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr); expr = NULL; goto err; } ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); |
︙ | ︙ | |||
13916 13917 13918 13919 13920 13921 13922 | if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) { ScriptTokenListFree(&tokenlist); Jim_DecrRefCount(interp, fileNameObj); return JIM_ERR; } | | | | > > > | > > | > > > > > > > > > | | | | | | | | | | | < | < < < < < < | | < < < < < < < | < < < < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | > | | | > | | | | 14034 14035 14036 14037 14038 14039 14040 14041 14042 14043 14044 14045 14046 14047 14048 14049 14050 14051 14052 14053 14054 14055 14056 14057 14058 14059 14060 14061 14062 14063 14064 14065 14066 14067 14068 14069 14070 14071 14072 14073 14074 14075 14076 14077 14078 14079 14080 14081 14082 14083 14084 14085 14086 14087 14088 14089 14090 14091 14092 14093 14094 14095 14096 14097 14098 14099 14100 14101 14102 14103 14104 14105 14106 14107 14108 14109 14110 14111 14112 14113 14114 14115 14116 14117 14118 14119 14120 14121 14122 14123 14124 14125 14126 14127 14128 14129 14130 14131 14132 14133 14134 14135 14136 14137 14138 14139 14140 14141 14142 14143 14144 14145 14146 14147 14148 14149 14150 14151 14152 14153 14154 14155 14156 14157 14158 14159 14160 14161 14162 | if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) { ScriptTokenListFree(&tokenlist); Jim_DecrRefCount(interp, fileNameObj); return JIM_ERR; } expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj); ScriptTokenListFree(&tokenlist); if (!expr) { goto err; } #ifdef DEBUG_SHOW_EXPR { int i; printf("==== Expr ====\n"); for (i = 0; i < expr->len; i++) { ScriptToken *t = &expr->token[i]; printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr)); } } #endif if (ExprCheckCorrectness(expr) != JIM_OK) { ExprFreeByteCode(interp, expr); goto invalidexpr; } rc = JIM_OK; err: Jim_DecrRefCount(interp, fileNameObj); Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, expr); objPtr->typePtr = &exprObjType; return rc; } static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &exprObjType) { if (SetExprFromAny(interp, objPtr) != JIM_OK) { return NULL; } } return (ExprByteCode *) Jim_GetIntRepPtr(objPtr); } #ifdef JIM_OPTIMIZATION static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, const ScriptToken *token) { if (token->type == JIM_TT_EXPR_INT) return token->objPtr; else if (token->type == JIM_TT_VAR) return Jim_GetVariable(interp, token->objPtr, JIM_NONE); else if (token->type == JIM_TT_DICTSUGAR) return JimExpandDictSugar(interp, token->objPtr); else return NULL; } #endif #define JIM_EE_STATICSTACK_LEN 10 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr) { ExprByteCode *expr; Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN]; int i; int retcode = JIM_OK; struct JimExprState e; expr = JimGetExpression(interp, exprObjPtr); if (!expr) { return JIM_ERR; } #ifdef JIM_OPTIMIZATION { Jim_Obj *objPtr; switch (expr->len) { case 1: objPtr = JimExprIntValOrVar(interp, &expr->token[0]); if (objPtr) { Jim_IncrRefCount(objPtr); *exprResultPtrPtr = objPtr; return JIM_OK; } break; case 2: if (expr->token[1].type == JIM_EXPROP_NOT) { objPtr = JimExprIntValOrVar(interp, &expr->token[0]); if (objPtr && JimIsWide(objPtr)) { *exprResultPtrPtr = JimWideValue(objPtr) ? interp->falseObj : interp->trueObj; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } } break; case 3: objPtr = JimExprIntValOrVar(interp, &expr->token[0]); if (objPtr && JimIsWide(objPtr)) { Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, &expr->token[1]); if (objPtr2 && JimIsWide(objPtr2)) { jim_wide wideValueA = JimWideValue(objPtr); jim_wide wideValueB = JimWideValue(objPtr2); int cmpRes; switch (expr->token[2].type) { case JIM_EXPROP_LT: cmpRes = wideValueA < wideValueB; break; case JIM_EXPROP_LTE: cmpRes = wideValueA <= wideValueB; break; case JIM_EXPROP_GT: |
︙ | ︙ | |||
14101 14102 14103 14104 14105 14106 14107 | break; case JIM_EXPROP_NUMNE: cmpRes = wideValueA != wideValueB; break; default: goto noopt; } | | > | > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > | < > > | | | | > | | | < < < | > | > | | | | | | | | | | | | | | | | 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180 14181 14182 14183 14184 14185 14186 14187 14188 14189 14190 14191 14192 14193 14194 14195 14196 14197 14198 14199 14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218 14219 14220 14221 14222 14223 14224 14225 14226 14227 14228 14229 14230 14231 14232 14233 14234 14235 14236 14237 14238 14239 14240 14241 14242 14243 14244 14245 14246 14247 14248 14249 14250 14251 14252 14253 14254 14255 14256 14257 14258 14259 14260 14261 14262 14263 14264 14265 14266 14267 14268 14269 14270 14271 14272 14273 14274 14275 14276 14277 14278 14279 14280 14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 14296 14297 14298 14299 14300 14301 14302 14303 14304 14305 14306 14307 14308 14309 14310 14311 14312 14313 14314 14315 14316 14317 14318 14319 14320 14321 14322 14323 14324 14325 14326 14327 14328 14329 14330 14331 | break; case JIM_EXPROP_NUMNE: cmpRes = wideValueA != wideValueB; break; default: goto noopt; } *exprResultPtrPtr = cmpRes ? interp->trueObj : interp->falseObj; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } } break; } } noopt: #endif expr->inUse++; if (expr->len > JIM_EE_STATICSTACK_LEN) e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len); else e.stack = staticStack; e.stacklen = 0; for (i = 0; i < expr->len && retcode == JIM_OK; i++) { Jim_Obj *objPtr; switch (expr->token[i].type) { case JIM_TT_EXPR_INT: case JIM_TT_EXPR_DOUBLE: case JIM_TT_STR: ExprPush(&e, expr->token[i].objPtr); break; case JIM_TT_VAR: objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG); if (objPtr) { ExprPush(&e, objPtr); } else { retcode = JIM_ERR; } break; case JIM_TT_DICTSUGAR: objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr); if (objPtr) { ExprPush(&e, objPtr); } else { retcode = JIM_ERR; } break; case JIM_TT_ESC: retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE); if (retcode == JIM_OK) { ExprPush(&e, objPtr); } break; case JIM_TT_CMD: retcode = Jim_EvalObj(interp, expr->token[i].objPtr); if (retcode == JIM_OK) { ExprPush(&e, Jim_GetResult(interp)); } break; default:{ e.skip = 0; e.opcode = expr->token[i].type; retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e); i += e.skip; continue; } } } expr->inUse--; if (retcode == JIM_OK) { *exprResultPtrPtr = ExprPop(&e); } else { for (i = 0; i < e.stacklen; i++) { Jim_DecrRefCount(interp, e.stack[i]); } } if (e.stack != staticStack) { Jim_Free(e.stack); } return retcode; } int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr) { int retcode; jim_wide wideValue; double doubleValue; Jim_Obj *exprResultPtr; retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr); if (retcode != JIM_OK) return retcode; if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) { if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) { Jim_DecrRefCount(interp, exprResultPtr); return JIM_ERR; } else { Jim_DecrRefCount(interp, exprResultPtr); *boolPtr = doubleValue != 0; return JIM_OK; } } *boolPtr = wideValue != 0; Jim_DecrRefCount(interp, exprResultPtr); return JIM_OK; } typedef struct ScanFmtPartDescr { char *arg; char *prefix; size_t width; int pos; char type; char modifier; } ScanFmtPartDescr; typedef struct ScanFmtStringObj { jim_wide size; char *stringRep; size_t count; size_t convCount; size_t maxPos; const char *error; char *scratch; ScanFmtPartDescr descr[1]; } ScanFmtStringObj; static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfScanFmt(Jim_Obj *objPtr); |
︙ | ︙ | |||
14211 14212 14213 14214 14215 14216 14217 | static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { ScanFmtStringObj *fmtObj; char *buffer; int maxCount, i, approxSize, lastPos = -1; | | | | | | | | | | | | | | | | | | | | | | | < < < < | < | | | | | | < < < < < | 14362 14363 14364 14365 14366 14367 14368 14369 14370 14371 14372 14373 14374 14375 14376 14377 14378 14379 14380 14381 14382 14383 14384 14385 14386 14387 14388 14389 14390 14391 14392 14393 14394 14395 14396 14397 14398 14399 14400 14401 14402 14403 14404 14405 14406 14407 14408 14409 14410 14411 14412 14413 14414 14415 14416 14417 14418 14419 14420 14421 14422 14423 14424 14425 14426 14427 14428 14429 14430 14431 14432 14433 14434 14435 14436 14437 14438 14439 14440 14441 14442 14443 14444 14445 14446 14447 14448 14449 14450 14451 14452 14453 14454 14455 14456 14457 14458 14459 14460 14461 14462 14463 14464 14465 14466 14467 14468 14469 14470 14471 14472 14473 14474 14475 14476 14477 14478 14479 14480 14481 14482 14483 14484 14485 14486 14487 14488 14489 14490 14491 14492 14493 14494 14495 14496 14497 14498 14499 14500 14501 14502 14503 14504 14505 14506 14507 14508 14509 14510 14511 14512 14513 14514 14515 | static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { ScanFmtStringObj *fmtObj; char *buffer; int maxCount, i, approxSize, lastPos = -1; const char *fmt = objPtr->bytes; int maxFmtLen = objPtr->length; const char *fmtEnd = fmt + maxFmtLen; int curr; Jim_FreeIntRep(interp, objPtr); for (i = 0, maxCount = 0; i < maxFmtLen; ++i) if (fmt[i] == '%') ++maxCount; approxSize = sizeof(ScanFmtStringObj) +(maxCount + 1) * sizeof(ScanFmtPartDescr) +maxFmtLen * sizeof(char) + 3 + 1 + maxFmtLen * sizeof(char) + 1 + maxFmtLen * sizeof(char) +(maxCount + 1) * sizeof(char) +1; fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize); memset(fmtObj, 0, approxSize); fmtObj->size = approxSize; fmtObj->maxPos = 0; fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1]; fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1; memcpy(fmtObj->stringRep, fmt, maxFmtLen); buffer = fmtObj->stringRep + maxFmtLen + 1; objPtr->internalRep.ptr = fmtObj; objPtr->typePtr = &scanFmtStringObjType; for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) { int width = 0, skip; ScanFmtPartDescr *descr = &fmtObj->descr[curr]; fmtObj->count++; descr->width = 0; if (*fmt != '%' || fmt[1] == '%') { descr->type = 0; descr->prefix = &buffer[i]; for (; fmt < fmtEnd; ++fmt) { if (*fmt == '%') { if (fmt[1] != '%') break; ++fmt; } buffer[i++] = *fmt; } buffer[i++] = 0; } ++fmt; if (fmt >= fmtEnd) goto done; descr->pos = 0; if (*fmt == '*') { descr->pos = -1; ++fmt; } else fmtObj->convCount++; if (sscanf(fmt, "%d%n", &width, &skip) == 1) { fmt += skip; if (descr->pos != -1 && *fmt == '$') { int prev; ++fmt; descr->pos = width; width = 0; if ((lastPos == 0 && descr->pos > 0) || (lastPos > 0 && descr->pos == 0)) { fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers"; return JIM_ERR; } for (prev = 0; prev < curr; ++prev) { if (fmtObj->descr[prev].pos == -1) continue; if (fmtObj->descr[prev].pos == descr->pos) { fmtObj->error = "variable is assigned by multiple \"%n$\" conversion specifiers"; return JIM_ERR; } } if (sscanf(fmt, "%d%n", &width, &skip) == 1) { descr->width = width; fmt += skip; } if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos) fmtObj->maxPos = descr->pos; } else { descr->width = width; } } if (lastPos == -1) lastPos = descr->pos; if (*fmt == '[') { int swapped = 1, beg = i, end, j; descr->type = '['; descr->arg = &buffer[i]; ++fmt; if (*fmt == '^') buffer[i++] = *fmt++; if (*fmt == ']') buffer[i++] = *fmt++; while (*fmt && *fmt != ']') buffer[i++] = *fmt++; if (*fmt != ']') { fmtObj->error = "unmatched [ in format string"; return JIM_ERR; } end = i; buffer[i++] = 0; while (swapped) { swapped = 0; for (j = beg + 1; j < end - 1; ++j) { if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) { char tmp = buffer[j - 1]; buffer[j - 1] = buffer[j + 1]; buffer[j + 1] = tmp; swapped = 1; } } } } else { if (strchr("hlL", *fmt) != 0) descr->modifier = tolower((int)*fmt++); descr->type = *fmt; if (strchr("efgcsndoxui", *fmt) == 0) { fmtObj->error = "bad scan conversion character"; return JIM_ERR; } else if (*fmt == 'c' && descr->width != 0) { fmtObj->error = "field width may not be specified in %c " "conversion"; |
︙ | ︙ | |||
14400 14401 14402 14403 14404 14405 14406 | char *p = buffer; while (*str) { int c; int n; if (!sdescr && isspace(UCHAR(*str))) | | | 14541 14542 14543 14544 14545 14546 14547 14548 14549 14550 14551 14552 14553 14554 14555 | char *p = buffer; while (*str) { int c; int n; if (!sdescr && isspace(UCHAR(*str))) break; n = utf8_tounicode(str, &c); if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN)) break; while (n--) *p++ = *str++; } |
︙ | ︙ | |||
14423 14424 14425 14426 14427 14428 14429 | const char *tok; const ScanFmtPartDescr *descr = &fmtObj->descr[idx]; size_t scanned = 0; size_t anchor = pos; int i; Jim_Obj *tmpObj = NULL; | | | | | | | | | | | | | | | | | | | | | 14564 14565 14566 14567 14568 14569 14570 14571 14572 14573 14574 14575 14576 14577 14578 14579 14580 14581 14582 14583 14584 14585 14586 14587 14588 14589 14590 14591 14592 14593 14594 14595 14596 14597 14598 14599 14600 14601 14602 14603 14604 14605 14606 14607 14608 14609 14610 14611 14612 14613 14614 14615 14616 14617 14618 14619 14620 14621 14622 14623 14624 14625 14626 14627 14628 14629 14630 14631 14632 14633 14634 14635 14636 14637 14638 14639 14640 14641 14642 14643 14644 14645 14646 14647 14648 14649 14650 14651 14652 14653 14654 14655 14656 14657 14658 14659 14660 14661 14662 14663 14664 14665 14666 14667 14668 14669 14670 14671 14672 14673 14674 14675 14676 14677 14678 14679 | const char *tok; const ScanFmtPartDescr *descr = &fmtObj->descr[idx]; size_t scanned = 0; size_t anchor = pos; int i; Jim_Obj *tmpObj = NULL; *valObjPtr = 0; if (descr->prefix) { for (i = 0; pos < strLen && descr->prefix[i]; ++i) { if (isspace(UCHAR(descr->prefix[i]))) while (pos < strLen && isspace(UCHAR(str[pos]))) ++pos; else if (descr->prefix[i] != str[pos]) break; else ++pos; } if (pos >= strLen) { return -1; } else if (descr->prefix[i] != 0) return 0; } if (descr->type != 'c' && descr->type != '[' && descr->type != 'n') while (isspace(UCHAR(str[pos]))) ++pos; scanned = pos - anchor; if (descr->type == 'n') { *valObjPtr = Jim_NewIntObj(interp, anchor + scanned); } else if (pos >= strLen) { return -1; } else if (descr->type == 'c') { int c; scanned += utf8_tounicode(&str[pos], &c); *valObjPtr = Jim_NewIntObj(interp, c); return scanned; } else { if (descr->width > 0) { size_t sLen = utf8_strlen(&str[pos], strLen - pos); size_t tLen = descr->width > sLen ? sLen : descr->width; tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen); tok = tmpObj->bytes; } else { tok = &str[pos]; } switch (descr->type) { case 'd': case 'o': case 'x': case 'u': case 'i':{ char *endp; jim_wide w; int base = descr->type == 'o' ? 8 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; if (base == 0) { w = jim_strtoull(tok, &endp); } else { w = strtoull(tok, &endp, base); } if (endp != tok) { *valObjPtr = Jim_NewIntObj(interp, w); scanned += endp - tok; } else { scanned = *tok ? 0 : -1; } break; } case 's': case '[':{ *valObjPtr = JimScanAString(interp, descr->arg, tok); scanned += Jim_Length(*valObjPtr); break; } case 'e': case 'f': case 'g':{ char *endp; double value = strtod(tok, &endp); if (endp != tok) { *valObjPtr = Jim_NewDoubleObj(interp, value); scanned += endp - tok; } else { scanned = *tok ? 0 : -1; } break; } |
︙ | ︙ | |||
14553 14554 14555 14556 14557 14558 14559 | int strLen = Jim_Utf8Length(interp, strObjPtr); Jim_Obj *resultList = 0; Jim_Obj **resultVec = 0; int resultc; Jim_Obj *emptyStr = 0; ScanFmtStringObj *fmtObj; | | | | | | | | | | | | | | | | 14694 14695 14696 14697 14698 14699 14700 14701 14702 14703 14704 14705 14706 14707 14708 14709 14710 14711 14712 14713 14714 14715 14716 14717 14718 14719 14720 14721 14722 14723 14724 14725 14726 14727 14728 14729 14730 14731 14732 14733 14734 14735 14736 14737 14738 14739 14740 14741 14742 14743 14744 14745 14746 14747 14748 14749 14750 14751 14752 14753 14754 14755 14756 14757 14758 14759 14760 14761 14762 | int strLen = Jim_Utf8Length(interp, strObjPtr); Jim_Obj *resultList = 0; Jim_Obj **resultVec = 0; int resultc; Jim_Obj *emptyStr = 0; ScanFmtStringObj *fmtObj; JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format")); fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr; if (fmtObj->error != 0) { if (flags & JIM_ERRMSG) Jim_SetResultString(interp, fmtObj->error, -1); return 0; } emptyStr = Jim_NewEmptyStringObj(interp); Jim_IncrRefCount(emptyStr); resultList = Jim_NewListObj(interp, NULL, 0); if (fmtObj->maxPos > 0) { for (i = 0; i < fmtObj->maxPos; ++i) Jim_ListAppendElement(interp, resultList, emptyStr); JimListGetElements(interp, resultList, &resultc, &resultVec); } for (i = 0, pos = 0; i < fmtObj->count; ++i) { ScanFmtPartDescr *descr = &(fmtObj->descr[i]); Jim_Obj *value = 0; if (descr->type == 0) continue; if (scanned > 0) scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value); if (scanned == -1 && i == 0) goto eof; pos += scanned; if (value == 0) value = Jim_NewEmptyStringObj(interp); if (descr->pos == -1) { Jim_FreeNewObj(interp, value); } else if (descr->pos == 0) Jim_ListAppendElement(interp, resultList, value); else if (resultVec[descr->pos - 1] == emptyStr) { Jim_DecrRefCount(interp, resultVec[descr->pos - 1]); Jim_IncrRefCount(value); resultVec[descr->pos - 1] = value; } else { Jim_FreeNewObj(interp, value); goto err; } } Jim_DecrRefCount(interp, emptyStr); return resultList; eof: |
︙ | ︙ | |||
14649 14650 14651 14652 14653 14654 14655 | static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len) { Jim_PrngState *prng; unsigned char *destByte = (unsigned char *)dest; unsigned int si, sj, x; | | | | | | | 14790 14791 14792 14793 14794 14795 14796 14797 14798 14799 14800 14801 14802 14803 14804 14805 14806 14807 14808 14809 14810 14811 14812 14813 14814 14815 14816 14817 14818 14819 14820 14821 14822 14823 14824 14825 14826 14827 14828 14829 14830 14831 14832 14833 14834 | static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len) { Jim_PrngState *prng; unsigned char *destByte = (unsigned char *)dest; unsigned int si, sj, x; if (interp->prngState == NULL) JimPrngInit(interp); prng = interp->prngState; for (x = 0; x < len; x++) { prng->i = (prng->i + 1) & 0xff; si = prng->sbox[prng->i]; prng->j = (prng->j + si) & 0xff; sj = prng->sbox[prng->j]; prng->sbox[prng->i] = sj; prng->sbox[prng->j] = si; *destByte++ = prng->sbox[(si + sj) & 0xff]; } } static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen) { int i; Jim_PrngState *prng; if (interp->prngState == NULL) JimPrngInit(interp); prng = interp->prngState; for (i = 0; i < 256; i++) prng->sbox[i] = i; for (i = 0; i < seedLen; i++) { unsigned char t; t = prng->sbox[i & 0xFF]; prng->sbox[i & 0xFF] = prng->sbox[seed[i]]; prng->sbox[seed[i]] = t; } |
︙ | ︙ | |||
14710 14711 14712 14713 14714 14715 14716 | } if (argc == 3) { if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK) return JIM_ERR; } intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!intObjPtr) { | | | | | | | | < | < | < | | | 14851 14852 14853 14854 14855 14856 14857 14858 14859 14860 14861 14862 14863 14864 14865 14866 14867 14868 14869 14870 14871 14872 14873 14874 14875 14876 14877 14878 14879 14880 14881 14882 14883 14884 14885 14886 14887 14888 14889 14890 14891 14892 14893 14894 14895 14896 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 14909 14910 14911 14912 14913 14914 14915 14916 14917 14918 14919 14920 14921 14922 14923 14924 14925 14926 14927 14928 14929 14930 14931 14932 14933 14934 14935 14936 14937 14938 14939 14940 14941 14942 14943 14944 14945 14946 14947 14948 14949 14950 14951 14952 14953 14954 14955 14956 14957 14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971 14972 14973 14974 14975 14976 14977 14978 14979 | } if (argc == 3) { if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK) return JIM_ERR; } intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!intObjPtr) { wideValue = 0; } else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) { return JIM_ERR; } if (!intObjPtr || Jim_IsShared(intObjPtr)) { intObjPtr = Jim_NewIntObj(interp, wideValue + increment); if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) { Jim_FreeNewObj(interp, intObjPtr); return JIM_ERR; } } else { Jim_InvalidateStringRep(intObjPtr); JimWideValue(intObjPtr) = wideValue + increment; if (argv[1]->typePtr != &variableObjType) { Jim_SetVariable(interp, argv[1], intObjPtr); } } Jim_SetResult(interp, intObjPtr); return JIM_OK; } #define JIM_EVAL_SARGV_LEN 8 #define JIM_EVAL_SINTV_LEN 8 static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retcode; if (interp->unknown_called > 50) { return JIM_ERR; } if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL) return JIM_ERR; interp->unknown_called++; retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv); interp->unknown_called--; return retcode; } static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int retcode; Jim_Cmd *cmdPtr; #if 0 printf("invoke"); int j; for (j = 0; j < objc; j++) { printf(" '%s'", Jim_String(objv[j])); } printf("\n"); #endif if (interp->framePtr->tailcallCmd) { cmdPtr = interp->framePtr->tailcallCmd; interp->framePtr->tailcallCmd = NULL; } else { cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); if (cmdPtr == NULL) { return JimUnknown(interp, objc, objv); } JimIncrCmdRefCount(cmdPtr); } if (interp->evalDepth == interp->maxEvalDepth) { Jim_SetResultString(interp, "Infinite eval recursion", -1); retcode = JIM_ERR; goto out; } interp->evalDepth++; Jim_SetEmptyResult(interp); if (cmdPtr->isproc) { retcode = JimCallProcedure(interp, cmdPtr, objc, objv); } else { interp->cmdPrivData = cmdPtr->u.native.privData; retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); } interp->evalDepth--; out: JimDecrCmdRefCount(interp, cmdPtr); return retcode; } int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int i, retcode; for (i = 0; i < objc; i++) Jim_IncrRefCount(objv[i]); retcode = JimInvokeCommand(interp, objc, objv); for (i = 0; i < objc; i++) Jim_DecrRefCount(interp, objv[i]); return retcode; } int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv) |
︙ | ︙ | |||
14849 14850 14851 14852 14853 14854 14855 | Jim_Free(nargv); return ret; } static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script) { if (!interp->errorFlag) { | | | | | | 14987 14988 14989 14990 14991 14992 14993 14994 14995 14996 14997 14998 14999 15000 15001 15002 15003 15004 15005 15006 15007 15008 15009 15010 15011 15012 15013 15014 15015 | Jim_Free(nargv); return ret; } static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script) { if (!interp->errorFlag) { interp->errorFlag = 1; Jim_IncrRefCount(script->fileNameObj); Jim_DecrRefCount(interp, interp->errorFileNameObj); interp->errorFileNameObj = script->fileNameObj; interp->errorLine = script->linenr; JimResetStackTrace(interp); interp->addStackTrace++; } if (interp->addStackTrace > 0) { JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr); if (Jim_Length(script->fileNameObj)) { interp->addStackTrace = 0; } |
︙ | ︙ | |||
14902 14903 14904 14905 14906 14907 14908 | case JIM_TT_CMD: switch (Jim_EvalObj(interp, token->objPtr)) { case JIM_OK: case JIM_RETURN: objPtr = interp->result; break; case JIM_BREAK: | | | | 15040 15041 15042 15043 15044 15045 15046 15047 15048 15049 15050 15051 15052 15053 15054 15055 15056 15057 | case JIM_TT_CMD: switch (Jim_EvalObj(interp, token->objPtr)) { case JIM_OK: case JIM_RETURN: objPtr = interp->result; break; case JIM_BREAK: return JIM_BREAK; case JIM_CONTINUE: return JIM_CONTINUE; default: return JIM_ERR; } break; default: JimPanic((1, |
︙ | ︙ | |||
14944 14945 14946 14947 14948 14949 14950 | for (i = 0; i < tokens; i++) { switch (JimSubstOneToken(interp, &token[i], &intv[i])) { case JIM_OK: case JIM_RETURN: break; case JIM_BREAK: if (flags & JIM_SUBST_FLAG) { | | | | | | | | < | | | | 15082 15083 15084 15085 15086 15087 15088 15089 15090 15091 15092 15093 15094 15095 15096 15097 15098 15099 15100 15101 15102 15103 15104 15105 15106 15107 15108 15109 15110 15111 15112 15113 15114 15115 15116 15117 15118 15119 15120 15121 15122 15123 15124 15125 15126 15127 15128 15129 15130 15131 15132 15133 15134 15135 15136 15137 15138 15139 15140 15141 15142 15143 15144 15145 15146 15147 15148 15149 15150 15151 15152 15153 15154 15155 | for (i = 0; i < tokens; i++) { switch (JimSubstOneToken(interp, &token[i], &intv[i])) { case JIM_OK: case JIM_RETURN: break; case JIM_BREAK: if (flags & JIM_SUBST_FLAG) { tokens = i; continue; } case JIM_CONTINUE: if (flags & JIM_SUBST_FLAG) { intv[i] = NULL; continue; } default: while (i--) { Jim_DecrRefCount(interp, intv[i]); } if (intv != sintv) { Jim_Free(intv); } return NULL; } Jim_IncrRefCount(intv[i]); Jim_String(intv[i]); totlen += intv[i]->length; } if (tokens == 1 && intv[0] && intv == sintv) { Jim_DecrRefCount(interp, intv[0]); return intv[0]; } objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0); if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC && token[2].type == JIM_TT_VAR) { objPtr->typePtr = &interpolatedObjType; objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr; objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2]; Jim_IncrRefCount(intv[2]); } else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) { JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber); } s = objPtr->bytes = Jim_Alloc(totlen + 1); objPtr->length = totlen; for (i = 0; i < tokens; i++) { if (intv[i]) { memcpy(s, intv[i]->bytes, intv[i]->length); s += intv[i]->length; Jim_DecrRefCount(interp, intv[i]); } } objPtr->bytes[totlen] = '\0'; if (intv != sintv) { Jim_Free(intv); } return objPtr; } |
︙ | ︙ | |||
15048 15049 15050 15051 15052 15053 15054 | Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL; Jim_Obj *prevScriptObj; if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) { return JimEvalObjList(interp, scriptObjPtr); } | | | 15185 15186 15187 15188 15189 15190 15191 15192 15193 15194 15195 15196 15197 15198 15199 | Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL; Jim_Obj *prevScriptObj; if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) { return JimEvalObjList(interp, scriptObjPtr); } Jim_IncrRefCount(scriptObjPtr); script = JimGetScript(interp, scriptObjPtr); if (!JimScriptValid(interp, script)) { Jim_DecrRefCount(interp, scriptObjPtr); return JIM_ERR; } Jim_SetEmptyResult(interp); |
︙ | ︙ | |||
15084 15085 15086 15087 15088 15089 15090 | return JIM_OK; } } #endif script->inUse++; | | | | | | 15221 15222 15223 15224 15225 15226 15227 15228 15229 15230 15231 15232 15233 15234 15235 15236 15237 15238 15239 15240 15241 15242 15243 15244 15245 15246 15247 15248 15249 15250 15251 15252 15253 15254 | return JIM_OK; } } #endif script->inUse++; prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; interp->errorFlag = 0; argv = sargv; for (i = 0; i < script->len && retcode == JIM_OK; ) { int argc; int j; argc = token[i].objPtr->internalRep.scriptLineValue.argc; script->linenr = token[i].objPtr->internalRep.scriptLineValue.line; if (argc > JIM_EVAL_SARGV_LEN) argv = Jim_Alloc(sizeof(Jim_Obj *) * argc); i++; for (j = 0; j < argc; j++) { long wordtokens = 1; int expand = 0; Jim_Obj *wordObjPtr = NULL; |
︙ | ︙ | |||
15163 15164 15165 15166 15167 15168 15169 | Jim_IncrRefCount(wordObjPtr); i += wordtokens; if (!expand) { argv[j] = wordObjPtr; } else { | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | < | | | | 15300 15301 15302 15303 15304 15305 15306 15307 15308 15309 15310 15311 15312 15313 15314 15315 15316 15317 15318 15319 15320 15321 15322 15323 15324 15325 15326 15327 15328 15329 15330 15331 15332 15333 15334 15335 15336 15337 15338 15339 15340 15341 15342 15343 15344 15345 15346 15347 15348 15349 15350 15351 15352 15353 15354 15355 15356 15357 15358 15359 15360 15361 15362 15363 15364 15365 15366 15367 15368 15369 15370 15371 15372 15373 15374 15375 15376 15377 15378 15379 15380 15381 15382 15383 15384 15385 15386 15387 15388 15389 15390 15391 15392 15393 15394 15395 15396 15397 15398 15399 15400 15401 15402 15403 15404 15405 15406 15407 15408 15409 15410 15411 15412 15413 15414 15415 15416 15417 15418 15419 15420 15421 15422 15423 15424 15425 15426 15427 15428 15429 15430 15431 15432 15433 15434 15435 15436 15437 15438 15439 15440 15441 15442 15443 15444 15445 15446 15447 15448 15449 15450 15451 15452 15453 15454 15455 15456 15457 15458 15459 15460 15461 15462 15463 15464 15465 15466 15467 15468 15469 15470 15471 15472 15473 15474 15475 15476 15477 15478 15479 15480 15481 15482 15483 15484 15485 15486 15487 15488 15489 15490 15491 15492 15493 15494 15495 15496 15497 15498 15499 15500 15501 15502 15503 15504 15505 15506 15507 15508 15509 15510 15511 15512 15513 15514 15515 15516 15517 15518 15519 15520 15521 15522 15523 15524 15525 15526 15527 15528 15529 15530 15531 15532 15533 15534 15535 15536 15537 15538 15539 15540 15541 15542 15543 15544 15545 15546 15547 15548 15549 15550 15551 15552 15553 15554 15555 15556 15557 15558 15559 15560 15561 15562 15563 15564 15565 15566 15567 15568 15569 15570 15571 15572 15573 15574 15575 15576 15577 15578 15579 15580 15581 15582 15583 15584 15585 15586 15587 15588 15589 15590 15591 15592 15593 15594 15595 15596 15597 15598 15599 15600 15601 15602 15603 15604 15605 15606 15607 | Jim_IncrRefCount(wordObjPtr); i += wordtokens; if (!expand) { argv[j] = wordObjPtr; } else { int len = Jim_ListLength(interp, wordObjPtr); int newargc = argc + len - 1; int k; if (len > 1) { if (argv == sargv) { if (newargc > JIM_EVAL_SARGV_LEN) { argv = Jim_Alloc(sizeof(*argv) * newargc); memcpy(argv, sargv, sizeof(*argv) * j); } } else { argv = Jim_Realloc(argv, sizeof(*argv) * newargc); } } for (k = 0; k < len; k++) { argv[j++] = wordObjPtr->internalRep.listValue.ele[k]; Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]); } Jim_DecrRefCount(interp, wordObjPtr); j--; argc += len - 1; } } if (retcode == JIM_OK && argc) { retcode = JimInvokeCommand(interp, argc, argv); if (Jim_CheckSignal(interp)) { retcode = JIM_SIGNAL; } } while (j-- > 0) { Jim_DecrRefCount(interp, argv[j]); } if (argv != sargv) { Jim_Free(argv); argv = sargv; } } if (retcode == JIM_ERR) { JimAddErrorToStack(interp, script); } else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) { interp->addStackTrace = 0; } interp->currentScriptObj = prevScriptObj; Jim_FreeIntRep(interp, scriptObjPtr); scriptObjPtr->typePtr = &scriptObjType; Jim_SetIntRepPtr(scriptObjPtr, script); Jim_DecrRefCount(interp, scriptObjPtr); return retcode; } static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj) { int retcode; const char *varname = Jim_String(argNameObj); if (*varname == '&') { Jim_Obj *objPtr; Jim_CallFrame *savedCallFrame = interp->framePtr; interp->framePtr = interp->framePtr->parent; objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG); interp->framePtr = savedCallFrame; if (!objPtr) { return JIM_ERR; } objPtr = Jim_NewStringObj(interp, varname + 1, -1); Jim_IncrRefCount(objPtr); retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent); Jim_DecrRefCount(interp, objPtr); } else { retcode = Jim_SetVariable(interp, argNameObj, argValObj); } return retcode; } static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd) { Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0); int i; for (i = 0; i < cmd->u.proc.argListLen; i++) { Jim_AppendString(interp, argmsg, " ", 1); if (i == cmd->u.proc.argsPos) { if (cmd->u.proc.arglist[i].defaultObjPtr) { Jim_AppendString(interp, argmsg, "?", 1); Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr); Jim_AppendString(interp, argmsg, " ...?", -1); } else { Jim_AppendString(interp, argmsg, "?arg...?", -1); } } else { if (cmd->u.proc.arglist[i].defaultObjPtr) { Jim_AppendString(interp, argmsg, "?", 1); Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr); Jim_AppendString(interp, argmsg, "?", 1); } else { const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr); if (*arg == '&') { arg++; } Jim_AppendString(interp, argmsg, arg, -1); } } } Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg); Jim_FreeNewObj(interp, argmsg); } #ifdef jim_ext_namespace int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj) { Jim_CallFrame *callFramePtr; int retcode; callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj); callFramePtr->argv = &interp->emptyObj; callFramePtr->argc = 0; callFramePtr->procArgsObjPtr = NULL; callFramePtr->procBodyObjPtr = scriptObj; callFramePtr->staticVars = NULL; callFramePtr->fileNameObj = interp->emptyObj; callFramePtr->line = 0; Jim_IncrRefCount(scriptObj); interp->framePtr = callFramePtr; if (interp->framePtr->level == interp->maxCallFrameDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); retcode = JIM_ERR; } else { retcode = Jim_EvalObj(interp, scriptObj); } interp->framePtr = interp->framePtr->parent; JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); return retcode; } #endif static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv) { Jim_CallFrame *callFramePtr; int i, d, retcode, optargs; ScriptObj *script; if (argc - 1 < cmd->u.proc.reqArity || (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) { JimSetProcWrongArgs(interp, argv[0], cmd); return JIM_ERR; } if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) { return JIM_OK; } if (interp->framePtr->level == interp->maxCallFrameDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); return JIM_ERR; } callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj); callFramePtr->argv = argv; callFramePtr->argc = argc; callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr; callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr; callFramePtr->staticVars = cmd->u.proc.staticVars; script = JimGetScript(interp, interp->currentScriptObj); callFramePtr->fileNameObj = script->fileNameObj; callFramePtr->line = script->linenr; Jim_IncrRefCount(cmd->u.proc.argListObjPtr); Jim_IncrRefCount(cmd->u.proc.bodyObjPtr); interp->framePtr = callFramePtr; optargs = (argc - 1 - cmd->u.proc.reqArity); i = 1; for (d = 0; d < cmd->u.proc.argListLen; d++) { Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr; if (d == cmd->u.proc.argsPos) { Jim_Obj *listObjPtr; int argsLen = 0; if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) { argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity); } listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen); if (cmd->u.proc.arglist[d].defaultObjPtr) { nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr; } retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr); if (retcode != JIM_OK) { goto badargset; } i += argsLen; continue; } if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) { retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]); } else { retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr); } if (retcode != JIM_OK) { goto badargset; } } retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr); badargset: interp->framePtr = interp->framePtr->parent; JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); if (interp->framePtr->tailcallObj) { do { Jim_Obj *tailcallObj = interp->framePtr->tailcallObj; interp->framePtr->tailcallObj = NULL; if (retcode == JIM_EVAL) { retcode = Jim_EvalObjList(interp, tailcallObj); if (retcode == JIM_RETURN) { interp->returnLevel++; } } Jim_DecrRefCount(interp, tailcallObj); } while (interp->framePtr->tailcallObj); if (interp->framePtr->tailcallCmd) { JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd); interp->framePtr->tailcallCmd = NULL; } } if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; interp->returnCode = JIM_OK; interp->returnLevel = 0; } } |
︙ | ︙ | |||
15572 15573 15574 15575 15576 15577 15578 | Jim_IncrRefCount(scriptObjPtr); prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; retcode = Jim_EvalObj(interp, scriptObjPtr); | | | | 15709 15710 15711 15712 15713 15714 15715 15716 15717 15718 15719 15720 15721 15722 15723 15724 15725 15726 15727 15728 15729 15730 15731 15732 | Jim_IncrRefCount(scriptObjPtr); prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; retcode = Jim_EvalObj(interp, scriptObjPtr); if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; interp->returnCode = JIM_OK; interp->returnLevel = 0; } } if (retcode == JIM_ERR) { interp->addStackTrace++; } interp->currentScriptObj = prevScriptObj; Jim_DecrRefCount(interp, scriptObjPtr); |
︙ | ︙ | |||
15611 15612 15613 15614 15615 15616 15617 | JimParseCmd(pc); return; } if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { if (JimParseVar(pc) == JIM_OK) { return; } | | | 15748 15749 15750 15751 15752 15753 15754 15755 15756 15757 15758 15759 15760 15761 15762 | JimParseCmd(pc); return; } if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { if (JimParseVar(pc) == JIM_OK) { return; } pc->tstart = pc->p; flags |= JIM_SUBST_NOVAR; } while (pc->len) { if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { break; } |
︙ | ︙ | |||
15642 15643 15644 15645 15646 15647 15648 | { int scriptTextLen; const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); struct JimParserCtx parser; struct ScriptObj *script = Jim_Alloc(sizeof(*script)); ParseTokenList tokenlist; | | | | | | | < < < < | | > > | | 15779 15780 15781 15782 15783 15784 15785 15786 15787 15788 15789 15790 15791 15792 15793 15794 15795 15796 15797 15798 15799 15800 15801 15802 15803 15804 15805 15806 15807 15808 15809 15810 15811 15812 15813 15814 15815 15816 15817 15818 15819 15820 15821 15822 15823 15824 15825 15826 15827 15828 15829 15830 15831 15832 15833 15834 15835 15836 15837 15838 15839 15840 15841 15842 15843 15844 15845 15846 15847 15848 15849 15850 15851 15852 15853 15854 15855 15856 15857 15858 15859 15860 15861 15862 15863 15864 15865 15866 15867 15868 15869 15870 15871 15872 15873 15874 15875 15876 15877 15878 15879 15880 15881 15882 15883 15884 15885 15886 15887 15888 | { int scriptTextLen; const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); struct JimParserCtx parser; struct ScriptObj *script = Jim_Alloc(sizeof(*script)); ParseTokenList tokenlist; ScriptTokenListInit(&tokenlist); JimParserInit(&parser, scriptText, scriptTextLen, 1); while (1) { JimParseSubst(&parser, flags); if (parser.eof) { break; } ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } script->inUse = 1; script->substFlags = flags; script->fileNameObj = interp->emptyObj; Jim_IncrRefCount(script->fileNameObj); SubstObjAddTokens(interp, script, &tokenlist); ScriptTokenListFree(&tokenlist); #ifdef DEBUG_SHOW_SUBST { int i; printf("==== Subst ====\n"); for (i = 0; i < script->len; i++) { printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type), Jim_String(script->token[i].objPtr)); } } #endif Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; return JIM_OK; } static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags) SetSubstFromAny(interp, objPtr, flags); return (ScriptObj *) Jim_GetIntRepPtr(objPtr); } int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags) { ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags); Jim_IncrRefCount(substObjPtr); script->inUse++; *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags); script->inUse--; Jim_DecrRefCount(interp, substObjPtr); if (*resObjPtrPtr == NULL) { return JIM_ERR; } return JIM_OK; } void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg) { Jim_Obj *objPtr; Jim_Obj *listObjPtr = Jim_NewListObj(interp, argv, argc); if (*msg) { Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1)); } Jim_IncrRefCount(listObjPtr); objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1); Jim_DecrRefCount(interp, listObjPtr); Jim_IncrRefCount(objPtr); Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr); Jim_DecrRefCount(interp, objPtr); } typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type); #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, JimHashtableIteratorCallbackType *callback, int type) { Jim_HashEntry *he; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) { he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr)); if (he) { callback(interp, listObjPtr, he, type); } } else { |
︙ | ︙ | |||
15770 15771 15772 15773 15774 15775 15776 | static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he); Jim_Obj *objPtr; if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) { | | | 15905 15906 15907 15908 15909 15910 15911 15912 15913 15914 15915 15916 15917 15918 15919 | static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he); Jim_Obj *objPtr; if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) { return; } objPtr = Jim_NewStringObj(interp, he->key, -1); Jim_IncrRefCount(objPtr); if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, objPtr)) { |
︙ | ︙ | |||
15830 15831 15832 15833 15834 15835 15836 | { Jim_CallFrame *targetCallFrame; targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr); if (targetCallFrame == NULL) { return JIM_ERR; } | | | 15965 15966 15967 15968 15969 15970 15971 15972 15973 15974 15975 15976 15977 15978 15979 | { Jim_CallFrame *targetCallFrame; targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr); if (targetCallFrame == NULL) { return JIM_ERR; } if (targetCallFrame == interp->topFramePtr) { Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr); return JIM_ERR; } if (info_level_cmd) { *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc); } |
︙ | ︙ | |||
15958 15959 15960 15961 15962 15963 15964 | for (i = 2; i < argc; i++) { if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) { doubleRes = (double)res; goto trydouble; } if (op == JIM_EXPROP_SUB) res -= wideValue; | | < < < < < | 16093 16094 16095 16096 16097 16098 16099 16100 16101 16102 16103 16104 16105 16106 16107 16108 | for (i = 2; i < argc; i++) { if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) { doubleRes = (double)res; goto trydouble; } if (op == JIM_EXPROP_SUB) res -= wideValue; else res /= wideValue; } Jim_SetResultInt(interp, res); return JIM_OK; trydouble: for (; i < argc; i++) { if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK) return JIM_ERR; |
︙ | ︙ | |||
16022 16023 16024 16025 16026 16027 16028 | objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); if (!objPtr) return JIM_ERR; Jim_SetResult(interp, objPtr); return JIM_OK; } | | | 16152 16153 16154 16155 16156 16157 16158 16159 16160 16161 16162 16163 16164 16165 16166 | objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); if (!objPtr) return JIM_ERR; Jim_SetResult(interp, objPtr); return JIM_OK; } if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); return JIM_OK; } static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
︙ | ︙ | |||
16065 16066 16067 16068 16069 16070 16071 | static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "condition body"); return JIM_ERR; } | | | 16195 16196 16197 16198 16199 16200 16201 16202 16203 16204 16205 16206 16207 16208 16209 | static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "condition body"); return JIM_ERR; } while (1) { int boolean, retval; if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK) return retval; if (!boolean) break; |
︙ | ︙ | |||
16105 16106 16107 16108 16109 16110 16111 | Jim_Obj *stopVarNamePtr = NULL; if (argc != 5) { Jim_WrongNumArgs(interp, 1, argv, "start test next body"); return JIM_ERR; } | | | | | | | > > | | < < | < < < < < < | | | | | | | | | | | | | | | | 16235 16236 16237 16238 16239 16240 16241 16242 16243 16244 16245 16246 16247 16248 16249 16250 16251 16252 16253 16254 16255 16256 16257 16258 16259 16260 16261 16262 16263 16264 16265 16266 16267 16268 16269 16270 16271 16272 16273 16274 16275 16276 16277 16278 16279 16280 16281 16282 16283 16284 16285 16286 16287 16288 16289 16290 16291 16292 16293 16294 16295 16296 16297 16298 16299 16300 16301 16302 16303 16304 16305 16306 16307 16308 16309 16310 16311 16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 16324 16325 16326 16327 16328 16329 16330 16331 16332 16333 16334 16335 16336 16337 16338 16339 16340 16341 16342 16343 16344 16345 16346 | Jim_Obj *stopVarNamePtr = NULL; if (argc != 5) { Jim_WrongNumArgs(interp, 1, argv, "start test next body"); return JIM_ERR; } if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) { return retval; } retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); #ifdef JIM_OPTIMIZATION if (retval == JIM_OK && boolean) { ScriptObj *incrScript; ExprByteCode *expr; jim_wide stop, currentVal; Jim_Obj *objPtr; int cmpOffset; expr = JimGetExpression(interp, argv[2]); incrScript = JimGetScript(interp, argv[3]); if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) { goto evalstart; } if (incrScript->token[1].type != JIM_TT_ESC || expr->token[0].type != JIM_TT_VAR || (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) { goto evalstart; } if (expr->token[2].type == JIM_EXPROP_LT) { cmpOffset = 0; } else if (expr->token[2].type == JIM_EXPROP_LTE) { cmpOffset = 1; } else { goto evalstart; } if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) { goto evalstart; } if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) { goto evalstart; } if (expr->token[1].type == JIM_TT_EXPR_INT) { if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) { goto evalstart; } } else { stopVarNamePtr = expr->token[1].objPtr; Jim_IncrRefCount(stopVarNamePtr); stop = 0; } varNamePtr = expr->token[0].objPtr; Jim_IncrRefCount(varNamePtr); objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE); if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) { goto testcond; } while (retval == JIM_OK) { if (stopVarNamePtr) { objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE); if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) { goto testcond; } } if (currentVal >= stop + cmpOffset) { break; } retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { retval = JIM_OK; objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG); if (objPtr == NULL) { retval = JIM_ERR; goto out; } if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { currentVal = ++JimWideValue(objPtr); Jim_InvalidateStringRep(objPtr); |
︙ | ︙ | |||
16232 16233 16234 16235 16236 16237 16238 | } goto out; } evalstart: #endif while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) { | | | | | | | | 16356 16357 16358 16359 16360 16361 16362 16363 16364 16365 16366 16367 16368 16369 16370 16371 16372 16373 16374 16375 16376 16377 16378 16379 16380 16381 16382 16383 16384 | } goto out; } evalstart: #endif while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) { retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { evalnext: retval = Jim_EvalObj(interp, argv[3]); if (retval == JIM_OK || retval == JIM_CONTINUE) { testcond: retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); } } } out: if (stopVarNamePtr) { Jim_DecrRefCount(interp, stopVarNamePtr); } if (varNamePtr) { Jim_DecrRefCount(interp, varNamePtr); } |
︙ | ︙ | |||
16292 16293 16294 16295 16296 16297 16298 | while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) { retval = Jim_EvalObj(interp, bodyObjPtr); if (retval == JIM_OK || retval == JIM_CONTINUE) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); retval = JIM_OK; | | | 16416 16417 16418 16419 16420 16421 16422 16423 16424 16425 16426 16427 16428 16429 16430 | while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) { retval = Jim_EvalObj(interp, bodyObjPtr); if (retval == JIM_OK || retval == JIM_CONTINUE) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); retval = JIM_OK; i += incr; if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { if (argv[1]->typePtr != &variableObjType) { if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { return JIM_ERR; } |
︙ | ︙ | |||
16357 16358 16359 16360 16361 16362 16363 | } static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) { int result = JIM_OK; int i, numargs; | | | | | | | | | | | | 16481 16482 16483 16484 16485 16486 16487 16488 16489 16490 16491 16492 16493 16494 16495 16496 16497 16498 16499 16500 16501 16502 16503 16504 16505 16506 16507 16508 16509 16510 16511 16512 16513 16514 16515 16516 16517 16518 16519 16520 16521 16522 16523 16524 16525 16526 16527 16528 16529 16530 16531 16532 16533 16534 16535 16536 16537 16538 16539 16540 16541 16542 16543 16544 16545 16546 16547 16548 16549 16550 16551 16552 16553 16554 16555 16556 | } static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) { int result = JIM_OK; int i, numargs; Jim_ListIter twoiters[2]; Jim_ListIter *iters; Jim_Obj *script; Jim_Obj *resultObj; if (argc < 4 || argc % 2 != 0) { Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script"); return JIM_ERR; } script = argv[argc - 1]; numargs = (argc - 1 - 1); if (numargs == 2) { iters = twoiters; } else { iters = Jim_Alloc(numargs * sizeof(*iters)); } for (i = 0; i < numargs; i++) { JimListIterInit(&iters[i], argv[i + 1]); if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) { result = JIM_ERR; } } if (result != JIM_OK) { Jim_SetResultString(interp, "foreach varlist is empty", -1); return result; } if (doMap) { resultObj = Jim_NewListObj(interp, NULL, 0); } else { resultObj = interp->emptyObj; } Jim_IncrRefCount(resultObj); while (1) { for (i = 0; i < numargs; i += 2) { if (!JimListIterDone(interp, &iters[i + 1])) { break; } } if (i == numargs) { break; } for (i = 0; i < numargs; i += 2) { Jim_Obj *varName; JimListIterInit(&iters[i], argv[i + 1]); while ((varName = JimListIterNext(interp, &iters[i])) != NULL) { Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]); if (!valObj) { valObj = interp->emptyObj; } Jim_IncrRefCount(valObj); result = Jim_SetVariable(interp, varName, valObj); Jim_DecrRefCount(interp, valObj); if (result != JIM_OK) { goto err; } } |
︙ | ︙ | |||
16446 16447 16448 16449 16450 16451 16452 | } } out: result = JIM_OK; Jim_SetResult(interp, resultObj); err: Jim_DecrRefCount(interp, resultObj); | < | 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 16580 16581 16582 16583 | } } out: result = JIM_OK; Jim_SetResult(interp, resultObj); err: Jim_DecrRefCount(interp, resultObj); if (numargs > 2) { Jim_Free(iters); } return result; } |
︙ | ︙ | |||
16505 16506 16507 16508 16509 16510 16511 | static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int boolean, retval, current = 1, falsebody = 0; if (argc >= 3) { while (1) { | | | | | | | | 16628 16629 16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643 16644 16645 16646 16647 16648 16649 16650 16651 16652 16653 16654 16655 16656 16657 16658 16659 16660 16661 16662 16663 16664 16665 16666 16667 16668 16669 16670 16671 16672 | static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int boolean, retval, current = 1, falsebody = 0; if (argc >= 3) { while (1) { if (current >= argc) goto err; if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean)) != JIM_OK) return retval; if (current >= argc) goto err; if (Jim_CompareStringImmediate(interp, argv[current], "then")) current++; if (current >= argc) goto err; if (boolean) return Jim_EvalObj(interp, argv[current]); if (++current >= argc) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return JIM_OK; } falsebody = current++; if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) { if (current != argc - 1) goto err; return Jim_EvalObj(interp, argv[current]); } else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif")) continue; else if (falsebody != argc - 1) goto err; return Jim_EvalObj(interp, argv[falsebody]); } return JIM_OK; } err: |
︙ | ︙ | |||
16573 16574 16575 16576 16577 16578 16579 16580 16581 16582 | if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) { eq = -rc; } return eq; } static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { | > > > < | | | 16696 16697 16698 16699 16700 16701 16702 16703 16704 16705 16706 16707 16708 16709 16710 16711 16712 16713 16714 16715 16716 16717 16718 | if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) { eq = -rc; } return eq; } enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD }; static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int matchOpt = SWITCH_EXACT, opt = 1, patCount, i; Jim_Obj *command = 0, *const *caseList = 0, *strObj; Jim_Obj *script = 0; if (argc < 3) { wrongnumargs: Jim_WrongNumArgs(interp, 1, argv, "?options? string " "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}"); return JIM_ERR; } |
︙ | ︙ | |||
16620 16621 16622 16623 16624 16625 16626 | } if ((argc - opt) < 2) goto wrongnumargs; } strObj = argv[opt++]; patCount = argc - opt; if (patCount == 1) { | > > | > | | | | | > > | > | | | | | | | | | 16745 16746 16747 16748 16749 16750 16751 16752 16753 16754 16755 16756 16757 16758 16759 16760 16761 16762 16763 16764 16765 16766 16767 16768 16769 16770 16771 16772 16773 16774 16775 16776 16777 16778 16779 16780 16781 16782 16783 16784 16785 16786 16787 16788 16789 16790 16791 16792 16793 16794 16795 16796 16797 16798 16799 16800 16801 16802 16803 16804 16805 16806 16807 16808 16809 16810 16811 16812 16813 16814 16815 16816 | } if ((argc - opt) < 2) goto wrongnumargs; } strObj = argv[opt++]; patCount = argc - opt; if (patCount == 1) { Jim_Obj **vector; JimListGetElements(interp, argv[opt], &patCount, &vector); caseList = vector; } else caseList = &argv[opt]; if (patCount == 0 || patCount % 2 != 0) goto wrongnumargs; for (i = 0; script == 0 && i < patCount; i += 2) { Jim_Obj *patObj = caseList[i]; if (!Jim_CompareStringImmediate(interp, patObj, "default") || i < (patCount - 2)) { switch (matchOpt) { case SWITCH_EXACT: if (Jim_StringEqObj(strObj, patObj)) script = caseList[i + 1]; break; case SWITCH_GLOB: if (Jim_StringMatchObj(interp, patObj, strObj, 0)) script = caseList[i + 1]; break; case SWITCH_RE: command = Jim_NewStringObj(interp, "regexp", -1); case SWITCH_CMD:{ int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0); if (argc - opt == 1) { Jim_Obj **vector; JimListGetElements(interp, argv[opt], &patCount, &vector); caseList = vector; } if (rc < 0) { return -rc; } if (rc) script = caseList[i + 1]; break; } } } else { script = caseList[i + 1]; } } for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2) script = caseList[i + 1]; if (script && Jim_CompareStringImmediate(interp, script, "-")) { Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]); return JIM_ERR; } Jim_SetEmptyResult(interp); if (script) { return Jim_EvalObj(interp, script); } return JIM_OK; } static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { |
︙ | ︙ | |||
16787 16788 16789 16790 16791 16792 16793 | opt_all = 1; break; case OPT_COMMAND: if (i >= argc - 2) { goto wrongargs; } commandObj = argv[++i]; | | | 16918 16919 16920 16921 16922 16923 16924 16925 16926 16927 16928 16929 16930 16931 16932 | opt_all = 1; break; case OPT_COMMAND: if (i >= argc - 2) { goto wrongargs; } commandObj = argv[++i]; case OPT_EXACT: case OPT_GLOB: case OPT_REGEXP: opt_match = option; break; } } |
︙ | ︙ | |||
16835 16836 16837 16838 16839 16840 16841 | } rc = JIM_ERR; goto done; } break; } | | | | 16966 16967 16968 16969 16970 16971 16972 16973 16974 16975 16976 16977 16978 16979 16980 16981 16982 16983 16984 16985 16986 | } rc = JIM_ERR; goto done; } break; } if (!eq && opt_bool && opt_not && !opt_all) { continue; } if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) { Jim_Obj *resultObj; if (opt_bool) { resultObj = Jim_NewIntObj(interp, eq ^ opt_not); } else if (!opt_inline) { resultObj = Jim_NewIntObj(interp, i); |
︙ | ︙ | |||
16868 16869 16870 16871 16872 16873 16874 | } } if (opt_all) { Jim_SetResult(interp, listObjPtr); } else { | | | 16999 17000 17001 17002 17003 17004 17005 17006 17007 17008 17009 17010 17011 17012 17013 | } } if (opt_all) { Jim_SetResult(interp, listObjPtr); } else { if (opt_bool) { Jim_SetResultBool(interp, opt_not); } else if (!opt_inline) { Jim_SetResultInt(interp, -1); } } |
︙ | ︙ | |||
16897 16898 16899 16900 16901 16902 16903 | if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?"); return JIM_ERR; } listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!listObjPtr) { | | | 17028 17029 17030 17031 17032 17033 17034 17035 17036 17037 17038 17039 17040 17041 17042 | if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?"); return JIM_ERR; } listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!listObjPtr) { listObjPtr = Jim_NewListObj(interp, NULL, 0); new_obj = 1; } else if (Jim_IsShared(listObjPtr)) { listObjPtr = Jim_DuplicateObj(interp, listObjPtr); new_obj = 1; } |
︙ | ︙ | |||
16970 16971 16972 16973 16974 16975 16976 | len = Jim_ListLength(interp, listObj); first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, &first, &last, &rangeLen); | > | > > > > | > > > > | > | | | < | 17101 17102 17103 17104 17105 17106 17107 17108 17109 17110 17111 17112 17113 17114 17115 17116 17117 17118 17119 17120 17121 17122 17123 17124 17125 17126 17127 17128 17129 17130 17131 17132 17133 17134 17135 17136 17137 17138 17139 17140 17141 17142 17143 17144 17145 17146 17147 17148 17149 17150 17151 17152 17153 17154 17155 17156 17157 17158 17159 17160 17161 17162 17163 17164 17165 17166 17167 17168 17169 | len = Jim_ListLength(interp, listObj); first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, &first, &last, &rangeLen); if (first < len) { } else if (len == 0) { first = 0; } else { Jim_SetResultString(interp, "list doesn't contain element ", -1); Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]); return JIM_ERR; } newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first); ListInsertElements(newListObj, -1, argc - 4, argv + 4); ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen); Jim_SetResult(interp, newListObj); return JIM_OK; } static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal"); return JIM_ERR; } else if (argc == 3) { if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); return JIM_OK; } return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]); } static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[]) { static const char * const options[] = { "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL }; enum { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE }; Jim_Obj *resObj; int i; int retCode; struct lsort_info info; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "?options? list"); return JIM_ERR; } |
︙ | ︙ | |||
17081 17082 17083 17084 17085 17086 17087 | return JIM_ERR; } info.indexed = 1; i++; break; } } | < < | | | 17221 17222 17223 17224 17225 17226 17227 17228 17229 17230 17231 17232 17233 17234 17235 17236 17237 17238 17239 17240 | return JIM_ERR; } info.indexed = 1; i++; break; } } resObj = Jim_DuplicateObj(interp, argv[argc - 1]); retCode = ListSortElements(interp, resObj, &info); if (retCode == JIM_OK) { Jim_SetResult(interp, resObj); } else { Jim_FreeNewObj(interp, resObj); } return retCode; } static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
︙ | ︙ | |||
17113 17114 17115 17116 17117 17118 17119 | if (!stringObjPtr) return JIM_ERR; } else { int new_obj = 0; stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!stringObjPtr) { | | < | 17251 17252 17253 17254 17255 17256 17257 17258 17259 17260 17261 17262 17263 17264 17265 17266 17267 17268 17269 17270 17271 17272 17273 17274 17275 17276 17277 17278 17279 17280 17281 17282 17283 17284 17285 | if (!stringObjPtr) return JIM_ERR; } else { int new_obj = 0; stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!stringObjPtr) { stringObjPtr = Jim_NewEmptyStringObj(interp); new_obj = 1; } else if (Jim_IsShared(stringObjPtr)) { new_obj = 1; stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr); } for (i = 2; i < argc; i++) { Jim_AppendObj(interp, stringObjPtr, argv[i]); } if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) { if (new_obj) { Jim_FreeNewObj(interp, stringObjPtr); } return JIM_ERR; } } Jim_SetResult(interp, stringObjPtr); return JIM_OK; } static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #if !defined(JIM_DEBUG_COMMAND) Jim_SetResultString(interp, "unsupported", -1); return JIM_ERR; |
︙ | ︙ | |||
17163 17164 17165 17166 17167 17168 17169 | rc = Jim_EvalObj(interp, argv[1]); } else { rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); } if (rc == JIM_ERR) { | | | | | > | | > > | 17300 17301 17302 17303 17304 17305 17306 17307 17308 17309 17310 17311 17312 17313 17314 17315 17316 17317 17318 17319 17320 17321 17322 17323 17324 17325 17326 17327 17328 17329 17330 17331 17332 17333 17334 17335 17336 17337 17338 17339 17340 17341 17342 17343 17344 17345 17346 17347 17348 17349 17350 17351 17352 17353 17354 17355 17356 17357 17358 17359 17360 17361 17362 17363 17364 17365 17366 17367 17368 17369 17370 17371 17372 17373 17374 17375 17376 17377 17378 17379 17380 17381 17382 17383 17384 17385 17386 17387 17388 17389 | rc = Jim_EvalObj(interp, argv[1]); } else { rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); } if (rc == JIM_ERR) { interp->addStackTrace++; } return rc; } static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc >= 2) { int retcode; Jim_CallFrame *savedCallFrame, *targetCallFrame; const char *str; savedCallFrame = interp->framePtr; str = Jim_String(argv[1]); if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') { targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); argc--; argv++; } else { targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); } if (targetCallFrame == NULL) { return JIM_ERR; } if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?"); return JIM_ERR; } interp->framePtr = targetCallFrame; if (argc == 2) { retcode = Jim_EvalObj(interp, argv[1]); } else { retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); } interp->framePtr = savedCallFrame; return retcode; } else { Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); return JIM_ERR; } } static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *exprResultPtr; int retcode; if (argc == 2) { retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr); } else if (argc > 2) { Jim_Obj *objPtr; objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1); Jim_IncrRefCount(objPtr); retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr); Jim_DecrRefCount(interp, objPtr); } else { Jim_WrongNumArgs(interp, 1, argv, "expression ?...?"); return JIM_ERR; } if (retcode != JIM_OK) return retcode; Jim_SetResult(interp, exprResultPtr); Jim_DecrRefCount(interp, exprResultPtr); return JIM_OK; } static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { |
︙ | ︙ | |||
17296 17297 17298 17299 17300 17301 17302 | } if (i != argc - 1 && i != argc) { Jim_WrongNumArgs(interp, 1, argv, "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?"); } | | | | | | | | | 17436 17437 17438 17439 17440 17441 17442 17443 17444 17445 17446 17447 17448 17449 17450 17451 17452 17453 17454 17455 17456 17457 17458 17459 17460 17461 17462 17463 17464 17465 17466 17467 17468 17469 17470 17471 17472 17473 17474 17475 17476 17477 17478 17479 17480 17481 17482 17483 17484 17485 17486 17487 17488 17489 17490 17491 17492 17493 17494 17495 17496 17497 17498 17499 17500 17501 17502 17503 17504 17505 17506 | } if (i != argc - 1 && i != argc) { Jim_WrongNumArgs(interp, 1, argv, "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?"); } if (stackTraceObj && returnCode == JIM_ERR) { JimSetStackTrace(interp, stackTraceObj); } if (errorCodeObj && returnCode == JIM_ERR) { Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj); } interp->returnCode = returnCode; interp->returnLevel = level; if (i == argc - 1) { Jim_SetResult(interp, argv[i]); } return JIM_RETURN; } static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (interp->framePtr->level == 0) { Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1); return JIM_ERR; } else if (argc >= 2) { Jim_CallFrame *cf = interp->framePtr->parent; Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); if (cmdPtr == NULL) { return JIM_ERR; } JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd")); JimIncrCmdRefCount(cmdPtr); cf->tailcallCmd = cmdPtr; JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj")); cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1); Jim_IncrRefCount(cf->tailcallObj); return JIM_EVAL; } return JIM_OK; } static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *cmdList; Jim_Obj *prefixListObj = Jim_CmdPrivData(interp); cmdList = Jim_DuplicateObj(interp, prefixListObj); Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1); return JimEvalObjList(interp, cmdList); } static void JimAliasCmdDelete(Jim_Interp *interp, void *privData) |
︙ | ︙ | |||
17410 17411 17412 17413 17414 17415 17416 | cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL); } else { cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL); } if (cmd) { | | | | | | | 17550 17551 17552 17553 17554 17555 17556 17557 17558 17559 17560 17561 17562 17563 17564 17565 17566 17567 17568 17569 17570 17571 17572 17573 17574 17575 17576 17577 17578 17579 17580 17581 17582 17583 17584 17585 17586 17587 17588 17589 17590 17591 17592 17593 17594 17595 17596 17597 17598 | cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL); } else { cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL); } if (cmd) { Jim_Obj *qualifiedCmdNameObj; const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj); JimCreateCommand(interp, cmdname, cmd); JimUpdateProcNamespace(interp, cmd, cmdname); JimFreeQualifiedName(interp, qualifiedCmdNameObj); Jim_SetResult(interp, argv[1]); return JIM_OK; } return JIM_ERR; } static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retcode; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?"); return JIM_ERR; } interp->local++; retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); interp->local--; if (retcode == 0) { Jim_Obj *cmdNameObj = Jim_GetResult(interp); if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) { return JIM_ERR; } if (interp->framePtr->localCommands == NULL) { |
︙ | ︙ | |||
17477 17478 17479 17480 17481 17482 17483 | int retcode; Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) { Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]); return JIM_ERR; } | | | | | 17617 17618 17619 17620 17621 17622 17623 17624 17625 17626 17627 17628 17629 17630 17631 17632 17633 17634 17635 17636 17637 17638 | int retcode; Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) { Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]); return JIM_ERR; } cmdPtr->u.proc.upcall++; JimIncrCmdRefCount(cmdPtr); retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); cmdPtr->u.proc.upcall--; JimDecrCmdRefCount(interp, cmdPtr); return retcode; } } |
︙ | ︙ | |||
17515 17516 17517 17518 17519 17520 17521 | if (len != 2 && len != 3) { Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]); return JIM_ERR; } if (len == 3) { #ifdef jim_ext_namespace | | | | 17655 17656 17657 17658 17659 17660 17661 17662 17663 17664 17665 17666 17667 17668 17669 17670 17671 17672 17673 17674 17675 17676 17677 17678 17679 17680 17681 17682 | if (len != 2 && len != 3) { Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]); return JIM_ERR; } if (len == 3) { #ifdef jim_ext_namespace nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2)); #else Jim_SetResultString(interp, "namespaces not enabled", -1); return JIM_ERR; #endif } argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0); bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1); cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj); if (cmd) { nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv)); nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1); Jim_IncrRefCount(nargv[0]); memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv)); ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv); Jim_DecrRefCount(interp, nargv[0]); Jim_Free(nargv); |
︙ | ︙ | |||
17558 17559 17560 17561 17562 17563 17564 | static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; Jim_CallFrame *targetCallFrame; | | | | | | | | 17698 17699 17700 17701 17702 17703 17704 17705 17706 17707 17708 17709 17710 17711 17712 17713 17714 17715 17716 17717 17718 17719 17720 17721 17722 17723 17724 17725 17726 17727 17728 17729 17730 17731 17732 17733 17734 17735 17736 17737 17738 17739 17740 17741 17742 17743 17744 17745 17746 17747 17748 17749 17750 17751 17752 | static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; Jim_CallFrame *targetCallFrame; if (argc > 3 && (argc % 2 == 0)) { targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); argc--; argv++; } else { targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); } if (targetCallFrame == NULL) { return JIM_ERR; } if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?"); return JIM_ERR; } for (i = 1; i < argc; i += 2) { if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK) return JIM_ERR; } return JIM_OK; } static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?"); return JIM_ERR; } if (interp->framePtr->level == 0) return JIM_OK; for (i = 1; i < argc; i++) { const char *name = Jim_String(argv[i]); if (name[0] != ':' || name[1] != ':') { if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK) return JIM_ERR; } } return JIM_OK; |
︙ | ︙ | |||
17625 17626 17627 17628 17629 17630 17631 | Jim_SetResultString(interp, "list must contain an even number of elements", -1); return NULL; } str = Jim_String(objPtr); strLen = Jim_Utf8Length(interp, objPtr); | | | | | | | | 17765 17766 17767 17768 17769 17770 17771 17772 17773 17774 17775 17776 17777 17778 17779 17780 17781 17782 17783 17784 17785 17786 17787 17788 17789 17790 17791 17792 17793 17794 17795 17796 17797 17798 17799 17800 17801 17802 17803 17804 17805 17806 | Jim_SetResultString(interp, "list must contain an even number of elements", -1); return NULL; } str = Jim_String(objPtr); strLen = Jim_Utf8Length(interp, objPtr); resultObjPtr = Jim_NewStringObj(interp, "", 0); while (strLen) { for (i = 0; i < numMaps; i += 2) { Jim_Obj *objPtr; const char *k; int kl; objPtr = Jim_ListGetIndex(interp, mapListObjPtr, i); k = Jim_String(objPtr); kl = Jim_Utf8Length(interp, objPtr); if (strLen >= kl && kl) { int rc; rc = JimStringCompareLen(str, k, kl, nocase); if (rc == 0) { if (noMatchStart) { Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); noMatchStart = NULL; } Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1)); str += utf8_index(str, kl); strLen -= kl; break; } } } if (i == numMaps) { int c; if (noMatchStart == NULL) noMatchStart = str; str += utf8_tounicode(str, &c); strLen--; } } |
︙ | ︙ | |||
17696 17697 17698 17699 17700 17701 17702 | if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) | | | | | | | | 17836 17837 17838 17839 17840 17841 17842 17843 17844 17845 17846 17847 17848 17849 17850 17851 17852 17853 17854 17855 17856 17857 17858 17859 17860 17861 17862 17863 17864 17865 17866 17867 17868 17869 17870 17871 17872 17873 17874 17875 17876 17877 17878 17879 17880 17881 17882 17883 17884 17885 17886 17887 17888 17889 17890 17891 17892 17893 17894 17895 17896 17897 17898 17899 17900 17901 17902 17903 17904 17905 17906 17907 17908 17909 17910 17911 17912 17913 17914 17915 17916 17917 17918 17919 17920 17921 17922 17923 | if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) return JIM_ERR; switch (option) { case OPT_LENGTH: case OPT_BYTELENGTH: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; } if (option == OPT_LENGTH) { len = Jim_Utf8Length(interp, argv[2]); } else { len = Jim_Length(argv[2]); } Jim_SetResultInt(interp, len); return JIM_OK; case OPT_CAT:{ Jim_Obj *objPtr; if (argc == 3) { objPtr = argv[2]; } else { int i; objPtr = Jim_NewStringObj(interp, "", 0); for (i = 2; i < argc; i++) { Jim_AppendObj(interp, objPtr, argv[i]); } } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_COMPARE: case OPT_EQUAL: { long opt_length = -1; int n = argc - 4; int i = 2; while (n > 0) { int subopt; if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL, JIM_ENUM_ABBREV) != JIM_OK) { badcompareargs: Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2"); return JIM_ERR; } if (subopt == 0) { opt_case = 0; n--; } else { if (n < 2) { goto badcompareargs; } if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) { return JIM_ERR; } n -= 2; } } if (n) { goto badcompareargs; } argv += argc - 2; if (opt_length < 0 && option != OPT_COMPARE && opt_case) { Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1])); } else { if (opt_length >= 0) { n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case); } else { |
︙ | ︙ | |||
17883 17884 17885 17886 17887 17888 17889 17890 17891 17892 17893 17894 17895 17896 | Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_REVERSE:{ char *buf, *p; const char *str; int i; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; } | > | 18023 18024 18025 18026 18027 18028 18029 18030 18031 18032 18033 18034 18035 18036 18037 | Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_REVERSE:{ char *buf, *p; const char *str; int len; int i; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; } |
︙ | ︙ | |||
17926 17927 17928 17929 17930 17931 17932 | if (idx != INT_MIN && idx != INT_MAX) { idx = JimRelToAbsIndex(len, idx); } if (idx < 0 || idx >= len || str == NULL) { Jim_SetResultString(interp, "", 0); } else if (len == Jim_Length(argv[2])) { | | | 18067 18068 18069 18070 18071 18072 18073 18074 18075 18076 18077 18078 18079 18080 18081 | if (idx != INT_MIN && idx != INT_MAX) { idx = JimRelToAbsIndex(len, idx); } if (idx < 0 || idx >= len || str == NULL) { Jim_SetResultString(interp, "", 0); } else if (len == Jim_Length(argv[2])) { Jim_SetResultString(interp, str + idx, 1); } else { int c; int i = utf8_index(str, idx); Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c)); } |
︙ | ︙ | |||
18080 18081 18082 18083 18084 18085 18086 | static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int exitCode = 0; int i; int sig = 0; | | | | 18221 18222 18223 18224 18225 18226 18227 18228 18229 18230 18231 18232 18233 18234 18235 18236 18237 18238 18239 18240 18241 18242 18243 18244 18245 18246 | static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int exitCode = 0; int i; int sig = 0; jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL); static const int max_ignore_code = sizeof(ignore_mask) * 8; Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1)); for (i = 1; i < argc - 1; i++) { const char *arg = Jim_String(argv[i]); jim_wide option; int ignore; if (strcmp(arg, "--") == 0) { i++; break; } if (*arg != '-') { break; } |
︙ | ︙ | |||
18142 18143 18144 18145 18146 18147 18148 | if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) { sig++; } interp->signal_level += sig; if (Jim_CheckSignal(interp)) { | | | | | | | 18283 18284 18285 18286 18287 18288 18289 18290 18291 18292 18293 18294 18295 18296 18297 18298 18299 18300 18301 18302 18303 18304 18305 18306 18307 18308 18309 18310 18311 18312 18313 18314 | if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) { sig++; } interp->signal_level += sig; if (Jim_CheckSignal(interp)) { exitCode = JIM_SIGNAL; } else { exitCode = Jim_EvalObj(interp, argv[0]); interp->errorFlag = 0; } interp->signal_level -= sig; if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) { return exitCode; } if (sig && exitCode == JIM_SIGNAL) { if (interp->signal_set_result) { interp->signal_set_result(interp, interp->sigmask); } else { Jim_SetResultInt(interp, interp->sigmask); } interp->sigmask = 0; |
︙ | ︙ | |||
18202 18203 18204 18205 18206 18207 18208 18209 18210 18211 18212 18213 18214 18215 18216 18217 18218 18219 18220 18221 18222 18223 18224 | } } } Jim_SetResultInt(interp, exitCode); return JIM_OK; } static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "oldName newName"); return JIM_ERR; } if (JimValidName(interp, "new procedure", argv[2])) { return JIM_ERR; } return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2])); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | > | > | > > | > > > > > > | > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < | | | | | < > > | | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 18343 18344 18345 18346 18347 18348 18349 18350 18351 18352 18353 18354 18355 18356 18357 18358 18359 18360 18361 18362 18363 18364 18365 18366 18367 18368 18369 18370 18371 18372 18373 18374 18375 18376 18377 18378 18379 18380 18381 18382 18383 18384 18385 18386 18387 18388 18389 18390 18391 18392 18393 18394 18395 18396 18397 18398 18399 18400 18401 18402 18403 18404 18405 18406 18407 18408 18409 18410 18411 18412 18413 18414 18415 18416 18417 18418 18419 18420 18421 18422 18423 18424 18425 18426 18427 18428 18429 18430 18431 18432 18433 18434 18435 18436 18437 18438 18439 18440 18441 18442 18443 18444 18445 18446 18447 18448 18449 18450 18451 18452 18453 18454 18455 18456 18457 18458 18459 18460 18461 18462 18463 18464 18465 18466 18467 18468 18469 18470 18471 18472 18473 18474 18475 18476 18477 18478 18479 18480 18481 18482 18483 18484 18485 18486 18487 18488 18489 18490 18491 18492 18493 18494 18495 18496 18497 18498 18499 18500 18501 18502 18503 18504 18505 18506 18507 18508 18509 18510 18511 18512 18513 18514 18515 18516 18517 18518 18519 18520 18521 18522 18523 18524 18525 18526 18527 18528 18529 18530 18531 18532 18533 18534 18535 18536 18537 18538 18539 18540 18541 18542 18543 18544 18545 18546 18547 18548 18549 18550 18551 18552 18553 18554 18555 18556 18557 18558 18559 18560 18561 18562 18563 18564 18565 18566 18567 18568 18569 18570 18571 18572 18573 18574 18575 18576 18577 18578 18579 18580 18581 18582 18583 18584 18585 18586 18587 18588 18589 18590 18591 18592 18593 18594 18595 18596 18597 18598 18599 18600 18601 18602 18603 18604 18605 18606 18607 18608 | } } } Jim_SetResultInt(interp, exitCode); return JIM_OK; } #ifdef JIM_REFERENCES static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?"); return JIM_ERR; } if (argc == 3) { Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL)); } else { Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3])); } return JIM_OK; } static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Reference *refPtr; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "reference"); return JIM_ERR; } if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL) return JIM_ERR; Jim_SetResult(interp, refPtr->objPtr); return JIM_OK; } static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Reference *refPtr; if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "reference newValue"); return JIM_ERR; } if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL) return JIM_ERR; Jim_IncrRefCount(argv[2]); Jim_DecrRefCount(interp, refPtr->objPtr); refPtr->objPtr = argv[2]; Jim_SetResult(interp, argv[2]); return JIM_OK; } static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, ""); return JIM_ERR; } Jim_SetResultInt(interp, Jim_Collect(interp)); while (interp->freeList) { Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr; Jim_Free(interp->freeList); interp->freeList = nextObjPtr; } return JIM_OK; } static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?"); return JIM_ERR; } if (argc == 2) { Jim_Obj *cmdNamePtr; if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK) return JIM_ERR; if (cmdNamePtr != NULL) Jim_SetResult(interp, cmdNamePtr); } else { if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); } return JIM_OK; } static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; Jim_HashTableIterator htiter; Jim_HashEntry *he; listObjPtr = Jim_NewListObj(interp, NULL, 0); JimInitHashTableIterator(&interp->references, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { char buf[JIM_REFERENCE_SPACE + 1]; Jim_Reference *refPtr = Jim_GetHashEntryVal(he); const unsigned long *refId = he->key; JimFormatReference(buf, refPtr, *refId); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1)); } Jim_SetResult(interp, listObjPtr); return JIM_OK; } #endif static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "oldName newName"); return JIM_ERR; } if (JimValidName(interp, "new procedure", argv[2])) { return JIM_ERR; } return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2])); } #define JIM_DICTMATCH_VALUES 0x0001 typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type); static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key); if (type & JIM_DICTMATCH_VALUES) { Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he)); } } static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, JimDictMatchCallbackType *callback, int type) { Jim_HashEntry *he; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); Jim_HashTableIterator htiter; JimInitHashTableIterator(ht, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) { callback(interp, listObjPtr, he, type); } } return listObjPtr; } int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr) { if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, 0)); return JIM_OK; } int Jim_DictValues(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr) { if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, JIM_DICTMATCH_VALUES)); return JIM_OK; } int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr) { if (SetDictFromAny(interp, objPtr) != JIM_OK) { return -1; } return ((Jim_HashTable *)objPtr->internalRep.ptr)->used; } int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_HashTable *ht; unsigned int i; if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } ht = (Jim_HashTable *)objPtr->internalRep.ptr; printf("%d entries in table, %d buckets\n", ht->used, ht->size); for (i = 0; i < ht->size; i++) { Jim_HashEntry *he = ht->table[i]; if (he) { printf("%d: ", i); while (he) { printf(" %s", Jim_String(he->key)); he = he->next; } printf("\n"); } } return JIM_OK; } static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv) { Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1); Jim_AppendString(interp, prefixObj, " ", 1); Jim_AppendString(interp, prefixObj, subcmd, -1); return Jim_EvalObjPrefix(interp, prefixObj, argc, argv); } static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; int option; static const char * const options[] = { "create", "get", "set", "unset", "exists", "keys", "size", "info", "merge", "with", "append", "lappend", "incr", "remove", "values", "for", "replace", "update", NULL }; enum { OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXISTS, OPT_KEYS, OPT_SIZE, OPT_INFO, OPT_MERGE, OPT_WITH, OPT_APPEND, OPT_LAPPEND, OPT_INCR, OPT_REMOVE, OPT_VALUES, OPT_FOR, OPT_REPLACE, OPT_UPDATE, }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } switch (option) { case OPT_GET: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "dictionary ?key ...?"); return JIM_ERR; |
︙ | ︙ | |||
18472 18473 18474 18475 18476 18477 18478 | return JIM_ERR; } if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) { return JIM_ERR; } return JIM_OK; | < < < | | < | | | | < < < < | < < < | 18641 18642 18643 18644 18645 18646 18647 18648 18649 18650 18651 18652 18653 18654 18655 18656 18657 18658 18659 18660 18661 18662 18663 18664 18665 18666 18667 18668 18669 18670 18671 18672 18673 18674 18675 18676 18677 18678 18679 18680 18681 18682 18683 18684 18685 18686 18687 18688 18689 18690 18691 18692 18693 18694 18695 18696 18697 18698 18699 18700 18701 18702 18703 18704 18705 18706 | return JIM_ERR; } if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) { return JIM_ERR; } return JIM_OK; case OPT_KEYS: if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?"); return JIM_ERR; } return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL); case OPT_SIZE: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "dictionary"); return JIM_ERR; } else if (Jim_DictSize(interp, argv[2]) < 0) { return JIM_ERR; } Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2])); return JIM_OK; case OPT_MERGE: if (argc == 2) { return JIM_OK; } if (Jim_DictSize(interp, argv[2]) < 0) { return JIM_ERR; } break; case OPT_UPDATE: if (argc < 6 || argc % 2) { argc = 2; } break; case OPT_CREATE: if (argc % 2) { Jim_WrongNumArgs(interp, 2, argv, "?key value ...?"); return JIM_ERR; } objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2); Jim_SetResult(interp, objPtr); return JIM_OK; case OPT_INFO: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "dictionary"); return JIM_ERR; } return Jim_DictInfo(interp, argv[2]); } return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2); } static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static const char * const options[] = { |
︙ | ︙ | |||
18604 18605 18606 18607 18608 18609 18610 | INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS, }; #ifdef jim_ext_namespace int nons = 0; if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { | | | > | | | 18762 18763 18764 18765 18766 18767 18768 18769 18770 18771 18772 18773 18774 18775 18776 18777 18778 18779 18780 18781 18782 18783 18784 18785 18786 18787 18788 18789 18790 18791 18792 | INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS, }; #ifdef jim_ext_namespace int nons = 0; if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { argc--; argv++; nons = 1; } #endif if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; } switch (cmd) { case INFO_EXISTS: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "varName"); return JIM_ERR; } Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL); |
︙ | ︙ | |||
18648 18649 18650 18651 18652 18653 18654 | return JIM_ERR; } Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData); return JIM_OK; } case INFO_CHANNELS: | | | | | | | | | | | | 18807 18808 18809 18810 18811 18812 18813 18814 18815 18816 18817 18818 18819 18820 18821 18822 18823 18824 18825 18826 18827 18828 18829 18830 18831 18832 18833 18834 18835 18836 18837 18838 18839 18840 18841 18842 18843 18844 18845 18846 18847 18848 18849 18850 18851 18852 18853 | return JIM_ERR; } Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData); return JIM_OK; } case INFO_CHANNELS: mode++; #ifndef jim_ext_aio Jim_SetResultString(interp, "aio not enabled", -1); return JIM_ERR; #endif case INFO_PROCS: mode++; case INFO_COMMANDS: if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; } #ifdef jim_ext_namespace if (!nons) { if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) { return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); } } #endif Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode)); break; case INFO_VARS: mode++; case INFO_LOCALS: mode++; case INFO_GLOBALS: if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; } #ifdef jim_ext_namespace if (!nons) { if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) { |
︙ | ︙ | |||
18790 18791 18792 18793 18794 18795 18796 18797 | Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr); break; case INFO_ARGS: Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr); break; case INFO_STATICS: if (cmdPtr->u.proc.staticVars) { Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars, | > | | 18949 18950 18951 18952 18953 18954 18955 18956 18957 18958 18959 18960 18961 18962 18963 18964 18965 | Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr); break; case INFO_ARGS: Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr); break; case INFO_STATICS: if (cmdPtr->u.proc.staticVars) { int mode = JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES; Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars, NULL, JimVariablesMatch, mode)); } break; } break; } case INFO_VERSION: |
︙ | ︙ | |||
18823 18824 18825 18826 18827 18828 18829 | if (missing != ' ' && argc == 4) { Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1)); } } break; case INFO_HOSTNAME: | | | | 18983 18984 18985 18986 18987 18988 18989 18990 18991 18992 18993 18994 18995 18996 18997 18998 18999 19000 19001 | if (missing != ' ' && argc == 4) { Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1)); } } break; case INFO_HOSTNAME: return Jim_Eval(interp, "os.gethostname"); case INFO_NAMEOFEXECUTABLE: return Jim_Eval(interp, "{info nameofexecutable}"); case INFO_RETURNCODES: if (argc == 2) { int i; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); |
︙ | ︙ | |||
18908 18909 18910 18911 18912 18913 18914 | return JIM_ERR; } if (option == OPT_VAR) { result = Jim_GetVariable(interp, objPtr, 0) != NULL; } else { | | | 19068 19069 19070 19071 19072 19073 19074 19075 19076 19077 19078 19079 19080 19081 19082 | return JIM_ERR; } if (option == OPT_VAR) { result = Jim_GetVariable(interp, objPtr, 0) != NULL; } else { Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE); if (cmd) { switch (option) { case OPT_COMMAND: result = 1; break; |
︙ | ︙ | |||
18951 18952 18953 18954 18955 18956 18957 | str = Jim_GetString(argv[1], &len); if (len == 0) { return JIM_OK; } strLen = Jim_Utf8Length(interp, argv[1]); | | | | 19111 19112 19113 19114 19115 19116 19117 19118 19119 19120 19121 19122 19123 19124 19125 19126 19127 19128 19129 19130 19131 19132 19133 19134 19135 19136 19137 19138 | str = Jim_GetString(argv[1], &len); if (len == 0) { return JIM_OK; } strLen = Jim_Utf8Length(interp, argv[1]); if (argc == 2) { splitChars = " \n\t\r"; splitLen = 4; } else { splitChars = Jim_String(argv[2]); splitLen = Jim_Utf8Length(interp, argv[2]); } noMatchStart = str; resObjPtr = Jim_NewListObj(interp, NULL, 0); if (splitLen) { Jim_Obj *objPtr; while (strLen--) { const char *sc = splitChars; int scLen = splitLen; int sl = utf8_tounicode(str, &c); while (scLen--) { |
︙ | ︙ | |||
18993 18994 18995 18996 18997 18998 18999 | else { Jim_Obj **commonObj = NULL; #define NUM_COMMON (128 - 9) while (strLen--) { int n = utf8_tounicode(str, &c); #ifdef JIM_OPTIMIZATION if (c >= 9 && c < 128) { | | | 19153 19154 19155 19156 19157 19158 19159 19160 19161 19162 19163 19164 19165 19166 19167 | else { Jim_Obj **commonObj = NULL; #define NUM_COMMON (128 - 9) while (strLen--) { int n = utf8_tounicode(str, &c); #ifdef JIM_OPTIMIZATION if (c >= 9 && c < 128) { c -= 9; if (!commonObj) { commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON); memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON); } if (!commonObj[c]) { commonObj[c] = Jim_NewStringObj(interp, str, 1); |
︙ | ︙ | |||
19027 19028 19029 19030 19031 19032 19033 | const char *joinStr; int joinStrLen; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?"); return JIM_ERR; } | | | 19187 19188 19189 19190 19191 19192 19193 19194 19195 19196 19197 19198 19199 19200 19201 | const char *joinStr; int joinStrLen; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?"); return JIM_ERR; } if (argc == 2) { joinStr = " "; joinStrLen = 1; } else { joinStr = Jim_GetString(argv[2], &joinStrLen); } |
︙ | ︙ | |||
19306 19307 19308 19309 19310 19311 19312 | return 0; else if (step > 0 && start > end) return -1; else if (step < 0 && end > start) return -1; len = end - start; if (len < 0) | | | | 19466 19467 19468 19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480 19481 19482 | return 0; else if (step > 0 && start > end) return -1; else if (step < 0 && end > start) return -1; len = end - start; if (len < 0) len = -len; if (step < 0) step = -step; len = 1 + ((len - 1) / step); if (len > INT_MAX) len = INT_MAX; return (int)((len < 0) ? -1 : len); } |
︙ | ︙ | |||
19482 19483 19484 19485 19486 19487 19488 | argv[0] = Jim_NewStringObj(interp, "errorInfo", -1); argv[1] = interp->result; Jim_EvalObjVector(interp, 2, argv); } | > | | < < < < < < < < < < < < < < < | | | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < | 19642 19643 19644 19645 19646 19647 19648 19649 19650 19651 19652 19653 19654 19655 19656 19657 19658 19659 19660 19661 19662 19663 19664 19665 19666 19667 19668 19669 19670 19671 19672 19673 19674 19675 19676 19677 19678 19679 19680 19681 19682 19683 19684 19685 19686 19687 19688 19689 19690 19691 19692 19693 19694 19695 19696 19697 19698 19699 19700 19701 19702 19703 19704 19705 19706 19707 19708 19709 19710 19711 19712 19713 19714 19715 19716 19717 19718 19719 | argv[0] = Jim_NewStringObj(interp, "errorInfo", -1); argv[1] = interp->result; Jim_EvalObjVector(interp, 2, argv); } static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char *const *tablePtr, const char *name) { int count; char **tablePtrSorted; int i; for (count = 0; tablePtr[count]; count++) { } if (name == NULL) { name = "option"; } Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg); tablePtrSorted = Jim_Alloc(sizeof(char *) * count); memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count); qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers); for (i = 0; i < count; i++) { if (i + 1 == count && count > 1) { Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1); } Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL); if (i + 1 != count) { Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1); } } Jim_Free(tablePtrSorted); } int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr, int *indexPtr, const char *name, int flags) { const char *bad = "bad "; const char *const *entryPtr = NULL; int i; int match = -1; int arglen; const char *arg = Jim_GetString(objPtr, &arglen); *indexPtr = -1; for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) { if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) { *indexPtr = i; return JIM_OK; } if (flags & JIM_ENUM_ABBREV) { if (strncmp(arg, *entryPtr, arglen) == 0) { if (*arg == '-' && arglen == 1) { break; } if (match >= 0) { bad = "ambiguous "; goto ambiguous; } match = i; } } } if (match >= 0) { *indexPtr = match; return JIM_OK; } ambiguous: if (flags & JIM_ERRMSG) { JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name); |
︙ | ︙ | |||
19634 19635 19636 19637 19638 19639 19640 | int Jim_IsList(Jim_Obj *objPtr) { return objPtr->typePtr == &listObjType; } void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...) { | | < < < < < < < < | 19741 19742 19743 19744 19745 19746 19747 19748 19749 19750 19751 19752 19753 19754 19755 19756 19757 19758 19759 19760 19761 19762 19763 19764 19765 19766 19767 19768 19769 19770 19771 19772 19773 19774 19775 19776 19777 19778 19779 19780 19781 19782 19783 19784 19785 19786 19787 19788 19789 19790 19791 19792 19793 19794 19795 | int Jim_IsList(Jim_Obj *objPtr) { return objPtr->typePtr == &listObjType; } void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...) { int len = strlen(format); int extra = 0; int n = 0; const char *params[5]; char *buf; va_list args; int i; va_start(args, format); for (i = 0; i < len && n < 5; i++) { int l; if (strncmp(format + i, "%s", 2) == 0) { params[n] = va_arg(args, char *); l = strlen(params[n]); } else if (strncmp(format + i, "%#s", 3) == 0) { Jim_Obj *objPtr = va_arg(args, Jim_Obj *); params[n] = Jim_GetString(objPtr, &l); } else { if (format[i] == '%') { i++; } continue; } n++; extra += l; } len += extra; buf = Jim_Alloc(len + 1); len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]); va_end(args); Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); } #ifndef jim_ext_package int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags) { return JIM_OK; |
︙ | ︙ | |||
19707 19708 19709 19710 19711 19712 19713 | #include <stdio.h> #include <string.h> static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { | | | 19806 19807 19808 19809 19810 19811 19812 19813 19814 19815 19816 19817 19818 19819 19820 | #include <stdio.h> #include <string.h> static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JIM_OK; } static const jim_subcmd_type dummy_subcmd = { "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN }; |
︙ | ︙ | |||
19730 19731 19732 19733 19734 19735 19736 | } } } static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type, Jim_Obj *cmd, Jim_Obj *subcmd) { | > > | > > | | 19829 19830 19831 19832 19833 19834 19835 19836 19837 19838 19839 19840 19841 19842 19843 19844 19845 19846 19847 19848 19849 19850 19851 19852 19853 19854 | } } } static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type, Jim_Obj *cmd, Jim_Obj *subcmd) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type, " command \"", Jim_String(subcmd), "\": should be ", NULL); add_commands(interp, command_table, ", "); } static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc, Jim_Obj *const *argv) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]), " command ... \", where command is one of: ", NULL); add_commands(interp, command_table, ", "); } static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd) { if (cmd) { Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL); |
︙ | ︙ | |||
19759 19760 19761 19762 19763 19764 19765 | static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd) { Jim_SetResultString(interp, "wrong # args: should be \"", -1); add_cmd_usage(interp, command_table, subcmd); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); } | < < < < < < < < > > > > | > | | < < < < < < < < | | | | | | | | | | | | < < < < < < < | | | 19862 19863 19864 19865 19866 19867 19868 19869 19870 19871 19872 19873 19874 19875 19876 19877 19878 19879 19880 19881 19882 19883 19884 19885 19886 19887 19888 19889 19890 19891 19892 19893 19894 19895 19896 19897 19898 19899 19900 19901 19902 19903 19904 19905 19906 19907 19908 19909 19910 19911 19912 19913 19914 19915 19916 19917 19918 19919 19920 19921 19922 19923 19924 19925 19926 19927 19928 19929 19930 19931 19932 19933 19934 19935 19936 19937 19938 19939 19940 19941 19942 19943 19944 19945 19946 19947 19948 19949 19950 19951 19952 19953 19954 19955 19956 19957 19958 19959 19960 19961 19962 19963 19964 19965 19966 19967 19968 19969 19970 19971 19972 19973 19974 19975 19976 | static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd) { Jim_SetResultString(interp, "wrong # args: should be \"", -1); add_cmd_usage(interp, command_table, subcmd); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); } const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc, Jim_Obj *const *argv) { const jim_subcmd_type *ct; const jim_subcmd_type *partial = 0; int cmdlen; Jim_Obj *cmd; const char *cmdstr; const char *cmdname; int help = 0; cmdname = Jim_String(argv[0]); if (argc < 2) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname, " command ...\"\n", NULL); Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help ?command?\" for help", NULL); return 0; } cmd = argv[1]; if (Jim_CompareStringImmediate(interp, cmd, "-help")) { if (argc == 2) { show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } help = 1; cmd = argv[2]; } if (Jim_CompareStringImmediate(interp, cmd, "-commands")) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); add_commands(interp, command_table, " "); return &dummy_subcmd; } cmdstr = Jim_GetString(cmd, &cmdlen); for (ct = command_table; ct->cmd; ct++) { if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) { break; } if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) { if (partial) { if (help) { show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]); return 0; } partial = ct; } continue; } if (partial && !ct->cmd) { ct = partial; } if (!ct->cmd) { if (help) { show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]); return 0; } if (help) { Jim_SetResultString(interp, "Usage: ", -1); add_cmd_usage(interp, ct, argv[0]); return &dummy_subcmd; } if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) { Jim_SetResultString(interp, "wrong # args: should be \"", -1); add_cmd_usage(interp, ct, argv[0]); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); return 0; } return ct; } int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv) { int ret = JIM_ERR; |
︙ | ︙ | |||
19932 19933 19934 19935 19936 19937 19938 | } else if (uc <= 0xffff) { *p++ = 0xe0 | ((uc & 0xf000) >> 12); *p++ = 0x80 | ((uc & 0xfc0) >> 6); *p = 0x80 | (uc & 0x3f); return 3; } | | | 20017 20018 20019 20020 20021 20022 20023 20024 20025 20026 20027 20028 20029 20030 20031 | } else if (uc <= 0xffff) { *p++ = 0xe0 | ((uc & 0xf000) >> 12); *p++ = 0x80 | ((uc & 0xfc0) >> 6); *p = 0x80 | (uc & 0x3f); return 3; } else { *p++ = 0xf0 | ((uc & 0x1c0000) >> 18); *p++ = 0x80 | ((uc & 0x3f000) >> 12); *p++ = 0x80 | ((uc & 0xfc0) >> 6); *p = 0x80 | (uc & 0x3f); return 4; } |
︙ | ︙ | |||
20059 20060 20061 20062 20063 20064 20065 | default: sawFlag = 0; continue; } *p++ = ch; format += step; step = utf8_tounicode(format, &ch); | < | | 20144 20145 20146 20147 20148 20149 20150 20151 20152 20153 20154 20155 20156 20157 20158 | default: sawFlag = 0; continue; } *p++ = ch; format += step; step = utf8_tounicode(format, &ch); } while (sawFlag); width = 0; if (isdigit(ch)) { width = strtoul(format, &end, 10); format = end; step = utf8_tounicode(format, &ch); |
︙ | ︙ | |||
20124 20125 20126 20127 20128 20129 20130 | useShort = 0; if (ch == 'h') { useShort = 1; format += step; step = utf8_tounicode(format, &ch); } else if (ch == 'l') { | | | 20208 20209 20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 | useShort = 0; if (ch == 'h') { useShort = 1; format += step; step = utf8_tounicode(format, &ch); } else if (ch == 'l') { format += step; step = utf8_tounicode(format, &ch); if (ch == 'l') { format += step; step = utf8_tounicode(format, &ch); } } |
︙ | ︙ | |||
20151 20152 20153 20154 20155 20156 20157 | case '\0': msg = "format string ended in middle of field specifier"; goto errorMsg; case 's': { formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes); formatted_chars = Jim_Utf8Length(interp, objv[objIndex]); if (gotPrecision && (precision < formatted_chars)) { | | | | | 20235 20236 20237 20238 20239 20240 20241 20242 20243 20244 20245 20246 20247 20248 20249 20250 20251 20252 20253 20254 20255 20256 20257 20258 20259 20260 20261 20262 20263 20264 20265 20266 20267 20268 20269 20270 20271 20272 20273 20274 20275 20276 20277 20278 20279 | case '\0': msg = "format string ended in middle of field specifier"; goto errorMsg; case 's': { formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes); formatted_chars = Jim_Utf8Length(interp, objv[objIndex]); if (gotPrecision && (precision < formatted_chars)) { formatted_chars = precision; formatted_bytes = utf8_index(formatted_buf, precision); } break; } case 'c': { jim_wide code; if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) { goto error; } formatted_bytes = utf8_getchars(spec, code); formatted_buf = spec; formatted_chars = 1; break; } case 'b': { unsigned jim_wide w; int length; int i; int j; if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) { goto error; } length = sizeof(w) * 8; if (num_buffer_size < length + 1) { num_buffer_size = length + 1; num_buffer = Jim_Realloc(num_buffer, num_buffer_size); } j = 0; for (i = length; i > 0; ) { |
︙ | ︙ | |||
20209 20210 20211 20212 20213 20214 20215 | case 'e': case 'E': case 'f': case 'g': case 'G': doubleType = 1; | | | | | 20293 20294 20295 20296 20297 20298 20299 20300 20301 20302 20303 20304 20305 20306 20307 20308 20309 20310 20311 20312 20313 20314 20315 20316 20317 20318 20319 20320 20321 20322 20323 20324 20325 | case 'e': case 'E': case 'f': case 'g': case 'G': doubleType = 1; case 'd': case 'u': case 'o': case 'x': case 'X': { jim_wide w; double d; int length; if (width) { p += sprintf(p, "%ld", width); } if (gotPrecision) { p += sprintf(p, ".%ld", precision); } if (doubleType) { if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) { goto error; } length = MAX_FLOAT_WIDTH; } else { |
︙ | ︙ | |||
20258 20259 20260 20261 20262 20263 20264 | } #endif } *p++ = (char) ch; *p = '\0'; | | < < < < < < < | | | 20342 20343 20344 20345 20346 20347 20348 20349 20350 20351 20352 20353 20354 20355 20356 20357 20358 20359 20360 20361 20362 20363 20364 20365 20366 20367 20368 20369 20370 20371 20372 20373 20374 20375 20376 20377 20378 20379 20380 20381 20382 | } #endif } *p++ = (char) ch; *p = '\0'; if (width > length) { length = width; } if (gotPrecision) { length += precision; } if (num_buffer_size < length + 1) { num_buffer_size = length + 1; num_buffer = Jim_Realloc(num_buffer, num_buffer_size); } if (doubleType) { snprintf(num_buffer, length + 1, spec, d); } else { formatted_bytes = snprintf(num_buffer, length + 1, spec, w); } formatted_chars = formatted_bytes = strlen(num_buffer); formatted_buf = num_buffer; break; } default: { spec[0] = ch; spec[1] = '\0'; Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec); goto error; } } |
︙ | ︙ | |||
20343 20344 20345 20346 20347 20348 20349 | #define REG_MAX_PAREN 100 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 20420 20421 20422 20423 20424 20425 20426 20427 20428 20429 20430 20431 20432 20433 20434 20435 20436 20437 20438 20439 20440 20441 20442 20443 20444 20445 20446 20447 20448 20449 20450 20451 20452 20453 20454 20455 20456 20457 20458 20459 20460 20461 20462 20463 20464 20465 20466 20467 20468 20469 20470 20471 20472 20473 20474 20475 20476 20477 20478 20479 20480 20481 20482 20483 20484 | #define REG_MAX_PAREN 100 #define END 0 #define BOL 1 #define EOL 2 #define ANY 3 #define ANYOF 4 #define ANYBUT 5 #define BRANCH 6 #define BACK 7 #define EXACTLY 8 #define NOTHING 9 #define REP 10 #define REPMIN 11 #define REPX 12 #define REPXMIN 13 #define BOLX 14 #define EOLX 15 #define WORDA 16 #define WORDZ 17 #define OPENNC 1000 #define OPEN 1001 #define CLOSENC 2000 #define CLOSE 2001 #define CLOSE_END (CLOSE+REG_MAX_PAREN) #define REG_MAGIC 0xFADED00D #define OP(preg, p) (preg->program[p]) #define NEXT(preg, p) (preg->program[p + 1]) #define OPERAND(p) ((p) + 2) #define FAIL(R,M) { (R)->err = (M); return (M); } #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{') #define META "^$.[()|?{+*" #define HASWIDTH 1 #define SIMPLE 2 #define SPSTART 4 #define WORST 0 #define MAX_REP_COUNT 1000000 static int reg(regex_t *preg, int paren , int *flagp ); static int regpiece(regex_t *preg, int *flagp ); static int regbranch(regex_t *preg, int *flagp ); static int regatom(regex_t *preg, int *flagp ); static int regnode(regex_t *preg, int op ); static int regnext(regex_t *preg, int p ); static void regc(regex_t *preg, int b ); static int reginsert(regex_t *preg, int op, int size, int opnd ); |
︙ | ︙ | |||
20441 20442 20443 20444 20445 20446 20447 | fprintf(stderr, "Compiling: '%s'\n", exp); #endif memset(preg, 0, sizeof(*preg)); if (exp == NULL) FAIL(preg, REG_ERR_NULL_ARGUMENT); | | | | | | | | | | | 20518 20519 20520 20521 20522 20523 20524 20525 20526 20527 20528 20529 20530 20531 20532 20533 20534 20535 20536 20537 20538 20539 20540 20541 20542 20543 20544 20545 20546 20547 20548 20549 20550 20551 20552 20553 20554 20555 20556 20557 20558 20559 20560 | fprintf(stderr, "Compiling: '%s'\n", exp); #endif memset(preg, 0, sizeof(*preg)); if (exp == NULL) FAIL(preg, REG_ERR_NULL_ARGUMENT); preg->cflags = cflags; preg->regparse = exp; preg->proglen = (strlen(exp) + 1) * 5; preg->program = malloc(preg->proglen * sizeof(int)); if (preg->program == NULL) FAIL(preg, REG_ERR_NOMEM); regc(preg, REG_MAGIC); if (reg(preg, 0, &flags) == 0) { return preg->err; } if (preg->re_nsub >= REG_MAX_PAREN) FAIL(preg,REG_ERR_TOO_BIG); preg->regstart = 0; preg->reganch = 0; preg->regmust = 0; preg->regmlen = 0; scan = 1; if (OP(preg, regnext(preg, scan)) == END) { scan = OPERAND(scan); if (OP(preg, scan) == EXACTLY) { preg->regstart = preg->program[OPERAND(scan)]; } else if (OP(preg, scan) == BOL) preg->reganch++; if (flags&SPSTART) { |
︙ | ︙ | |||
20500 20501 20502 20503 20504 20505 20506 | #ifdef DEBUG regdump(preg); #endif return 0; } | | | | | | | | | | | | 20577 20578 20579 20580 20581 20582 20583 20584 20585 20586 20587 20588 20589 20590 20591 20592 20593 20594 20595 20596 20597 20598 20599 20600 20601 20602 20603 20604 20605 20606 20607 20608 20609 20610 20611 20612 20613 20614 20615 20616 20617 20618 20619 20620 20621 20622 20623 20624 20625 20626 20627 20628 20629 20630 20631 20632 20633 20634 20635 20636 20637 20638 20639 20640 20641 20642 20643 20644 20645 | #ifdef DEBUG regdump(preg); #endif return 0; } static int reg(regex_t *preg, int paren , int *flagp ) { int ret; int br; int ender; int parno = 0; int flags; *flagp = HASWIDTH; if (paren) { if (preg->regparse[0] == '?' && preg->regparse[1] == ':') { preg->regparse += 2; parno = -1; } else { parno = ++preg->re_nsub; } ret = regnode(preg, OPEN+parno); } else ret = 0; br = regbranch(preg, &flags); if (br == 0) return 0; if (ret != 0) regtail(preg, ret, br); else ret = br; if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; while (*preg->regparse == '|') { preg->regparse++; br = regbranch(preg, &flags); if (br == 0) return 0; regtail(preg, ret, br); if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; } ender = regnode(preg, (paren) ? CLOSE+parno : END); regtail(preg, ret, ender); for (br = ret; br != 0; br = regnext(preg, br)) regoptail(preg, br, ender); if (paren && *preg->regparse++ != ')') { preg->err = REG_ERR_UNMATCHED_PAREN; return 0; } else if (!paren && *preg->regparse != '\0') { if (*preg->regparse == ')') { preg->err = REG_ERR_UNMATCHED_PAREN; return 0; |
︙ | ︙ | |||
20578 20579 20580 20581 20582 20583 20584 | static int regbranch(regex_t *preg, int *flagp ) { int ret; int chain; int latest; int flags; | | | | 20655 20656 20657 20658 20659 20660 20661 20662 20663 20664 20665 20666 20667 20668 20669 20670 20671 20672 20673 20674 20675 20676 20677 20678 20679 20680 20681 20682 20683 20684 20685 20686 20687 | static int regbranch(regex_t *preg, int *flagp ) { int ret; int chain; int latest; int flags; *flagp = WORST; ret = regnode(preg, BRANCH); chain = 0; while (*preg->regparse != '\0' && *preg->regparse != ')' && *preg->regparse != '|') { latest = regpiece(preg, &flags); if (latest == 0) return 0; *flagp |= flags&HASWIDTH; if (chain == 0) { *flagp |= flags&SPSTART; } else { regtail(preg, chain, latest); } chain = latest; } if (chain == 0) (void) regnode(preg, NOTHING); return(ret); } static int regpiece(regex_t *preg, int *flagp) { |
︙ | ︙ | |||
20626 20627 20628 20629 20630 20631 20632 | } if (!(flags&HASWIDTH) && op != '?') { preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY; return 0; } | | < < < < | 20703 20704 20705 20706 20707 20708 20709 20710 20711 20712 20713 20714 20715 20716 20717 20718 20719 20720 20721 20722 20723 20724 20725 20726 20727 20728 | } if (!(flags&HASWIDTH) && op != '?') { preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY; return 0; } if (op == '{') { char *end; min = strtoul(preg->regparse + 1, &end, 10); if (end == preg->regparse + 1) { preg->err = REG_ERR_BAD_COUNT; return 0; } if (*end == '}') { max = min; } else { preg->regparse = end; max = strtoul(preg->regparse + 1, &end, 10); if (*end != '}') { preg->err = REG_ERR_UNMATCHED_BRACES; return 0; } |
︙ | ︙ | |||
20702 20703 20704 20705 20706 20707 20708 | } static void reg_addrange(regex_t *preg, int lower, int upper) { if (lower > upper) { reg_addrange(preg, upper, lower); } | | | 20775 20776 20777 20778 20779 20780 20781 20782 20783 20784 20785 20786 20787 20788 20789 | } static void reg_addrange(regex_t *preg, int lower, int upper) { if (lower > upper) { reg_addrange(preg, upper, lower); } regc(preg, upper - lower + 1); regc(preg, lower); } static void reg_addrange_str(regex_t *preg, const char *str) { while (*str) { |
︙ | ︙ | |||
20770 20771 20772 20773 20774 20775 20776 | case 'f': *ch = '\f'; break; case 'n': *ch = '\n'; break; case 'r': *ch = '\r'; break; case 't': *ch = '\t'; break; case 'v': *ch = '\v'; break; case 'u': if (*s == '{') { | | | | 20843 20844 20845 20846 20847 20848 20849 20850 20851 20852 20853 20854 20855 20856 20857 20858 20859 20860 20861 20862 20863 | case 'f': *ch = '\f'; break; case 'n': *ch = '\n'; break; case 'r': *ch = '\r'; break; case 't': *ch = '\t'; break; case 'v': *ch = '\v'; break; case 'u': if (*s == '{') { n = parse_hex(s + 1, 6, ch); if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) { s += n + 2; } else { *ch = 'u'; } } else if ((n = parse_hex(s, 4, ch)) > 0) { s += n; } break; |
︙ | ︙ | |||
20811 20812 20813 20814 20815 20816 20817 | int ret; int flags; int nocase = (preg->cflags & REG_ICASE); int ch; int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase); | | | | | | < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > | | | | | < | | | 20884 20885 20886 20887 20888 20889 20890 20891 20892 20893 20894 20895 20896 20897 20898 20899 20900 20901 20902 20903 20904 20905 20906 20907 20908 20909 20910 20911 20912 20913 20914 20915 20916 20917 20918 20919 20920 20921 20922 20923 20924 20925 20926 20927 20928 20929 20930 20931 20932 20933 20934 20935 20936 20937 20938 20939 20940 20941 20942 20943 20944 20945 20946 20947 20948 20949 20950 20951 20952 20953 20954 20955 20956 20957 20958 20959 20960 20961 20962 20963 20964 20965 20966 20967 20968 20969 20970 20971 20972 20973 20974 20975 20976 20977 20978 20979 20980 | int ret; int flags; int nocase = (preg->cflags & REG_ICASE); int ch; int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase); *flagp = WORST; preg->regparse += n; switch (ch) { case '^': ret = regnode(preg, BOL); break; case '$': ret = regnode(preg, EOL); break; case '.': ret = regnode(preg, ANY); *flagp |= HASWIDTH|SIMPLE; break; case '[': { const char *pattern = preg->regparse; if (*pattern == '^') { ret = regnode(preg, ANYBUT); pattern++; } else ret = regnode(preg, ANYOF); if (*pattern == ']' || *pattern == '-') { reg_addrange(preg, *pattern, *pattern); pattern++; } while (*pattern && *pattern != ']') { int start; int end; pattern += reg_utf8_tounicode_case(pattern, &start, nocase); if (start == '\\') { pattern += reg_decode_escape(pattern, &start); if (start == 0) { preg->err = REG_ERR_NULL_CHAR; return 0; } } if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') { pattern += utf8_tounicode(pattern, &end); pattern += reg_utf8_tounicode_case(pattern, &end, nocase); if (end == '\\') { pattern += reg_decode_escape(pattern, &end); if (end == 0) { preg->err = REG_ERR_NULL_CHAR; return 0; } } reg_addrange(preg, start, end); continue; } if (start == '[' && pattern[0] == ':') { static const char *character_class[] = { ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:", ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:", }; enum { CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER, CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT, CC_NUM }; int i; for (i = 0; i < CC_NUM; i++) { int n = strlen(character_class[i]); if (strncmp(pattern, character_class[i], n) == 0) { pattern += n + 1; break; } } if (i != CC_NUM) { switch (i) { case CC_ALNUM: reg_addrange(preg, '0', '9'); case CC_ALPHA: if ((preg->cflags & REG_ICASE) == 0) { reg_addrange(preg, 'a', 'z'); } reg_addrange(preg, 'A', 'Z'); break; case CC_SPACE: |
︙ | ︙ | |||
20933 20934 20935 20936 20937 20938 20939 | break; case CC_LOWER: reg_addrange(preg, 'a', 'z'); break; case CC_XDIGIT: reg_addrange(preg, 'a', 'f'); reg_addrange(preg, 'A', 'F'); | | | 20988 20989 20990 20991 20992 20993 20994 20995 20996 20997 20998 20999 21000 21001 21002 | break; case CC_LOWER: reg_addrange(preg, 'a', 'z'); break; case CC_XDIGIT: reg_addrange(preg, 'a', 'f'); reg_addrange(preg, 'A', 'F'); case CC_DIGIT: reg_addrange(preg, '0', '9'); break; case CC_CNTRL: reg_addrange(preg, 0, 31); reg_addrange(preg, 127, 127); break; |
︙ | ︙ | |||
20957 20958 20959 20960 20961 20962 20963 | reg_addrange(preg, '[', '`'); reg_addrange(preg, '{', '~'); break; } continue; } } | | | 21012 21013 21014 21015 21016 21017 21018 21019 21020 21021 21022 21023 21024 21025 21026 | reg_addrange(preg, '[', '`'); reg_addrange(preg, '{', '~'); break; } continue; } } reg_addrange(preg, start, start); } regc(preg, '\0'); if (*pattern) { pattern++; } |
︙ | ︙ | |||
20980 20981 20982 20983 20984 20985 20986 | return 0; *flagp |= flags&(HASWIDTH|SPSTART); break; case '\0': case '|': case ')': preg->err = REG_ERR_INTERNAL; | | | 21035 21036 21037 21038 21039 21040 21041 21042 21043 21044 21045 21046 21047 21048 21049 | return 0; *flagp |= flags&(HASWIDTH|SPSTART); break; case '\0': case '|': case ')': preg->err = REG_ERR_INTERNAL; return 0; case '?': case '+': case '*': case '{': preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING; return 0; case '\\': |
︙ | ︙ | |||
21033 21034 21035 21036 21037 21038 21039 | case 's': case 'S': ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT); reg_addrange_str(preg," \t\r\n\f\v"); regc(preg, '\0'); *flagp |= HASWIDTH|SIMPLE; break; | | | | | | | | | | | | 21088 21089 21090 21091 21092 21093 21094 21095 21096 21097 21098 21099 21100 21101 21102 21103 21104 21105 21106 21107 21108 21109 21110 21111 21112 21113 21114 21115 21116 21117 21118 21119 21120 21121 21122 21123 21124 21125 21126 21127 21128 21129 21130 21131 21132 21133 21134 21135 21136 21137 21138 21139 21140 21141 21142 21143 21144 21145 21146 21147 21148 21149 | case 's': case 'S': ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT); reg_addrange_str(preg," \t\r\n\f\v"); regc(preg, '\0'); *flagp |= HASWIDTH|SIMPLE; break; default: preg->regparse--; goto de_fault; } break; de_fault: default: { int added = 0; preg->regparse -= n; ret = regnode(preg, EXACTLY); while (*preg->regparse && strchr(META, *preg->regparse) == NULL) { n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE)); if (ch == '\\' && preg->regparse[n]) { if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) { break; } n += reg_decode_escape(preg->regparse + n, &ch); if (ch == 0) { preg->err = REG_ERR_NULL_CHAR; return 0; } } if (ISMULT(preg->regparse[n])) { if (added) { break; } regc(preg, ch); added++; preg->regparse += n; break; } regc(preg, ch); added++; preg->regparse += n; } regc(preg, '\0'); *flagp |= HASWIDTH; |
︙ | ︙ | |||
21111 21112 21113 21114 21115 21116 21117 | } static int regnode(regex_t *preg, int op) { reg_grow(preg, 2); | | | | | | | | | | | | | | | | | | | | | | | 21166 21167 21168 21169 21170 21171 21172 21173 21174 21175 21176 21177 21178 21179 21180 21181 21182 21183 21184 21185 21186 21187 21188 21189 21190 21191 21192 21193 21194 21195 21196 21197 21198 21199 21200 21201 21202 21203 21204 21205 21206 21207 21208 21209 21210 21211 21212 21213 21214 21215 21216 21217 21218 21219 21220 21221 21222 21223 21224 21225 21226 21227 21228 21229 21230 21231 21232 21233 21234 21235 21236 21237 21238 21239 21240 21241 21242 21243 21244 21245 21246 21247 21248 21249 21250 21251 21252 21253 21254 21255 21256 21257 21258 21259 21260 21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275 21276 21277 21278 21279 21280 21281 21282 21283 21284 21285 21286 21287 21288 21289 21290 21291 21292 21293 21294 21295 21296 21297 21298 21299 21300 21301 21302 21303 21304 21305 21306 21307 21308 21309 21310 21311 21312 21313 21314 21315 21316 21317 21318 21319 21320 21321 21322 21323 21324 21325 21326 21327 21328 21329 21330 21331 21332 21333 21334 21335 21336 21337 21338 21339 21340 21341 21342 21343 21344 21345 21346 21347 21348 21349 21350 | } static int regnode(regex_t *preg, int op) { reg_grow(preg, 2); preg->program[preg->p++] = op; preg->program[preg->p++] = 0; return preg->p - 2; } static void regc(regex_t *preg, int b ) { reg_grow(preg, 1); preg->program[preg->p++] = b; } static int reginsert(regex_t *preg, int op, int size, int opnd ) { reg_grow(preg, size); memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd)); memset(preg->program + opnd, 0, sizeof(int) * size); preg->program[opnd] = op; preg->p += size; return opnd + size; } static void regtail(regex_t *preg, int p, int val) { int scan; int temp; int offset; scan = p; for (;;) { temp = regnext(preg, scan); if (temp == 0) break; scan = temp; } if (OP(preg, scan) == BACK) offset = scan - val; else offset = val - scan; preg->program[scan + 1] = offset; } static void regoptail(regex_t *preg, int p, int val ) { if (p != 0 && OP(preg, p) == BRANCH) { regtail(preg, OPERAND(p), val); } } static int regtry(regex_t *preg, const char *string ); static int regmatch(regex_t *preg, int prog); static int regrepeat(regex_t *preg, int p, int max); int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) { const char *s; int scan; if (preg == NULL || preg->program == NULL || string == NULL) { return REG_ERR_NULL_ARGUMENT; } if (*preg->program != REG_MAGIC) { return REG_ERR_CORRUPTED; } #ifdef DEBUG fprintf(stderr, "regexec: %s\n", string); regdump(preg); #endif preg->eflags = eflags; preg->pmatch = pmatch; preg->nmatch = nmatch; preg->start = string; for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) { int op = OP(preg, scan); if (op == END) break; if (op == REPX || op == REPXMIN) preg->program[scan + 4] = 0; } if (preg->regmust != 0) { s = string; while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) { if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) { break; } s++; } if (s == NULL) return REG_NOMATCH; } preg->regbol = string; if (preg->reganch) { if (eflags & REG_NOTBOL) { goto nextline; } while (1) { if (regtry(preg, string)) { return REG_NOERROR; } if (*string) { nextline: if (preg->cflags & REG_NEWLINE) { string = strchr(string, '\n'); if (string) { preg->regbol = ++string; continue; } } } return REG_NOMATCH; } } s = string; if (preg->regstart != '\0') { while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) { if (regtry(preg, s)) return REG_NOERROR; s++; } } else while (1) { if (regtry(preg, s)) return REG_NOERROR; if (*s == '\0') { break; } else { int c; s += utf8_tounicode(s, &c); } } return REG_NOMATCH; } static int regtry( regex_t *preg, const char *string ) { int i; preg->reginput = string; for (i = 0; i < preg->nmatch; i++) { |
︙ | ︙ | |||
21322 21323 21324 21325 21326 21327 21328 | } return -1; } static int reg_range_find(const int *range, int c) { while (*range) { | | | | 21377 21378 21379 21380 21381 21382 21383 21384 21385 21386 21387 21388 21389 21390 21391 21392 21393 21394 21395 21396 21397 21398 21399 21400 21401 21402 21403 | } return -1; } static int reg_range_find(const int *range, int c) { while (*range) { if (c >= range[1] && c <= (range[0] + range[1] - 1)) { return 1; } range += 2; } return 0; } static const char *str_find(const char *string, int c, int nocase) { if (nocase) { c = utf8_upper(c); } while (*string) { int ch; int n = reg_utf8_tounicode_case(string, &ch, nocase); if (c == ch) { return string; |
︙ | ︙ | |||
21378 21379 21380 21381 21382 21383 21384 | } save = preg->reginput; no = regrepeat(preg, scan + 5, max); if (no < min) { return 0; } if (matchmin) { | | | | | | | | | | | | | | | | | | | | | | | | 21433 21434 21435 21436 21437 21438 21439 21440 21441 21442 21443 21444 21445 21446 21447 21448 21449 21450 21451 21452 21453 21454 21455 21456 21457 21458 21459 21460 21461 21462 21463 21464 21465 21466 21467 21468 21469 21470 21471 21472 21473 21474 21475 21476 21477 21478 21479 21480 21481 21482 21483 21484 21485 21486 21487 21488 21489 21490 21491 21492 21493 21494 21495 21496 21497 21498 21499 21500 21501 21502 21503 21504 21505 21506 21507 21508 21509 21510 21511 21512 21513 21514 21515 21516 21517 21518 21519 21520 21521 21522 21523 21524 21525 21526 21527 21528 21529 21530 21531 21532 21533 21534 21535 21536 21537 21538 21539 21540 21541 21542 21543 21544 21545 21546 21547 21548 21549 21550 21551 21552 21553 21554 21555 21556 21557 21558 21559 21560 21561 21562 21563 21564 21565 21566 21567 21568 21569 21570 21571 21572 21573 21574 21575 21576 21577 21578 21579 21580 21581 21582 21583 21584 21585 21586 21587 21588 21589 21590 21591 21592 21593 21594 21595 21596 | } save = preg->reginput; no = regrepeat(preg, scan + 5, max); if (no < min) { return 0; } if (matchmin) { max = no; no = min; } while (1) { if (matchmin) { if (no > max) { break; } } else { if (no < min) { break; } } preg->reginput = save + utf8_index(save, no); reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE)); if (reg_iseol(preg, nextch) || c == nextch) { if (regmatch(preg, next)) { return(1); } } if (matchmin) { no++; } else { no--; } } return(0); } static int regmatchrepeat(regex_t *preg, int scan, int matchmin) { int *scanpt = preg->program + scan; int max = scanpt[2]; int min = scanpt[3]; if (scanpt[4] < min) { scanpt[4]++; if (regmatch(preg, scan + 5)) { return 1; } scanpt[4]--; return 0; } if (scanpt[4] > max) { return 0; } if (matchmin) { if (regmatch(preg, regnext(preg, scan))) { return 1; } scanpt[4]++; if (regmatch(preg, scan + 5)) { return 1; } scanpt[4]--; return 0; } if (scanpt[4] < max) { scanpt[4]++; if (regmatch(preg, scan + 5)) { return 1; } scanpt[4]--; } return regmatch(preg, regnext(preg, scan)); } static int regmatch(regex_t *preg, int prog) { int scan; int next; const char *save; scan = prog; #ifdef DEBUG if (scan != 0 && regnarrate) fprintf(stderr, "%s(\n", regprop(scan)); #endif while (scan != 0) { int n; int c; #ifdef DEBUG if (regnarrate) { fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan))); } #endif next = regnext(preg, scan); n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE)); switch (OP(preg, scan)) { case BOLX: if ((preg->eflags & REG_NOTBOL)) { return(0); } case BOL: if (preg->reginput != preg->regbol) { return(0); } break; case EOLX: if (c != 0) { return 0; } break; case EOL: if (!reg_iseol(preg, c)) { return(0); } break; case WORDA: if ((!isalnum(UCHAR(c))) && c != '_') return(0); if (preg->reginput > preg->regbol && (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_')) return(0); break; case WORDZ: if (preg->reginput > preg->regbol) { if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') { c = preg->reginput[-1]; if (isalnum(UCHAR(c)) || c == '_') { break; } } } return(0); case ANY: if (reg_iseol(preg, c)) return 0; preg->reginput += n; break; |
︙ | ︙ | |||
21567 21568 21569 21570 21571 21572 21573 | preg->reginput += n; break; case NOTHING: break; case BACK: break; case BRANCH: | | | | | | 21622 21623 21624 21625 21626 21627 21628 21629 21630 21631 21632 21633 21634 21635 21636 21637 21638 21639 21640 21641 21642 21643 21644 21645 21646 21647 21648 21649 21650 21651 21652 21653 21654 21655 21656 21657 21658 21659 21660 | preg->reginput += n; break; case NOTHING: break; case BACK: break; case BRANCH: if (OP(preg, next) != BRANCH) next = OPERAND(scan); else { do { save = preg->reginput; if (regmatch(preg, OPERAND(scan))) { return(1); } preg->reginput = save; scan = regnext(preg, scan); } while (scan != 0 && OP(preg, scan) == BRANCH); return(0); } break; case REP: case REPMIN: return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN); case REPX: case REPXMIN: return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN); case END: return 1; case OPENNC: case CLOSENC: return regmatch(preg, next); default: if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) { |
︙ | ︙ | |||
21638 21639 21640 21641 21642 21643 21644 | int ch; int n; scan = preg->reginput; opnd = OPERAND(p); switch (OP(preg, p)) { case ANY: | | | 21693 21694 21695 21696 21697 21698 21699 21700 21701 21702 21703 21704 21705 21706 21707 | int ch; int n; scan = preg->reginput; opnd = OPERAND(p); switch (OP(preg, p)) { case ANY: while (!reg_iseol(preg, *scan) && count < max) { count++; scan++; } break; case EXACTLY: while (count < max) { |
︙ | ︙ | |||
21674 21675 21676 21677 21678 21679 21680 | if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) { break; } count++; scan += n; } break; | | | | 21729 21730 21731 21732 21733 21734 21735 21736 21737 21738 21739 21740 21741 21742 21743 21744 21745 | if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) { break; } count++; scan += n; } break; default: preg->err = REG_ERR_INTERNAL; count = 0; break; } preg->reginput = scan; return(count); } |
︙ | ︙ | |||
21701 21702 21703 21704 21705 21706 21707 | return(p-offset); else return(p+offset); } static int regopsize(regex_t *preg, int p ) { | | | 21756 21757 21758 21759 21760 21761 21762 21763 21764 21765 21766 21767 21768 21769 21770 | return(p-offset); else return(p+offset); } static int regopsize(regex_t *preg, int p ) { switch (OP(preg, p)) { case REP: case REPMIN: case REPX: case REPXMIN: return 5; |
︙ | ︙ | |||
21762 21763 21764 21765 21766 21767 21768 | } void regfree(regex_t *preg) { free(preg->program); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 21817 21818 21819 21820 21821 21822 21823 21824 21825 21826 21827 21828 21829 21830 | } void regfree(regex_t *preg) { free(preg->program); } #endif #if defined(_WIN32) || defined(WIN32) #ifndef STRICT #define STRICT #endif #define WIN32_LEAN_AND_MEAN |
︙ | ︙ | |||
22035 22036 22037 22038 22039 22040 22041 | DIR *opendir(const char *name) { DIR *dir = 0; if (name && name[0]) { size_t base_length = strlen(name); | | | | | 21877 21878 21879 21880 21881 21882 21883 21884 21885 21886 21887 21888 21889 21890 21891 21892 21893 21894 21895 21896 21897 21898 21899 21900 21901 21902 21903 21904 21905 21906 | DIR *opendir(const char *name) { DIR *dir = 0; if (name && name[0]) { size_t base_length = strlen(name); const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*"; if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 && (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) { strcat(strcpy(dir->name, name), all); if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1) dir->result.d_name = 0; else { Jim_Free(dir->name); Jim_Free(dir); dir = 0; } } else { Jim_Free(dir); dir = 0; errno = ENOMEM; } } else { errno = EINVAL; |
︙ | ︙ | |||
22072 22073 22074 22075 22076 22077 22078 | if (dir) { if (dir->handle != -1) result = _findclose(dir->handle); Jim_Free(dir->name); Jim_Free(dir); } | | | 21914 21915 21916 21917 21918 21919 21920 21921 21922 21923 21924 21925 21926 21927 21928 | if (dir) { if (dir->handle != -1) result = _findclose(dir->handle); Jim_Free(dir->name); Jim_Free(dir); } if (result == -1) errno = EBADF; return result; } struct dirent *readdir(DIR * dir) { struct dirent *result = 0; |
︙ | ︙ | |||
22094 22095 22096 22097 22098 22099 22100 | else { errno = EBADF; } return result; } #endif #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < | 21936 21937 21938 21939 21940 21941 21942 21943 21944 21945 21946 21947 21948 21949 21950 21951 21952 21953 21954 21955 21956 21957 21958 21959 21960 21961 21962 21963 21964 21965 21966 21967 | else { errno = EBADF; } return result; } #endif #endif #ifndef JIM_BOOTSTRAP_LIB_ONLY #include <errno.h> #include <string.h> #ifdef USE_LINENOISE #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include "linenoise.h" #else #define MAX_LINE_LEN 512 #endif char *Jim_HistoryGetline(const char *prompt) { #ifdef USE_LINENOISE return linenoise(prompt); #else int len; char *line = malloc(MAX_LINE_LEN); fputs(prompt, stdout); fflush(stdout); |
︙ | ︙ | |||
22197 22198 22199 22200 22201 22202 22203 | linenoiseHistoryAdd(line); #endif } void Jim_HistorySave(const char *filename) { #ifdef USE_LINENOISE | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 21990 21991 21992 21993 21994 21995 21996 21997 21998 21999 22000 22001 22002 22003 22004 22005 22006 22007 22008 22009 22010 22011 22012 22013 22014 22015 22016 22017 22018 22019 22020 22021 22022 22023 22024 22025 22026 22027 22028 22029 22030 22031 22032 22033 22034 | linenoiseHistoryAdd(line); #endif } void Jim_HistorySave(const char *filename) { #ifdef USE_LINENOISE linenoiseHistorySave(filename); #endif } void Jim_HistoryShow(void) { #ifdef USE_LINENOISE int i; int len; char **history = linenoiseHistory(&len); for (i = 0; i < len; i++) { printf("%4d %s\n", i + 1, history[i]); } #endif } int Jim_InteractivePrompt(Jim_Interp *interp) { int retcode = JIM_OK; char *history_file = NULL; #ifdef USE_LINENOISE const char *home; home = getenv("HOME"); if (home && isatty(STDIN_FILENO)) { int history_len = strlen(home) + sizeof("/.jim_history"); history_file = Jim_Alloc(history_len); snprintf(history_file, history_len, "%s/.jim_history", home); Jim_HistoryLoad(history_file); } #endif printf("Welcome to Jim version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100); Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1"); while (1) { |
︙ | ︙ | |||
22328 22329 22330 22331 22332 22333 22334 | scriptObjPtr = Jim_NewStringObj(interp, "", 0); Jim_IncrRefCount(scriptObjPtr); while (1) { char state; char *line; | | | | | 22053 22054 22055 22056 22057 22058 22059 22060 22061 22062 22063 22064 22065 22066 22067 22068 22069 22070 22071 22072 22073 22074 22075 22076 22077 22078 22079 22080 22081 22082 22083 22084 22085 22086 22087 22088 22089 | scriptObjPtr = Jim_NewStringObj(interp, "", 0); Jim_IncrRefCount(scriptObjPtr); while (1) { char state; char *line; line = Jim_HistoryGetline(prompt); if (line == NULL) { if (errno == EINTR) { continue; } Jim_DecrRefCount(interp, scriptObjPtr); retcode = JIM_OK; goto out; } if (Jim_Length(scriptObjPtr) != 0) { Jim_AppendString(interp, scriptObjPtr, "\n", 1); } Jim_AppendString(interp, scriptObjPtr, line, -1); free(line); if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state)) break; snprintf(prompt, sizeof(prompt), "%c> ", state); } #ifdef USE_LINENOISE if (strcmp(Jim_String(scriptObjPtr), "h") == 0) { Jim_HistoryShow(); Jim_DecrRefCount(interp, scriptObjPtr); continue; } Jim_HistoryAdd(Jim_String(scriptObjPtr)); if (history_file) { |
︙ | ︙ | |||
22377 22378 22379 22380 22381 22382 22383 | result = Jim_GetString(Jim_GetResult(interp), &reslen); if (reslen) { printf("%s\n", result); } } out: Jim_Free(history_file); | < | | 22102 22103 22104 22105 22106 22107 22108 22109 22110 22111 22112 22113 22114 22115 22116 22117 22118 22119 22120 22121 22122 22123 22124 22125 22126 22127 22128 22129 22130 22131 22132 | result = Jim_GetString(Jim_GetResult(interp), &reslen); if (reslen) { printf("%s\n", result); } } out: Jim_Free(history_file); return retcode; } #include <stdio.h> #include <stdlib.h> #include <string.h> extern int Jim_initjimshInit(Jim_Interp *interp); static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[]) { int n; Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); for (n = 0; n < argc; n++) { Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1); Jim_ListAppendElement(interp, listObj, obj); } Jim_SetVariableStr(interp, "argv", listObj); |
︙ | ︙ | |||
22420 22421 22422 22423 22424 22425 22426 | printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100); printf("Usage: %s\n", executable_name); printf("or : %s [options] [filename]\n", executable_name); printf("\n"); printf("Without options: Interactive mode\n"); printf("\n"); printf("Options:\n"); | | | | | | | | | | | | | < < < | < | 22144 22145 22146 22147 22148 22149 22150 22151 22152 22153 22154 22155 22156 22157 22158 22159 22160 22161 22162 22163 22164 22165 22166 22167 22168 22169 22170 22171 22172 22173 22174 22175 22176 22177 22178 22179 22180 22181 22182 22183 22184 22185 22186 22187 22188 22189 22190 22191 22192 22193 22194 22195 22196 22197 22198 22199 22200 22201 22202 22203 22204 22205 22206 22207 22208 22209 22210 22211 22212 22213 22214 22215 22216 22217 22218 | printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100); printf("Usage: %s\n", executable_name); printf("or : %s [options] [filename]\n", executable_name); printf("\n"); printf("Without options: Interactive mode\n"); printf("\n"); printf("Options:\n"); printf(" --version : prints the version string\n"); printf(" --help : prints this text\n"); printf(" -e CMD : executes command CMD\n"); printf(" NOTE: all subsequent options will be passed as arguments to the command\n"); printf(" [filename] : executes the script contained in the named file\n"); printf(" NOTE: all subsequent options will be passed to the script\n\n"); } int main(int argc, char *const argv[]) { int retcode; Jim_Interp *interp; char *const orig_argv0 = argv[0]; if (argc > 1 && strcmp(argv[1], "--version") == 0) { printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100); return 0; } else if (argc > 1 && strcmp(argv[1], "--help") == 0) { usage(argv[0]); return 0; } interp = Jim_CreateInterp(); Jim_RegisterCoreCommands(interp); if (Jim_InitStaticExtensions(interp) != JIM_OK) { JimPrintErrorMessage(interp); } Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0); Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0"); retcode = Jim_initjimshInit(interp); if (argc == 1) { if (retcode == JIM_ERR) { JimPrintErrorMessage(interp); } if (retcode != JIM_EXIT) { JimSetArgv(interp, 0, NULL); retcode = Jim_InteractivePrompt(interp); } } else { if (argc > 2 && strcmp(argv[1], "-e") == 0) { JimSetArgv(interp, argc - 3, argv + 3); retcode = Jim_Eval(interp, argv[2]); if (retcode != JIM_ERR) { printf("%s\n", Jim_String(Jim_GetResult(interp))); } } else { Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1)); JimSetArgv(interp, argc - 2, argv + 2); retcode = Jim_EvalFile(interp, argv[1]); } if (retcode == JIM_ERR) { JimPrintErrorMessage(interp); } } if (retcode == JIM_EXIT) { retcode = Jim_GetExitCode(interp); |
︙ | ︙ |
Changes to autosetup/pkg-config.tcl.
1 2 3 4 5 | # Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # | | | | | | | | < | | | 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 | # Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'pkg-config' module allows package information to be found via pkg-config # # If not cross-compiling, the package path should be determined automatically # by pkg-config. # If cross-compiling, the default package path is the compiler sysroot. # If the C compiler doesn't support -print-sysroot, the path can be supplied # by the --sysroot option or by defining SYSROOT. # # PKG_CONFIG may be set to use an alternative to pkg-config use cc module-options { sysroot:dir => "Override compiler sysroot for pkg-config search path" } # @pkg-config-init ?required? # # Initialises the pkg-config system. Unless required is set to 0, # it is a fatal error if the pkg-config # This command will normally be called automatically as required, # but it may be invoked explicitly if lack of pkg-config is acceptable. # # Returns 1 if ok, or 0 if pkg-config not found/usable (only if required=0) # proc pkg-config-init {{required 1}} { if {[is-defined HAVE_PKG_CONFIG]} { return [get-define HAVE_PKG_CONFIG] } set found 0 |
︙ | ︙ | |||
45 46 47 48 49 50 51 | } } else { msg-result $version define PKG_CONFIG_VERSION $version set found 1 | | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | } } else { msg-result $version define PKG_CONFIG_VERSION $version set found 1 if {[opt-val sysroot] ne ""} { define SYSROOT [file-normalize [opt-val sysroot]] msg-result "Using specified sysroot [get-define SYSROOT]" } elseif {[get-define build] ne [get-define host]} { if {[catch {exec-with-stderr [get-define CC] -print-sysroot} result errinfo] == 0} { # Use the compiler sysroot, if there is one define SYSROOT $result msg-result "Found compiler sysroot $result" } else { |
︙ | ︙ | |||
80 81 82 83 84 85 86 | } define HAVE_PKG_CONFIG $found return $found } # @pkg-config module ?requirements? # | | | | | | 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 | } define HAVE_PKG_CONFIG $found return $found } # @pkg-config module ?requirements? # # Use pkg-config to find the given module meeting the given requirements. # e.g. # ## pkg-config pango >= 1.37.0 # # If found, returns 1 and sets HAVE_PKG_PANGO to 1 along with: # ## PKG_PANGO_VERSION to the found version ## PKG_PANGO_LIBS to the required libs (--libs-only-l) ## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L) ## PKG_PANGO_CFLAGS to the required compiler flags (--cflags) # # If not found, returns 0. # proc pkg-config {module args} { set ok [pkg-config-init] msg-checking "Checking for $module $args..." |
︙ | ︙ | |||
121 122 123 124 125 126 127 | define ${prefix}_LDFLAGS [exec pkg-config --libs-only-L $module] define ${prefix}_CFLAGS [exec pkg-config --cflags $module] return 1 } # @pkg-config-get module setting # | | | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | define ${prefix}_LDFLAGS [exec pkg-config --libs-only-L $module] define ${prefix}_CFLAGS [exec pkg-config --cflags $module] return 1 } # @pkg-config-get module setting # # Convenience access to the results of pkg-config # # For example, [pkg-config-get pango CFLAGS] returns # the value of PKG_PANGO_CFLAGS, or "" if not defined. proc pkg-config-get {module name} { set prefix [feature-define-name $module PKG_] get-define ${prefix}_${name} "" } |
Changes to autosetup/system.tcl.
1 2 3 4 5 6 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # This module supports common system interrogation and options | | | | | | < < | < < | < | < < < < < | < < < < < | < | | | < | | | | | | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | | | | < < | | < | | | 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 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # This module supports common system interrogation and options # such as --host, --build, --prefix, and setting srcdir, builddir, and EXEEXT # # It also support the 'feature' naming convention, where searching # for a feature such as sys/type.h defines HAVE_SYS_TYPES_H # # It defines the following variables, based on --prefix unless overridden by the user: # ## datadir ## sysconfdir ## sharedstatedir ## localstatedir ## infodir ## mandir ## includedir # Do "define defaultprefix myvalue" to set the default prefix *before* the first "use" set defaultprefix [get-define defaultprefix /usr/local] module-options [subst -noc -nob { host:host-alias => {a complete or partial cpu-vendor-opsys for the system where the application will run (defaults to the same value as --build)} build:build-alias => {a complete or partial cpu-vendor-opsys for the system where the application will be built (defaults to the result of running config.guess)} prefix:dir => {the target directory for the build (defaults to '$defaultprefix')} # These (hidden) options are supported for autoconf/automake compatibility exec-prefix: bindir: sbindir: includedir: mandir: infodir: libexecdir: datadir: libdir: sysconfdir: sharedstatedir: localstatedir: maintainer-mode=0 dependency-tracking=0 }] # Returns 1 if exists, or 0 if not # proc check-feature {name code} { msg-checking "Checking for $name..." set r [uplevel 1 $code] define-feature $name $r if {$r} { msg-result "ok" } else { msg-result "not found" } return $r } # @have-feature name ?default=0? # # Returns the value of the feature if defined, or $default if not. # See 'feature-define-name' for how the feature name # is translated into the define name. # proc have-feature {name {default 0}} { get-define [feature-define-name $name] $default } # @define-feature name ?value=1? # # Sets the feature 'define' to the given value. # See 'feature-define-name' for how the feature name # is translated into the define name. # proc define-feature {name {value 1}} { define [feature-define-name $name] $value } # @feature-checked name # # Returns 1 if the feature has been checked, whether true or not # proc feature-checked {name} { is-defined [feature-define-name $name] } # @feature-define-name name ?prefix=HAVE_? # # Converts a name to the corresponding define, # e.g. sys/stat.h becomes HAVE_SYS_STAT_H. # # Converts * to P and all non-alphanumeric to underscore. # proc feature-define-name {name {prefix HAVE_}} { string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _] } # If $file doesn't exist, or it's contents are different than $buf, # the file is written and $script is executed. # Otherwise a "file is unchanged" message is displayed. proc write-if-changed {file buf {script {}}} { set old [readfile $file ""] if {$old eq $buf && [file exists $file]} { msg-result "$file is unchanged" } else { writefile $file $buf\n uplevel 1 $script } } # @make-template template ?outfile? # # Reads the input file <srcdir>/$template and writes the output file $outfile. # If $outfile is blank/omitted, $template should end with ".in" which # is removed to create the output file name. # # Each pattern of the form @define@ is replaced with the corresponding # define, if it exists, or left unchanged if not. # # The special value @srcdir@ is substituted with the relative # path to the source directory from the directory where the output # file is created, while the special value @top_srcdir@ is substituted # with the relative path to the top level source directory. # # Conditional sections may be specified as follows: ## @if name == value ## lines ## @else ## lines ## @endif # # Where 'name' is a defined variable name and @else is optional. # If the expression does not match, all lines through '@endif' are ignored. # # The alternative forms may also be used: ## @if name ## @if name != value # # Where the first form is true if the variable is defined, but not empty or 0 # # Currently these expressions can't be nested. # proc make-template {template {out {}}} { set infile [file join $::autosetup(srcdir) $template] if {![file exists $infile]} { user-error "Template $template is missing" } |
︙ | ︙ | |||
287 288 289 290 291 292 293 | # Make sure the directory exists file mkdir $outdir # Set up srcdir and top_srcdir to be relative to the target dir define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir] define top_srcdir [relative-path $::autosetup(srcdir) $outdir] | < < < | | | | > > > > > > | | > | > | > | | > > > > | < < > > > > > | > > > > > > | | | | | < < < < < < < < < < | < > | < < > | | > > | < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | # Make sure the directory exists file mkdir $outdir # Set up srcdir and top_srcdir to be relative to the target dir define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir] define top_srcdir [relative-path $::autosetup(srcdir) $outdir] set mapping {} foreach {n v} [array get ::define] { lappend mapping @$n@ $v } set result {} foreach line [split [readfile $infile] \n] { if {[info exists cond]} { set l [string trimright $line] if {$l eq "@endif"} { unset cond continue } if {$l eq "@else"} { set cond [expr {!$cond}] continue } if {$cond} { lappend result $line } continue } if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} { lassign $expression equal value set varval [get-define $name ""] if {$equal eq ""} { set cond [expr {$varval ni {"" 0}}] } else { set cond [expr {$varval eq $value}] if {$equal ne "=="} { set cond [expr {!$cond}] } } continue } lappend result $line } write-if-changed $out [string map $mapping [join $result \n]]\n { msg-result "Created [relative-path $out] from [relative-path $template]" } } # build/host tuples and cross-compilation prefix set build [opt-val build] define build_alias $build if {$build eq ""} { define build [config_guess] } else { define build [config_sub $build] } set host [opt-val host] define host_alias $host if {$host eq ""} { define host [get-define build] set cross "" } else { define host [config_sub $host] set cross $host- } define cross [get-env CROSS $cross] set prefix [opt-val prefix $defaultprefix] # These are for compatibility with autoconf define target [get-define host] define prefix $prefix define builddir $autosetup(builddir) define srcdir $autosetup(srcdir) # Allow this to come from the environment define top_srcdir [get-env top_srcdir [get-define srcdir]] # autoconf supports all of these set exec_prefix [opt-val exec-prefix $prefix] define exec_prefix $exec_prefix foreach {name defpath} { bindir /bin sbindir /sbin libexecdir /libexec libdir /lib } { define $name [opt-val $name $exec_prefix$defpath] } foreach {name defpath} { datadir /share sysconfdir /etc sharedstatedir /com localstatedir /var infodir /share/info mandir /share/man includedir /include } { define $name [opt-val $name $prefix$defpath] } define SHELL [get-env SHELL [find-an-executable sh bash ksh]] # Windows vs. non-Windows switch -glob -- [get-define host] { *-*-ming* - *-*-cygwin - *-*-msys { define-feature windows define EXEEXT .exe } default { |
︙ | ︙ |
Added autosetup/test-tclsh.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # A small Tcl script to verify that the chosen # interpreter works. Sometimes we might e.g. pick up # an interpreter for a different arch. # Outputs the full path to the interpreter if {[catch {info version} version] == 0} { # This is Jim Tcl if {$version >= 0.72} { # Ensure that regexp works regexp (a.*?) a puts [info nameofexecutable] exit 0 } } elseif {[catch {info tclversion} version] == 0} { if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} { puts [info nameofexecutable] exit 0 } } exit 1 |
Changes to autosetup/tmake.auto.
︙ | ︙ | |||
19 20 21 22 23 24 25 | } cc-check-tools ar ranlib set objdir [get-env BUILDDIR objdir] make-config-header $objdir/include/autoconf.h | | < < > > > > > > > > | > > > > > > > | < < < < | | > > | 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 | } cc-check-tools ar ranlib set objdir [get-env BUILDDIR objdir] make-config-header $objdir/include/autoconf.h make-tmake-settings $objdir/settings.conf {[A-Z]*} } autosetup_check_create project.spec \ {# Initial project.spec created by 'autosetup --init=tmake' # vim:set syntax=tcl: define? DESTDIR _install # XXX If configure creates additional/different files than include/autoconf.h # that should be reflected here # We use [set AUTOREMAKE] here to avoid rebuilding settings.conf # if the AUTOREMAKE command changes Depends {settings.conf include/autoconf.h} auto.def -msg {note Configuring...} -do { run [set AUTOREMAKE] >$build/config.out } -onerror {puts [readfile $build/config.out]} -fatal Clean config.out DistClean --source config.log DistClean settings.conf include/autoconf.h # If not configured, configure with default options # Note that it is expected that configure will normally be run # separately. This is just a convenience for a host build define? AUTOREMAKE configure TOPBUILDDIR=$TOPBUILDDIR --conf=auto.def Load settings.conf # e.g. for up autoconf.h IncludePaths include ifconfig CONFIGURED # Hmmm, but should we turn off AutoSubDirs? #AutoSubDirs off } if {![file exists build.spec]} { puts "Note: I don't see build.spec. Try running: tmake --genie" } } |
Changes to autosetup/tmake.tcl.
︙ | ︙ | |||
13 14 15 16 17 18 19 | module-options {} define CONFIGURED # @make-tmake-settings outfile patterns ... # | | | | | 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 | module-options {} define CONFIGURED # @make-tmake-settings outfile patterns ... # # Examines all defined variables which match the given patterns (defaults to "*") # and writes a tmake-compatible .conf file defining those variables. # For example, if ABC is "3 monkeys" and ABC matches a pattern, then the file will include: # ## define ABC {3 monkeys} # # If the file would be unchanged, it is not written. # # Typical usage is: # # make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*} proc make-tmake-settings {file args} { file mkdir [file dirname $file] set lines {} if {[llength $args] == 0} { set args * } |
︙ | ︙ |
Changes to compat/zlib/CMakeLists.txt.
|
| | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | cmake_minimum_required(VERSION 2.4.4) set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) project(zlib C) set(VERSION "1.2.11") option(ASM686 "Enable building i686 assembly implementation") option(AMD64 "Enable building amd64 assembly implementation") set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") |
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 | ) if(NOT MINGW) set(ZLIB_DLL_SRCS win32/zlib1.rc # If present will override custom build rule below. ) endif() # parse the full version number from zlib.h and include in ZLIB_FULL_VERSION file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) if(MINGW) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ) if(NOT MINGW) set(ZLIB_DLL_SRCS win32/zlib1.rc # If present will override custom build rule below. ) endif() if(CMAKE_COMPILER_IS_GNUCC) if(ASM686) set(ZLIB_ASMS contrib/asm686/match.S) elseif (AMD64) set(ZLIB_ASMS contrib/amd64/amd64-match.S) endif () if(ZLIB_ASMS) add_definitions(-DASMV) set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) endif() endif() if(MSVC) if(ASM686) ENABLE_LANGUAGE(ASM_MASM) set(ZLIB_ASMS contrib/masmx86/inffas32.asm contrib/masmx86/match686.asm ) elseif (AMD64) ENABLE_LANGUAGE(ASM_MASM) set(ZLIB_ASMS contrib/masmx64/gvmat64.asm contrib/masmx64/inffasx64.asm ) endif() if(ZLIB_ASMS) add_definitions(-DASMV -DASMINF) endif() endif() # parse the full version number from zlib.h and include in ZLIB_FULL_VERSION file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) if(MINGW) |
︙ | ︙ | |||
145 146 147 148 149 150 151 | -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${CMAKE_CURRENT_BINARY_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) endif(MINGW) | | < | < | | 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 | -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${CMAKE_CURRENT_BINARY_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) endif(MINGW) add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) set_target_properties(zlib PROPERTIES SOVERSION 1) if(NOT CYGWIN) # This property causes shared libraries on Linux to have the full version # encoded into their final filename. We disable this on Cygwin because # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll # seems to be the default. # # This has no effect with MSVC, on that platform the version info for # the DLL comes from the resource file win32/zlib1.rc set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) endif() if(UNIX) # On unix-like platforms the library is almost always called libz set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) if(NOT APPLE) set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") endif() elseif(BUILD_SHARED_LIBS AND WIN32) # Creates zlib1.dll when building shared library version set_target_properties(zlib PROPERTIES SUFFIX "1.dll") endif() |
︙ | ︙ | |||
193 194 195 196 197 198 199 | if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") endif() #============================================================================ # Example binaries #============================================================================ | | | | | | | | | | | | | | | | < | 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 | if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") endif() #============================================================================ # Example binaries #============================================================================ add_executable(example test/example.c) target_link_libraries(example zlib) add_test(example example) add_executable(minigzip test/minigzip.c) target_link_libraries(minigzip zlib) if(HAVE_OFF64_T) add_executable(example64 test/example.c) target_link_libraries(example64 zlib) set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") add_test(example64 example64) add_executable(minigzip64 test/minigzip.c) target_link_libraries(minigzip64 zlib) set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") endif() |
Changes to compat/zlib/ChangeLog.
1 2 3 | ChangeLog file for zlib | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 | ChangeLog file for zlib Changes in 1.2.11 (15 Jan 2017) - Fix deflate stored bug when pulling last block from window - Permit immediate deflateParams changes before any deflate input Changes in 1.2.10 (2 Jan 2017) - Avoid warnings on snprintf() return value - Fix bug in deflate_stored() for zero-length input |
︙ | ︙ | |||
195 196 197 198 199 200 201 | - Add contrib/vstudio/vc10 pre-build step for static only - Quote --version-script argument in CMakeLists.txt - Don't specify --version-script on Apple platforms in CMakeLists.txt - Fix casting error in contrib/testzlib/testzlib.c - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | - Add contrib/vstudio/vc10 pre-build step for static only - Quote --version-script argument in CMakeLists.txt - Don't specify --version-script on Apple platforms in CMakeLists.txt - Fix casting error in contrib/testzlib/testzlib.c - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc - Suport i686 and amd64 assembler builds in CMakeLists.txt - Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h - Add vc11 and vc12 build files to contrib/vstudio - Add gzvprintf() as an undocumented function in zlib - Fix configure for Sun shell - Remove runtime check in configure for four-byte integer type - Add casts and consts to ease user conversion to C++ - Add man pages for minizip and miniunzip |
︙ | ︙ | |||
395 396 397 398 399 400 401 | - Avoid deflate sensitivity to volatile input data - Avoid division in adler32_combine for NO_DIVIDE - Clarify the use of Z_FINISH with deflateBound() amount of space - Set binary for output file in puff.c - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] | | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | - Avoid deflate sensitivity to volatile input data - Avoid division in adler32_combine for NO_DIVIDE - Clarify the use of Z_FINISH with deflateBound() amount of space - Set binary for output file in puff.c - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] - Improve inflateSync() documentation to note indeterminancy - Add deflatePending() function to return the amount of pending output - Correct the spelling of "specification" in FAQ [Randers-Pehrson] - Add a check in configure for stdarg.h, use for gzprintf() - Check that pointers fit in ints when gzprint() compiled old style - Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] - Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] - Add debug records in assmebler code [Londer] - Update RFC references to use http://tools.ietf.org/html/... [Li] - Add --archs option, use of libtool to configure for Mac OS X [Borstel] Changes in 1.2.5 (19 Apr 2010) - Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] - Default to libdir as sharedlibdir in configure [Nieder] - Update copyright dates on modified source files |
︙ | ︙ | |||
610 611 612 613 614 615 616 | - Use zlib header window size if windowBits is 0 in inflateInit2() - Remove compressBound() call in deflate.c to avoid linking compress.o - Replace use of errno in gz* with functions, support WinCE [Alves] - Provide alternative to perror() in minigzip.c for WinCE [Alves] - Don't use _vsnprintf on later versions of MSVC [Lowman] - Add CMake build script and input file [Lowman] - Update contrib/minizip to 1.1 [Svensson, Vollant] | | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | - Use zlib header window size if windowBits is 0 in inflateInit2() - Remove compressBound() call in deflate.c to avoid linking compress.o - Replace use of errno in gz* with functions, support WinCE [Alves] - Provide alternative to perror() in minigzip.c for WinCE [Alves] - Don't use _vsnprintf on later versions of MSVC [Lowman] - Add CMake build script and input file [Lowman] - Update contrib/minizip to 1.1 [Svensson, Vollant] - Moved nintendods directory from contrib to . - Replace gzio.c with a new set of routines with the same functionality - Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above - Update contrib/minizip to 1.1b - Change gzeof() to return 0 on error instead of -1 to agree with zlib.h Changes in 1.2.3.4 (21 Dec 2009) - Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility |
︙ | ︙ | |||
784 785 786 787 788 789 790 | - Add cast in trees.c t avoid a warning [Oberhumer] - Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] - Update make_vms.com [Zinser] - Initialize state->write in inflateReset() since copied in inflate_fast() - Be more strict on incomplete code sets in inflate_table() and increase ENOUGH and MAXD -- this repairs a possible security vulnerability for invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | - Add cast in trees.c t avoid a warning [Oberhumer] - Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] - Update make_vms.com [Zinser] - Initialize state->write in inflateReset() since copied in inflate_fast() - Be more strict on incomplete code sets in inflate_table() and increase ENOUGH and MAXD -- this repairs a possible security vulnerability for invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for discovering the vulnerability and providing test cases. - Add ia64 support to configure for HP-UX [Smith] - Add error return to gzread() for format or i/o error [Levin] - Use malloc.h for OS/2 [Necasek] Changes in 1.2.2.3 (27 May 2005) - Replace 1U constants in inflate.c and inftrees.c for 64-bit compile - Typecast fread() return values in gzio.c [Vollant] |
︙ | ︙ | |||
820 821 822 823 824 825 826 | - Increase sprintf() buffer size in gzdopen() to allow for large numbers - Add INFLATE_STRICT to check distances against zlib header - Improve WinCE errno handling and comments [Chang] - Remove comment about no gzip header processing in FAQ - Add Z_FIXED strategy option to deflateInit2() to force fixed trees - Add updated make_vms.com [Coghlan], update README - Create a new "examples" directory, move gzappend.c there, add zpipe.c, | | | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | - Increase sprintf() buffer size in gzdopen() to allow for large numbers - Add INFLATE_STRICT to check distances against zlib header - Improve WinCE errno handling and comments [Chang] - Remove comment about no gzip header processing in FAQ - Add Z_FIXED strategy option to deflateInit2() to force fixed trees - Add updated make_vms.com [Coghlan], update README - Create a new "examples" directory, move gzappend.c there, add zpipe.c, fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. - Add FAQ entry and comments in deflate.c on uninitialized memory access - Add Solaris 9 make options in configure [Gilbert] - Allow strerror() usage in gzio.c for STDC - Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] - Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] - Use z_off_t for adler32_combine() and crc32_combine() lengths - Make adler32() much faster for small len |
︙ | ︙ | |||
891 892 893 894 895 896 897 | Changes in 1.2.1.1 (9 January 2004) - Update email address in README - Several FAQ updates - Fix a big fat bug in inftrees.c that prevented decoding valid dynamic blocks with only literals and no distance codes -- Thanks to "Hot Emu" for the bug report and sample file | | | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | Changes in 1.2.1.1 (9 January 2004) - Update email address in README - Several FAQ updates - Fix a big fat bug in inftrees.c that prevented decoding valid dynamic blocks with only literals and no distance codes -- Thanks to "Hot Emu" for the bug report and sample file - Add a note to puff.c on no distance codes case. Changes in 1.2.1 (17 November 2003) - Remove a tab in contrib/gzappend/gzappend.c - Update some interfaces in contrib for new zlib functions - Update zlib version number in some contrib entries - Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] - Support shared libraries on Hurd and KFreeBSD [Brown] |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 | - Clean up what gets compiled for FASTEST - Incorporate changes to zconf.in.h [Vollant] - Refine detection of Turbo C need for dummy returns - Refine ZLIB_DLL compilation - Include additional header file on VMS for off_t typedef - Try to use _vsnprintf where it supplants vsprintf [Vollant] - Add some casts in inffast.c | | | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | - Clean up what gets compiled for FASTEST - Incorporate changes to zconf.in.h [Vollant] - Refine detection of Turbo C need for dummy returns - Refine ZLIB_DLL compilation - Include additional header file on VMS for off_t typedef - Try to use _vsnprintf where it supplants vsprintf [Vollant] - Add some casts in inffast.c - Enchance comments in zlib.h on what happens if gzprintf() tries to write more than 4095 bytes before compression - Remove unused state from inflateBackEnd() - Remove exit(0) from minigzip.c, example.c - Get rid of all those darn tabs - Add "check" target to Makefile.in that does the same thing as "test" - Add "mostlyclean" and "maintainer-clean" targets to Makefile.in - Update contrib/inflate86 [Anderson] |
︙ | ︙ | |||
1135 1136 1137 1138 1139 1140 1141 | - Note permitted values of flush parameter of inflate() - Add some FAQs (and even answers) to the FAQ - Add contrib/inflate86/ for x86 faster inflate - Add contrib/blast/ for PKWare Data Compression Library decompression - Add contrib/puff/ simple inflate for deflate format description Changes in 1.1.4 (11 March 2002) | | | | | 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 | - Note permitted values of flush parameter of inflate() - Add some FAQs (and even answers) to the FAQ - Add contrib/inflate86/ for x86 faster inflate - Add contrib/blast/ for PKWare Data Compression Library decompression - Add contrib/puff/ simple inflate for deflate format description Changes in 1.1.4 (11 March 2002) - ZFREE was repeated on same allocation on some error conditions. This creates a security problem described in http://www.zlib.org/advisory-2002-03-11.txt - Returned incorrect error (Z_MEM_ERROR) on some invalid data - Avoid accesses before window for invalid distances with inflate window less than 32K. - force windowBits > 8 to avoid a bug in the encoder for a window size of 256 bytes. (A complete fix will be available in 1.1.5). Changes in 1.1.3 (9 July 1998) - fix "an inflate input buffer bug that shows up on rare but persistent occasions" (Mark) - fix gzread and gztell for concatenated .gz files (Didier Le Botlan) - fix gzseek(..., SEEK_SET) in write mode - fix crc check after a gzeek (Frank Faubert) |
︙ | ︙ | |||
1216 1217 1218 1219 1220 1221 1222 | - move Makefile.sas to amiga/Makefile.sas Changes in 1.1.1 (27 Feb 98) - fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) - remove block truncation heuristic which had very marginal effect for zlib (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the compression ratio on some files. This also allows inlining _tr_tally for | | | 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | - move Makefile.sas to amiga/Makefile.sas Changes in 1.1.1 (27 Feb 98) - fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) - remove block truncation heuristic which had very marginal effect for zlib (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the compression ratio on some files. This also allows inlining _tr_tally for matches in deflate_slow. - added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) Changes in 1.1.0 (24 Feb 98) - do not return STREAM_END prematurely in inflate (John Bowler) - revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) - compile with -DFASTEST to get compression code optimized for speed only - in minigzip, try mmap'ing the input file first (Miguel Albrecht) |
︙ | ︙ | |||
1247 1248 1249 1250 1251 1252 1253 | . ZALLOC the length list in inflate_trees_fixed() instead of using stack . ZALLOC the value area for huft_build() instead of using stack . Simplify Z_FINISH check in inflate() - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with | | | | 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 | . ZALLOC the length list in inflate_trees_fixed() instead of using stack . ZALLOC the value area for huft_build() instead of using stack . Simplify Z_FINISH check in inflate() - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with the declaration of FAR (Gilles VOllant) - install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) - read_buf buf parameter of type Bytef* instead of charf* - zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) - do not redeclare unlink in minigzip.c for WIN32 (John Bowler) - fix check for presence of directories in "make install" (Ian Willis) Changes in 1.0.8 (27 Jan 1998) - fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) - fix gzgetc and gzputc for big endian systems (Markus Oberhumer) - added compress2() to allow setting the compression level - include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) - use constant arrays for the static trees in trees.c instead of computing them at run time (thanks to Ken Raeburn for this suggestion). To create trees.h, compile with GEN_TREES_H and run "make test". - check return code of example in "make test" and display result - pass minigzip command line options to file_compress - simplifying code of inflateSync to avoid gcc 2.8 bug - support CC="gcc -Wall" in configure -s (QingLong) - avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) - fix test for shared library support to avoid compiler warnings |
︙ | ︙ | |||
1300 1301 1302 1303 1304 1305 1306 | - add inflateSyncPoint in zconf.h - fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def Changes in 1.0.6 (19 Jan 1998) - add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) - Fix a deflate bug occurring only with compression level 0 (thanks to | | | | | | | | | | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | - add inflateSyncPoint in zconf.h - fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def Changes in 1.0.6 (19 Jan 1998) - add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) - Fix a deflate bug occurring only with compression level 0 (thanks to Andy Buckler for finding this one). - In minigzip, pass transparently also the first byte for .Z files. - return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() - check Z_FINISH in inflate (thanks to Marc Schluper) - Implement deflateCopy (thanks to Adam Costello) - make static libraries by default in configure, add --shared option. - move MSDOS or Windows specific files to directory msdos - suppress the notion of partial flush to simplify the interface (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) - suppress history buffer provided by application to simplify the interface (this feature was not implemented anyway in 1.0.4) - next_in and avail_in must be initialized before calling inflateInit or inflateInit2 - add EXPORT in all exported functions (for Windows DLL) - added Makefile.nt (thanks to Stephen Williams) - added the unsupported "contrib" directory: contrib/asm386/ by Gilles Vollant <info@winimage.com> 386 asm code replacing longest_match(). contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu> A C++ I/O streams interface to the zlib gz* functions contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no> Another C++ I/O streams interface contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es> A very simple tar.gz file extractor using zlib contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl> How to use compress(), uncompress() and the gz* functions from VB. - pass params -f (filtered data), -h (huffman only), -1 to -9 (compression level) in minigzip (thanks to Tom Lane) - use const for rommable constants in deflate - added test for gzseek and gztell in example.c - add undocumented function inflateSyncPoint() (hack for Paul Mackerras) - add undocumented function zError to convert error code to string (for Tim Smithers) - Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. - Use default memcpy for Symantec MSDOS compiler. - Add EXPORT keyword for check_func (needed for Windows DLL) - add current directory to LD_LIBRARY_PATH for "make test" - create also a link for libz.so.1 - added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) - use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) - added -soname for Linux in configure (Chun-Chung Chen, - assign numbers to the exported functions in zlib.def (for Windows DLL) - add advice in zlib.h for best usage of deflateSetDictionary - work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) - allow compilation with ANSI keywords only enabled for TurboC in large model - avoid "versionString"[0] (Borland bug) - add NEED_DUMMY_RETURN for Borland - use variable z_verbose for tracing in debug mode (L. Peter Deutsch). - allow compilation with CC - defined STDC for OS/2 (David Charlap) - limit external names to 8 chars for MVS (Thomas Lund) - in minigzip.c, use static buffers only for 16-bit systems - fix suffix check for "minigzip -d foo.gz" - do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) - use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) - added makelcc.bat for lcc-win32 (Tom St Denis) - in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) - Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. - check for unistd.h in configure (for off_t) - remove useless check parameter in inflate_blocks_free - avoid useless assignment of s->check to itself in inflate_blocks_new - do not flush twice in gzclose (thanks to Ken Raeburn) - rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h - use NO_ERRNO_H instead of enumeration of operating systems with errno.h - work around buggy fclose on pipes for HP/UX - support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) - fix configure if CC is already equal to gcc Changes in 1.0.5 (3 Jan 98) - Fix inflate to terminate gracefully when fed corrupted or invalid data - Use const for rommable constants in inflate - Eliminate memory leaks on error conditions in inflate - Removed some vestigial code in inflate - Update web address in README Changes in 1.0.4 (24 Jul 96) - In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF bit, so the decompressor could decompress all the correct data but went on to attempt decompressing extra garbage data. This affected minigzip too. - zlibVersion and gzerror return const char* (needed for DLL) - port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) - use z_error only for DEBUG (avoid problem with DLLs) Changes in 1.0.3 (2 Jul 96) - use z_streamp instead of z_stream *, which is now a far pointer in MSDOS small and medium models; this makes the library incompatible with previous |
︙ | ︙ | |||
1409 1410 1411 1412 1413 1414 1415 | - updated Makefile.dj2 - added algorithm.doc Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] - fix array overlay in deflate.c which sometimes caused bad compressed data - fix inflate bug with empty stored block - fix MSDOS medium model which was broken in 0.99 | | | | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 | - updated Makefile.dj2 - added algorithm.doc Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] - fix array overlay in deflate.c which sometimes caused bad compressed data - fix inflate bug with empty stored block - fix MSDOS medium model which was broken in 0.99 - fix deflateParams() which could generate bad compressed data. - Bytef is define'd instead of typedef'ed (work around Borland bug) - added an INDEX file - new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) - speed up adler32 for modern machines without auto-increment - added -ansi for IRIX in configure - static_init_done in trees.c is an int - define unlink as delete for VMS - fix configure for QNX - add configure branch for SCO and HPUX - avoid many warnings (unused variables, dead assignments, etc...) - no fdopen for BeOS - fix the Watcom fix for 32 bit mode (define FAR as empty) - removed redefinition of Byte for MKWERKS - work around an MWKERKS bug (incorrect merge of all .h files) Changes in 0.99 (27 Jan 96) - allow preset dictionary shared between compressor and decompressor - allow compression level 0 (no compression) - add deflateParams in zlib.h: allow dynamic change of compression level and compression strategy. - test large buffers and deflateParams in example.c - add optional "configure" to build zlib as a shared library - suppress Makefile.qnx, use configure instead - fixed deflate for 64-bit systems (detected on Cray) - fixed inflate_blocks for 64-bit systems (detected on Alpha) - declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) - always return Z_BUF_ERROR when deflate() has nothing to do |
︙ | ︙ | |||
1469 1470 1471 1472 1473 1474 1475 | - clear z->msg in inflateInit2 before any error return - initialize opaque in example.c, gzio.c, deflate.c and inflate.c - fixed typo in zconf.h (_GNUC__ => __GNUC__) - check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) - fix typo in Make_vms.com (f$trnlnm -> f$getsyi) - in fcalloc, normalize pointer if size > 65520 bytes - don't use special fcalloc for 32 bit Borland C++ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 | - clear z->msg in inflateInit2 before any error return - initialize opaque in example.c, gzio.c, deflate.c and inflate.c - fixed typo in zconf.h (_GNUC__ => __GNUC__) - check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) - fix typo in Make_vms.com (f$trnlnm -> f$getsyi) - in fcalloc, normalize pointer if size > 65520 bytes - don't use special fcalloc for 32 bit Borland C++ - use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... - use Z_BINARY instead of BINARY - document that gzclose after gzdopen will close the file - allow "a" as mode in gzopen. - fix error checking in gzread - allow skipping .gz extra-field on pipes - added reference to Perl interface in README - put the crc table in FAR data (I dislike more and more the medium model :) - added get_crc_table - added a dimension to all arrays (Borland C can't count). - workaround Borland C bug in declaration of inflate_codes_new & inflate_fast - guard against multiple inclusion of *.h (for precompiled header on Mac) - Watcom C pretends to be Microsoft C small model even in 32 bit mode. - don't use unsized arrays to avoid silly warnings by Visual C++: warning C4746: 'inflate_mask' : unsized array treated as '__far' (what's wrong with far data in far model?). - define enum out of inflate_blocks_state to allow compilation with C++ Changes in 0.95 (16 Aug 95) - fix MSDOS small and medium model (now easier to adapt to any compiler) - inlined send_bits - fix the final (:-) bug for deflate with flush (output was correct but not completely flushed in rare occasions). - default window size is same for compression and decompression (it's now sufficient to set MAX_WBITS in zconf.h). - voidp -> voidpf and voidnp -> voidp (for consistency with other typedefs and because voidnp was not near in large model). Changes in 0.94 (13 Aug 95) - support MSDOS medium model - fix deflate with flush (could sometimes generate bad output) - fix deflateReset (zlib header was incorrectly suppressed) - added support for VMS - allow a compression level in gzopen() - gzflush now calls fflush - For deflate with flush, flush even if no more input is provided. - rename libgz.a as libz.a - avoid complex expression in infcodes.c triggering Turbo C bug - work around a problem with gcc on Alpha (in INSERT_STRING) - don't use inline functions (problem with some gcc versions) - allow renaming of Byte, uInt, etc... with #define. - avoid warning about (unused) pointer before start of array in deflate.c - avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c - avoid reserved word 'new' in trees.c Changes in 0.93 (25 June 95) - temporarily disable inline functions - make deflate deterministic - give enough lookahead for PARTIAL_FLUSH - Set binary mode for stdin/stdout in minigzip.c for OS/2 - don't even use signed char in inflate (not portable enough) - fix inflate memory leak for segmented architectures Changes in 0.92 (3 May 95) - don't assume that char is signed (problem on SGI) - Clear bit buffer when starting a stored block - no memcpy on Pyramid - suppressed inftest.c - optimized fill_window, put longest_match inline for gcc - optimized inflate on stored blocks. - untabify all sources to simplify patches Changes in 0.91 (2 May 95) - Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h - Document the memory requirements in zconf.h - added "make install" - fix sync search logic in inflateSync - deflate(Z_FULL_FLUSH) now works even if output buffer too short - after inflateSync, don't scare people with just "lo world" - added support for DJGPP Changes in 0.9 (1 May 95) - don't assume that zalloc clears the allocated memory (the TurboC bug was Mark's bug after all :) - let again gzread copy uncompressed data unchanged (was working in 0.71) - deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented - added a test of inflateSync in example.c - moved MAX_WBITS to zconf.h because users might want to change that. - document explicitly that zalloc(64K) on MSDOS must return a normalized pointer (zero offset) - added Makefiles for Microsoft C, Turbo C, Borland C++ - faster crc32() Changes in 0.8 (29 April 95) - added fast inflate (inffast.c) - deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this is incompatible with previous versions of zlib which returned Z_OK. - work around a TurboC compiler bug (bad code for b << 0, see infutil.h) (actually that was not a compiler bug, see 0.81 above) - gzread no longer reads one extra byte in certain cases - In gzio destroy(), don't reference a freed structure - avoid many warnings for MSDOS - avoid the ERROR symbol which is used by MS Windows Changes in 0.71 (14 April 95) - Fixed more MSDOS compilation problems :( There is still a bug with TurboC large model. Changes in 0.7 (14 April 95) - Added full inflate support. - Simplified the crc32() interface. The pre- and post-conditioning (one's complement) is now done inside crc32(). WARNING: this is incompatible with previous versions; see zlib.h for the new usage. Changes in 0.61 (12 April 95) - workaround for a bug in TurboC. example and minigzip now work on MSDOS. Changes in 0.6 (11 April 95) - added minigzip.c - added gzdopen to reopen a file descriptor as gzFile - added transparent reading of non-gziped files in gzread. - fixed bug in gzread (don't read crc as data) - fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). - don't allocate big arrays in the stack (for MSDOS) - fix some MSDOS compilation problems Changes in 0.5: - do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but not yet Z_FULL_FLUSH. - support decompression but only in a single step (forced Z_FINISH) - added opaque object for zalloc and zfree. - added deflateReset and inflateReset - added a variable zlib_version for consistency checking. - renamed the 'filter' parameter of deflateInit2 as 'strategy'. Added Z_FILTERED and Z_HUFFMAN_ONLY constants. Changes in 0.4: - avoid "zip" everywhere, use zlib instead of ziplib. - suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush if compression method == 8. - added adler32 and crc32 - renamed deflateOptions as deflateInit2, call one or the other but not both - added the method parameter for deflateInit2. - added inflateInit2 - simplied considerably deflateInit and inflateInit by not supporting user-provided history buffer. This is supported only in deflateInit2 and inflateInit2. Changes in 0.3: - prefix all macro names with Z_ - use Z_FINISH instead of deflateEnd to finish compression. - added Z_HUFFMAN_ONLY - added gzerror() |
Changes to compat/zlib/FAQ.
1 2 3 4 5 6 | Frequently Asked Questions about zlib If your question is not there, please check the zlib home page http://zlib.net/ which may have more recent information. | | | > | 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 | Frequently Asked Questions about zlib If your question is not there, please check the zlib home page http://zlib.net/ which may have more recent information. The lastest zlib FAQ is at http://zlib.net/zlib_faq.html 1. Is zlib Y2K-compliant? Yes. zlib doesn't handle dates. 2. Where can I get a Windows DLL version? The zlib sources can be compiled without change to produce a DLL. See the file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the precompiled DLL are found in the zlib web site at http://zlib.net/ . 3. Where can I get a Visual Basic interface to zlib? See * http://marknelson.us/1997/01/01/zlib-engine/ * win32/DLL_FAQ.txt in the zlib distribution |
︙ | ︙ |
Deleted compat/zlib/LICENSE.
|
| < < < < < < < < < < < < < < < < < < < < < < |
Changes to compat/zlib/Makefile.in.
1 | # Makefile for zlib | | > > > > | | | 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 | # Makefile for zlib # Copyright (C) 1995-2017 Jean-loup Gailly, Mark Adler # For conditions of distribution and use, see copyright notice in zlib.h # To compile and test, type: # ./configure; make test # Normally configure builds both a static and a shared library. # If you want to build just a static library, use: ./configure --static # To use the asm code, type: # cp contrib/asm?86/match.S ./match.S # make LOC=-DASMV OBJA=match.o # To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: # make install # To install in $HOME instead of /usr/local, use: # make install prefix=$HOME CC=cc CFLAGS=-O #CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 #CFLAGS=-g -DZLIB_DEBUG #CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ # -Wstrict-prototypes -Wmissing-prototypes SFLAGS=-O LDFLAGS= TEST_LDFLAGS=-L. libz.a LDSHARED=$(CC) CPP=$(CC) -E STATICLIB=libz.a SHAREDLIB=libz.so SHAREDLIBV=libz.so.1.2.11 SHAREDLIBM=libz.so.1 LIBS=$(STATICLIB) $(SHAREDLIBV) AR=ar ARFLAGS=rc RANLIB=ranlib LDCONFIG=ldconfig |
︙ | ︙ | |||
79 80 81 82 83 84 85 | check: test test: all teststatic testshared teststatic: static @TMPST=tmpst_$$; \ | | | | | | | | | | | | 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 | check: test test: all teststatic testshared teststatic: static @TMPST=tmpst_$$; \ if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \ echo ' *** zlib test OK ***'; \ else \ echo ' *** zlib test FAILED ***'; false; \ fi; \ rm -f $$TMPST testshared: shared @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \ DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \ TMPSH=tmpsh_$$; \ if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \ echo ' *** zlib shared test OK ***'; \ else \ echo ' *** zlib shared test FAILED ***'; false; \ fi; \ rm -f $$TMPSH test64: all64 @TMP64=tmp64_$$; \ if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \ echo ' *** zlib 64-bit test OK ***'; \ else \ echo ' *** zlib 64-bit test FAILED ***'; false; \ fi; \ rm -f $$TMP64 infcover.o: $(SRCDIR)test/infcover.c $(SRCDIR)zlib.h zconf.h $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/infcover.c infcover: infcover.o libz.a $(CC) $(CFLAGS) -o $@ infcover.o libz.a cover: infcover rm -f *.gcda ./infcover gcov inf*.c libz.a: $(OBJS) $(AR) $(ARFLAGS) $@ $(OBJS) -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 match.o: match.S |
︙ | ︙ | |||
196 197 198 199 200 201 202 | gzwrite.o: $(SRCDIR)gzwrite.c $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzwrite.c adler32.lo: $(SRCDIR)adler32.c -@mkdir objs 2>/dev/null || test -d objs | | | | | | | | | | | | | | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | gzwrite.o: $(SRCDIR)gzwrite.c $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzwrite.c adler32.lo: $(SRCDIR)adler32.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/adler32.o $(SRCDIR)adler32.c -@mv objs/adler32.o $@ crc32.lo: $(SRCDIR)crc32.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/crc32.o $(SRCDIR)crc32.c -@mv objs/crc32.o $@ deflate.lo: $(SRCDIR)deflate.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/deflate.o $(SRCDIR)deflate.c -@mv objs/deflate.o $@ infback.lo: $(SRCDIR)infback.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/infback.o $(SRCDIR)infback.c -@mv objs/infback.o $@ inffast.lo: $(SRCDIR)inffast.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inffast.o $(SRCDIR)inffast.c -@mv objs/inffast.o $@ inflate.lo: $(SRCDIR)inflate.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inflate.o $(SRCDIR)inflate.c -@mv objs/inflate.o $@ inftrees.lo: $(SRCDIR)inftrees.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inftrees.o $(SRCDIR)inftrees.c -@mv objs/inftrees.o $@ trees.lo: $(SRCDIR)trees.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/trees.o $(SRCDIR)trees.c -@mv objs/trees.o $@ zutil.lo: $(SRCDIR)zutil.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/zutil.o $(SRCDIR)zutil.c -@mv objs/zutil.o $@ compress.lo: $(SRCDIR)compress.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/compress.o $(SRCDIR)compress.c -@mv objs/compress.o $@ uncompr.lo: $(SRCDIR)uncompr.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/uncompr.o $(SRCDIR)uncompr.c -@mv objs/uncompr.o $@ gzclose.lo: $(SRCDIR)gzclose.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzclose.o $(SRCDIR)gzclose.c -@mv objs/gzclose.o $@ gzlib.lo: $(SRCDIR)gzlib.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzlib.o $(SRCDIR)gzlib.c -@mv objs/gzlib.o $@ gzread.lo: $(SRCDIR)gzread.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzread.o $(SRCDIR)gzread.c -@mv objs/gzread.o $@ gzwrite.lo: $(SRCDIR)gzwrite.c -@mkdir objs 2>/dev/null || test -d objs $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzwrite.o $(SRCDIR)gzwrite.c -@mv objs/gzwrite.o $@ placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS) rm -f $(SHAREDLIB) $(SHAREDLIBM) ln -s $@ $(SHAREDLIB) ln -s $@ $(SHAREDLIBM) -@rmdir objs example$(EXE): example.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) minigzip$(EXE): minigzip.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) examplesh$(EXE): example.o $(SHAREDLIBV) $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV) minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV) example64$(EXE): example64.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) minigzip64$(EXE): minigzip64.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS) install-libs: $(LIBS) -@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi |
︙ | ︙ | |||
355 356 357 358 359 360 361 | sed -f $$TEMPFILE $(SRCDIR)zconf.h.in > $@ &&\ touch -r $(SRCDIR)zconf.h.in $@ &&\ rm $$TEMPFILE zconf: $(SRCDIR)zconf.h.in cp -p $(SRCDIR)zconf.h.in zconf.h | < < < < < < | | > > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | sed -f $$TEMPFILE $(SRCDIR)zconf.h.in > $@ &&\ touch -r $(SRCDIR)zconf.h.in $@ &&\ rm $$TEMPFILE zconf: $(SRCDIR)zconf.h.in cp -p $(SRCDIR)zconf.h.in zconf.h mostlyclean: clean clean: rm -f *.o *.lo *~ \ example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \ example64$(EXE) minigzip64$(EXE) \ infcover \ libz.* foo.gz so_locations \ _match.s maketree contrib/infback9/*.o rm -rf objs rm -f *.gcda *.gcno *.gcov rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov maintainer-clean: distclean distclean: clean zconf zconf.h.cmakein docs rm -f Makefile zlib.pc configure.log -@rm -f .DS_Store @if [ -f Makefile.in ]; then \ printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile ; \ printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile ; \ touch -r $(SRCDIR)Makefile.in Makefile ; fi @if [ ! -f zconf.h.in ]; then rm -f zconf.h zconf.h.cmakein ; fi @if [ ! -f zlib.3 ]; then rm -f zlib.3.pdf ; fi tags: etags $(SRCDIR)*.[ch] adler32.o zutil.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h gzclose.o gzlib.o gzread.o gzwrite.o: $(SRCDIR)zlib.h zconf.h $(SRCDIR)gzguts.h compress.o example.o minigzip.o uncompr.o: $(SRCDIR)zlib.h zconf.h |
︙ | ︙ |
Changes to compat/zlib/README.
1 2 | ZLIB DATA COMPRESSION LIBRARY | | | 1 2 3 4 5 6 7 8 9 10 | ZLIB DATA COMPRESSION LIBRARY zlib 1.2.11 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example |
︙ | ︙ | |||
25 26 27 28 29 30 31 | verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at | | | | | | > | | 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 | verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . The changes made in version 1.2.11 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . zlib is available in Java using the java.util.zip package, documented at http://java.sun.com/developer/technicalArticles/Programming/compression/ . A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available at CPAN (Comprehensive Perl Archive Network) sites, including http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is available in Python 1.5 and later versions, see http://docs.python.org/library/zlib.html . zlib is built into tcl: http://wiki.tcl.tk/4610 . |
︙ | ︙ | |||
59 60 61 62 63 64 65 | - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. | | | | 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 | - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. - On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is necessary to get gzprintf working correctly. This is done by configure. - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with other compilers. Use "make test" to check your compiler. - gzdopen is not supported on RISCOS or BEOS. - For PalmOs, see http://palmzlib.sourceforge.net/ Acknowledgments: The deflate format used by zlib was defined by Phil Katz. The deflate and zlib specifications were written by L. Peter Deutsch. Thanks to all the people who reported problems and suggested various improvements in zlib; they are too numerous to cite here. Copyright notice: (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it |
︙ | ︙ | |||
103 104 105 106 107 108 109 | Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup | | < < < | 104 105 106 107 108 109 110 111 112 113 114 115 | Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup Gailly and Mark Adler; it does not include third-party code. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. |
Changes to compat/zlib/adler32.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); |
︙ | ︙ | |||
54 55 56 57 58 59 60 | #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ | | > > > > | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32_z(adler, buf, len) uLong adler; const Bytef *buf; z_size_t len; { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; |
︙ | ︙ | |||
121 122 123 124 125 126 127 | } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ | | > > > > | > > > > | 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 | } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { return adler32_z(adler, buf, len); } /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; |
︙ | ︙ | |||
151 152 153 154 155 156 157 | if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ | | > > > > | > > > > | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong adler1; uLong adler2; z_off_t len2; { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { return adler32_combine_(adler1, adler2, len2); } |
Changes to compat/zlib/compress.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ | > > > | | > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; int level; { z_stream stream; int err; const uInt max = (uInt)-1; uLong left; left = *destLen; *destLen = 0; |
︙ | ︙ | |||
56 57 58 59 60 61 62 | *destLen = stream.total_out; deflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ | > > > | | > | > > | 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 | *destLen = stream.total_out; deflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ int ZEXPORT compress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound (sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } |
Changes to compat/zlib/configure.
︙ | ︙ | |||
21 22 23 24 25 26 27 | # get source directory SRCDIR=`dirname $0` if test $SRCDIR = "."; then ZINC="" ZINCOUT="-I." SRCDIR="" else | | | < < < | > | | 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 | # get source directory SRCDIR=`dirname $0` if test $SRCDIR = "."; then ZINC="" ZINCOUT="-I." SRCDIR="" else ZINC='-include zconf.h' ZINCOUT='-I. -I$(SRCDIR)' SRCDIR="$SRCDIR/" fi # set command prefix for cross-compilation if [ -n "${CHOST}" ]; then uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`" CROSS_PREFIX="${CHOST}-" fi # destination name for static library STATICLIB=libz.a # extract zlib version numbers from zlib.h VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < ${SRCDIR}zlib.h` VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < ${SRCDIR}zlib.h` VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h` VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h` # establish commands for library building if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then AR=${AR-"${CROSS_PREFIX}ar"} test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log else AR=${AR-"ar"} |
︙ | ︙ | |||
85 86 87 88 89 90 91 | cover=0 zprefix=0 zconst=0 build64=0 gcc=0 warn=0 debug=0 | < < | | 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 | cover=0 zprefix=0 zconst=0 build64=0 gcc=0 warn=0 debug=0 old_cc="$CC" old_cflags="$CFLAGS" OBJC='$(OBJZ) $(OBJG)' PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)' # leave this script, optionally in a bad way leave() { if test "$*" != "0"; then echo "** $0 aborting." | tee -a configure.log fi rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version echo -------------------- >> configure.log echo >> configure.log echo >> configure.log exit $1 } # process command line options |
︙ | ︙ | |||
137 138 139 140 141 142 143 | -6* | --64) build64=1; shift ;; -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;; --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;; --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;; -c* | --const) zconst=1; shift ;; -w* | --warn) warn=1; shift ;; -d* | --debug) debug=1; shift ;; | < < < | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | -6* | --64) build64=1; shift ;; -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;; --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;; --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;; -c* | --const) zconst=1; shift ;; -w* | --warn) warn=1; shift ;; -d* | --debug) debug=1; shift ;; *) echo "unknown option: $1" | tee -a configure.log echo "$0 --help for help" | tee -a configure.log leave 1;; esac done |
︙ | ︙ | |||
168 169 170 171 172 173 174 | # check for gcc vs. cc and set compile and link flags based on the system identified by uname cat > $test.c <<EOF extern int getchar(); int hello() {return getchar();} EOF | < | < | < < < < | < | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | # check for gcc vs. cc and set compile and link flags based on the system identified by uname cat > $test.c <<EOF extern int getchar(); int hello() {return getchar();} EOF test -z "$CC" && echo Checking for ${CROSS_PREFIX}gcc... | tee -a configure.log cc=${CC-${CROSS_PREFIX}gcc} cflags=${CFLAGS-"-O3"} # to force the asm version use: CFLAGS="-O3 -DASMV" ./configure case "$cc" in *gcc*) gcc=1 ;; *clang*) gcc=1 ;; esac case `$cc -v 2>&1` in *gcc*) gcc=1 ;; *clang*) gcc=1 ;; |
︙ | ︙ | |||
204 205 206 207 208 209 210 | fi if test $build64 -eq 1; then CFLAGS="${CFLAGS} -m64" SFLAGS="${SFLAGS} -m64" fi if test "$warn" -eq 1; then if test "$zconst" -eq 1; then | | | < < < < < < | < < < < | | > | > | | | | | | | | | | | | < < | | | | | | < < | | | | | | < | | 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 256 257 | fi if test $build64 -eq 1; then CFLAGS="${CFLAGS} -m64" SFLAGS="${SFLAGS} -m64" fi if test "$warn" -eq 1; then if test "$zconst" -eq 1; then CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST" else CFLAGS="${CFLAGS} -Wall -Wextra -pedantic" fi fi if test $debug -eq 1; then CFLAGS="${CFLAGS} -DZLIB_DEBUG" SFLAGS="${SFLAGS} -DZLIB_DEBUG" fi if test -z "$uname"; then uname=`(uname -s || echo unknown) 2>/dev/null` fi case "$uname" in Linux* | linux* | GNU | GNU/* | solaris*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} ;; *BSD | *bsd* | DragonFly) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} LDCONFIG="ldconfig -m" ;; CYGWIN* | Cygwin* | cygwin* | OS/2*) EXE='.exe' ;; MINGW* | mingw*) # temporary bypass rm -f $test.[co] $test $test$shared_ext echo "Please use win32/Makefile.gcc instead." | tee -a configure.log leave 1 LDSHARED=${LDSHARED-"$cc -shared"} LDSHAREDLIBC="" EXE='.exe' ;; QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 # (alain.bonnefoy@icbt.com) LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; HP-UX*) LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} case `(uname -m || echo unknown) 2>/dev/null` in ia64) shared_ext='.so' SHAREDLIB='libz.so' ;; *) shared_ext='.sl' SHAREDLIB='libz.sl' ;; esac ;; Darwin* | darwin*) shared_ext='.dylib' SHAREDLIB=libz$shared_ext SHAREDLIBV=libz.$VER$shared_ext SHAREDLIBM=libz.$VER1$shared_ext LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} if libtool -V 2>&1 | grep Apple > /dev/null; then AR="libtool" else AR="/usr/bin/libtool" fi ARFLAGS="-o" ;; *) LDSHARED=${LDSHARED-"$cc -shared"} ;; esac else # find system name and corresponding cc options CC=${CC-cc} gcc=0 echo ... using $CC >> configure.log if test -z "$uname"; then |
︙ | ︙ | |||
390 391 392 393 394 395 396 | test "`( $* ) 2>&1 | tee -a configure.log`" = "" } echo - using any output from compiler to indicate an error >> configure.log else try() { show $* | | < < < < | < < | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | test "`( $* ) 2>&1 | tee -a configure.log`" = "" } echo - using any output from compiler to indicate an error >> configure.log else try() { show $* ( $* ) >> configure.log 2>&1 ret=$? if test $ret -ne 0; then echo "(exit code "$ret")" >> configure.log fi return $ret } fi tryboth() { show $* got=`( $* ) 2>&1` ret=$? printf %s "$got" >> configure.log if test $ret -ne 0; then return $ret fi test "$got" = "" } cat > $test.c << EOF int foo() { return 0; } |
︙ | ︙ | |||
438 439 440 441 442 443 444 | cat > $test.c <<EOF extern int getchar(); int hello() {return getchar();} EOF if test $shared -eq 1; then echo Checking for shared library support... | tee -a configure.log # we must test in two steps (cc then ld), required at least on SunOS 4.x | | | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | cat > $test.c <<EOF extern int getchar(); int hello() {return getchar();} EOF if test $shared -eq 1; then echo Checking for shared library support... | tee -a configure.log # we must test in two steps (cc then ld), required at least on SunOS 4.x if try $CC -w -c $SFLAGS $test.c && try $LDSHARED $SFLAGS -o $test$shared_ext $test.o; then echo Building shared library $SHAREDLIBV with $CC. | tee -a configure.log elif test -z "$old_cc" -a -z "$old_cflags"; then echo No shared library support. | tee -a configure.log shared=0; else echo 'No shared library support; try without defining CC and CFLAGS' | tee -a configure.log |
︙ | ︙ | |||
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | SHAREDLIBV="" SHAREDLIBM="" echo Building static library $STATICLIB version $VER with $CC. | tee -a configure.log else ALL="static shared" TEST="all teststatic testshared" fi echo >> configure.log # check for size_t cat > $test.c <<EOF #include <stdio.h> #include <stdlib.h> size_t dummy = 0; EOF if try $CC -c $CFLAGS $test.c; then echo "Checking for size_t... Yes." | tee -a configure.log else echo "Checking for size_t... No." | tee -a configure.log | > > > > > > > > > > > > > > > > > | > | > > | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | SHAREDLIBV="" SHAREDLIBM="" echo Building static library $STATICLIB version $VER with $CC. | tee -a configure.log else ALL="static shared" TEST="all teststatic testshared" fi # check for underscores in external names for use by assembler code CPP=${CPP-"$CC -E"} case $CFLAGS in *ASMV*) echo >> configure.log show "$NM $test.o | grep _hello" if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then CPP="$CPP -DNO_UNDERLINE" echo Checking for underline in external names... No. | tee -a configure.log else echo Checking for underline in external names... Yes. | tee -a configure.log fi ;; esac echo >> configure.log # check for size_t cat > $test.c <<EOF #include <stdio.h> #include <stdlib.h> size_t dummy = 0; EOF if try $CC -c $CFLAGS $test.c; then echo "Checking for size_t... Yes." | tee -a configure.log need_sizet=0 else echo "Checking for size_t... No." | tee -a configure.log need_sizet=1 fi echo >> configure.log # find the size_t integer type, if needed if test $need_sizet -eq 1; then cat > $test.c <<EOF long long dummy = 0; EOF if try $CC -c $CFLAGS $test.c; then echo "Checking for long long... Yes." | tee -a configure.log cat > $test.c <<EOF #include <stdio.h> int main(void) { |
︙ | ︙ | |||
504 505 506 507 508 509 510 | return 0; } EOF fi if try $CC $CFLAGS -o $test $test.c; then sizet=`./$test` echo "Checking for a pointer-size integer type..." $sizet"." | tee -a configure.log | < < | > > > > > > | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | return 0; } EOF fi if try $CC $CFLAGS -o $test $test.c; then sizet=`./$test` echo "Checking for a pointer-size integer type..." $sizet"." | tee -a configure.log else echo "Failed to find a pointer-size integer type." | tee -a configure.log leave 1 fi fi if test $need_sizet -eq 1; then CFLAGS="${CFLAGS} -DNO_SIZE_T=${sizet}" SFLAGS="${SFLAGS} -DNO_SIZE_T=${sizet}" fi echo >> configure.log # check for large file support, and if none, check for fseeko() cat > $test.c <<EOF #include <sys/types.h> off64_t dummy = 0; |
︙ | ︙ | |||
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | echo SFLAGS = $SFLAGS >> configure.log echo SHAREDLIB = $SHAREDLIB >> configure.log echo SHAREDLIBM = $SHAREDLIBM >> configure.log echo SHAREDLIBV = $SHAREDLIBV >> configure.log echo STATICLIB = $STATICLIB >> configure.log echo TEST = $TEST >> configure.log echo VER = $VER >> configure.log echo SRCDIR = $SRCDIR >> configure.log echo exec_prefix = $exec_prefix >> configure.log echo includedir = $includedir >> configure.log echo libdir = $libdir >> configure.log echo mandir = $mandir >> configure.log echo prefix = $prefix >> configure.log echo sharedlibdir = $sharedlibdir >> configure.log echo uname = $uname >> configure.log | > | | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | echo SFLAGS = $SFLAGS >> configure.log echo SHAREDLIB = $SHAREDLIB >> configure.log echo SHAREDLIBM = $SHAREDLIBM >> configure.log echo SHAREDLIBV = $SHAREDLIBV >> configure.log echo STATICLIB = $STATICLIB >> configure.log echo TEST = $TEST >> configure.log echo VER = $VER >> configure.log echo Z_U4 = $Z_U4 >> configure.log echo SRCDIR = $SRCDIR >> configure.log echo exec_prefix = $exec_prefix >> configure.log echo includedir = $includedir >> configure.log echo libdir = $libdir >> configure.log echo mandir = $mandir >> configure.log echo prefix = $prefix >> configure.log echo sharedlibdir = $sharedlibdir >> configure.log echo uname = $uname >> configure.log # udpate Makefile with the configure results sed < ${SRCDIR}Makefile.in " /^CC *=/s#=.*#=$CC# /^CFLAGS *=/s#=.*#=$CFLAGS# /^SFLAGS *=/s#=.*#=$SFLAGS# /^LDFLAGS *=/s#=.*#=$LDFLAGS# /^LDSHARED *=/s#=.*#=$LDSHARED# /^CPP *=/s#=.*#=$CPP# |
︙ | ︙ |
Changes to compat/zlib/contrib/README.contrib.
|
| | > > > > > > > > > > > > > > > > > > > > > | 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 | All files under this contrib directory are UNSUPPORTED. There were provided by users of zlib and were not tested by the authors of zlib. Use at your own risk. Please contact the authors of the contributions for help about these, not the zlib authors. Thanks. ada/ by Dmitriy Anisimkov <anisimkov@yahoo.com> Support for Ada See http://zlib-ada.sourceforge.net/ amd64/ by Mikhail Teterin <mi@ALDAN.algebra.com> asm code for AMD64 See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393 asm686/ by Brian Raiter <breadbox@muppetlabs.com> asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax See http://www.muppetlabs.com/~breadbox/software/assembly.html blast/ by Mark Adler <madler@alumni.caltech.edu> Decompressor for output of PKWare Data Compression Library (DCL) delphi/ by Cosmin Truta <cosmint@cs.ubbcluj.ro> Support for Delphi and C++ Builder dotzlib/ by Henrik Ravn <henrik@ravn.com> Support for Microsoft .Net and Visual C++ .Net gcc_gvmat64/by Gilles Vollant <info@winimage.com> GCC Version of x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to replace longest_match() and inflate_fast() infback9/ by Mark Adler <madler@alumni.caltech.edu> Unsupported diffs to infback to decode the deflate64 format inflate86/ by Chris Anderson <christop@charm.net> Tuned x86 gcc asm code to replace inflate_fast() iostream/ by Kevin Ruland <kevin@rodin.wustl.edu> A C++ I/O streams interface to the zlib gz* functions iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no> Another C++ I/O streams interface iostream3/ by Ludwig Schwardt <schwardt@sun.ac.za> and Kevin Ruland <kevin@rodin.wustl.edu> Yet another C++ I/O streams interface masmx64/ by Gilles Vollant <info@winimage.com> x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to replace longest_match() and inflate_fast(), also masm x86 64-bits translation of Chris Anderson inflate_fast() masmx86/ by Gilles Vollant <info@winimage.com> x86 asm code to replace longest_match() and inflate_fast(), for Visual C++ and MASM (32 bits). Based on Brian Raiter (asm686) and Chris Anderson (inflate86) minizip/ by Gilles Vollant <info@winimage.com> Mini zip and unzip based on zlib Includes Zip64 support by Mathias Svensson <mathias@result42.com> See http://www.winimage.com/zLibDll/minizip.html pascal/ by Bob Dellaca <bobdl@xtra.co.nz> et al. Support for Pascal |
︙ | ︙ |
Added compat/zlib/contrib/ada/buffer_demo.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2004 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- -- $Id: buffer_demo.adb,v 1.3 2004/09/06 06:55:35 vagul Exp $ -- This demo program provided by Dr Steve Sangwine <sjs@essex.ac.uk> -- -- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer -- of exactly the correct size is used for decompressed data, and the last -- few bytes passed in to Zlib are checksum bytes. -- This program compresses a string of text, and then decompresses the -- compressed text into a buffer of the same size as the original text. with Ada.Streams; use Ada.Streams; with Ada.Text_IO; with ZLib; use ZLib; procedure Buffer_Demo is EOL : Character renames ASCII.LF; Text : constant String := "Four score and seven years ago our fathers brought forth," & EOL & "upon this continent, a new nation, conceived in liberty," & EOL & "and dedicated to the proposition that `all men are created equal'."; Source : Stream_Element_Array (1 .. Text'Length); for Source'Address use Text'Address; begin Ada.Text_IO.Put (Text); Ada.Text_IO.New_Line; Ada.Text_IO.Put_Line ("Uncompressed size : " & Positive'Image (Text'Length) & " bytes"); declare Compressed_Data : Stream_Element_Array (1 .. Text'Length); L : Stream_Element_Offset; begin Compress : declare Compressor : Filter_Type; I : Stream_Element_Offset; begin Deflate_Init (Compressor); -- Compress the whole of T at once. Translate (Compressor, Source, I, Compressed_Data, L, Finish); pragma Assert (I = Source'Last); Close (Compressor); Ada.Text_IO.Put_Line ("Compressed size : " & Stream_Element_Offset'Image (L) & " bytes"); end Compress; -- Now we decompress the data, passing short blocks of data to Zlib -- (because this demonstrates the problem - the last block passed will -- contain checksum information and there will be no output, only a -- check inside Zlib that the checksum is correct). Decompress : declare Decompressor : Filter_Type; Uncompressed_Data : Stream_Element_Array (1 .. Text'Length); Block_Size : constant := 4; -- This makes sure that the last block contains -- only Adler checksum data. P : Stream_Element_Offset := Compressed_Data'First - 1; O : Stream_Element_Offset; begin Inflate_Init (Decompressor); loop Translate (Decompressor, Compressed_Data (P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)), P, Uncompressed_Data (Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last), O, No_Flush); Ada.Text_IO.Put_Line ("Total in : " & Count'Image (Total_In (Decompressor)) & ", out : " & Count'Image (Total_Out (Decompressor))); exit when P = L; end loop; Ada.Text_IO.New_Line; Ada.Text_IO.Put_Line ("Decompressed text matches original text : " & Boolean'Image (Uncompressed_Data = Source)); end Decompress; end; end Buffer_Demo; |
Added compat/zlib/contrib/ada/mtest.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- Continuous test for ZLib multithreading. If the test would fail -- we should provide thread safe allocation routines for the Z_Stream. -- -- $Id: mtest.adb,v 1.4 2004/07/23 07:49:54 vagul Exp $ with ZLib; with Ada.Streams; with Ada.Numerics.Discrete_Random; with Ada.Text_IO; with Ada.Exceptions; with Ada.Task_Identification; procedure MTest is use Ada.Streams; use ZLib; Stop : Boolean := False; pragma Atomic (Stop); subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; package Random_Elements is new Ada.Numerics.Discrete_Random (Visible_Symbols); task type Test_Task; task body Test_Task is Buffer : Stream_Element_Array (1 .. 100_000); Gen : Random_Elements.Generator; Buffer_First : Stream_Element_Offset; Compare_First : Stream_Element_Offset; Deflate : Filter_Type; Inflate : Filter_Type; procedure Further (Item : in Stream_Element_Array); procedure Read_Buffer (Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset); ------------- -- Further -- ------------- procedure Further (Item : in Stream_Element_Array) is procedure Compare (Item : in Stream_Element_Array); ------------- -- Compare -- ------------- procedure Compare (Item : in Stream_Element_Array) is Next_First : Stream_Element_Offset := Compare_First + Item'Length; begin if Buffer (Compare_First .. Next_First - 1) /= Item then raise Program_Error; end if; Compare_First := Next_First; end Compare; procedure Compare_Write is new ZLib.Write (Write => Compare); begin Compare_Write (Inflate, Item, No_Flush); end Further; ----------------- -- Read_Buffer -- ----------------- procedure Read_Buffer (Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset) is Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First; Next_First : Stream_Element_Offset; begin if Item'Length <= Buff_Diff then Last := Item'Last; Next_First := Buffer_First + Item'Length; Item := Buffer (Buffer_First .. Next_First - 1); Buffer_First := Next_First; else Last := Item'First + Buff_Diff; Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last); Buffer_First := Buffer'Last + 1; end if; end Read_Buffer; procedure Translate is new Generic_Translate (Data_In => Read_Buffer, Data_Out => Further); begin Random_Elements.Reset (Gen); Buffer := (others => 20); Main : loop for J in Buffer'Range loop Buffer (J) := Random_Elements.Random (Gen); Deflate_Init (Deflate); Inflate_Init (Inflate); Buffer_First := Buffer'First; Compare_First := Buffer'First; Translate (Deflate); if Compare_First /= Buffer'Last + 1 then raise Program_Error; end if; Ada.Text_IO.Put_Line (Ada.Task_Identification.Image (Ada.Task_Identification.Current_Task) & Stream_Element_Offset'Image (J) & ZLib.Count'Image (Total_Out (Deflate))); Close (Deflate); Close (Inflate); exit Main when Stop; end loop; end loop Main; exception when E : others => Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E)); Stop := True; end Test_Task; Test : array (1 .. 4) of Test_Task; pragma Unreferenced (Test); Dummy : Character; begin Ada.Text_IO.Get_Immediate (Dummy); Stop := True; end MTest; |
Added compat/zlib/contrib/ada/read.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: read.adb,v 1.8 2004/05/31 10:53:40 vagul Exp $ -- Test/demo program for the generic read interface. with Ada.Numerics.Discrete_Random; with Ada.Streams; with Ada.Text_IO; with ZLib; procedure Read is use Ada.Streams; ------------------------------------ -- Test configuration parameters -- ------------------------------------ File_Size : Stream_Element_Offset := 100_000; Continuous : constant Boolean := False; -- If this constant is True, the test would be repeated again and again, -- with increment File_Size for every iteration. Header : constant ZLib.Header_Type := ZLib.Default; -- Do not use Header other than Default in ZLib versions 1.1.4 and older. Init_Random : constant := 8; -- We are using the same random sequence, in case of we catch bug, -- so we would be able to reproduce it. -- End -- Pack_Size : Stream_Element_Offset; Offset : Stream_Element_Offset; Filter : ZLib.Filter_Type; subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; package Random_Elements is new Ada.Numerics.Discrete_Random (Visible_Symbols); Gen : Random_Elements.Generator; Period : constant Stream_Element_Offset := 200; -- Period constant variable for random generator not to be very random. -- Bigger period, harder random. Read_Buffer : Stream_Element_Array (1 .. 2048); Read_First : Stream_Element_Offset; Read_Last : Stream_Element_Offset; procedure Reset; procedure Read (Item : out Stream_Element_Array; Last : out Stream_Element_Offset); -- this procedure is for generic instantiation of -- ZLib.Read -- reading data from the File_In. procedure Read is new ZLib.Read (Read, Read_Buffer, Rest_First => Read_First, Rest_Last => Read_Last); ---------- -- Read -- ---------- procedure Read (Item : out Stream_Element_Array; Last : out Stream_Element_Offset) is begin Last := Stream_Element_Offset'Min (Item'Last, Item'First + File_Size - Offset); for J in Item'First .. Last loop if J < Item'First + Period then Item (J) := Random_Elements.Random (Gen); else Item (J) := Item (J - Period); end if; Offset := Offset + 1; end loop; end Read; ----------- -- Reset -- ----------- procedure Reset is begin Random_Elements.Reset (Gen, Init_Random); Pack_Size := 0; Offset := 1; Read_First := Read_Buffer'Last + 1; Read_Last := Read_Buffer'Last; end Reset; begin Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); loop for Level in ZLib.Compression_Level'Range loop Ada.Text_IO.Put ("Level =" & ZLib.Compression_Level'Image (Level)); -- Deflate using generic instantiation. ZLib.Deflate_Init (Filter, Level, Header => Header); Reset; Ada.Text_IO.Put (Stream_Element_Offset'Image (File_Size) & " ->"); loop declare Buffer : Stream_Element_Array (1 .. 1024); Last : Stream_Element_Offset; begin Read (Filter, Buffer, Last); Pack_Size := Pack_Size + Last - Buffer'First + 1; exit when Last < Buffer'Last; end; end loop; Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size)); ZLib.Close (Filter); end loop; exit when not Continuous; File_Size := File_Size + 1; end loop; end Read; |
Added compat/zlib/contrib/ada/readme.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ZLib for Ada thick binding (ZLib.Ada) Release 1.3 ZLib.Ada is a thick binding interface to the popular ZLib data compression library, available at http://www.gzip.org/zlib/. It provides Ada-style access to the ZLib C library. Here are the main changes since ZLib.Ada 1.2: - Attension: ZLib.Read generic routine have a initialization requirement for Read_Last parameter now. It is a bit incompartible with previous version, but extends functionality, we could use new parameters Allow_Read_Some and Flush now. - Added Is_Open routines to ZLib and ZLib.Streams packages. - Add pragma Assert to check Stream_Element is 8 bit. - Fix extraction to buffer with exact known decompressed size. Error reported by Steve Sangwine. - Fix definition of ULong (changed to unsigned_long), fix regression on 64 bits computers. Patch provided by Pascal Obry. - Add Status_Error exception definition. - Add pragma Assertion that Ada.Streams.Stream_Element size is 8 bit. How to build ZLib.Ada under GNAT You should have the ZLib library already build on your computer, before building ZLib.Ada. Make the directory of ZLib.Ada sources current and issue the command: gnatmake test -largs -L<directory where libz.a is> -lz Or use the GNAT project file build for GNAT 3.15 or later: gnatmake -Pzlib.gpr -L<directory where libz.a is> How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2 1. Make a project with all *.ads and *.adb files from the distribution. 2. Build the libz.a library from the ZLib C sources. 3. Rename libz.a to z.lib. 4. Add the library z.lib to the project. 5. Add the libc.lib library from the ObjectAda distribution to the project. 6. Build the executable using test.adb as a main procedure. How to use ZLib.Ada The source files test.adb and read.adb are small demo programs that show the main functionality of ZLib.Ada. The routines from the package specifications are commented. Homepage: http://zlib-ada.sourceforge.net/ Author: Dmitriy Anisimkov <anisimkov@yahoo.com> Contributors: Pascal Obry <pascal@obry.org>, Steve Sangwine <sjs@essex.ac.uk> |
Added compat/zlib/contrib/ada/test.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: test.adb,v 1.17 2003/08/12 12:13:30 vagul Exp $ -- The program has a few aims. -- 1. Test ZLib.Ada95 thick binding functionality. -- 2. Show the example of use main functionality of the ZLib.Ada95 binding. -- 3. Build this program automatically compile all ZLib.Ada95 packages under -- GNAT Ada95 compiler. with ZLib.Streams; with Ada.Streams.Stream_IO; with Ada.Numerics.Discrete_Random; with Ada.Text_IO; with Ada.Calendar; procedure Test is use Ada.Streams; use Stream_IO; ------------------------------------ -- Test configuration parameters -- ------------------------------------ File_Size : Count := 100_000; Continuous : constant Boolean := False; Header : constant ZLib.Header_Type := ZLib.Default; -- ZLib.None; -- ZLib.Auto; -- ZLib.GZip; -- Do not use Header other then Default in ZLib versions 1.1.4 -- and older. Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy; Init_Random : constant := 10; -- End -- In_File_Name : constant String := "testzlib.in"; -- Name of the input file Z_File_Name : constant String := "testzlib.zlb"; -- Name of the compressed file. Out_File_Name : constant String := "testzlib.out"; -- Name of the decompressed file. File_In : File_Type; File_Out : File_Type; File_Back : File_Type; File_Z : ZLib.Streams.Stream_Type; Filter : ZLib.Filter_Type; Time_Stamp : Ada.Calendar.Time; procedure Generate_File; -- Generate file of spetsified size with some random data. -- The random data is repeatable, for the good compression. procedure Compare_Streams (Left, Right : in out Root_Stream_Type'Class); -- The procedure compearing data in 2 streams. -- It is for compare data before and after compression/decompression. procedure Compare_Files (Left, Right : String); -- Compare files. Based on the Compare_Streams. procedure Copy_Streams (Source, Target : in out Root_Stream_Type'Class; Buffer_Size : in Stream_Element_Offset := 1024); -- Copying data from one stream to another. It is for test stream -- interface of the library. procedure Data_In (Item : out Stream_Element_Array; Last : out Stream_Element_Offset); -- this procedure is for generic instantiation of -- ZLib.Generic_Translate. -- reading data from the File_In. procedure Data_Out (Item : in Stream_Element_Array); -- this procedure is for generic instantiation of -- ZLib.Generic_Translate. -- writing data to the File_Out. procedure Stamp; -- Store the timestamp to the local variable. procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count); -- Print the time statistic with the message. procedure Translate is new ZLib.Generic_Translate (Data_In => Data_In, Data_Out => Data_Out); -- This procedure is moving data from File_In to File_Out -- with compression or decompression, depend on initialization of -- Filter parameter. ------------------- -- Compare_Files -- ------------------- procedure Compare_Files (Left, Right : String) is Left_File, Right_File : File_Type; begin Open (Left_File, In_File, Left); Open (Right_File, In_File, Right); Compare_Streams (Stream (Left_File).all, Stream (Right_File).all); Close (Left_File); Close (Right_File); end Compare_Files; --------------------- -- Compare_Streams -- --------------------- procedure Compare_Streams (Left, Right : in out Ada.Streams.Root_Stream_Type'Class) is Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#); Left_Last, Right_Last : Stream_Element_Offset; begin loop Read (Left, Left_Buffer, Left_Last); Read (Right, Right_Buffer, Right_Last); if Left_Last /= Right_Last then Ada.Text_IO.Put_Line ("Compare error :" & Stream_Element_Offset'Image (Left_Last) & " /= " & Stream_Element_Offset'Image (Right_Last)); raise Constraint_Error; elsif Left_Buffer (0 .. Left_Last) /= Right_Buffer (0 .. Right_Last) then Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal."); raise Constraint_Error; end if; exit when Left_Last < Left_Buffer'Last; end loop; end Compare_Streams; ------------------ -- Copy_Streams -- ------------------ procedure Copy_Streams (Source, Target : in out Ada.Streams.Root_Stream_Type'Class; Buffer_Size : in Stream_Element_Offset := 1024) is Buffer : Stream_Element_Array (1 .. Buffer_Size); Last : Stream_Element_Offset; begin loop Read (Source, Buffer, Last); Write (Target, Buffer (1 .. Last)); exit when Last < Buffer'Last; end loop; end Copy_Streams; ------------- -- Data_In -- ------------- procedure Data_In (Item : out Stream_Element_Array; Last : out Stream_Element_Offset) is begin Read (File_In, Item, Last); end Data_In; -------------- -- Data_Out -- -------------- procedure Data_Out (Item : in Stream_Element_Array) is begin Write (File_Out, Item); end Data_Out; ------------------- -- Generate_File -- ------------------- procedure Generate_File is subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; package Random_Elements is new Ada.Numerics.Discrete_Random (Visible_Symbols); Gen : Random_Elements.Generator; Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10; Buffer_Count : constant Count := File_Size / Buffer'Length; -- Number of same buffers in the packet. Density : constant Count := 30; -- from 0 to Buffer'Length - 2; procedure Fill_Buffer (J, D : in Count); -- Change the part of the buffer. ----------------- -- Fill_Buffer -- ----------------- procedure Fill_Buffer (J, D : in Count) is begin for K in 0 .. D loop Buffer (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1)) := Random_Elements.Random (Gen); end loop; end Fill_Buffer; begin Random_Elements.Reset (Gen, Init_Random); Create (File_In, Out_File, In_File_Name); Fill_Buffer (1, Buffer'Length - 2); for J in 1 .. Buffer_Count loop Write (File_In, Buffer); Fill_Buffer (J, Density); end loop; -- fill remain size. Write (File_In, Buffer (1 .. Stream_Element_Offset (File_Size - Buffer'Length * Buffer_Count))); Flush (File_In); Close (File_In); end Generate_File; --------------------- -- Print_Statistic -- --------------------- procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is use Ada.Calendar; use Ada.Text_IO; package Count_IO is new Integer_IO (ZLib.Count); Curr_Dur : Duration := Clock - Time_Stamp; begin Put (Msg); Set_Col (20); Ada.Text_IO.Put ("size ="); Count_IO.Put (Data_Size, Width => Stream_IO.Count'Image (File_Size)'Length); Put_Line (" duration =" & Duration'Image (Curr_Dur)); end Print_Statistic; ----------- -- Stamp -- ----------- procedure Stamp is begin Time_Stamp := Ada.Calendar.Clock; end Stamp; begin Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); loop Generate_File; for Level in ZLib.Compression_Level'Range loop Ada.Text_IO.Put_Line ("Level =" & ZLib.Compression_Level'Image (Level)); -- Test generic interface. Open (File_In, In_File, In_File_Name); Create (File_Out, Out_File, Z_File_Name); Stamp; -- Deflate using generic instantiation. ZLib.Deflate_Init (Filter => Filter, Level => Level, Strategy => Strategy, Header => Header); Translate (Filter); Print_Statistic ("Generic compress", ZLib.Total_Out (Filter)); ZLib.Close (Filter); Close (File_In); Close (File_Out); Open (File_In, In_File, Z_File_Name); Create (File_Out, Out_File, Out_File_Name); Stamp; -- Inflate using generic instantiation. ZLib.Inflate_Init (Filter, Header => Header); Translate (Filter); Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter)); ZLib.Close (Filter); Close (File_In); Close (File_Out); Compare_Files (In_File_Name, Out_File_Name); -- Test stream interface. -- Compress to the back stream. Open (File_In, In_File, In_File_Name); Create (File_Back, Out_File, Z_File_Name); Stamp; ZLib.Streams.Create (Stream => File_Z, Mode => ZLib.Streams.Out_Stream, Back => ZLib.Streams.Stream_Access (Stream (File_Back)), Back_Compressed => True, Level => Level, Strategy => Strategy, Header => Header); Copy_Streams (Source => Stream (File_In).all, Target => File_Z); -- Flushing internal buffers to the back stream. ZLib.Streams.Flush (File_Z, ZLib.Finish); Print_Statistic ("Write compress", ZLib.Streams.Write_Total_Out (File_Z)); ZLib.Streams.Close (File_Z); Close (File_In); Close (File_Back); -- Compare reading from original file and from -- decompression stream. Open (File_In, In_File, In_File_Name); Open (File_Back, In_File, Z_File_Name); ZLib.Streams.Create (Stream => File_Z, Mode => ZLib.Streams.In_Stream, Back => ZLib.Streams.Stream_Access (Stream (File_Back)), Back_Compressed => True, Header => Header); Stamp; Compare_Streams (Stream (File_In).all, File_Z); Print_Statistic ("Read decompress", ZLib.Streams.Read_Total_Out (File_Z)); ZLib.Streams.Close (File_Z); Close (File_In); Close (File_Back); -- Compress by reading from compression stream. Open (File_Back, In_File, In_File_Name); Create (File_Out, Out_File, Z_File_Name); ZLib.Streams.Create (Stream => File_Z, Mode => ZLib.Streams.In_Stream, Back => ZLib.Streams.Stream_Access (Stream (File_Back)), Back_Compressed => False, Level => Level, Strategy => Strategy, Header => Header); Stamp; Copy_Streams (Source => File_Z, Target => Stream (File_Out).all); Print_Statistic ("Read compress", ZLib.Streams.Read_Total_Out (File_Z)); ZLib.Streams.Close (File_Z); Close (File_Out); Close (File_Back); -- Decompress to decompression stream. Open (File_In, In_File, Z_File_Name); Create (File_Back, Out_File, Out_File_Name); ZLib.Streams.Create (Stream => File_Z, Mode => ZLib.Streams.Out_Stream, Back => ZLib.Streams.Stream_Access (Stream (File_Back)), Back_Compressed => False, Header => Header); Stamp; Copy_Streams (Source => Stream (File_In).all, Target => File_Z); Print_Statistic ("Write decompress", ZLib.Streams.Write_Total_Out (File_Z)); ZLib.Streams.Close (File_Z); Close (File_In); Close (File_Back); Compare_Files (In_File_Name, Out_File_Name); end loop; Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok."); exit when not Continuous; File_Size := File_Size + 1; end loop; end Test; |
Added compat/zlib/contrib/ada/zlib-streams.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: zlib-streams.adb,v 1.10 2004/05/31 10:53:40 vagul Exp $ with Ada.Unchecked_Deallocation; package body ZLib.Streams is ----------- -- Close -- ----------- procedure Close (Stream : in out Stream_Type) is procedure Free is new Ada.Unchecked_Deallocation (Stream_Element_Array, Buffer_Access); begin if Stream.Mode = Out_Stream or Stream.Mode = Duplex then -- We should flush the data written by the writer. Flush (Stream, Finish); Close (Stream.Writer); end if; if Stream.Mode = In_Stream or Stream.Mode = Duplex then Close (Stream.Reader); Free (Stream.Buffer); end if; end Close; ------------ -- Create -- ------------ procedure Create (Stream : out Stream_Type; Mode : in Stream_Mode; Back : in Stream_Access; Back_Compressed : in Boolean; Level : in Compression_Level := Default_Compression; Strategy : in Strategy_Type := Default_Strategy; Header : in Header_Type := Default; Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset := Default_Buffer_Size; Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset := Default_Buffer_Size) is subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size); procedure Init_Filter (Filter : in out Filter_Type; Compress : in Boolean); ----------------- -- Init_Filter -- ----------------- procedure Init_Filter (Filter : in out Filter_Type; Compress : in Boolean) is begin if Compress then Deflate_Init (Filter, Level, Strategy, Header => Header); else Inflate_Init (Filter, Header => Header); end if; end Init_Filter; begin Stream.Back := Back; Stream.Mode := Mode; if Mode = Out_Stream or Mode = Duplex then Init_Filter (Stream.Writer, Back_Compressed); Stream.Buffer_Size := Write_Buffer_Size; else Stream.Buffer_Size := 0; end if; if Mode = In_Stream or Mode = Duplex then Init_Filter (Stream.Reader, not Back_Compressed); Stream.Buffer := new Buffer_Subtype; Stream.Rest_First := Stream.Buffer'Last + 1; Stream.Rest_Last := Stream.Buffer'Last; end if; end Create; ----------- -- Flush -- ----------- procedure Flush (Stream : in out Stream_Type; Mode : in Flush_Mode := Sync_Flush) is Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size); Last : Stream_Element_Offset; begin loop Flush (Stream.Writer, Buffer, Last, Mode); Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last)); exit when Last < Buffer'Last; end loop; end Flush; ------------- -- Is_Open -- ------------- function Is_Open (Stream : Stream_Type) return Boolean is begin return Is_Open (Stream.Reader) or else Is_Open (Stream.Writer); end Is_Open; ---------- -- Read -- ---------- procedure Read (Stream : in out Stream_Type; Item : out Stream_Element_Array; Last : out Stream_Element_Offset) is procedure Read (Item : out Stream_Element_Array; Last : out Stream_Element_Offset); ---------- -- Read -- ---------- procedure Read (Item : out Stream_Element_Array; Last : out Stream_Element_Offset) is begin Ada.Streams.Read (Stream.Back.all, Item, Last); end Read; procedure Read is new ZLib.Read (Read => Read, Buffer => Stream.Buffer.all, Rest_First => Stream.Rest_First, Rest_Last => Stream.Rest_Last); begin Read (Stream.Reader, Item, Last); end Read; ------------------- -- Read_Total_In -- ------------------- function Read_Total_In (Stream : in Stream_Type) return Count is begin return Total_In (Stream.Reader); end Read_Total_In; -------------------- -- Read_Total_Out -- -------------------- function Read_Total_Out (Stream : in Stream_Type) return Count is begin return Total_Out (Stream.Reader); end Read_Total_Out; ----------- -- Write -- ----------- procedure Write (Stream : in out Stream_Type; Item : in Stream_Element_Array) is procedure Write (Item : in Stream_Element_Array); ----------- -- Write -- ----------- procedure Write (Item : in Stream_Element_Array) is begin Ada.Streams.Write (Stream.Back.all, Item); end Write; procedure Write is new ZLib.Write (Write => Write, Buffer_Size => Stream.Buffer_Size); begin Write (Stream.Writer, Item, No_Flush); end Write; -------------------- -- Write_Total_In -- -------------------- function Write_Total_In (Stream : in Stream_Type) return Count is begin return Total_In (Stream.Writer); end Write_Total_In; --------------------- -- Write_Total_Out -- --------------------- function Write_Total_Out (Stream : in Stream_Type) return Count is begin return Total_Out (Stream.Writer); end Write_Total_Out; end ZLib.Streams; |
Added compat/zlib/contrib/ada/zlib-streams.ads.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: zlib-streams.ads,v 1.12 2004/05/31 10:53:40 vagul Exp $ package ZLib.Streams is type Stream_Mode is (In_Stream, Out_Stream, Duplex); type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class; type Stream_Type is new Ada.Streams.Root_Stream_Type with private; procedure Read (Stream : in out Stream_Type; Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset); procedure Write (Stream : in out Stream_Type; Item : in Ada.Streams.Stream_Element_Array); procedure Flush (Stream : in out Stream_Type; Mode : in Flush_Mode := Sync_Flush); -- Flush the written data to the back stream, -- all data placed to the compressor is flushing to the Back stream. -- Should not be used until necessary, because it is decreasing -- compression. function Read_Total_In (Stream : in Stream_Type) return Count; pragma Inline (Read_Total_In); -- Return total number of bytes read from back stream so far. function Read_Total_Out (Stream : in Stream_Type) return Count; pragma Inline (Read_Total_Out); -- Return total number of bytes read so far. function Write_Total_In (Stream : in Stream_Type) return Count; pragma Inline (Write_Total_In); -- Return total number of bytes written so far. function Write_Total_Out (Stream : in Stream_Type) return Count; pragma Inline (Write_Total_Out); -- Return total number of bytes written to the back stream. procedure Create (Stream : out Stream_Type; Mode : in Stream_Mode; Back : in Stream_Access; Back_Compressed : in Boolean; Level : in Compression_Level := Default_Compression; Strategy : in Strategy_Type := Default_Strategy; Header : in Header_Type := Default; Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset := Default_Buffer_Size; Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset := Default_Buffer_Size); -- Create the Comression/Decompression stream. -- If mode is In_Stream then Write operation is disabled. -- If mode is Out_Stream then Read operation is disabled. -- If Back_Compressed is true then -- Data written to the Stream is compressing to the Back stream -- and data read from the Stream is decompressed data from the Back stream. -- If Back_Compressed is false then -- Data written to the Stream is decompressing to the Back stream -- and data read from the Stream is compressed data from the Back stream. -- !!! When the Need_Header is False ZLib-Ada is using undocumented -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers. function Is_Open (Stream : Stream_Type) return Boolean; procedure Close (Stream : in out Stream_Type); private use Ada.Streams; type Buffer_Access is access all Stream_Element_Array; type Stream_Type is new Root_Stream_Type with record Mode : Stream_Mode; Buffer : Buffer_Access; Rest_First : Stream_Element_Offset; Rest_Last : Stream_Element_Offset; -- Buffer for Read operation. -- We need to have this buffer in the record -- because not all read data from back stream -- could be processed during the read operation. Buffer_Size : Stream_Element_Offset; -- Buffer size for write operation. -- We do not need to have this buffer -- in the record because all data could be -- processed in the write operation. Back : Stream_Access; Reader : Filter_Type; Writer : Filter_Type; end record; end ZLib.Streams; |
Added compat/zlib/contrib/ada/zlib-thin.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: zlib-thin.adb,v 1.8 2003/12/14 18:27:31 vagul Exp $ package body ZLib.Thin is ZLIB_VERSION : constant Chars_Ptr := zlibVersion; Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit; -------------- -- Avail_In -- -------------- function Avail_In (Strm : in Z_Stream) return UInt is begin return Strm.Avail_In; end Avail_In; --------------- -- Avail_Out -- --------------- function Avail_Out (Strm : in Z_Stream) return UInt is begin return Strm.Avail_Out; end Avail_Out; ------------------ -- Deflate_Init -- ------------------ function Deflate_Init (strm : Z_Streamp; level : Int; method : Int; windowBits : Int; memLevel : Int; strategy : Int) return Int is begin return deflateInit2 (strm, level, method, windowBits, memLevel, strategy, ZLIB_VERSION, Z_Stream_Size); end Deflate_Init; ------------------ -- Inflate_Init -- ------------------ function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is begin return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size); end Inflate_Init; ------------------------ -- Last_Error_Message -- ------------------------ function Last_Error_Message (Strm : in Z_Stream) return String is use Interfaces.C.Strings; begin if Strm.msg = Null_Ptr then return ""; else return Value (Strm.msg); end if; end Last_Error_Message; ------------ -- Set_In -- ------------ procedure Set_In (Strm : in out Z_Stream; Buffer : in Voidp; Size : in UInt) is begin Strm.Next_In := Buffer; Strm.Avail_In := Size; end Set_In; ------------------ -- Set_Mem_Func -- ------------------ procedure Set_Mem_Func (Strm : in out Z_Stream; Opaque : in Voidp; Alloc : in alloc_func; Free : in free_func) is begin Strm.opaque := Opaque; Strm.zalloc := Alloc; Strm.zfree := Free; end Set_Mem_Func; ------------- -- Set_Out -- ------------- procedure Set_Out (Strm : in out Z_Stream; Buffer : in Voidp; Size : in UInt) is begin Strm.Next_Out := Buffer; Strm.Avail_Out := Size; end Set_Out; -------------- -- Total_In -- -------------- function Total_In (Strm : in Z_Stream) return ULong is begin return Strm.Total_In; end Total_In; --------------- -- Total_Out -- --------------- function Total_Out (Strm : in Z_Stream) return ULong is begin return Strm.Total_Out; end Total_Out; end ZLib.Thin; |
Added compat/zlib/contrib/ada/zlib-thin.ads.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2003 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: zlib-thin.ads,v 1.11 2004/07/23 06:33:11 vagul Exp $ with Interfaces.C.Strings; with System; private package ZLib.Thin is -- From zconf.h MAX_MEM_LEVEL : constant := 9; -- zconf.h:105 -- zconf.h:105 MAX_WBITS : constant := 15; -- zconf.h:115 -- 32K LZ77 window -- zconf.h:115 SEEK_SET : constant := 8#0000#; -- zconf.h:244 -- Seek from beginning of file. -- zconf.h:244 SEEK_CUR : constant := 1; -- zconf.h:245 -- Seek from current position. -- zconf.h:245 SEEK_END : constant := 2; -- zconf.h:246 -- Set file pointer to EOF plus "offset" -- zconf.h:246 type Byte is new Interfaces.C.unsigned_char; -- 8 bits -- zconf.h:214 type UInt is new Interfaces.C.unsigned; -- 16 bits or more -- zconf.h:216 type Int is new Interfaces.C.int; type ULong is new Interfaces.C.unsigned_long; -- 32 bits or more -- zconf.h:217 subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr; type ULong_Access is access ULong; type Int_Access is access Int; subtype Voidp is System.Address; -- zconf.h:232 subtype Byte_Access is Voidp; Nul : constant Voidp := System.Null_Address; -- end from zconf Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125 -- zlib.h:125 Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126 -- will be removed, use -- Z_SYNC_FLUSH instead -- zlib.h:126 Z_SYNC_FLUSH : constant := 2; -- zlib.h:127 -- zlib.h:127 Z_FULL_FLUSH : constant := 3; -- zlib.h:128 -- zlib.h:128 Z_FINISH : constant := 4; -- zlib.h:129 -- zlib.h:129 Z_OK : constant := 8#0000#; -- zlib.h:132 -- zlib.h:132 Z_STREAM_END : constant := 1; -- zlib.h:133 -- zlib.h:133 Z_NEED_DICT : constant := 2; -- zlib.h:134 -- zlib.h:134 Z_ERRNO : constant := -1; -- zlib.h:135 -- zlib.h:135 Z_STREAM_ERROR : constant := -2; -- zlib.h:136 -- zlib.h:136 Z_DATA_ERROR : constant := -3; -- zlib.h:137 -- zlib.h:137 Z_MEM_ERROR : constant := -4; -- zlib.h:138 -- zlib.h:138 Z_BUF_ERROR : constant := -5; -- zlib.h:139 -- zlib.h:139 Z_VERSION_ERROR : constant := -6; -- zlib.h:140 -- zlib.h:140 Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145 -- zlib.h:145 Z_BEST_SPEED : constant := 1; -- zlib.h:146 -- zlib.h:146 Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147 -- zlib.h:147 Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148 -- zlib.h:148 Z_FILTERED : constant := 1; -- zlib.h:151 -- zlib.h:151 Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152 -- zlib.h:152 Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153 -- zlib.h:153 Z_BINARY : constant := 8#0000#; -- zlib.h:156 -- zlib.h:156 Z_ASCII : constant := 1; -- zlib.h:157 -- zlib.h:157 Z_UNKNOWN : constant := 2; -- zlib.h:158 -- zlib.h:158 Z_DEFLATED : constant := 8; -- zlib.h:161 -- zlib.h:161 Z_NULL : constant := 8#0000#; -- zlib.h:164 -- for initializing zalloc, zfree, opaque -- zlib.h:164 type gzFile is new Voidp; -- zlib.h:646 type Z_Stream is private; type Z_Streamp is access all Z_Stream; -- zlib.h:89 type alloc_func is access function (Opaque : Voidp; Items : UInt; Size : UInt) return Voidp; -- zlib.h:63 type free_func is access procedure (opaque : Voidp; address : Voidp); function zlibVersion return Chars_Ptr; function Deflate (strm : Z_Streamp; flush : Int) return Int; function DeflateEnd (strm : Z_Streamp) return Int; function Inflate (strm : Z_Streamp; flush : Int) return Int; function InflateEnd (strm : Z_Streamp) return Int; function deflateSetDictionary (strm : Z_Streamp; dictionary : Byte_Access; dictLength : UInt) return Int; function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int; -- zlib.h:478 function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495 function deflateParams (strm : Z_Streamp; level : Int; strategy : Int) return Int; -- zlib.h:506 function inflateSetDictionary (strm : Z_Streamp; dictionary : Byte_Access; dictLength : UInt) return Int; -- zlib.h:548 function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565 function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580 function compress (dest : Byte_Access; destLen : ULong_Access; source : Byte_Access; sourceLen : ULong) return Int; -- zlib.h:601 function compress2 (dest : Byte_Access; destLen : ULong_Access; source : Byte_Access; sourceLen : ULong; level : Int) return Int; -- zlib.h:615 function uncompress (dest : Byte_Access; destLen : ULong_Access; source : Byte_Access; sourceLen : ULong) return Int; function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile; function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile; function gzsetparams (file : gzFile; level : Int; strategy : Int) return Int; function gzread (file : gzFile; buf : Voidp; len : UInt) return Int; function gzwrite (file : in gzFile; buf : in Voidp; len : in UInt) return Int; function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int; function gzputs (file : in gzFile; s : in Chars_Ptr) return Int; function gzgets (file : gzFile; buf : Chars_Ptr; len : Int) return Chars_Ptr; function gzputc (file : gzFile; char : Int) return Int; function gzgetc (file : gzFile) return Int; function gzflush (file : gzFile; flush : Int) return Int; function gzseek (file : gzFile; offset : Int; whence : Int) return Int; function gzrewind (file : gzFile) return Int; function gztell (file : gzFile) return Int; function gzeof (file : gzFile) return Int; function gzclose (file : gzFile) return Int; function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr; function adler32 (adler : ULong; buf : Byte_Access; len : UInt) return ULong; function crc32 (crc : ULong; buf : Byte_Access; len : UInt) return ULong; function deflateInit (strm : Z_Streamp; level : Int; version : Chars_Ptr; stream_size : Int) return Int; function deflateInit2 (strm : Z_Streamp; level : Int; method : Int; windowBits : Int; memLevel : Int; strategy : Int; version : Chars_Ptr; stream_size : Int) return Int; function Deflate_Init (strm : Z_Streamp; level : Int; method : Int; windowBits : Int; memLevel : Int; strategy : Int) return Int; pragma Inline (Deflate_Init); function inflateInit (strm : Z_Streamp; version : Chars_Ptr; stream_size : Int) return Int; function inflateInit2 (strm : in Z_Streamp; windowBits : in Int; version : in Chars_Ptr; stream_size : in Int) return Int; function inflateBackInit (strm : in Z_Streamp; windowBits : in Int; window : in Byte_Access; version : in Chars_Ptr; stream_size : in Int) return Int; -- Size of window have to be 2**windowBits. function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int; pragma Inline (Inflate_Init); function zError (err : Int) return Chars_Ptr; function inflateSyncPoint (z : Z_Streamp) return Int; function get_crc_table return ULong_Access; -- Interface to the available fields of the z_stream structure. -- The application must update next_in and avail_in when avail_in has -- dropped to zero. It must update next_out and avail_out when avail_out -- has dropped to zero. The application must initialize zalloc, zfree and -- opaque before calling the init function. procedure Set_In (Strm : in out Z_Stream; Buffer : in Voidp; Size : in UInt); pragma Inline (Set_In); procedure Set_Out (Strm : in out Z_Stream; Buffer : in Voidp; Size : in UInt); pragma Inline (Set_Out); procedure Set_Mem_Func (Strm : in out Z_Stream; Opaque : in Voidp; Alloc : in alloc_func; Free : in free_func); pragma Inline (Set_Mem_Func); function Last_Error_Message (Strm : in Z_Stream) return String; pragma Inline (Last_Error_Message); function Avail_Out (Strm : in Z_Stream) return UInt; pragma Inline (Avail_Out); function Avail_In (Strm : in Z_Stream) return UInt; pragma Inline (Avail_In); function Total_In (Strm : in Z_Stream) return ULong; pragma Inline (Total_In); function Total_Out (Strm : in Z_Stream) return ULong; pragma Inline (Total_Out); function inflateCopy (dest : in Z_Streamp; Source : in Z_Streamp) return Int; function compressBound (Source_Len : in ULong) return ULong; function deflateBound (Strm : in Z_Streamp; Source_Len : in ULong) return ULong; function gzungetc (C : in Int; File : in gzFile) return Int; function zlibCompileFlags return ULong; private type Z_Stream is record -- zlib.h:68 Next_In : Voidp := Nul; -- next input byte Avail_In : UInt := 0; -- number of bytes available at next_in Total_In : ULong := 0; -- total nb of input bytes read so far Next_Out : Voidp := Nul; -- next output byte should be put there Avail_Out : UInt := 0; -- remaining free space at next_out Total_Out : ULong := 0; -- total nb of bytes output so far msg : Chars_Ptr; -- last error message, NULL if no error state : Voidp; -- not visible by applications zalloc : alloc_func := null; -- used to allocate the internal state zfree : free_func := null; -- used to free the internal state opaque : Voidp; -- private data object passed to -- zalloc and zfree data_type : Int; -- best guess about the data type: -- ascii or binary adler : ULong; -- adler32 value of the uncompressed -- data reserved : ULong; -- reserved for future use end record; pragma Convention (C, Z_Stream); pragma Import (C, zlibVersion, "zlibVersion"); pragma Import (C, Deflate, "deflate"); pragma Import (C, DeflateEnd, "deflateEnd"); pragma Import (C, Inflate, "inflate"); pragma Import (C, InflateEnd, "inflateEnd"); pragma Import (C, deflateSetDictionary, "deflateSetDictionary"); pragma Import (C, deflateCopy, "deflateCopy"); pragma Import (C, deflateReset, "deflateReset"); pragma Import (C, deflateParams, "deflateParams"); pragma Import (C, inflateSetDictionary, "inflateSetDictionary"); pragma Import (C, inflateSync, "inflateSync"); pragma Import (C, inflateReset, "inflateReset"); pragma Import (C, compress, "compress"); pragma Import (C, compress2, "compress2"); pragma Import (C, uncompress, "uncompress"); pragma Import (C, gzopen, "gzopen"); pragma Import (C, gzdopen, "gzdopen"); pragma Import (C, gzsetparams, "gzsetparams"); pragma Import (C, gzread, "gzread"); pragma Import (C, gzwrite, "gzwrite"); pragma Import (C, gzprintf, "gzprintf"); pragma Import (C, gzputs, "gzputs"); pragma Import (C, gzgets, "gzgets"); pragma Import (C, gzputc, "gzputc"); pragma Import (C, gzgetc, "gzgetc"); pragma Import (C, gzflush, "gzflush"); pragma Import (C, gzseek, "gzseek"); pragma Import (C, gzrewind, "gzrewind"); pragma Import (C, gztell, "gztell"); pragma Import (C, gzeof, "gzeof"); pragma Import (C, gzclose, "gzclose"); pragma Import (C, gzerror, "gzerror"); pragma Import (C, adler32, "adler32"); pragma Import (C, crc32, "crc32"); pragma Import (C, deflateInit, "deflateInit_"); pragma Import (C, inflateInit, "inflateInit_"); pragma Import (C, deflateInit2, "deflateInit2_"); pragma Import (C, inflateInit2, "inflateInit2_"); pragma Import (C, zError, "zError"); pragma Import (C, inflateSyncPoint, "inflateSyncPoint"); pragma Import (C, get_crc_table, "get_crc_table"); -- since zlib 1.2.0: pragma Import (C, inflateCopy, "inflateCopy"); pragma Import (C, compressBound, "compressBound"); pragma Import (C, deflateBound, "deflateBound"); pragma Import (C, gzungetc, "gzungetc"); pragma Import (C, zlibCompileFlags, "zlibCompileFlags"); pragma Import (C, inflateBackInit, "inflateBackInit_"); -- I stopped binding the inflateBack routines, because realize that -- it does not support zlib and gzip headers for now, and have no -- symmetric deflateBack routines. -- ZLib-Ada is symmetric regarding deflate/inflate data transformation -- and has a similar generic callback interface for the -- deflate/inflate transformation based on the regular Deflate/Inflate -- routines. -- pragma Import (C, inflateBack, "inflateBack"); -- pragma Import (C, inflateBackEnd, "inflateBackEnd"); end ZLib.Thin; |
Added compat/zlib/contrib/ada/zlib.adb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 | ---------------------------------------------------------------- -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2004 Dmitriy Anisimkov -- -- -- -- Open source license information is in the zlib.ads file. -- ---------------------------------------------------------------- -- $Id: zlib.adb,v 1.31 2004/09/06 06:53:19 vagul Exp $ with Ada.Exceptions; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; with Interfaces.C.Strings; with ZLib.Thin; package body ZLib is use type Thin.Int; type Z_Stream is new Thin.Z_Stream; type Return_Code_Enum is (OK, STREAM_END, NEED_DICT, ERRNO, STREAM_ERROR, DATA_ERROR, MEM_ERROR, BUF_ERROR, VERSION_ERROR); type Flate_Step_Function is access function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int; pragma Convention (C, Flate_Step_Function); type Flate_End_Function is access function (Ctrm : in Thin.Z_Streamp) return Thin.Int; pragma Convention (C, Flate_End_Function); type Flate_Type is record Step : Flate_Step_Function; Done : Flate_End_Function; end record; subtype Footer_Array is Stream_Element_Array (1 .. 8); Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) := (16#1f#, 16#8b#, -- Magic header 16#08#, -- Z_DEFLATED 16#00#, -- Flags 16#00#, 16#00#, 16#00#, 16#00#, -- Time 16#00#, -- XFlags 16#03# -- OS code ); -- The simplest gzip header is not for informational, but just for -- gzip format compatibility. -- Note that some code below is using assumption -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make -- Simple_GZip_Header'Last <= Footer_Array'Last. Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum := (0 => OK, 1 => STREAM_END, 2 => NEED_DICT, -1 => ERRNO, -2 => STREAM_ERROR, -3 => DATA_ERROR, -4 => MEM_ERROR, -5 => BUF_ERROR, -6 => VERSION_ERROR); Flate : constant array (Boolean) of Flate_Type := (True => (Step => Thin.Deflate'Access, Done => Thin.DeflateEnd'Access), False => (Step => Thin.Inflate'Access, Done => Thin.InflateEnd'Access)); Flush_Finish : constant array (Boolean) of Flush_Mode := (True => Finish, False => No_Flush); procedure Raise_Error (Stream : in Z_Stream); pragma Inline (Raise_Error); procedure Raise_Error (Message : in String); pragma Inline (Raise_Error); procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int); procedure Free is new Ada.Unchecked_Deallocation (Z_Stream, Z_Stream_Access); function To_Thin_Access is new Ada.Unchecked_Conversion (Z_Stream_Access, Thin.Z_Streamp); procedure Translate_GZip (Filter : in out Filter_Type; In_Data : in Ada.Streams.Stream_Element_Array; In_Last : out Ada.Streams.Stream_Element_Offset; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode); -- Separate translate routine for make gzip header. procedure Translate_Auto (Filter : in out Filter_Type; In_Data : in Ada.Streams.Stream_Element_Array; In_Last : out Ada.Streams.Stream_Element_Offset; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode); -- translate routine without additional headers. ----------------- -- Check_Error -- ----------------- procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is use type Thin.Int; begin if Code /= Thin.Z_OK then Raise_Error (Return_Code_Enum'Image (Return_Code (Code)) & ": " & Last_Error_Message (Stream)); end if; end Check_Error; ----------- -- Close -- ----------- procedure Close (Filter : in out Filter_Type; Ignore_Error : in Boolean := False) is Code : Thin.Int; begin if not Ignore_Error and then not Is_Open (Filter) then raise Status_Error; end if; Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm)); if Ignore_Error or else Code = Thin.Z_OK then Free (Filter.Strm); else declare Error_Message : constant String := Last_Error_Message (Filter.Strm.all); begin Free (Filter.Strm); Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Return_Code_Enum'Image (Return_Code (Code)) & ": " & Error_Message); end; end if; end Close; ----------- -- CRC32 -- ----------- function CRC32 (CRC : in Unsigned_32; Data : in Ada.Streams.Stream_Element_Array) return Unsigned_32 is use Thin; begin return Unsigned_32 (crc32 (ULong (CRC), Data'Address, Data'Length)); end CRC32; procedure CRC32 (CRC : in out Unsigned_32; Data : in Ada.Streams.Stream_Element_Array) is begin CRC := CRC32 (CRC, Data); end CRC32; ------------------ -- Deflate_Init -- ------------------ procedure Deflate_Init (Filter : in out Filter_Type; Level : in Compression_Level := Default_Compression; Strategy : in Strategy_Type := Default_Strategy; Method : in Compression_Method := Deflated; Window_Bits : in Window_Bits_Type := Default_Window_Bits; Memory_Level : in Memory_Level_Type := Default_Memory_Level; Header : in Header_Type := Default) is use type Thin.Int; Win_Bits : Thin.Int := Thin.Int (Window_Bits); begin if Is_Open (Filter) then raise Status_Error; end if; -- We allow ZLib to make header only in case of default header type. -- Otherwise we would either do header by ourselfs, or do not do -- header at all. if Header = None or else Header = GZip then Win_Bits := -Win_Bits; end if; -- For the GZip CRC calculation and make headers. if Header = GZip then Filter.CRC := 0; Filter.Offset := Simple_GZip_Header'First; else Filter.Offset := Simple_GZip_Header'Last + 1; end if; Filter.Strm := new Z_Stream; Filter.Compression := True; Filter.Stream_End := False; Filter.Header := Header; if Thin.Deflate_Init (To_Thin_Access (Filter.Strm), Level => Thin.Int (Level), method => Thin.Int (Method), windowBits => Win_Bits, memLevel => Thin.Int (Memory_Level), strategy => Thin.Int (Strategy)) /= Thin.Z_OK then Raise_Error (Filter.Strm.all); end if; end Deflate_Init; ----------- -- Flush -- ----------- procedure Flush (Filter : in out Filter_Type; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode) is No_Data : Stream_Element_Array := (1 .. 0 => 0); Last : Stream_Element_Offset; begin Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); end Flush; ----------------------- -- Generic_Translate -- ----------------------- procedure Generic_Translate (Filter : in out ZLib.Filter_Type; In_Buffer_Size : in Integer := Default_Buffer_Size; Out_Buffer_Size : in Integer := Default_Buffer_Size) is In_Buffer : Stream_Element_Array (1 .. Stream_Element_Offset (In_Buffer_Size)); Out_Buffer : Stream_Element_Array (1 .. Stream_Element_Offset (Out_Buffer_Size)); Last : Stream_Element_Offset; In_Last : Stream_Element_Offset; In_First : Stream_Element_Offset; Out_Last : Stream_Element_Offset; begin Main : loop Data_In (In_Buffer, Last); In_First := In_Buffer'First; loop Translate (Filter => Filter, In_Data => In_Buffer (In_First .. Last), In_Last => In_Last, Out_Data => Out_Buffer, Out_Last => Out_Last, Flush => Flush_Finish (Last < In_Buffer'First)); if Out_Buffer'First <= Out_Last then Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); end if; exit Main when Stream_End (Filter); -- The end of in buffer. exit when In_Last = Last; In_First := In_Last + 1; end loop; end loop Main; end Generic_Translate; ------------------ -- Inflate_Init -- ------------------ procedure Inflate_Init (Filter : in out Filter_Type; Window_Bits : in Window_Bits_Type := Default_Window_Bits; Header : in Header_Type := Default) is use type Thin.Int; Win_Bits : Thin.Int := Thin.Int (Window_Bits); procedure Check_Version; -- Check the latest header types compatibility. procedure Check_Version is begin if Version <= "1.1.4" then Raise_Error ("Inflate header type " & Header_Type'Image (Header) & " incompatible with ZLib version " & Version); end if; end Check_Version; begin if Is_Open (Filter) then raise Status_Error; end if; case Header is when None => Check_Version; -- Inflate data without headers determined -- by negative Win_Bits. Win_Bits := -Win_Bits; when GZip => Check_Version; -- Inflate gzip data defined by flag 16. Win_Bits := Win_Bits + 16; when Auto => Check_Version; -- Inflate with automatic detection -- of gzip or native header defined by flag 32. Win_Bits := Win_Bits + 32; when Default => null; end case; Filter.Strm := new Z_Stream; Filter.Compression := False; Filter.Stream_End := False; Filter.Header := Header; if Thin.Inflate_Init (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK then Raise_Error (Filter.Strm.all); end if; end Inflate_Init; ------------- -- Is_Open -- ------------- function Is_Open (Filter : in Filter_Type) return Boolean is begin return Filter.Strm /= null; end Is_Open; ----------------- -- Raise_Error -- ----------------- procedure Raise_Error (Message : in String) is begin Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); end Raise_Error; procedure Raise_Error (Stream : in Z_Stream) is begin Raise_Error (Last_Error_Message (Stream)); end Raise_Error; ---------- -- Read -- ---------- procedure Read (Filter : in out Filter_Type; Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode := No_Flush) is In_Last : Stream_Element_Offset; Item_First : Ada.Streams.Stream_Element_Offset := Item'First; V_Flush : Flush_Mode := Flush; begin pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); loop if Rest_Last = Buffer'First - 1 then V_Flush := Finish; elsif Rest_First > Rest_Last then Read (Buffer, Rest_Last); Rest_First := Buffer'First; if Rest_Last < Buffer'First then V_Flush := Finish; end if; end if; Translate (Filter => Filter, In_Data => Buffer (Rest_First .. Rest_Last), In_Last => In_Last, Out_Data => Item (Item_First .. Item'Last), Out_Last => Last, Flush => V_Flush); Rest_First := In_Last + 1; exit when Stream_End (Filter) or else Last = Item'Last or else (Last >= Item'First and then Allow_Read_Some); Item_First := Last + 1; end loop; end Read; ---------------- -- Stream_End -- ---------------- function Stream_End (Filter : in Filter_Type) return Boolean is begin if Filter.Header = GZip and Filter.Compression then return Filter.Stream_End and then Filter.Offset = Footer_Array'Last + 1; else return Filter.Stream_End; end if; end Stream_End; -------------- -- Total_In -- -------------- function Total_In (Filter : in Filter_Type) return Count is begin return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); end Total_In; --------------- -- Total_Out -- --------------- function Total_Out (Filter : in Filter_Type) return Count is begin return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); end Total_Out; --------------- -- Translate -- --------------- procedure Translate (Filter : in out Filter_Type; In_Data : in Ada.Streams.Stream_Element_Array; In_Last : out Ada.Streams.Stream_Element_Offset; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode) is begin if Filter.Header = GZip and then Filter.Compression then Translate_GZip (Filter => Filter, In_Data => In_Data, In_Last => In_Last, Out_Data => Out_Data, Out_Last => Out_Last, Flush => Flush); else Translate_Auto (Filter => Filter, In_Data => In_Data, In_Last => In_Last, Out_Data => Out_Data, Out_Last => Out_Last, Flush => Flush); end if; end Translate; -------------------- -- Translate_Auto -- -------------------- procedure Translate_Auto (Filter : in out Filter_Type; In_Data : in Ada.Streams.Stream_Element_Array; In_Last : out Ada.Streams.Stream_Element_Offset; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode) is use type Thin.Int; Code : Thin.Int; begin if not Is_Open (Filter) then raise Status_Error; end if; if Out_Data'Length = 0 and then In_Data'Length = 0 then raise Constraint_Error; end if; Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length); Code := Flate (Filter.Compression).Step (To_Thin_Access (Filter.Strm), Thin.Int (Flush)); if Code = Thin.Z_STREAM_END then Filter.Stream_End := True; else Check_Error (Filter.Strm.all, Code); end if; In_Last := In_Data'Last - Stream_Element_Offset (Avail_In (Filter.Strm.all)); Out_Last := Out_Data'Last - Stream_Element_Offset (Avail_Out (Filter.Strm.all)); end Translate_Auto; -------------------- -- Translate_GZip -- -------------------- procedure Translate_GZip (Filter : in out Filter_Type; In_Data : in Ada.Streams.Stream_Element_Array; In_Last : out Ada.Streams.Stream_Element_Offset; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode) is Out_First : Stream_Element_Offset; procedure Add_Data (Data : in Stream_Element_Array); -- Add data to stream from the Filter.Offset till necessary, -- used for add gzip headr/footer. procedure Put_32 (Item : in out Stream_Element_Array; Data : in Unsigned_32); pragma Inline (Put_32); -------------- -- Add_Data -- -------------- procedure Add_Data (Data : in Stream_Element_Array) is Data_First : Stream_Element_Offset renames Filter.Offset; Data_Last : Stream_Element_Offset; Data_Len : Stream_Element_Offset; -- -1 Out_Len : Stream_Element_Offset; -- -1 begin Out_First := Out_Last + 1; if Data_First > Data'Last then return; end if; Data_Len := Data'Last - Data_First; Out_Len := Out_Data'Last - Out_First; if Data_Len <= Out_Len then Out_Last := Out_First + Data_Len; Data_Last := Data'Last; else Out_Last := Out_Data'Last; Data_Last := Data_First + Out_Len; end if; Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); Data_First := Data_Last + 1; Out_First := Out_Last + 1; end Add_Data; ------------ -- Put_32 -- ------------ procedure Put_32 (Item : in out Stream_Element_Array; Data : in Unsigned_32) is D : Unsigned_32 := Data; begin for J in Item'First .. Item'First + 3 loop Item (J) := Stream_Element (D and 16#FF#); D := Shift_Right (D, 8); end loop; end Put_32; begin Out_Last := Out_Data'First - 1; if not Filter.Stream_End then Add_Data (Simple_GZip_Header); Translate_Auto (Filter => Filter, In_Data => In_Data, In_Last => In_Last, Out_Data => Out_Data (Out_First .. Out_Data'Last), Out_Last => Out_Last, Flush => Flush); CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); end if; if Filter.Stream_End and then Out_Last <= Out_Data'Last then -- This detection method would work only when -- Simple_GZip_Header'Last > Footer_Array'Last if Filter.Offset = Simple_GZip_Header'Last + 1 then Filter.Offset := Footer_Array'First; end if; declare Footer : Footer_Array; begin Put_32 (Footer, Filter.CRC); Put_32 (Footer (Footer'First + 4 .. Footer'Last), Unsigned_32 (Total_In (Filter))); Add_Data (Footer); end; end if; end Translate_GZip; ------------- -- Version -- ------------- function Version return String is begin return Interfaces.C.Strings.Value (Thin.zlibVersion); end Version; ----------- -- Write -- ----------- procedure Write (Filter : in out Filter_Type; Item : in Ada.Streams.Stream_Element_Array; Flush : in Flush_Mode := No_Flush) is Buffer : Stream_Element_Array (1 .. Buffer_Size); In_Last : Stream_Element_Offset; Out_Last : Stream_Element_Offset; In_First : Stream_Element_Offset := Item'First; begin if Item'Length = 0 and Flush = No_Flush then return; end if; loop Translate (Filter => Filter, In_Data => Item (In_First .. Item'Last), In_Last => In_Last, Out_Data => Buffer, Out_Last => Out_Last, Flush => Flush); if Out_Last >= Buffer'First then Write (Buffer (1 .. Out_Last)); end if; exit when In_Last = Item'Last or Stream_End (Filter); In_First := In_Last + 1; end loop; end Write; end ZLib; |
Added compat/zlib/contrib/ada/zlib.ads.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | ------------------------------------------------------------------------------ -- ZLib for Ada thick binding. -- -- -- -- Copyright (C) 2002-2004 Dmitriy Anisimkov -- -- -- -- This library 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 library 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 library; if not, write to the Free Software Foundation, -- -- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- ------------------------------------------------------------------------------ -- $Id: zlib.ads,v 1.26 2004/09/06 06:53:19 vagul Exp $ with Ada.Streams; with Interfaces; package ZLib is ZLib_Error : exception; Status_Error : exception; type Compression_Level is new Integer range -1 .. 9; type Flush_Mode is private; type Compression_Method is private; type Window_Bits_Type is new Integer range 8 .. 15; type Memory_Level_Type is new Integer range 1 .. 9; type Unsigned_32 is new Interfaces.Unsigned_32; type Strategy_Type is private; type Header_Type is (None, Auto, Default, GZip); -- Header type usage have a some limitation for inflate. -- See comment for Inflate_Init. subtype Count is Ada.Streams.Stream_Element_Count; Default_Memory_Level : constant Memory_Level_Type := 8; Default_Window_Bits : constant Window_Bits_Type := 15; ---------------------------------- -- Compression method constants -- ---------------------------------- Deflated : constant Compression_Method; -- Only one method allowed in this ZLib version --------------------------------- -- Compression level constants -- --------------------------------- No_Compression : constant Compression_Level := 0; Best_Speed : constant Compression_Level := 1; Best_Compression : constant Compression_Level := 9; Default_Compression : constant Compression_Level := -1; -------------------------- -- Flush mode constants -- -------------------------- No_Flush : constant Flush_Mode; -- Regular way for compression, no flush Partial_Flush : constant Flush_Mode; -- Will be removed, use Z_SYNC_FLUSH instead Sync_Flush : constant Flush_Mode; -- All pending output is flushed to the output buffer and the output -- is aligned on a byte boundary, so that the decompressor can get all -- input data available so far. (In particular avail_in is zero after the -- call if enough output space has been provided before the call.) -- Flushing may degrade compression for some compression algorithms and so -- it should be used only when necessary. Block_Flush : constant Flush_Mode; -- Z_BLOCK requests that inflate() stop -- if and when it get to the next deflate block boundary. When decoding the -- zlib or gzip format, this will cause inflate() to return immediately -- after the header and before the first block. When doing a raw inflate, -- inflate() will go ahead and process the first block, and will return -- when it gets to the end of that block, or when it runs out of data. Full_Flush : constant Flush_Mode; -- All output is flushed as with SYNC_FLUSH, and the compression state -- is reset so that decompression can restart from this point if previous -- compressed data has been damaged or if random access is desired. Using -- Full_Flush too often can seriously degrade the compression. Finish : constant Flush_Mode; -- Just for tell the compressor that input data is complete. ------------------------------------ -- Compression strategy constants -- ------------------------------------ -- RLE stategy could be used only in version 1.2.0 and later. Filtered : constant Strategy_Type; Huffman_Only : constant Strategy_Type; RLE : constant Strategy_Type; Default_Strategy : constant Strategy_Type; Default_Buffer_Size : constant := 4096; type Filter_Type is tagged limited private; -- The filter is for compression and for decompression. -- The usage of the type is depend of its initialization. function Version return String; pragma Inline (Version); -- Return string representation of the ZLib version. procedure Deflate_Init (Filter : in out Filter_Type; Level : in Compression_Level := Default_Compression; Strategy : in Strategy_Type := Default_Strategy; Method : in Compression_Method := Deflated; Window_Bits : in Window_Bits_Type := Default_Window_Bits; Memory_Level : in Memory_Level_Type := Default_Memory_Level; Header : in Header_Type := Default); -- Compressor initialization. -- When Header parameter is Auto or Default, then default zlib header -- would be provided for compressed data. -- When Header is GZip, then gzip header would be set instead of -- default header. -- When Header is None, no header would be set for compressed data. procedure Inflate_Init (Filter : in out Filter_Type; Window_Bits : in Window_Bits_Type := Default_Window_Bits; Header : in Header_Type := Default); -- Decompressor initialization. -- Default header type mean that ZLib default header is expecting in the -- input compressed stream. -- Header type None mean that no header is expecting in the input stream. -- GZip header type mean that GZip header is expecting in the -- input compressed stream. -- Auto header type mean that header type (GZip or Native) would be -- detected automatically in the input stream. -- Note that header types parameter values None, GZip and Auto are -- supported for inflate routine only in ZLib versions 1.2.0.2 and later. -- Deflate_Init is supporting all header types. function Is_Open (Filter : in Filter_Type) return Boolean; pragma Inline (Is_Open); -- Is the filter opened for compression or decompression. procedure Close (Filter : in out Filter_Type; Ignore_Error : in Boolean := False); -- Closing the compression or decompressor. -- If stream is closing before the complete and Ignore_Error is False, -- The exception would be raised. generic with procedure Data_In (Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset); with procedure Data_Out (Item : in Ada.Streams.Stream_Element_Array); procedure Generic_Translate (Filter : in out Filter_Type; In_Buffer_Size : in Integer := Default_Buffer_Size; Out_Buffer_Size : in Integer := Default_Buffer_Size); -- Compress/decompress data fetch from Data_In routine and pass the result -- to the Data_Out routine. User should provide Data_In and Data_Out -- for compression/decompression data flow. -- Compression or decompression depend on Filter initialization. function Total_In (Filter : in Filter_Type) return Count; pragma Inline (Total_In); -- Returns total number of input bytes read so far function Total_Out (Filter : in Filter_Type) return Count; pragma Inline (Total_Out); -- Returns total number of bytes output so far function CRC32 (CRC : in Unsigned_32; Data : in Ada.Streams.Stream_Element_Array) return Unsigned_32; pragma Inline (CRC32); -- Compute CRC32, it could be necessary for make gzip format procedure CRC32 (CRC : in out Unsigned_32; Data : in Ada.Streams.Stream_Element_Array); pragma Inline (CRC32); -- Compute CRC32, it could be necessary for make gzip format ------------------------------------------------- -- Below is more complex low level routines. -- ------------------------------------------------- procedure Translate (Filter : in out Filter_Type; In_Data : in Ada.Streams.Stream_Element_Array; In_Last : out Ada.Streams.Stream_Element_Offset; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode); -- Compress/decompress the In_Data buffer and place the result into -- Out_Data. In_Last is the index of last element from In_Data accepted by -- the Filter. Out_Last is the last element of the received data from -- Filter. To tell the filter that incoming data are complete put the -- Flush parameter to Finish. function Stream_End (Filter : in Filter_Type) return Boolean; pragma Inline (Stream_End); -- Return the true when the stream is complete. procedure Flush (Filter : in out Filter_Type; Out_Data : out Ada.Streams.Stream_Element_Array; Out_Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode); pragma Inline (Flush); -- Flushing the data from the compressor. generic with procedure Write (Item : in Ada.Streams.Stream_Element_Array); -- User should provide this routine for accept -- compressed/decompressed data. Buffer_Size : in Ada.Streams.Stream_Element_Offset := Default_Buffer_Size; -- Buffer size for Write user routine. procedure Write (Filter : in out Filter_Type; Item : in Ada.Streams.Stream_Element_Array; Flush : in Flush_Mode := No_Flush); -- Compress/Decompress data from Item to the generic parameter procedure -- Write. Output buffer size could be set in Buffer_Size generic parameter. generic with procedure Read (Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset); -- User should provide data for compression/decompression -- thru this routine. Buffer : in out Ada.Streams.Stream_Element_Array; -- Buffer for keep remaining data from the previous -- back read. Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset; -- Rest_First have to be initialized to Buffer'Last + 1 -- Rest_Last have to be initialized to Buffer'Last -- before usage. Allow_Read_Some : in Boolean := False; -- Is it allowed to return Last < Item'Last before end of data. procedure Read (Filter : in out Filter_Type; Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset; Flush : in Flush_Mode := No_Flush); -- Compress/Decompress data from generic parameter procedure Read to the -- Item. User should provide Buffer and initialized Rest_First, Rest_Last -- indicators. If Allow_Read_Some is True, Read routines could return -- Last < Item'Last only at end of stream. private use Ada.Streams; pragma Assert (Ada.Streams.Stream_Element'Size = 8); pragma Assert (Ada.Streams.Stream_Element'Modulus = 2**8); type Flush_Mode is new Integer range 0 .. 5; type Compression_Method is new Integer range 8 .. 8; type Strategy_Type is new Integer range 0 .. 3; No_Flush : constant Flush_Mode := 0; Partial_Flush : constant Flush_Mode := 1; Sync_Flush : constant Flush_Mode := 2; Full_Flush : constant Flush_Mode := 3; Finish : constant Flush_Mode := 4; Block_Flush : constant Flush_Mode := 5; Filtered : constant Strategy_Type := 1; Huffman_Only : constant Strategy_Type := 2; RLE : constant Strategy_Type := 3; Default_Strategy : constant Strategy_Type := 0; Deflated : constant Compression_Method := 8; type Z_Stream; type Z_Stream_Access is access all Z_Stream; type Filter_Type is tagged limited record Strm : Z_Stream_Access; Compression : Boolean; Stream_End : Boolean; Header : Header_Type; CRC : Unsigned_32; Offset : Stream_Element_Offset; -- Offset for gzip header/footer output. end record; end ZLib; |
Added compat/zlib/contrib/ada/zlib.gpr.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | project Zlib is for Languages use ("Ada"); for Source_Dirs use ("."); for Object_Dir use "."; for Main use ("test.adb", "mtest.adb", "read.adb", "buffer_demo"); package Compiler is for Default_Switches ("ada") use ("-gnatwcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst"); end Compiler; package Linker is for Default_Switches ("ada") use ("-lz"); end Linker; package Builder is for Default_Switches ("ada") use ("-s", "-gnatQ"); end Builder; end Zlib; |
Added compat/zlib/contrib/amd64/amd64-match.S.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | /* * match.S -- optimized version of longest_match() * based on the similar work by Gilles Vollant, and Brian Raiter, written 1998 * * This is free software; you can redistribute it and/or modify it * under the terms of the BSD License. Use by owners of Che Guevarra * parafernalia is prohibited, where possible, and highly discouraged * elsewhere. */ #ifndef NO_UNDERLINE # define match_init _match_init # define longest_match _longest_match #endif #define scanend ebx #define scanendw bx #define chainlenwmask edx /* high word: current chain len low word: s->wmask */ #define curmatch rsi #define curmatchd esi #define windowbestlen r8 #define scanalign r9 #define scanalignd r9d #define window r10 #define bestlen r11 #define bestlend r11d #define scanstart r12d #define scanstartw r12w #define scan r13 #define nicematch r14d #define limit r15 #define limitd r15d #define prev rcx /* * The 258 is a "magic number, not a parameter -- changing it * breaks the hell loose */ #define MAX_MATCH (258) #define MIN_MATCH (3) #define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) #define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) /* stack frame offsets */ #define LocalVarsSize (112) #define _chainlenwmask ( 8-LocalVarsSize)(%rsp) #define _windowbestlen (16-LocalVarsSize)(%rsp) #define save_r14 (24-LocalVarsSize)(%rsp) #define save_rsi (32-LocalVarsSize)(%rsp) #define save_rbx (40-LocalVarsSize)(%rsp) #define save_r12 (56-LocalVarsSize)(%rsp) #define save_r13 (64-LocalVarsSize)(%rsp) #define save_r15 (80-LocalVarsSize)(%rsp) .globl match_init, longest_match /* * On AMD64 the first argument of a function (in our case -- the pointer to * deflate_state structure) is passed in %rdi, hence our offsets below are * all off of that. */ /* you can check the structure offset by running #include <stdlib.h> #include <stdio.h> #include "deflate.h" void print_depl() { deflate_state ds; deflate_state *s=&ds; printf("size pointer=%u\n",(int)sizeof(void*)); printf("#define dsWSize (%3u)(%%rdi)\n",(int)(((char*)&(s->w_size))-((char*)s))); printf("#define dsWMask (%3u)(%%rdi)\n",(int)(((char*)&(s->w_mask))-((char*)s))); printf("#define dsWindow (%3u)(%%rdi)\n",(int)(((char*)&(s->window))-((char*)s))); printf("#define dsPrev (%3u)(%%rdi)\n",(int)(((char*)&(s->prev))-((char*)s))); printf("#define dsMatchLen (%3u)(%%rdi)\n",(int)(((char*)&(s->match_length))-((char*)s))); printf("#define dsPrevMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_match))-((char*)s))); printf("#define dsStrStart (%3u)(%%rdi)\n",(int)(((char*)&(s->strstart))-((char*)s))); printf("#define dsMatchStart (%3u)(%%rdi)\n",(int)(((char*)&(s->match_start))-((char*)s))); printf("#define dsLookahead (%3u)(%%rdi)\n",(int)(((char*)&(s->lookahead))-((char*)s))); printf("#define dsPrevLen (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_length))-((char*)s))); printf("#define dsMaxChainLen (%3u)(%%rdi)\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); printf("#define dsGoodMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->good_match))-((char*)s))); printf("#define dsNiceMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->nice_match))-((char*)s))); } */ /* to compile for XCode 3.2 on MacOSX x86_64 - run "gcc -g -c -DXCODE_MAC_X64_STRUCTURE amd64-match.S" */ #ifndef CURRENT_LINX_XCODE_MAC_X64_STRUCTURE #define dsWSize ( 68)(%rdi) #define dsWMask ( 76)(%rdi) #define dsWindow ( 80)(%rdi) #define dsPrev ( 96)(%rdi) #define dsMatchLen (144)(%rdi) #define dsPrevMatch (148)(%rdi) #define dsStrStart (156)(%rdi) #define dsMatchStart (160)(%rdi) #define dsLookahead (164)(%rdi) #define dsPrevLen (168)(%rdi) #define dsMaxChainLen (172)(%rdi) #define dsGoodMatch (188)(%rdi) #define dsNiceMatch (192)(%rdi) #else #ifndef STRUCT_OFFSET # define STRUCT_OFFSET (0) #endif #define dsWSize ( 56 + STRUCT_OFFSET)(%rdi) #define dsWMask ( 64 + STRUCT_OFFSET)(%rdi) #define dsWindow ( 72 + STRUCT_OFFSET)(%rdi) #define dsPrev ( 88 + STRUCT_OFFSET)(%rdi) #define dsMatchLen (136 + STRUCT_OFFSET)(%rdi) #define dsPrevMatch (140 + STRUCT_OFFSET)(%rdi) #define dsStrStart (148 + STRUCT_OFFSET)(%rdi) #define dsMatchStart (152 + STRUCT_OFFSET)(%rdi) #define dsLookahead (156 + STRUCT_OFFSET)(%rdi) #define dsPrevLen (160 + STRUCT_OFFSET)(%rdi) #define dsMaxChainLen (164 + STRUCT_OFFSET)(%rdi) #define dsGoodMatch (180 + STRUCT_OFFSET)(%rdi) #define dsNiceMatch (184 + STRUCT_OFFSET)(%rdi) #endif .text /* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ longest_match: /* * Retrieve the function arguments. %curmatch will hold cur_match * throughout the entire function (passed via rsi on amd64). * rdi will hold the pointer to the deflate_state (first arg on amd64) */ mov %rsi, save_rsi mov %rbx, save_rbx mov %r12, save_r12 mov %r13, save_r13 mov %r14, save_r14 mov %r15, save_r15 /* uInt wmask = s->w_mask; */ /* unsigned chain_length = s->max_chain_length; */ /* if (s->prev_length >= s->good_match) { */ /* chain_length >>= 2; */ /* } */ movl dsPrevLen, %eax movl dsGoodMatch, %ebx cmpl %ebx, %eax movl dsWMask, %eax movl dsMaxChainLen, %chainlenwmask jl LastMatchGood shrl $2, %chainlenwmask LastMatchGood: /* chainlen is decremented once beforehand so that the function can */ /* use the sign flag instead of the zero flag for the exit test. */ /* It is then shifted into the high word, to make room for the wmask */ /* value, which it will always accompany. */ decl %chainlenwmask shll $16, %chainlenwmask orl %eax, %chainlenwmask /* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ movl dsNiceMatch, %eax movl dsLookahead, %ebx cmpl %eax, %ebx jl LookaheadLess movl %eax, %ebx LookaheadLess: movl %ebx, %nicematch /* register Bytef *scan = s->window + s->strstart; */ mov dsWindow, %window movl dsStrStart, %limitd lea (%limit, %window), %scan /* Determine how many bytes the scan ptr is off from being */ /* dword-aligned. */ mov %scan, %scanalign negl %scanalignd andl $3, %scanalignd /* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ /* s->strstart - (IPos)MAX_DIST(s) : NIL; */ movl dsWSize, %eax subl $MIN_LOOKAHEAD, %eax xorl %ecx, %ecx subl %eax, %limitd cmovng %ecx, %limitd /* int best_len = s->prev_length; */ movl dsPrevLen, %bestlend /* Store the sum of s->window + best_len in %windowbestlen locally, and in memory. */ lea (%window, %bestlen), %windowbestlen mov %windowbestlen, _windowbestlen /* register ush scan_start = *(ushf*)scan; */ /* register ush scan_end = *(ushf*)(scan+best_len-1); */ /* Posf *prev = s->prev; */ movzwl (%scan), %scanstart movzwl -1(%scan, %bestlen), %scanend mov dsPrev, %prev /* Jump into the main loop. */ movl %chainlenwmask, _chainlenwmask jmp LoopEntry .balign 16 /* do { * match = s->window + cur_match; * if (*(ushf*)(match+best_len-1) != scan_end || * *(ushf*)match != scan_start) continue; * [...] * } while ((cur_match = prev[cur_match & wmask]) > limit * && --chain_length != 0); * * Here is the inner loop of the function. The function will spend the * majority of its time in this loop, and majority of that time will * be spent in the first ten instructions. */ LookupLoop: andl %chainlenwmask, %curmatchd movzwl (%prev, %curmatch, 2), %curmatchd cmpl %limitd, %curmatchd jbe LeaveNow subl $0x00010000, %chainlenwmask js LeaveNow LoopEntry: cmpw -1(%windowbestlen, %curmatch), %scanendw jne LookupLoop cmpw %scanstartw, (%window, %curmatch) jne LookupLoop /* Store the current value of chainlen. */ movl %chainlenwmask, _chainlenwmask /* %scan is the string under scrutiny, and %prev to the string we */ /* are hoping to match it up with. In actuality, %esi and %edi are */ /* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ /* initialized to -(MAX_MATCH_8 - scanalign). */ mov $(-MAX_MATCH_8), %rdx lea (%curmatch, %window), %windowbestlen lea MAX_MATCH_8(%windowbestlen, %scanalign), %windowbestlen lea MAX_MATCH_8(%scan, %scanalign), %prev /* the prefetching below makes very little difference... */ prefetcht1 (%windowbestlen, %rdx) prefetcht1 (%prev, %rdx) /* * Test the strings for equality, 8 bytes at a time. At the end, * adjust %rdx so that it is offset to the exact byte that mismatched. * * It should be confessed that this loop usually does not represent * much of the total running time. Replacing it with a more * straightforward "rep cmpsb" would not drastically degrade * performance -- unrolling it, for example, makes no difference. */ #undef USE_SSE /* works, but is 6-7% slower, than non-SSE... */ LoopCmps: #ifdef USE_SSE /* Preload the SSE registers */ movdqu (%windowbestlen, %rdx), %xmm1 movdqu (%prev, %rdx), %xmm2 pcmpeqb %xmm2, %xmm1 movdqu 16(%windowbestlen, %rdx), %xmm3 movdqu 16(%prev, %rdx), %xmm4 pcmpeqb %xmm4, %xmm3 movdqu 32(%windowbestlen, %rdx), %xmm5 movdqu 32(%prev, %rdx), %xmm6 pcmpeqb %xmm6, %xmm5 movdqu 48(%windowbestlen, %rdx), %xmm7 movdqu 48(%prev, %rdx), %xmm8 pcmpeqb %xmm8, %xmm7 /* Check the comparisions' results */ pmovmskb %xmm1, %rax notw %ax bsfw %ax, %ax jnz LeaveLoopCmps /* this is the only iteration of the loop with a possibility of having incremented rdx by 0x108 (each loop iteration add 16*4 = 0x40 and (0x40*4)+8=0x108 */ add $8, %rdx jz LenMaximum add $8, %rdx pmovmskb %xmm3, %rax notw %ax bsfw %ax, %ax jnz LeaveLoopCmps add $16, %rdx pmovmskb %xmm5, %rax notw %ax bsfw %ax, %ax jnz LeaveLoopCmps add $16, %rdx pmovmskb %xmm7, %rax notw %ax bsfw %ax, %ax jnz LeaveLoopCmps add $16, %rdx jmp LoopCmps LeaveLoopCmps: add %rax, %rdx #else mov (%windowbestlen, %rdx), %rax xor (%prev, %rdx), %rax jnz LeaveLoopCmps mov 8(%windowbestlen, %rdx), %rax xor 8(%prev, %rdx), %rax jnz LeaveLoopCmps8 mov 16(%windowbestlen, %rdx), %rax xor 16(%prev, %rdx), %rax jnz LeaveLoopCmps16 add $24, %rdx jnz LoopCmps jmp LenMaximum # if 0 /* * This three-liner is tantalizingly simple, but bsf is a slow instruction, * and the complicated alternative down below is quite a bit faster. Sad... */ LeaveLoopCmps: bsf %rax, %rax /* find the first non-zero bit */ shrl $3, %eax /* divide by 8 to get the byte */ add %rax, %rdx # else LeaveLoopCmps16: add $8, %rdx LeaveLoopCmps8: add $8, %rdx LeaveLoopCmps: testl $0xFFFFFFFF, %eax /* Check the first 4 bytes */ jnz Check16 add $4, %rdx shr $32, %rax Check16: testw $0xFFFF, %ax jnz LenLower add $2, %rdx shrl $16, %eax LenLower: subb $1, %al adc $0, %rdx # endif #endif /* Calculate the length of the match. If it is longer than MAX_MATCH, */ /* then automatically accept it as the best possible match and leave. */ lea (%prev, %rdx), %rax sub %scan, %rax cmpl $MAX_MATCH, %eax jge LenMaximum /* If the length of the match is not longer than the best match we */ /* have so far, then forget it and return to the lookup loop. */ cmpl %bestlend, %eax jg LongerMatch mov _windowbestlen, %windowbestlen mov dsPrev, %prev movl _chainlenwmask, %edx jmp LookupLoop /* s->match_start = cur_match; */ /* best_len = len; */ /* if (len >= nice_match) break; */ /* scan_end = *(ushf*)(scan+best_len-1); */ LongerMatch: movl %eax, %bestlend movl %curmatchd, dsMatchStart cmpl %nicematch, %eax jge LeaveNow lea (%window, %bestlen), %windowbestlen mov %windowbestlen, _windowbestlen movzwl -1(%scan, %rax), %scanend mov dsPrev, %prev movl _chainlenwmask, %chainlenwmask jmp LookupLoop /* Accept the current string, with the maximum possible length. */ LenMaximum: movl $MAX_MATCH, %bestlend movl %curmatchd, dsMatchStart /* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ /* return s->lookahead; */ LeaveNow: movl dsLookahead, %eax cmpl %eax, %bestlend cmovngl %bestlend, %eax LookaheadRet: /* Restore the registers and return from whence we came. */ mov save_rsi, %rsi mov save_rbx, %rbx mov save_r12, %r12 mov save_r13, %r13 mov save_r14, %r14 mov save_r15, %r15 ret match_init: ret |
Added compat/zlib/contrib/asm686/README.686.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | This is a patched version of zlib, modified to use Pentium-Pro-optimized assembly code in the deflation algorithm. The files changed/added by this patch are: README.686 match.S The speedup that this patch provides varies, depending on whether the compiler used to build the original version of zlib falls afoul of the PPro's speed traps. My own tests show a speedup of around 10-20% at the default compression level, and 20-30% using -9, against a version compiled using gcc 2.7.2.3. Your mileage may vary. Note that this code has been tailored for the PPro/PII in particular, and will not perform particuarly well on a Pentium. If you are using an assembler other than GNU as, you will have to translate match.S to use your assembler's syntax. (Have fun.) Brian Raiter breadbox@muppetlabs.com April, 1998 Added for zlib 1.1.3: The patches come from http://www.muppetlabs.com/~breadbox/software/assembly.html To compile zlib with this asm file, copy match.S to the zlib directory then do: CFLAGS="-O3 -DASMV" ./configure make OBJA=match.o Update: I've been ignoring these assembly routines for years, believing that gcc's generated code had caught up with it sometime around gcc 2.95 and the major rearchitecting of the Pentium 4. However, I recently learned that, despite what I believed, this code still has some life in it. On the Pentium 4 and AMD64 chips, it continues to run about 8% faster than the code produced by gcc 4.1. In acknowledgement of its continuing usefulness, I've altered the license to match that of the rest of zlib. Share and Enjoy! Brian Raiter breadbox@muppetlabs.com April, 2007 |
Added compat/zlib/contrib/asm686/match.S.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | /* match.S -- x86 assembly version of the zlib longest_match() function. * Optimized for the Intel 686 chips (PPro and later). * * Copyright (C) 1998, 2007 Brian Raiter <breadbox@muppetlabs.com> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef NO_UNDERLINE #define match_init _match_init #define longest_match _longest_match #endif #define MAX_MATCH (258) #define MIN_MATCH (3) #define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) #define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) /* stack frame offsets */ #define chainlenwmask 0 /* high word: current chain len */ /* low word: s->wmask */ #define window 4 /* local copy of s->window */ #define windowbestlen 8 /* s->window + bestlen */ #define scanstart 16 /* first two bytes of string */ #define scanend 12 /* last two bytes of string */ #define scanalign 20 /* dword-misalignment of string */ #define nicematch 24 /* a good enough match size */ #define bestlen 28 /* size of best match so far */ #define scan 32 /* ptr to string wanting match */ #define LocalVarsSize (36) /* saved ebx 36 */ /* saved edi 40 */ /* saved esi 44 */ /* saved ebp 48 */ /* return address 52 */ #define deflatestate 56 /* the function arguments */ #define curmatch 60 /* All the +zlib1222add offsets are due to the addition of fields * in zlib in the deflate_state structure since the asm code was first written * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). */ #define zlib1222add (8) #define dsWSize (36+zlib1222add) #define dsWMask (44+zlib1222add) #define dsWindow (48+zlib1222add) #define dsPrev (56+zlib1222add) #define dsMatchLen (88+zlib1222add) #define dsPrevMatch (92+zlib1222add) #define dsStrStart (100+zlib1222add) #define dsMatchStart (104+zlib1222add) #define dsLookahead (108+zlib1222add) #define dsPrevLen (112+zlib1222add) #define dsMaxChainLen (116+zlib1222add) #define dsGoodMatch (132+zlib1222add) #define dsNiceMatch (136+zlib1222add) .file "match.S" .globl match_init, longest_match .text /* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ .cfi_sections .debug_frame longest_match: .cfi_startproc /* Save registers that the compiler may be using, and adjust %esp to */ /* make room for our stack frame. */ pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset ebp, -8 pushl %edi .cfi_def_cfa_offset 12 pushl %esi .cfi_def_cfa_offset 16 pushl %ebx .cfi_def_cfa_offset 20 subl $LocalVarsSize, %esp .cfi_def_cfa_offset LocalVarsSize+20 /* Retrieve the function arguments. %ecx will hold cur_match */ /* throughout the entire function. %edx will hold the pointer to the */ /* deflate_state structure during the function's setup (before */ /* entering the main loop). */ movl deflatestate(%esp), %edx movl curmatch(%esp), %ecx /* uInt wmask = s->w_mask; */ /* unsigned chain_length = s->max_chain_length; */ /* if (s->prev_length >= s->good_match) { */ /* chain_length >>= 2; */ /* } */ movl dsPrevLen(%edx), %eax movl dsGoodMatch(%edx), %ebx cmpl %ebx, %eax movl dsWMask(%edx), %eax movl dsMaxChainLen(%edx), %ebx jl LastMatchGood shrl $2, %ebx LastMatchGood: /* chainlen is decremented once beforehand so that the function can */ /* use the sign flag instead of the zero flag for the exit test. */ /* It is then shifted into the high word, to make room for the wmask */ /* value, which it will always accompany. */ decl %ebx shll $16, %ebx orl %eax, %ebx movl %ebx, chainlenwmask(%esp) /* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ movl dsNiceMatch(%edx), %eax movl dsLookahead(%edx), %ebx cmpl %eax, %ebx jl LookaheadLess movl %eax, %ebx LookaheadLess: movl %ebx, nicematch(%esp) /* register Bytef *scan = s->window + s->strstart; */ movl dsWindow(%edx), %esi movl %esi, window(%esp) movl dsStrStart(%edx), %ebp lea (%esi,%ebp), %edi movl %edi, scan(%esp) /* Determine how many bytes the scan ptr is off from being */ /* dword-aligned. */ movl %edi, %eax negl %eax andl $3, %eax movl %eax, scanalign(%esp) /* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ /* s->strstart - (IPos)MAX_DIST(s) : NIL; */ movl dsWSize(%edx), %eax subl $MIN_LOOKAHEAD, %eax subl %eax, %ebp jg LimitPositive xorl %ebp, %ebp LimitPositive: /* int best_len = s->prev_length; */ movl dsPrevLen(%edx), %eax movl %eax, bestlen(%esp) /* Store the sum of s->window + best_len in %esi locally, and in %esi. */ addl %eax, %esi movl %esi, windowbestlen(%esp) /* register ush scan_start = *(ushf*)scan; */ /* register ush scan_end = *(ushf*)(scan+best_len-1); */ /* Posf *prev = s->prev; */ movzwl (%edi), %ebx movl %ebx, scanstart(%esp) movzwl -1(%edi,%eax), %ebx movl %ebx, scanend(%esp) movl dsPrev(%edx), %edi /* Jump into the main loop. */ movl chainlenwmask(%esp), %edx jmp LoopEntry .balign 16 /* do { * match = s->window + cur_match; * if (*(ushf*)(match+best_len-1) != scan_end || * *(ushf*)match != scan_start) continue; * [...] * } while ((cur_match = prev[cur_match & wmask]) > limit * && --chain_length != 0); * * Here is the inner loop of the function. The function will spend the * majority of its time in this loop, and majority of that time will * be spent in the first ten instructions. * * Within this loop: * %ebx = scanend * %ecx = curmatch * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) * %esi = windowbestlen - i.e., (window + bestlen) * %edi = prev * %ebp = limit */ LookupLoop: andl %edx, %ecx movzwl (%edi,%ecx,2), %ecx cmpl %ebp, %ecx jbe LeaveNow subl $0x00010000, %edx js LeaveNow LoopEntry: movzwl -1(%esi,%ecx), %eax cmpl %ebx, %eax jnz LookupLoop movl window(%esp), %eax movzwl (%eax,%ecx), %eax cmpl scanstart(%esp), %eax jnz LookupLoop /* Store the current value of chainlen. */ movl %edx, chainlenwmask(%esp) /* Point %edi to the string under scrutiny, and %esi to the string we */ /* are hoping to match it up with. In actuality, %esi and %edi are */ /* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ /* initialized to -(MAX_MATCH_8 - scanalign). */ movl window(%esp), %esi movl scan(%esp), %edi addl %ecx, %esi movl scanalign(%esp), %eax movl $(-MAX_MATCH_8), %edx lea MAX_MATCH_8(%edi,%eax), %edi lea MAX_MATCH_8(%esi,%eax), %esi /* Test the strings for equality, 8 bytes at a time. At the end, * adjust %edx so that it is offset to the exact byte that mismatched. * * We already know at this point that the first three bytes of the * strings match each other, and they can be safely passed over before * starting the compare loop. So what this code does is skip over 0-3 * bytes, as much as necessary in order to dword-align the %edi * pointer. (%esi will still be misaligned three times out of four.) * * It should be confessed that this loop usually does not represent * much of the total running time. Replacing it with a more * straightforward "rep cmpsb" would not drastically degrade * performance. */ LoopCmps: movl (%esi,%edx), %eax xorl (%edi,%edx), %eax jnz LeaveLoopCmps movl 4(%esi,%edx), %eax xorl 4(%edi,%edx), %eax jnz LeaveLoopCmps4 addl $8, %edx jnz LoopCmps jmp LenMaximum LeaveLoopCmps4: addl $4, %edx LeaveLoopCmps: testl $0x0000FFFF, %eax jnz LenLower addl $2, %edx shrl $16, %eax LenLower: subb $1, %al adcl $0, %edx /* Calculate the length of the match. If it is longer than MAX_MATCH, */ /* then automatically accept it as the best possible match and leave. */ lea (%edi,%edx), %eax movl scan(%esp), %edi subl %edi, %eax cmpl $MAX_MATCH, %eax jge LenMaximum /* If the length of the match is not longer than the best match we */ /* have so far, then forget it and return to the lookup loop. */ movl deflatestate(%esp), %edx movl bestlen(%esp), %ebx cmpl %ebx, %eax jg LongerMatch movl windowbestlen(%esp), %esi movl dsPrev(%edx), %edi movl scanend(%esp), %ebx movl chainlenwmask(%esp), %edx jmp LookupLoop /* s->match_start = cur_match; */ /* best_len = len; */ /* if (len >= nice_match) break; */ /* scan_end = *(ushf*)(scan+best_len-1); */ LongerMatch: movl nicematch(%esp), %ebx movl %eax, bestlen(%esp) movl %ecx, dsMatchStart(%edx) cmpl %ebx, %eax jge LeaveNow movl window(%esp), %esi addl %eax, %esi movl %esi, windowbestlen(%esp) movzwl -1(%edi,%eax), %ebx movl dsPrev(%edx), %edi movl %ebx, scanend(%esp) movl chainlenwmask(%esp), %edx jmp LookupLoop /* Accept the current string, with the maximum possible length. */ LenMaximum: movl deflatestate(%esp), %edx movl $MAX_MATCH, bestlen(%esp) movl %ecx, dsMatchStart(%edx) /* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ /* return s->lookahead; */ LeaveNow: movl deflatestate(%esp), %edx movl bestlen(%esp), %ebx movl dsLookahead(%edx), %eax cmpl %eax, %ebx jg LookaheadRet movl %ebx, %eax LookaheadRet: /* Restore the stack and return from whence we came. */ addl $LocalVarsSize, %esp .cfi_def_cfa_offset 20 popl %ebx .cfi_def_cfa_offset 16 popl %esi .cfi_def_cfa_offset 12 popl %edi .cfi_def_cfa_offset 8 popl %ebp .cfi_def_cfa_offset 4 .cfi_endproc match_init: ret |
Changes to compat/zlib/contrib/blast/blast.h.
︙ | ︙ | |||
53 54 55 56 57 58 59 | * The input function is invoked: len = infun(how, &buf), where buf is set by * infun() to point to the input buffer, and infun() returns the number of * available bytes there. If infun() returns zero, then blast() returns with * an input error. (blast() only asks for input if it needs it.) inhow is for * use by the application to pass an input descriptor to infun(), if desired. * * If left and in are not NULL and *left is not zero when blast() is called, | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | * The input function is invoked: len = infun(how, &buf), where buf is set by * infun() to point to the input buffer, and infun() returns the number of * available bytes there. If infun() returns zero, then blast() returns with * an input error. (blast() only asks for input if it needs it.) inhow is for * use by the application to pass an input descriptor to infun(), if desired. * * If left and in are not NULL and *left is not zero when blast() is called, * then the *left bytes are *in are consumed for input before infun() is used. * * The output function is invoked: err = outfun(how, buf, len), where the bytes * to be written are buf[0..len-1]. If err is not zero, then blast() returns * with an output error. outfun() is always called with len <= 4096. outhow * is for use by the application to pass an output descriptor to outfun(), if * desired. * |
︙ | ︙ |
Changes to compat/zlib/contrib/delphi/ZLib.pas.
︙ | ︙ | |||
148 149 150 151 152 153 154 | InBytes = number of bytes in InBuf Out: OutBuf = ptr to user-allocated buffer to contain decompressed data BufSize = number of bytes in OutBuf } procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; const OutBuf: Pointer; BufSize: Integer); const | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | InBytes = number of bytes in InBuf Out: OutBuf = ptr to user-allocated buffer to contain decompressed data BufSize = number of bytes in OutBuf } procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; const OutBuf: Pointer; BufSize: Integer); const zlib_version = '1.2.11'; type EZlibError = class(Exception); ECompressionError = class(EZlibError); EDecompressionError = class(EZlibError); implementation |
︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs.
︙ | ︙ | |||
30 31 32 33 34 35 36 | /// </summary> public ChecksumGeneratorBase() { _current = 0; } /// <summary> | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /// </summary> public ChecksumGeneratorBase() { _current = 0; } /// <summary> /// Initializes a new instance of the checksum generator basewith a specified value /// </summary> /// <param name="initialValue">The value to set the current checksum to</param> public ChecksumGeneratorBase(uint initialValue) { _current = initialValue; } |
︙ | ︙ | |||
57 58 59 60 61 62 63 | /// </summary> /// <param name="data">The data to update the checksum with</param> /// <param name="offset">Where in <c>data</c> to start updating</param> /// <param name="count">The number of bytes from <c>data</c> to use</param> /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception> /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception> /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception> | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /// </summary> /// <param name="data">The data to update the checksum with</param> /// <param name="offset">Where in <c>data</c> to start updating</param> /// <param name="count">The number of bytes from <c>data</c> to use</param> /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception> /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception> /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception> /// <remarks>All the other <c>Update</c> methods are implmeneted in terms of this one. /// This is therefore the only method a derived class has to implement</remarks> public abstract void Update(byte[] data, int offset, int count); /// <summary> /// Updates the current checksum with an array of bytes. /// </summary> /// <param name="data">The data to update the checksum with</param> |
︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs.
︙ | ︙ | |||
135 136 137 138 139 140 141 | /// <summary> /// Performs any codec specific cleanup /// </summary> /// <remarks>This must be implemented by a derived class</remarks> protected abstract void CleanUp(); | | | | 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 | /// <summary> /// Performs any codec specific cleanup /// </summary> /// <remarks>This must be implemented by a derived class</remarks> protected abstract void CleanUp(); // performs the release of the handles and calls the dereived CleanUp() private void CleanUp(bool isDisposing) { if (!_isDisposed) { CleanUp(); if (_hInput.IsAllocated) _hInput.Free(); if (_hOutput.IsAllocated) _hOutput.Free(); _isDisposed = true; } } #endregion #region Helper methods /// <summary> /// Copies a number of bytes to the internal codec buffer - ready for proccesing /// </summary> /// <param name="data">The byte array that contains the data to copy</param> /// <param name="startIndex">The index of the first byte to copy</param> /// <param name="count">The number of bytes to copy from <c>data</c></param> protected void copyInput(byte[] data, int startIndex, int count) { Array.Copy(data, startIndex, _inBuffer,0, count); |
︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs.
︙ | ︙ | |||
242 243 244 245 246 247 248 | /// <exception cref="NotSupportedException">Always thrown</exception> public override void SetLength(long value) { throw new NotSupportedException(); } /// <summary> | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | /// <exception cref="NotSupportedException">Always thrown</exception> public override void SetLength(long value) { throw new NotSupportedException(); } /// <summary> /// Not suppported. /// </summary> /// <param name="offset"></param> /// <param name="origin"></param> /// <returns></returns> /// <exception cref="NotSupportedException">Always thrown</exception> public override long Seek(long offset, SeekOrigin origin) { |
︙ | ︙ | |||
264 265 266 267 268 269 270 | /// flushing may degrade the achievable compression rates.</remarks> public override void Flush() { // left empty on purpose } /// <summary> | | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | /// flushing may degrade the achievable compression rates.</remarks> public override void Flush() { // left empty on purpose } /// <summary> /// Gets/sets the current position in the <c>GZipStream</c>. Not suppported. /// </summary> /// <remarks>In this implementation this property is not supported</remarks> /// <exception cref="NotSupportedException">Always thrown</exception> public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } /// <summary> /// Gets the size of the stream. Not suppported. /// </summary> /// <remarks>In this implementation this property is not supported</remarks> /// <exception cref="NotSupportedException">Always thrown</exception> public override long Length { get { throw new NotSupportedException(); } } #endregion } } |
Changes to compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs.
︙ | ︙ | |||
152 153 154 155 156 157 158 | public class InfoTests { #region Info tests [Test] public void Info_Version() { Info info = new Info(); | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | public class InfoTests { #region Info tests [Test] public void Info_Version() { Info info = new Info(); Assert.AreEqual("1.2.11", Info.Version); Assert.AreEqual(32, info.SizeOfUInt); Assert.AreEqual(32, info.SizeOfULong); Assert.AreEqual(32, info.SizeOfPointer); Assert.AreEqual(32, info.SizeOfOffset); } #endregion } |
︙ | ︙ |
Changes to compat/zlib/contrib/dotzlib/readme.txt.
︙ | ︙ | |||
32 33 34 35 36 37 38 | build. 2. Using NAnt: Open a command prompt with access to the build environment and run nant in the same directory as the DotZLib.build file. You can define 2 properties on the nant command-line to control the build: debug={true|false} to toggle between release/debug builds (default=true). | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | build. 2. Using NAnt: Open a command prompt with access to the build environment and run nant in the same directory as the DotZLib.build file. You can define 2 properties on the nant command-line to control the build: debug={true|false} to toggle between release/debug builds (default=true). nunit={true|false} to include or esclude unit tests (default=true). Also the target clean will remove binaries. Output file (DotZLib.dll) will be found in either ./DotZLib/bin/release or ./DotZLib/bin/debug, depending on whether you are building the release or debug version of the library. Examples: nant -D:debug=false -D:nunit=false |
︙ | ︙ |
Changes to compat/zlib/contrib/infback9/infback9.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. window is a user-supplied window and output buffer that is 64K bytes. */ | > > | | > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. window is a user-supplied window and output buffer that is 64K bytes. */ int ZEXPORT inflateBack9Init_(strm, window, version, stream_size) z_stream FAR *strm; unsigned char FAR *window; const char *version; int stream_size; { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL) return Z_STREAM_ERROR; |
︙ | ︙ | |||
43 44 45 46 47 48 49 | /* Build and output length and distance decoding tables for fixed code decoding. */ #ifdef MAKEFIXED #include <stdio.h> | | > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | /* Build and output length and distance decoding tables for fixed code decoding. */ #ifdef MAKEFIXED #include <stdio.h> void makefixed9(void) { unsigned sym, bits, low, size; code *next, *lenfix, *distfix; struct inflate_state state; code fixed[544]; /* literal/length table */ sym = 0; |
︙ | ︙ | |||
205 206 207 208 209 210 211 | Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ | > | > > | > > | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc) z_stream FAR *strm; in_func in; void FAR *in_desc; out_func out; void FAR *out_desc; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have; /* available input */ unsigned long left; /* available output */ inflate_mode mode; /* current inflate mode */ int lastblock; /* true if processing last block */ |
︙ | ︙ | |||
589 590 591 592 593 594 595 | /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } | | > > | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBack9End(strm) z_stream FAR *strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } |
Changes to compat/zlib/contrib/infback9/infback9.h.
︙ | ︙ | |||
16 17 18 19 20 21 22 | * zlib.h must be included before this header file. */ #ifdef __cplusplus extern "C" { #endif | | | | | | | | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | * zlib.h must be included before this header file. */ #ifdef __cplusplus extern "C" { #endif ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm)); ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm, unsigned char FAR *window, const char *version, int stream_size)); #define inflateBack9Init(strm, window) \ inflateBack9Init_((strm), (window), \ ZLIB_VERSION, sizeof(z_stream)) #ifdef __cplusplus } #endif |
Changes to compat/zlib/contrib/infback9/inftree9.c.
1 | /* inftree9.c -- generate Huffman trees for efficient decoding | | | > > | > | > | > | 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 | /* inftree9.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftree9.h" #define MAXBITS 15 const char inflate9_copyright[] = " inflate9 1.2.11 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int inflate_table9(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ |
︙ | ︙ | |||
55 56 57 58 59 60 61 | static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 144, 77, 202}; static const unsigned short dbase[32] = { /* Distance codes 0..31 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153}; static const unsigned short dext[32] = { /* Distance codes 0..31 extra */ 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, |
︙ | ︙ |
Changes to compat/zlib/contrib/infback9/inftree9.h.
︙ | ︙ | |||
34 35 36 37 38 39 40 | 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1446, which is the sum of 852 for literal/length codes and 594 for distance codes. These values were found by exhaustive searches using the program | | | | | | | | 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 | 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1446, which is the sum of 852 for literal/length codes and 594 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 32 6 15" for distance codes returns 594. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in infback9.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 594 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table9() */ typedef enum { CODES, LENS, DISTS } codetype; extern int inflate_table9 OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); |
Added compat/zlib/contrib/inflate86/inffas86.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | /* inffas86.c is a hand tuned assembler version of * * inffast.c -- fast decoding * Copyright (C) 1995-2003 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Copyright (C) 2003 Chris Anderson <christop@charm.net> * Please use the copyright conditions above. * * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also * slightly quicker on x86 systems because, instead of using rep movsb to copy * data, it uses rep movsw, which moves data in 2-byte chunks instead of single * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates * from http://fedora.linux.duke.edu/fc1_x86_64 * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, * when decompressing mozilla-source-1.3.tar.gz. * * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at * the moment. I have successfully compiled and tested this code with gcc2.96, * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX * enabled. I will attempt to merge the MMX code into this version. Newer * versions of this and inffast.S can be found at * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* Mark Adler's comments from inffast.c: */ /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; struct inffast_ar { /* 64 32 x86 x86_64 */ /* ar offset register */ /* 0 0 */ void *esp; /* esp save */ /* 8 4 */ void *ebp; /* ebp save */ /* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ /* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ /* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ /* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ /* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ /* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ /* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ /* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ /* 80 40 */ unsigned long hold; /* edx rdx local strm->hold */ /* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ /* 92 48 */ unsigned wsize; /* window size */ /* 96 52 */ unsigned write; /* window write index */ /*100 56 */ unsigned lmask; /* r12 mask for lcode */ /*104 60 */ unsigned dmask; /* r13 mask for dcode */ /*108 64 */ unsigned len; /* r14 match length */ /*112 68 */ unsigned dist; /* r15 match distance */ /*116 72 */ unsigned status; /* set when state chng*/ } ar; #if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) #define PAD_AVAIL_IN 6 #define PAD_AVAIL_OUT 258 #else #define PAD_AVAIL_IN 5 #define PAD_AVAIL_OUT 257 #endif /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; ar.in = strm->next_in; ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); ar.out = strm->next_out; ar.beg = ar.out - (start - strm->avail_out); ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); ar.wsize = state->wsize; ar.write = state->wnext; ar.window = state->window; ar.hold = state->hold; ar.bits = state->bits; ar.lcode = state->lencode; ar.dcode = state->distcode; ar.lmask = (1U << state->lenbits) - 1; ar.dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ /* align in on 1/2 hold size boundary */ while (((unsigned long)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { ar.hold += (unsigned long)*ar.in++ << ar.bits; ar.bits += 8; } #if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) __asm__ __volatile__ ( " leaq %0, %%rax\n" " movq %%rbp, 8(%%rax)\n" /* save regs rbp and rsp */ " movq %%rsp, (%%rax)\n" " movq %%rax, %%rsp\n" /* make rsp point to &ar */ " movq 16(%%rsp), %%rsi\n" /* rsi = in */ " movq 32(%%rsp), %%rdi\n" /* rdi = out */ " movq 24(%%rsp), %%r9\n" /* r9 = last */ " movq 48(%%rsp), %%r10\n" /* r10 = end */ " movq 64(%%rsp), %%rbp\n" /* rbp = lcode */ " movq 72(%%rsp), %%r11\n" /* r11 = dcode */ " movq 80(%%rsp), %%rdx\n" /* rdx = hold */ " movl 88(%%rsp), %%ebx\n" /* ebx = bits */ " movl 100(%%rsp), %%r12d\n" /* r12d = lmask */ " movl 104(%%rsp), %%r13d\n" /* r13d = dmask */ /* r14d = len */ /* r15d = dist */ " cld\n" " cmpq %%rdi, %%r10\n" " je .L_one_time\n" /* if only one decode left */ " cmpq %%rsi, %%r9\n" " je .L_one_time\n" " jmp .L_do_loop\n" ".L_one_time:\n" " movq %%r12, %%r8\n" /* r8 = lmask */ " cmpb $32, %%bl\n" " ja .L_get_length_code_one_time\n" " lodsl\n" /* eax = *(uint *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $32, %%bl\n" /* bits += 32 */ " shlq %%cl, %%rax\n" " orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ " jmp .L_get_length_code_one_time\n" ".align 32,0x90\n" ".L_while_test:\n" " cmpq %%rdi, %%r10\n" " jbe .L_break_loop\n" " cmpq %%rsi, %%r9\n" " jbe .L_break_loop\n" ".L_do_loop:\n" " movq %%r12, %%r8\n" /* r8 = lmask */ " cmpb $32, %%bl\n" " ja .L_get_length_code\n" /* if (32 < bits) */ " lodsl\n" /* eax = *(uint *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $32, %%bl\n" /* bits += 32 */ " shlq %%cl, %%rax\n" " orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ ".L_get_length_code:\n" " andq %%rdx, %%r8\n" /* r8 &= hold */ " movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ " movb %%ah, %%cl\n" /* cl = this.bits */ " subb %%ah, %%bl\n" /* bits -= this.bits */ " shrq %%cl, %%rdx\n" /* hold >>= this.bits */ " testb %%al, %%al\n" " jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ " movq %%r12, %%r8\n" /* r8 = lmask */ " shrl $16, %%eax\n" /* output this.val char */ " stosb\n" ".L_get_length_code_one_time:\n" " andq %%rdx, %%r8\n" /* r8 &= hold */ " movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ ".L_dolen:\n" " movb %%ah, %%cl\n" /* cl = this.bits */ " subb %%ah, %%bl\n" /* bits -= this.bits */ " shrq %%cl, %%rdx\n" /* hold >>= this.bits */ " testb %%al, %%al\n" " jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ " shrl $16, %%eax\n" /* output this.val char */ " stosb\n" " jmp .L_while_test\n" ".align 32,0x90\n" ".L_test_for_length_base:\n" " movl %%eax, %%r14d\n" /* len = this */ " shrl $16, %%r14d\n" /* len = this.val */ " movb %%al, %%cl\n" " testb $16, %%al\n" " jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ " andb $15, %%cl\n" /* op &= 15 */ " jz .L_decode_distance\n" /* if (!op) */ ".L_add_bits_to_len:\n" " subb %%cl, %%bl\n" " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" " andl %%edx, %%eax\n" /* eax &= hold */ " shrq %%cl, %%rdx\n" " addl %%eax, %%r14d\n" /* len += hold & mask[op] */ ".L_decode_distance:\n" " movq %%r13, %%r8\n" /* r8 = dmask */ " cmpb $32, %%bl\n" " ja .L_get_distance_code\n" /* if (32 < bits) */ " lodsl\n" /* eax = *(uint *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $32, %%bl\n" /* bits += 32 */ " shlq %%cl, %%rax\n" " orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ ".L_get_distance_code:\n" " andq %%rdx, %%r8\n" /* r8 &= hold */ " movl (%%r11,%%r8,4), %%eax\n" /* eax = dcode[hold & dmask] */ ".L_dodist:\n" " movl %%eax, %%r15d\n" /* dist = this */ " shrl $16, %%r15d\n" /* dist = this.val */ " movb %%ah, %%cl\n" " subb %%ah, %%bl\n" /* bits -= this.bits */ " shrq %%cl, %%rdx\n" /* hold >>= this.bits */ " movb %%al, %%cl\n" /* cl = this.op */ " testb $16, %%al\n" /* if ((op & 16) == 0) */ " jz .L_test_for_second_level_dist\n" " andb $15, %%cl\n" /* op &= 15 */ " jz .L_check_dist_one\n" ".L_add_bits_to_dist:\n" " subb %%cl, %%bl\n" " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" /* (1 << op) - 1 */ " andl %%edx, %%eax\n" /* eax &= hold */ " shrq %%cl, %%rdx\n" " addl %%eax, %%r15d\n" /* dist += hold & ((1 << op) - 1) */ ".L_check_window:\n" " movq %%rsi, %%r8\n" /* save in so from can use it's reg */ " movq %%rdi, %%rax\n" " subq 40(%%rsp), %%rax\n" /* nbytes = out - beg */ " cmpl %%r15d, %%eax\n" " jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ " movl %%r14d, %%ecx\n" /* ecx = len */ " movq %%rdi, %%rsi\n" " subq %%r15, %%rsi\n" /* from = out - dist */ " sarl %%ecx\n" " jnc .L_copy_two\n" /* if len % 2 == 0 */ " rep movsw\n" " movb (%%rsi), %%al\n" " movb %%al, (%%rdi)\n" " incq %%rdi\n" " movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ " jmp .L_while_test\n" ".L_copy_two:\n" " rep movsw\n" " movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ " jmp .L_while_test\n" ".align 32,0x90\n" ".L_check_dist_one:\n" " cmpl $1, %%r15d\n" /* if dist 1, is a memset */ " jne .L_check_window\n" " cmpq %%rdi, 40(%%rsp)\n" /* if out == beg, outside window */ " je .L_check_window\n" " movl %%r14d, %%ecx\n" /* ecx = len */ " movb -1(%%rdi), %%al\n" " movb %%al, %%ah\n" " sarl %%ecx\n" " jnc .L_set_two\n" " movb %%al, (%%rdi)\n" " incq %%rdi\n" ".L_set_two:\n" " rep stosw\n" " jmp .L_while_test\n" ".align 32,0x90\n" ".L_test_for_second_level_length:\n" " testb $64, %%al\n" " jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" " andl %%edx, %%eax\n" /* eax &= hold */ " addl %%r14d, %%eax\n" /* eax += len */ " movl (%%rbp,%%rax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ " jmp .L_dolen\n" ".align 32,0x90\n" ".L_test_for_second_level_dist:\n" " testb $64, %%al\n" " jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" " andl %%edx, %%eax\n" /* eax &= hold */ " addl %%r15d, %%eax\n" /* eax += dist */ " movl (%%r11,%%rax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ " jmp .L_dodist\n" ".align 32,0x90\n" ".L_clip_window:\n" " movl %%eax, %%ecx\n" /* ecx = nbytes */ " movl 92(%%rsp), %%eax\n" /* eax = wsize, prepare for dist cmp */ " negl %%ecx\n" /* nbytes = -nbytes */ " cmpl %%r15d, %%eax\n" " jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ " addl %%r15d, %%ecx\n" /* nbytes = dist - nbytes */ " cmpl $0, 96(%%rsp)\n" " jne .L_wrap_around_window\n" /* if (write != 0) */ " movq 56(%%rsp), %%rsi\n" /* from = window */ " subl %%ecx, %%eax\n" /* eax -= nbytes */ " addq %%rax, %%rsi\n" /* from += wsize - nbytes */ " movl %%r14d, %%eax\n" /* eax = len */ " cmpl %%ecx, %%r14d\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* eax -= nbytes */ " rep movsb\n" " movq %%rdi, %%rsi\n" " subq %%r15, %%rsi\n" /* from = &out[ -dist ] */ " jmp .L_do_copy\n" ".align 32,0x90\n" ".L_wrap_around_window:\n" " movl 96(%%rsp), %%eax\n" /* eax = write */ " cmpl %%eax, %%ecx\n" " jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ " movl 92(%%rsp), %%esi\n" /* from = wsize */ " addq 56(%%rsp), %%rsi\n" /* from += window */ " addq %%rax, %%rsi\n" /* from += write */ " subq %%rcx, %%rsi\n" /* from -= nbytes */ " subl %%eax, %%ecx\n" /* nbytes -= write */ " movl %%r14d, %%eax\n" /* eax = len */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movq 56(%%rsp), %%rsi\n" /* from = window */ " movl 96(%%rsp), %%ecx\n" /* nbytes = write */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movq %%rdi, %%rsi\n" " subq %%r15, %%rsi\n" /* from = out - dist */ " jmp .L_do_copy\n" ".align 32,0x90\n" ".L_contiguous_in_window:\n" " movq 56(%%rsp), %%rsi\n" /* rsi = window */ " addq %%rax, %%rsi\n" " subq %%rcx, %%rsi\n" /* from += write - nbytes */ " movl %%r14d, %%eax\n" /* eax = len */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movq %%rdi, %%rsi\n" " subq %%r15, %%rsi\n" /* from = out - dist */ " jmp .L_do_copy\n" /* if (nbytes >= len) */ ".align 32,0x90\n" ".L_do_copy:\n" " movl %%eax, %%ecx\n" /* ecx = len */ " rep movsb\n" " movq %%r8, %%rsi\n" /* move in back to %esi, toss from */ " jmp .L_while_test\n" ".L_test_for_end_of_block:\n" " testb $32, %%al\n" " jz .L_invalid_literal_length_code\n" " movl $1, 116(%%rsp)\n" " jmp .L_break_loop_with_status\n" ".L_invalid_literal_length_code:\n" " movl $2, 116(%%rsp)\n" " jmp .L_break_loop_with_status\n" ".L_invalid_distance_code:\n" " movl $3, 116(%%rsp)\n" " jmp .L_break_loop_with_status\n" ".L_invalid_distance_too_far:\n" " movl $4, 116(%%rsp)\n" " jmp .L_break_loop_with_status\n" ".L_break_loop:\n" " movl $0, 116(%%rsp)\n" ".L_break_loop_with_status:\n" /* put in, out, bits, and hold back into ar and pop esp */ " movq %%rsi, 16(%%rsp)\n" /* in */ " movq %%rdi, 32(%%rsp)\n" /* out */ " movl %%ebx, 88(%%rsp)\n" /* bits */ " movq %%rdx, 80(%%rsp)\n" /* hold */ " movq (%%rsp), %%rax\n" /* restore rbp and rsp */ " movq 8(%%rsp), %%rbp\n" " movq %%rax, %%rsp\n" : : "m" (ar) : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" ); #elif ( defined( __GNUC__ ) || defined( __ICC ) ) && defined( __i386 ) __asm__ __volatile__ ( " leal %0, %%eax\n" " movl %%esp, (%%eax)\n" /* save esp, ebp */ " movl %%ebp, 4(%%eax)\n" " movl %%eax, %%esp\n" " movl 8(%%esp), %%esi\n" /* esi = in */ " movl 16(%%esp), %%edi\n" /* edi = out */ " movl 40(%%esp), %%edx\n" /* edx = hold */ " movl 44(%%esp), %%ebx\n" /* ebx = bits */ " movl 32(%%esp), %%ebp\n" /* ebp = lcode */ " cld\n" " jmp .L_do_loop\n" ".align 32,0x90\n" ".L_while_test:\n" " cmpl %%edi, 24(%%esp)\n" /* out < end */ " jbe .L_break_loop\n" " cmpl %%esi, 12(%%esp)\n" /* in < last */ " jbe .L_break_loop\n" ".L_do_loop:\n" " cmpb $15, %%bl\n" " ja .L_get_length_code\n" /* if (15 < bits) */ " xorl %%eax, %%eax\n" " lodsw\n" /* al = *(ushort *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $16, %%bl\n" /* bits += 16 */ " shll %%cl, %%eax\n" " orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ ".L_get_length_code:\n" " movl 56(%%esp), %%eax\n" /* eax = lmask */ " andl %%edx, %%eax\n" /* eax &= hold */ " movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */ ".L_dolen:\n" " movb %%ah, %%cl\n" /* cl = this.bits */ " subb %%ah, %%bl\n" /* bits -= this.bits */ " shrl %%cl, %%edx\n" /* hold >>= this.bits */ " testb %%al, %%al\n" " jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ " shrl $16, %%eax\n" /* output this.val char */ " stosb\n" " jmp .L_while_test\n" ".align 32,0x90\n" ".L_test_for_length_base:\n" " movl %%eax, %%ecx\n" /* len = this */ " shrl $16, %%ecx\n" /* len = this.val */ " movl %%ecx, 64(%%esp)\n" /* save len */ " movb %%al, %%cl\n" " testb $16, %%al\n" " jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ " andb $15, %%cl\n" /* op &= 15 */ " jz .L_decode_distance\n" /* if (!op) */ " cmpb %%cl, %%bl\n" " jae .L_add_bits_to_len\n" /* if (op <= bits) */ " movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ " xorl %%eax, %%eax\n" " lodsw\n" /* al = *(ushort *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $16, %%bl\n" /* bits += 16 */ " shll %%cl, %%eax\n" " orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ " movb %%ch, %%cl\n" /* move op back to ecx */ ".L_add_bits_to_len:\n" " subb %%cl, %%bl\n" " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" " andl %%edx, %%eax\n" /* eax &= hold */ " shrl %%cl, %%edx\n" " addl %%eax, 64(%%esp)\n" /* len += hold & mask[op] */ ".L_decode_distance:\n" " cmpb $15, %%bl\n" " ja .L_get_distance_code\n" /* if (15 < bits) */ " xorl %%eax, %%eax\n" " lodsw\n" /* al = *(ushort *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $16, %%bl\n" /* bits += 16 */ " shll %%cl, %%eax\n" " orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ ".L_get_distance_code:\n" " movl 60(%%esp), %%eax\n" /* eax = dmask */ " movl 36(%%esp), %%ecx\n" /* ecx = dcode */ " andl %%edx, %%eax\n" /* eax &= hold */ " movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */ ".L_dodist:\n" " movl %%eax, %%ebp\n" /* dist = this */ " shrl $16, %%ebp\n" /* dist = this.val */ " movb %%ah, %%cl\n" " subb %%ah, %%bl\n" /* bits -= this.bits */ " shrl %%cl, %%edx\n" /* hold >>= this.bits */ " movb %%al, %%cl\n" /* cl = this.op */ " testb $16, %%al\n" /* if ((op & 16) == 0) */ " jz .L_test_for_second_level_dist\n" " andb $15, %%cl\n" /* op &= 15 */ " jz .L_check_dist_one\n" " cmpb %%cl, %%bl\n" " jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */ " movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ " xorl %%eax, %%eax\n" " lodsw\n" /* al = *(ushort *)in++ */ " movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ " addb $16, %%bl\n" /* bits += 16 */ " shll %%cl, %%eax\n" " orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ " movb %%ch, %%cl\n" /* move op back to ecx */ ".L_add_bits_to_dist:\n" " subb %%cl, %%bl\n" " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" /* (1 << op) - 1 */ " andl %%edx, %%eax\n" /* eax &= hold */ " shrl %%cl, %%edx\n" " addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */ ".L_check_window:\n" " movl %%esi, 8(%%esp)\n" /* save in so from can use it's reg */ " movl %%edi, %%eax\n" " subl 20(%%esp), %%eax\n" /* nbytes = out - beg */ " cmpl %%ebp, %%eax\n" " jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ " movl 64(%%esp), %%ecx\n" /* ecx = len */ " movl %%edi, %%esi\n" " subl %%ebp, %%esi\n" /* from = out - dist */ " sarl %%ecx\n" " jnc .L_copy_two\n" /* if len % 2 == 0 */ " rep movsw\n" " movb (%%esi), %%al\n" " movb %%al, (%%edi)\n" " incl %%edi\n" " movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ " movl 32(%%esp), %%ebp\n" /* ebp = lcode */ " jmp .L_while_test\n" ".L_copy_two:\n" " rep movsw\n" " movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ " movl 32(%%esp), %%ebp\n" /* ebp = lcode */ " jmp .L_while_test\n" ".align 32,0x90\n" ".L_check_dist_one:\n" " cmpl $1, %%ebp\n" /* if dist 1, is a memset */ " jne .L_check_window\n" " cmpl %%edi, 20(%%esp)\n" " je .L_check_window\n" /* out == beg, if outside window */ " movl 64(%%esp), %%ecx\n" /* ecx = len */ " movb -1(%%edi), %%al\n" " movb %%al, %%ah\n" " sarl %%ecx\n" " jnc .L_set_two\n" " movb %%al, (%%edi)\n" " incl %%edi\n" ".L_set_two:\n" " rep stosw\n" " movl 32(%%esp), %%ebp\n" /* ebp = lcode */ " jmp .L_while_test\n" ".align 32,0x90\n" ".L_test_for_second_level_length:\n" " testb $64, %%al\n" " jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" " andl %%edx, %%eax\n" /* eax &= hold */ " addl 64(%%esp), %%eax\n" /* eax += len */ " movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ " jmp .L_dolen\n" ".align 32,0x90\n" ".L_test_for_second_level_dist:\n" " testb $64, %%al\n" " jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ " xorl %%eax, %%eax\n" " incl %%eax\n" " shll %%cl, %%eax\n" " decl %%eax\n" " andl %%edx, %%eax\n" /* eax &= hold */ " addl %%ebp, %%eax\n" /* eax += dist */ " movl 36(%%esp), %%ecx\n" /* ecx = dcode */ " movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ " jmp .L_dodist\n" ".align 32,0x90\n" ".L_clip_window:\n" " movl %%eax, %%ecx\n" " movl 48(%%esp), %%eax\n" /* eax = wsize */ " negl %%ecx\n" /* nbytes = -nbytes */ " movl 28(%%esp), %%esi\n" /* from = window */ " cmpl %%ebp, %%eax\n" " jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ " addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */ " cmpl $0, 52(%%esp)\n" " jne .L_wrap_around_window\n" /* if (write != 0) */ " subl %%ecx, %%eax\n" " addl %%eax, %%esi\n" /* from += wsize - nbytes */ " movl 64(%%esp), %%eax\n" /* eax = len */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movl %%edi, %%esi\n" " subl %%ebp, %%esi\n" /* from = out - dist */ " jmp .L_do_copy\n" ".align 32,0x90\n" ".L_wrap_around_window:\n" " movl 52(%%esp), %%eax\n" /* eax = write */ " cmpl %%eax, %%ecx\n" " jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ " addl 48(%%esp), %%esi\n" /* from += wsize */ " addl %%eax, %%esi\n" /* from += write */ " subl %%ecx, %%esi\n" /* from -= nbytes */ " subl %%eax, %%ecx\n" /* nbytes -= write */ " movl 64(%%esp), %%eax\n" /* eax = len */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movl 28(%%esp), %%esi\n" /* from = window */ " movl 52(%%esp), %%ecx\n" /* nbytes = write */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movl %%edi, %%esi\n" " subl %%ebp, %%esi\n" /* from = out - dist */ " jmp .L_do_copy\n" ".align 32,0x90\n" ".L_contiguous_in_window:\n" " addl %%eax, %%esi\n" " subl %%ecx, %%esi\n" /* from += write - nbytes */ " movl 64(%%esp), %%eax\n" /* eax = len */ " cmpl %%ecx, %%eax\n" " jbe .L_do_copy\n" /* if (nbytes >= len) */ " subl %%ecx, %%eax\n" /* len -= nbytes */ " rep movsb\n" " movl %%edi, %%esi\n" " subl %%ebp, %%esi\n" /* from = out - dist */ " jmp .L_do_copy\n" /* if (nbytes >= len) */ ".align 32,0x90\n" ".L_do_copy:\n" " movl %%eax, %%ecx\n" " rep movsb\n" " movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ " movl 32(%%esp), %%ebp\n" /* ebp = lcode */ " jmp .L_while_test\n" ".L_test_for_end_of_block:\n" " testb $32, %%al\n" " jz .L_invalid_literal_length_code\n" " movl $1, 72(%%esp)\n" " jmp .L_break_loop_with_status\n" ".L_invalid_literal_length_code:\n" " movl $2, 72(%%esp)\n" " jmp .L_break_loop_with_status\n" ".L_invalid_distance_code:\n" " movl $3, 72(%%esp)\n" " jmp .L_break_loop_with_status\n" ".L_invalid_distance_too_far:\n" " movl 8(%%esp), %%esi\n" " movl $4, 72(%%esp)\n" " jmp .L_break_loop_with_status\n" ".L_break_loop:\n" " movl $0, 72(%%esp)\n" ".L_break_loop_with_status:\n" /* put in, out, bits, and hold back into ar and pop esp */ " movl %%esi, 8(%%esp)\n" /* save in */ " movl %%edi, 16(%%esp)\n" /* save out */ " movl %%ebx, 44(%%esp)\n" /* save bits */ " movl %%edx, 40(%%esp)\n" /* save hold */ " movl 4(%%esp), %%ebp\n" /* restore esp, ebp */ " movl (%%esp), %%esp\n" : : "m" (ar) : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); #elif defined( _MSC_VER ) && ! defined( _M_AMD64 ) __asm { lea eax, ar mov [eax], esp /* save esp, ebp */ mov [eax+4], ebp mov esp, eax mov esi, [esp+8] /* esi = in */ mov edi, [esp+16] /* edi = out */ mov edx, [esp+40] /* edx = hold */ mov ebx, [esp+44] /* ebx = bits */ mov ebp, [esp+32] /* ebp = lcode */ cld jmp L_do_loop ALIGN 4 L_while_test: cmp [esp+24], edi jbe L_break_loop cmp [esp+12], esi jbe L_break_loop L_do_loop: cmp bl, 15 ja L_get_length_code /* if (15 < bits) */ xor eax, eax lodsw /* al = *(ushort *)in++ */ mov cl, bl /* cl = bits, needs it for shifting */ add bl, 16 /* bits += 16 */ shl eax, cl or edx, eax /* hold |= *((ushort *)in)++ << bits */ L_get_length_code: mov eax, [esp+56] /* eax = lmask */ and eax, edx /* eax &= hold */ mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */ L_dolen: mov cl, ah /* cl = this.bits */ sub bl, ah /* bits -= this.bits */ shr edx, cl /* hold >>= this.bits */ test al, al jnz L_test_for_length_base /* if (op != 0) 45.7% */ shr eax, 16 /* output this.val char */ stosb jmp L_while_test ALIGN 4 L_test_for_length_base: mov ecx, eax /* len = this */ shr ecx, 16 /* len = this.val */ mov [esp+64], ecx /* save len */ mov cl, al test al, 16 jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ and cl, 15 /* op &= 15 */ jz L_decode_distance /* if (!op) */ cmp bl, cl jae L_add_bits_to_len /* if (op <= bits) */ mov ch, cl /* stash op in ch, freeing cl */ xor eax, eax lodsw /* al = *(ushort *)in++ */ mov cl, bl /* cl = bits, needs it for shifting */ add bl, 16 /* bits += 16 */ shl eax, cl or edx, eax /* hold |= *((ushort *)in)++ << bits */ mov cl, ch /* move op back to ecx */ L_add_bits_to_len: sub bl, cl xor eax, eax inc eax shl eax, cl dec eax and eax, edx /* eax &= hold */ shr edx, cl add [esp+64], eax /* len += hold & mask[op] */ L_decode_distance: cmp bl, 15 ja L_get_distance_code /* if (15 < bits) */ xor eax, eax lodsw /* al = *(ushort *)in++ */ mov cl, bl /* cl = bits, needs it for shifting */ add bl, 16 /* bits += 16 */ shl eax, cl or edx, eax /* hold |= *((ushort *)in)++ << bits */ L_get_distance_code: mov eax, [esp+60] /* eax = dmask */ mov ecx, [esp+36] /* ecx = dcode */ and eax, edx /* eax &= hold */ mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */ L_dodist: mov ebp, eax /* dist = this */ shr ebp, 16 /* dist = this.val */ mov cl, ah sub bl, ah /* bits -= this.bits */ shr edx, cl /* hold >>= this.bits */ mov cl, al /* cl = this.op */ test al, 16 /* if ((op & 16) == 0) */ jz L_test_for_second_level_dist and cl, 15 /* op &= 15 */ jz L_check_dist_one cmp bl, cl jae L_add_bits_to_dist /* if (op <= bits) 97.6% */ mov ch, cl /* stash op in ch, freeing cl */ xor eax, eax lodsw /* al = *(ushort *)in++ */ mov cl, bl /* cl = bits, needs it for shifting */ add bl, 16 /* bits += 16 */ shl eax, cl or edx, eax /* hold |= *((ushort *)in)++ << bits */ mov cl, ch /* move op back to ecx */ L_add_bits_to_dist: sub bl, cl xor eax, eax inc eax shl eax, cl dec eax /* (1 << op) - 1 */ and eax, edx /* eax &= hold */ shr edx, cl add ebp, eax /* dist += hold & ((1 << op) - 1) */ L_check_window: mov [esp+8], esi /* save in so from can use it's reg */ mov eax, edi sub eax, [esp+20] /* nbytes = out - beg */ cmp eax, ebp jb L_clip_window /* if (dist > nbytes) 4.2% */ mov ecx, [esp+64] /* ecx = len */ mov esi, edi sub esi, ebp /* from = out - dist */ sar ecx, 1 jnc L_copy_two rep movsw mov al, [esi] mov [edi], al inc edi mov esi, [esp+8] /* move in back to %esi, toss from */ mov ebp, [esp+32] /* ebp = lcode */ jmp L_while_test L_copy_two: rep movsw mov esi, [esp+8] /* move in back to %esi, toss from */ mov ebp, [esp+32] /* ebp = lcode */ jmp L_while_test ALIGN 4 L_check_dist_one: cmp ebp, 1 /* if dist 1, is a memset */ jne L_check_window cmp [esp+20], edi je L_check_window /* out == beg, if outside window */ mov ecx, [esp+64] /* ecx = len */ mov al, [edi-1] mov ah, al sar ecx, 1 jnc L_set_two mov [edi], al /* memset out with from[-1] */ inc edi L_set_two: rep stosw mov ebp, [esp+32] /* ebp = lcode */ jmp L_while_test ALIGN 4 L_test_for_second_level_length: test al, 64 jnz L_test_for_end_of_block /* if ((op & 64) != 0) */ xor eax, eax inc eax shl eax, cl dec eax and eax, edx /* eax &= hold */ add eax, [esp+64] /* eax += len */ mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/ jmp L_dolen ALIGN 4 L_test_for_second_level_dist: test al, 64 jnz L_invalid_distance_code /* if ((op & 64) != 0) */ xor eax, eax inc eax shl eax, cl dec eax and eax, edx /* eax &= hold */ add eax, ebp /* eax += dist */ mov ecx, [esp+36] /* ecx = dcode */ mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/ jmp L_dodist ALIGN 4 L_clip_window: mov ecx, eax mov eax, [esp+48] /* eax = wsize */ neg ecx /* nbytes = -nbytes */ mov esi, [esp+28] /* from = window */ cmp eax, ebp jb L_invalid_distance_too_far /* if (dist > wsize) */ add ecx, ebp /* nbytes = dist - nbytes */ cmp dword ptr [esp+52], 0 jne L_wrap_around_window /* if (write != 0) */ sub eax, ecx add esi, eax /* from += wsize - nbytes */ mov eax, [esp+64] /* eax = len */ cmp eax, ecx jbe L_do_copy /* if (nbytes >= len) */ sub eax, ecx /* len -= nbytes */ rep movsb mov esi, edi sub esi, ebp /* from = out - dist */ jmp L_do_copy ALIGN 4 L_wrap_around_window: mov eax, [esp+52] /* eax = write */ cmp ecx, eax jbe L_contiguous_in_window /* if (write >= nbytes) */ add esi, [esp+48] /* from += wsize */ add esi, eax /* from += write */ sub esi, ecx /* from -= nbytes */ sub ecx, eax /* nbytes -= write */ mov eax, [esp+64] /* eax = len */ cmp eax, ecx jbe L_do_copy /* if (nbytes >= len) */ sub eax, ecx /* len -= nbytes */ rep movsb mov esi, [esp+28] /* from = window */ mov ecx, [esp+52] /* nbytes = write */ cmp eax, ecx jbe L_do_copy /* if (nbytes >= len) */ sub eax, ecx /* len -= nbytes */ rep movsb mov esi, edi sub esi, ebp /* from = out - dist */ jmp L_do_copy ALIGN 4 L_contiguous_in_window: add esi, eax sub esi, ecx /* from += write - nbytes */ mov eax, [esp+64] /* eax = len */ cmp eax, ecx jbe L_do_copy /* if (nbytes >= len) */ sub eax, ecx /* len -= nbytes */ rep movsb mov esi, edi sub esi, ebp /* from = out - dist */ jmp L_do_copy ALIGN 4 L_do_copy: mov ecx, eax rep movsb mov esi, [esp+8] /* move in back to %esi, toss from */ mov ebp, [esp+32] /* ebp = lcode */ jmp L_while_test L_test_for_end_of_block: test al, 32 jz L_invalid_literal_length_code mov dword ptr [esp+72], 1 jmp L_break_loop_with_status L_invalid_literal_length_code: mov dword ptr [esp+72], 2 jmp L_break_loop_with_status L_invalid_distance_code: mov dword ptr [esp+72], 3 jmp L_break_loop_with_status L_invalid_distance_too_far: mov esi, [esp+4] mov dword ptr [esp+72], 4 jmp L_break_loop_with_status L_break_loop: mov dword ptr [esp+72], 0 L_break_loop_with_status: /* put in, out, bits, and hold back into ar and pop esp */ mov [esp+8], esi /* save in */ mov [esp+16], edi /* save out */ mov [esp+44], ebx /* save bits */ mov [esp+40], edx /* save hold */ mov ebp, [esp+4] /* restore esp, ebp */ mov esp, [esp] } #else #error "x86 architecture not defined" #endif if (ar.status > 1) { if (ar.status == 2) strm->msg = "invalid literal/length code"; else if (ar.status == 3) strm->msg = "invalid distance code"; else strm->msg = "invalid distance too far back"; state->mode = BAD; } else if ( ar.status == 1 ) { state->mode = TYPE; } /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ ar.len = ar.bits >> 3; ar.in -= ar.len; ar.bits -= ar.len << 3; ar.hold &= (1U << ar.bits) - 1; /* update state and return */ strm->next_in = ar.in; strm->next_out = ar.out; strm->avail_in = (unsigned)(ar.in < ar.last ? PAD_AVAIL_IN + (ar.last - ar.in) : PAD_AVAIL_IN - (ar.in - ar.last)); strm->avail_out = (unsigned)(ar.out < ar.end ? PAD_AVAIL_OUT + (ar.end - ar.out) : PAD_AVAIL_OUT - (ar.out - ar.end)); state->hold = ar.hold; state->bits = ar.bits; return; } |
Added compat/zlib/contrib/inflate86/inffast.S.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 | /* * inffast.S is a hand tuned assembler version of: * * inffast.c -- fast decoding * Copyright (C) 1995-2003 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Copyright (C) 2003 Chris Anderson <christop@charm.net> * Please use the copyright conditions above. * * This version (Jan-23-2003) of inflate_fast was coded and tested under * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that * machine, I found that gzip style archives decompressed about 20% faster than * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will * depend on how large of a buffer is used for z_stream.next_in & next_out * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in * stream processing I/O and crc32/addler32. In my case, this routine used * 70% of the cpu time and crc32 used 20%. * * I am confident that this version will work in the general case, but I have * not tested a wide variety of datasets or a wide variety of platforms. * * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating. * It should be a runtime flag instead of compile time flag... * * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction. * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code * is compiled. Without either option, runtime detection is enabled. Runtime * detection should work on all modern cpus and the recomended algorithm (flip * ID bit on eflags and then use the cpuid instruction) is used in many * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12 * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o * inffast.obj generates a COFF object which can then be linked with MSVC++ * compiled code. Tested under FreeBSD 4.7 with gcc-2.95. * * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and * slower than compiler generated code). Adjusted cpuid check to use the MMX * code only for Pentiums < P4 until I have more data on the P4. Speed * improvment is only about 15% on the Athlon when compared with code generated * with MSVC++. Not sure yet, but I think the P4 will also be slower using the * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and * have less latency than MMX ops. Added code to buffer the last 11 bytes of * the input stream since the MMX code grabs bits in chunks of 32, which * differs from the inffast.c algorithm. I don't think there would have been * read overruns where a page boundary was crossed (a segfault), but there * could have been overruns when next_in ends on unaligned memory (unintialized * memory read). * * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C * version of the non-MMX code so that it doesn't depend on zstrm and zstate * structure offsets which are hard coded in this file. This was last tested * with zlib-1.2.0 which is currently in beta testing, newer versions of this * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and * http://www.charm.net/~christop/zlib/ */ /* * if you have underscore linking problems (_inflate_fast undefined), try * using -DGAS_COFF */ #if ! defined( GAS_COFF ) && ! defined( GAS_ELF ) #if defined( WIN32 ) || defined( __CYGWIN__ ) #define GAS_COFF /* windows object format */ #else #define GAS_ELF #endif #endif /* ! GAS_COFF && ! GAS_ELF */ #if defined( GAS_COFF ) /* coff externals have underscores */ #define inflate_fast _inflate_fast #define inflate_fast_use_mmx _inflate_fast_use_mmx #endif /* GAS_COFF */ .file "inffast.S" .globl inflate_fast .text .align 4,0 .L_invalid_literal_length_code_msg: .string "invalid literal/length code" .align 4,0 .L_invalid_distance_code_msg: .string "invalid distance code" .align 4,0 .L_invalid_distance_too_far_msg: .string "invalid distance too far back" #if ! defined( NO_MMX ) .align 4,0 .L_mask: /* mask[N] = ( 1 << N ) - 1 */ .long 0 .long 1 .long 3 .long 7 .long 15 .long 31 .long 63 .long 127 .long 255 .long 511 .long 1023 .long 2047 .long 4095 .long 8191 .long 16383 .long 32767 .long 65535 .long 131071 .long 262143 .long 524287 .long 1048575 .long 2097151 .long 4194303 .long 8388607 .long 16777215 .long 33554431 .long 67108863 .long 134217727 .long 268435455 .long 536870911 .long 1073741823 .long 2147483647 .long 4294967295 #endif /* NO_MMX */ .text /* * struct z_stream offsets, in zlib.h */ #define next_in_strm 0 /* strm->next_in */ #define avail_in_strm 4 /* strm->avail_in */ #define next_out_strm 12 /* strm->next_out */ #define avail_out_strm 16 /* strm->avail_out */ #define msg_strm 24 /* strm->msg */ #define state_strm 28 /* strm->state */ /* * struct inflate_state offsets, in inflate.h */ #define mode_state 0 /* state->mode */ #define wsize_state 32 /* state->wsize */ #define write_state 40 /* state->write */ #define window_state 44 /* state->window */ #define hold_state 48 /* state->hold */ #define bits_state 52 /* state->bits */ #define lencode_state 68 /* state->lencode */ #define distcode_state 72 /* state->distcode */ #define lenbits_state 76 /* state->lenbits */ #define distbits_state 80 /* state->distbits */ /* * inflate_fast's activation record */ #define local_var_size 64 /* how much local space for vars */ #define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */ #define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */ /* * offsets for local vars on stack */ #define out 60 /* unsigned char* */ #define window 56 /* unsigned char* */ #define wsize 52 /* unsigned int */ #define write 48 /* unsigned int */ #define in 44 /* unsigned char* */ #define beg 40 /* unsigned char* */ #define buf 28 /* char[ 12 ] */ #define len 24 /* unsigned int */ #define last 20 /* unsigned char* */ #define end 16 /* unsigned char* */ #define dcode 12 /* code* */ #define lcode 8 /* code* */ #define dmask 4 /* unsigned int */ #define lmask 0 /* unsigned int */ /* * typedef enum inflate_mode consts, in inflate.h */ #define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */ #define INFLATE_MODE_BAD 26 #if ! defined( USE_MMX ) && ! defined( NO_MMX ) #define RUN_TIME_MMX #define CHECK_MMX 1 #define DO_USE_MMX 2 #define DONT_USE_MMX 3 .globl inflate_fast_use_mmx .data .align 4,0 inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */ .long CHECK_MMX #if defined( GAS_ELF ) /* elf info */ .type inflate_fast_use_mmx,@object .size inflate_fast_use_mmx,4 #endif #endif /* RUN_TIME_MMX */ #if defined( GAS_COFF ) /* coff info: scl 2 = extern, type 32 = function */ .def inflate_fast; .scl 2; .type 32; .endef #endif .text .align 32,0x90 inflate_fast: pushl %edi pushl %esi pushl %ebp pushl %ebx pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */ subl $local_var_size, %esp cld #define strm_r %esi #define state_r %edi movl strm_sp(%esp), strm_r movl state_strm(strm_r), state_r /* in = strm->next_in; * out = strm->next_out; * last = in + strm->avail_in - 11; * beg = out - (start - strm->avail_out); * end = out + (strm->avail_out - 257); */ movl avail_in_strm(strm_r), %edx movl next_in_strm(strm_r), %eax addl %eax, %edx /* avail_in += next_in */ subl $11, %edx /* avail_in -= 11 */ movl %eax, in(%esp) movl %edx, last(%esp) movl start_sp(%esp), %ebp movl avail_out_strm(strm_r), %ecx movl next_out_strm(strm_r), %ebx subl %ecx, %ebp /* start -= avail_out */ negl %ebp /* start = -start */ addl %ebx, %ebp /* start += next_out */ subl $257, %ecx /* avail_out -= 257 */ addl %ebx, %ecx /* avail_out += out */ movl %ebx, out(%esp) movl %ebp, beg(%esp) movl %ecx, end(%esp) /* wsize = state->wsize; * write = state->write; * window = state->window; * hold = state->hold; * bits = state->bits; * lcode = state->lencode; * dcode = state->distcode; * lmask = ( 1 << state->lenbits ) - 1; * dmask = ( 1 << state->distbits ) - 1; */ movl lencode_state(state_r), %eax movl distcode_state(state_r), %ecx movl %eax, lcode(%esp) movl %ecx, dcode(%esp) movl $1, %eax movl lenbits_state(state_r), %ecx shll %cl, %eax decl %eax movl %eax, lmask(%esp) movl $1, %eax movl distbits_state(state_r), %ecx shll %cl, %eax decl %eax movl %eax, dmask(%esp) movl wsize_state(state_r), %eax movl write_state(state_r), %ecx movl window_state(state_r), %edx movl %eax, wsize(%esp) movl %ecx, write(%esp) movl %edx, window(%esp) movl hold_state(state_r), %ebp movl bits_state(state_r), %ebx #undef strm_r #undef state_r #define in_r %esi #define from_r %esi #define out_r %edi movl in(%esp), in_r movl last(%esp), %ecx cmpl in_r, %ecx ja .L_align_long /* if in < last */ addl $11, %ecx /* ecx = &in[ avail_in ] */ subl in_r, %ecx /* ecx = avail_in */ movl $12, %eax subl %ecx, %eax /* eax = 12 - avail_in */ leal buf(%esp), %edi rep movsb /* memcpy( buf, in, avail_in ) */ movl %eax, %ecx xorl %eax, %eax rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */ leal buf(%esp), in_r /* in = buf */ movl in_r, last(%esp) /* last = in, do just one iteration */ jmp .L_is_aligned /* align in_r on long boundary */ .L_align_long: testl $3, in_r jz .L_is_aligned xorl %eax, %eax movb (in_r), %al incl in_r movl %ebx, %ecx addl $8, %ebx shll %cl, %eax orl %eax, %ebp jmp .L_align_long .L_is_aligned: movl out(%esp), out_r #if defined( NO_MMX ) jmp .L_do_loop #endif #if defined( USE_MMX ) jmp .L_init_mmx #endif /*** Runtime MMX check ***/ #if defined( RUN_TIME_MMX ) .L_check_mmx: cmpl $DO_USE_MMX, inflate_fast_use_mmx je .L_init_mmx ja .L_do_loop /* > 2 */ pushl %eax pushl %ebx pushl %ecx pushl %edx pushf movl (%esp), %eax /* copy eflags to eax */ xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21) * to see if cpu supports cpuid... * ID bit method not supported by NexGen but * bios may load a cpuid instruction and * cpuid may be disabled on Cyrix 5-6x86 */ popf pushf popl %edx /* copy new eflags to edx */ xorl %eax, %edx /* test if ID bit is flipped */ jz .L_dont_use_mmx /* not flipped if zero */ xorl %eax, %eax cpuid cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */ jne .L_dont_use_mmx cmpl $0x6c65746e, %ecx jne .L_dont_use_mmx cmpl $0x49656e69, %edx jne .L_dont_use_mmx movl $1, %eax cpuid /* get cpu features */ shrl $8, %eax andl $15, %eax cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */ jne .L_dont_use_mmx testl $0x800000, %edx /* test if MMX feature is set (bit 23) */ jnz .L_use_mmx jmp .L_dont_use_mmx .L_use_mmx: movl $DO_USE_MMX, inflate_fast_use_mmx jmp .L_check_mmx_pop .L_dont_use_mmx: movl $DONT_USE_MMX, inflate_fast_use_mmx .L_check_mmx_pop: popl %edx popl %ecx popl %ebx popl %eax jmp .L_check_mmx #endif /*** Non-MMX code ***/ #if defined ( NO_MMX ) || defined( RUN_TIME_MMX ) #define hold_r %ebp #define bits_r %bl #define bitslong_r %ebx .align 32,0x90 .L_while_test: /* while (in < last && out < end) */ cmpl out_r, end(%esp) jbe .L_break_loop /* if (out >= end) */ cmpl in_r, last(%esp) jbe .L_break_loop .L_do_loop: /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out * * do { * if (bits < 15) { * hold |= *((unsigned short *)in)++ << bits; * bits += 16 * } * this = lcode[hold & lmask] */ cmpb $15, bits_r ja .L_get_length_code /* if (15 < bits) */ xorl %eax, %eax lodsw /* al = *(ushort *)in++ */ movb bits_r, %cl /* cl = bits, needs it for shifting */ addb $16, bits_r /* bits += 16 */ shll %cl, %eax orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ .L_get_length_code: movl lmask(%esp), %edx /* edx = lmask */ movl lcode(%esp), %ecx /* ecx = lcode */ andl hold_r, %edx /* edx &= hold */ movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */ .L_dolen: /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out * * dolen: * bits -= this.bits; * hold >>= this.bits */ movb %ah, %cl /* cl = this.bits */ subb %ah, bits_r /* bits -= this.bits */ shrl %cl, hold_r /* hold >>= this.bits */ /* check if op is a literal * if (op == 0) { * PUP(out) = this.val; * } */ testb %al, %al jnz .L_test_for_length_base /* if (op != 0) 45.7% */ shrl $16, %eax /* output this.val char */ stosb jmp .L_while_test .L_test_for_length_base: /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len * * else if (op & 16) { * len = this.val * op &= 15 * if (op) { * if (op > bits) { * hold |= *((unsigned short *)in)++ << bits; * bits += 16 * } * len += hold & mask[op]; * bits -= op; * hold >>= op; * } */ #define len_r %edx movl %eax, len_r /* len = this */ shrl $16, len_r /* len = this.val */ movb %al, %cl testb $16, %al jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ andb $15, %cl /* op &= 15 */ jz .L_save_len /* if (!op) */ cmpb %cl, bits_r jae .L_add_bits_to_len /* if (op <= bits) */ movb %cl, %ch /* stash op in ch, freeing cl */ xorl %eax, %eax lodsw /* al = *(ushort *)in++ */ movb bits_r, %cl /* cl = bits, needs it for shifting */ addb $16, bits_r /* bits += 16 */ shll %cl, %eax orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ movb %ch, %cl /* move op back to ecx */ .L_add_bits_to_len: movl $1, %eax shll %cl, %eax decl %eax subb %cl, bits_r andl hold_r, %eax /* eax &= hold */ shrl %cl, hold_r addl %eax, len_r /* len += hold & mask[op] */ .L_save_len: movl len_r, len(%esp) /* save len */ #undef len_r .L_decode_distance: /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist * * if (bits < 15) { * hold |= *((unsigned short *)in)++ << bits; * bits += 16 * } * this = dcode[hold & dmask]; * dodist: * bits -= this.bits; * hold >>= this.bits; * op = this.op; */ cmpb $15, bits_r ja .L_get_distance_code /* if (15 < bits) */ xorl %eax, %eax lodsw /* al = *(ushort *)in++ */ movb bits_r, %cl /* cl = bits, needs it for shifting */ addb $16, bits_r /* bits += 16 */ shll %cl, %eax orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ .L_get_distance_code: movl dmask(%esp), %edx /* edx = dmask */ movl dcode(%esp), %ecx /* ecx = dcode */ andl hold_r, %edx /* edx &= hold */ movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */ #define dist_r %edx .L_dodist: movl %eax, dist_r /* dist = this */ shrl $16, dist_r /* dist = this.val */ movb %ah, %cl subb %ah, bits_r /* bits -= this.bits */ shrl %cl, hold_r /* hold >>= this.bits */ /* if (op & 16) { * dist = this.val * op &= 15 * if (op > bits) { * hold |= *((unsigned short *)in)++ << bits; * bits += 16 * } * dist += hold & mask[op]; * bits -= op; * hold >>= op; */ movb %al, %cl /* cl = this.op */ testb $16, %al /* if ((op & 16) == 0) */ jz .L_test_for_second_level_dist andb $15, %cl /* op &= 15 */ jz .L_check_dist_one cmpb %cl, bits_r jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */ movb %cl, %ch /* stash op in ch, freeing cl */ xorl %eax, %eax lodsw /* al = *(ushort *)in++ */ movb bits_r, %cl /* cl = bits, needs it for shifting */ addb $16, bits_r /* bits += 16 */ shll %cl, %eax orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ movb %ch, %cl /* move op back to ecx */ .L_add_bits_to_dist: movl $1, %eax shll %cl, %eax decl %eax /* (1 << op) - 1 */ subb %cl, bits_r andl hold_r, %eax /* eax &= hold */ shrl %cl, hold_r addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */ jmp .L_check_window .L_check_window: /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist * %ecx = nbytes * * nbytes = out - beg; * if (dist <= nbytes) { * from = out - dist; * do { * PUP(out) = PUP(from); * } while (--len > 0) { * } */ movl in_r, in(%esp) /* save in so from can use it's reg */ movl out_r, %eax subl beg(%esp), %eax /* nbytes = out - beg */ cmpl dist_r, %eax jb .L_clip_window /* if (dist > nbytes) 4.2% */ movl len(%esp), %ecx movl out_r, from_r subl dist_r, from_r /* from = out - dist */ subl $3, %ecx movb (from_r), %al movb %al, (out_r) movb 1(from_r), %al movb 2(from_r), %dl addl $3, from_r movb %al, 1(out_r) movb %dl, 2(out_r) addl $3, out_r rep movsb movl in(%esp), in_r /* move in back to %esi, toss from */ jmp .L_while_test .align 16,0x90 .L_check_dist_one: cmpl $1, dist_r jne .L_check_window cmpl out_r, beg(%esp) je .L_check_window decl out_r movl len(%esp), %ecx movb (out_r), %al subl $3, %ecx movb %al, 1(out_r) movb %al, 2(out_r) movb %al, 3(out_r) addl $4, out_r rep stosb jmp .L_while_test .align 16,0x90 .L_test_for_second_level_length: /* else if ((op & 64) == 0) { * this = lcode[this.val + (hold & mask[op])]; * } */ testb $64, %al jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ movl $1, %eax shll %cl, %eax decl %eax andl hold_r, %eax /* eax &= hold */ addl %edx, %eax /* eax += this.val */ movl lcode(%esp), %edx /* edx = lcode */ movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */ jmp .L_dolen .align 16,0x90 .L_test_for_second_level_dist: /* else if ((op & 64) == 0) { * this = dcode[this.val + (hold & mask[op])]; * } */ testb $64, %al jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ movl $1, %eax shll %cl, %eax decl %eax andl hold_r, %eax /* eax &= hold */ addl %edx, %eax /* eax += this.val */ movl dcode(%esp), %edx /* edx = dcode */ movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */ jmp .L_dodist .align 16,0x90 .L_clip_window: /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist * %ecx = nbytes * * else { * if (dist > wsize) { * invalid distance * } * from = window; * nbytes = dist - nbytes; * if (write == 0) { * from += wsize - nbytes; */ #define nbytes_r %ecx movl %eax, nbytes_r movl wsize(%esp), %eax /* prepare for dist compare */ negl nbytes_r /* nbytes = -nbytes */ movl window(%esp), from_r /* from = window */ cmpl dist_r, %eax jb .L_invalid_distance_too_far /* if (dist > wsize) */ addl dist_r, nbytes_r /* nbytes = dist - nbytes */ cmpl $0, write(%esp) jne .L_wrap_around_window /* if (write != 0) */ subl nbytes_r, %eax addl %eax, from_r /* from += wsize - nbytes */ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist * %ecx = nbytes, %eax = len * * if (nbytes < len) { * len -= nbytes; * do { * PUP(out) = PUP(from); * } while (--nbytes); * from = out - dist; * } * } */ #define len_r %eax movl len(%esp), len_r cmpl nbytes_r, len_r jbe .L_do_copy1 /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ jmp .L_do_copy1 cmpl nbytes_r, len_r jbe .L_do_copy1 /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ jmp .L_do_copy1 .L_wrap_around_window: /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist * %ecx = nbytes, %eax = write, %eax = len * * else if (write < nbytes) { * from += wsize + write - nbytes; * nbytes -= write; * if (nbytes < len) { * len -= nbytes; * do { * PUP(out) = PUP(from); * } while (--nbytes); * from = window; * nbytes = write; * if (nbytes < len) { * len -= nbytes; * do { * PUP(out) = PUP(from); * } while(--nbytes); * from = out - dist; * } * } * } */ #define write_r %eax movl write(%esp), write_r cmpl write_r, nbytes_r jbe .L_contiguous_in_window /* if (write >= nbytes) */ addl wsize(%esp), from_r addl write_r, from_r subl nbytes_r, from_r /* from += wsize + write - nbytes */ subl write_r, nbytes_r /* nbytes -= write */ #undef write_r movl len(%esp), len_r cmpl nbytes_r, len_r jbe .L_do_copy1 /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl window(%esp), from_r /* from = window */ movl write(%esp), nbytes_r /* nbytes = write */ cmpl nbytes_r, len_r jbe .L_do_copy1 /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ jmp .L_do_copy1 .L_contiguous_in_window: /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist * %ecx = nbytes, %eax = write, %eax = len * * else { * from += write - nbytes; * if (nbytes < len) { * len -= nbytes; * do { * PUP(out) = PUP(from); * } while (--nbytes); * from = out - dist; * } * } */ #define write_r %eax addl write_r, from_r subl nbytes_r, from_r /* from += write - nbytes */ #undef write_r movl len(%esp), len_r cmpl nbytes_r, len_r jbe .L_do_copy1 /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ .L_do_copy1: /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out * %eax = len * * while (len > 0) { * PUP(out) = PUP(from); * len--; * } * } * } while (in < last && out < end); */ #undef nbytes_r #define in_r %esi movl len_r, %ecx rep movsb movl in(%esp), in_r /* move in back to %esi, toss from */ jmp .L_while_test #undef len_r #undef dist_r #endif /* NO_MMX || RUN_TIME_MMX */ /*** MMX code ***/ #if defined( USE_MMX ) || defined( RUN_TIME_MMX ) .align 32,0x90 .L_init_mmx: emms #undef bits_r #undef bitslong_r #define bitslong_r %ebp #define hold_mm %mm0 movd %ebp, hold_mm movl %ebx, bitslong_r #define used_mm %mm1 #define dmask2_mm %mm2 #define lmask2_mm %mm3 #define lmask_mm %mm4 #define dmask_mm %mm5 #define tmp_mm %mm6 movd lmask(%esp), lmask_mm movq lmask_mm, lmask2_mm movd dmask(%esp), dmask_mm movq dmask_mm, dmask2_mm pxor used_mm, used_mm movl lcode(%esp), %ebx /* ebx = lcode */ jmp .L_do_loop_mmx .align 32,0x90 .L_while_test_mmx: /* while (in < last && out < end) */ cmpl out_r, end(%esp) jbe .L_break_loop /* if (out >= end) */ cmpl in_r, last(%esp) jbe .L_break_loop .L_do_loop_mmx: psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ cmpl $32, bitslong_r ja .L_get_length_code_mmx /* if (32 < bits) */ movd bitslong_r, tmp_mm movd (in_r), %mm7 addl $4, in_r psllq tmp_mm, %mm7 addl $32, bitslong_r por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ .L_get_length_code_mmx: pand hold_mm, lmask_mm movd lmask_mm, %eax movq lmask2_mm, lmask_mm movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */ .L_dolen_mmx: movzbl %ah, %ecx /* ecx = this.bits */ movd %ecx, used_mm subl %ecx, bitslong_r /* bits -= this.bits */ testb %al, %al jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */ shrl $16, %eax /* output this.val char */ stosb jmp .L_while_test_mmx .L_test_for_length_base_mmx: #define len_r %edx movl %eax, len_r /* len = this */ shrl $16, len_r /* len = this.val */ testb $16, %al jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */ andl $15, %eax /* op &= 15 */ jz .L_decode_distance_mmx /* if (!op) */ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ movd %eax, used_mm movd hold_mm, %ecx subl %eax, bitslong_r andl .L_mask(,%eax,4), %ecx addl %ecx, len_r /* len += hold & mask[op] */ .L_decode_distance_mmx: psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ cmpl $32, bitslong_r ja .L_get_dist_code_mmx /* if (32 < bits) */ movd bitslong_r, tmp_mm movd (in_r), %mm7 addl $4, in_r psllq tmp_mm, %mm7 addl $32, bitslong_r por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ .L_get_dist_code_mmx: movl dcode(%esp), %ebx /* ebx = dcode */ pand hold_mm, dmask_mm movd dmask_mm, %eax movq dmask2_mm, dmask_mm movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */ .L_dodist_mmx: #define dist_r %ebx movzbl %ah, %ecx /* ecx = this.bits */ movl %eax, dist_r shrl $16, dist_r /* dist = this.val */ subl %ecx, bitslong_r /* bits -= this.bits */ movd %ecx, used_mm testb $16, %al /* if ((op & 16) == 0) */ jz .L_test_for_second_level_dist_mmx andl $15, %eax /* op &= 15 */ jz .L_check_dist_one_mmx .L_add_bits_to_dist_mmx: psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ movd %eax, used_mm /* save bit length of current op */ movd hold_mm, %ecx /* get the next bits on input stream */ subl %eax, bitslong_r /* bits -= op bits */ andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */ addl %ecx, dist_r /* dist += hold & mask[op] */ .L_check_window_mmx: movl in_r, in(%esp) /* save in so from can use it's reg */ movl out_r, %eax subl beg(%esp), %eax /* nbytes = out - beg */ cmpl dist_r, %eax jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */ movl len_r, %ecx movl out_r, from_r subl dist_r, from_r /* from = out - dist */ subl $3, %ecx movb (from_r), %al movb %al, (out_r) movb 1(from_r), %al movb 2(from_r), %dl addl $3, from_r movb %al, 1(out_r) movb %dl, 2(out_r) addl $3, out_r rep movsb movl in(%esp), in_r /* move in back to %esi, toss from */ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ jmp .L_while_test_mmx .align 16,0x90 .L_check_dist_one_mmx: cmpl $1, dist_r jne .L_check_window_mmx cmpl out_r, beg(%esp) je .L_check_window_mmx decl out_r movl len_r, %ecx movb (out_r), %al subl $3, %ecx movb %al, 1(out_r) movb %al, 2(out_r) movb %al, 3(out_r) addl $4, out_r rep stosb movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ jmp .L_while_test_mmx .align 16,0x90 .L_test_for_second_level_length_mmx: testb $64, %al jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ andl $15, %eax psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ movd hold_mm, %ecx andl .L_mask(,%eax,4), %ecx addl len_r, %ecx movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */ jmp .L_dolen_mmx .align 16,0x90 .L_test_for_second_level_dist_mmx: testb $64, %al jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ andl $15, %eax psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ movd hold_mm, %ecx andl .L_mask(,%eax,4), %ecx movl dcode(%esp), %eax /* ecx = dcode */ addl dist_r, %ecx movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */ jmp .L_dodist_mmx .align 16,0x90 .L_clip_window_mmx: #define nbytes_r %ecx movl %eax, nbytes_r movl wsize(%esp), %eax /* prepare for dist compare */ negl nbytes_r /* nbytes = -nbytes */ movl window(%esp), from_r /* from = window */ cmpl dist_r, %eax jb .L_invalid_distance_too_far /* if (dist > wsize) */ addl dist_r, nbytes_r /* nbytes = dist - nbytes */ cmpl $0, write(%esp) jne .L_wrap_around_window_mmx /* if (write != 0) */ subl nbytes_r, %eax addl %eax, from_r /* from += wsize - nbytes */ cmpl nbytes_r, len_r jbe .L_do_copy1_mmx /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ jmp .L_do_copy1_mmx cmpl nbytes_r, len_r jbe .L_do_copy1_mmx /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ jmp .L_do_copy1_mmx .L_wrap_around_window_mmx: #define write_r %eax movl write(%esp), write_r cmpl write_r, nbytes_r jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */ addl wsize(%esp), from_r addl write_r, from_r subl nbytes_r, from_r /* from += wsize + write - nbytes */ subl write_r, nbytes_r /* nbytes -= write */ #undef write_r cmpl nbytes_r, len_r jbe .L_do_copy1_mmx /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl window(%esp), from_r /* from = window */ movl write(%esp), nbytes_r /* nbytes = write */ cmpl nbytes_r, len_r jbe .L_do_copy1_mmx /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ jmp .L_do_copy1_mmx .L_contiguous_in_window_mmx: #define write_r %eax addl write_r, from_r subl nbytes_r, from_r /* from += write - nbytes */ #undef write_r cmpl nbytes_r, len_r jbe .L_do_copy1_mmx /* if (nbytes >= len) */ subl nbytes_r, len_r /* len -= nbytes */ rep movsb movl out_r, from_r subl dist_r, from_r /* from = out - dist */ .L_do_copy1_mmx: #undef nbytes_r #define in_r %esi movl len_r, %ecx rep movsb movl in(%esp), in_r /* move in back to %esi, toss from */ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ jmp .L_while_test_mmx #undef hold_r #undef bitslong_r #endif /* USE_MMX || RUN_TIME_MMX */ /*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/ .L_invalid_distance_code: /* else { * strm->msg = "invalid distance code"; * state->mode = BAD; * } */ movl $.L_invalid_distance_code_msg, %ecx movl $INFLATE_MODE_BAD, %edx jmp .L_update_stream_state .L_test_for_end_of_block: /* else if (op & 32) { * state->mode = TYPE; * break; * } */ testb $32, %al jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */ movl $0, %ecx movl $INFLATE_MODE_TYPE, %edx jmp .L_update_stream_state .L_invalid_literal_length_code: /* else { * strm->msg = "invalid literal/length code"; * state->mode = BAD; * } */ movl $.L_invalid_literal_length_code_msg, %ecx movl $INFLATE_MODE_BAD, %edx jmp .L_update_stream_state .L_invalid_distance_too_far: /* strm->msg = "invalid distance too far back"; * state->mode = BAD; */ movl in(%esp), in_r /* from_r has in's reg, put in back */ movl $.L_invalid_distance_too_far_msg, %ecx movl $INFLATE_MODE_BAD, %edx jmp .L_update_stream_state .L_update_stream_state: /* set strm->msg = %ecx, strm->state->mode = %edx */ movl strm_sp(%esp), %eax testl %ecx, %ecx /* if (msg != NULL) */ jz .L_skip_msg movl %ecx, msg_strm(%eax) /* strm->msg = msg */ .L_skip_msg: movl state_strm(%eax), %eax /* state = strm->state */ movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */ jmp .L_break_loop .align 32,0x90 .L_break_loop: /* * Regs: * * bits = %ebp when mmx, and in %ebx when non-mmx * hold = %hold_mm when mmx, and in %ebp when non-mmx * in = %esi * out = %edi */ #if defined( USE_MMX ) || defined( RUN_TIME_MMX ) #if defined( RUN_TIME_MMX ) cmpl $DO_USE_MMX, inflate_fast_use_mmx jne .L_update_next_in #endif /* RUN_TIME_MMX */ movl %ebp, %ebx .L_update_next_in: #endif #define strm_r %eax #define state_r %edx /* len = bits >> 3; * in -= len; * bits -= len << 3; * hold &= (1U << bits) - 1; * state->hold = hold; * state->bits = bits; * strm->next_in = in; * strm->next_out = out; */ movl strm_sp(%esp), strm_r movl %ebx, %ecx movl state_strm(strm_r), state_r shrl $3, %ecx subl %ecx, in_r shll $3, %ecx subl %ecx, %ebx movl out_r, next_out_strm(strm_r) movl %ebx, bits_state(state_r) movl %ebx, %ecx leal buf(%esp), %ebx cmpl %ebx, last(%esp) jne .L_buf_not_used /* if buf != last */ subl %ebx, in_r /* in -= buf */ movl next_in_strm(strm_r), %ebx movl %ebx, last(%esp) /* last = strm->next_in */ addl %ebx, in_r /* in += strm->next_in */ movl avail_in_strm(strm_r), %ebx subl $11, %ebx addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */ .L_buf_not_used: movl in_r, next_in_strm(strm_r) movl $1, %ebx shll %cl, %ebx decl %ebx #if defined( USE_MMX ) || defined( RUN_TIME_MMX ) #if defined( RUN_TIME_MMX ) cmpl $DO_USE_MMX, inflate_fast_use_mmx jne .L_update_hold #endif /* RUN_TIME_MMX */ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ movd hold_mm, %ebp emms .L_update_hold: #endif /* USE_MMX || RUN_TIME_MMX */ andl %ebx, %ebp movl %ebp, hold_state(state_r) #define last_r %ebx /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */ movl last(%esp), last_r cmpl in_r, last_r jbe .L_last_is_smaller /* if (in >= last) */ subl in_r, last_r /* last -= in */ addl $11, last_r /* last += 11 */ movl last_r, avail_in_strm(strm_r) jmp .L_fixup_out .L_last_is_smaller: subl last_r, in_r /* in -= last */ negl in_r /* in = -in */ addl $11, in_r /* in += 11 */ movl in_r, avail_in_strm(strm_r) #undef last_r #define end_r %ebx .L_fixup_out: /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/ movl end(%esp), end_r cmpl out_r, end_r jbe .L_end_is_smaller /* if (out >= end) */ subl out_r, end_r /* end -= out */ addl $257, end_r /* end += 257 */ movl end_r, avail_out_strm(strm_r) jmp .L_done .L_end_is_smaller: subl end_r, out_r /* out -= end */ negl out_r /* out = -out */ addl $257, out_r /* out += 257 */ movl out_r, avail_out_strm(strm_r) #undef end_r #undef strm_r #undef state_r .L_done: addl $local_var_size, %esp popf popl %ebx popl %ebp popl %esi popl %edi ret #if defined( GAS_ELF ) /* elf info */ .type inflate_fast,@function .size inflate_fast,.-inflate_fast #endif |
Changes to compat/zlib/contrib/iostream3/zfstream.h.
︙ | ︙ | |||
409 410 411 412 413 414 415 | * This class defines a two-argument manipulator for gzofstream. It is used * as base for the setcompression(int,int) manipulator. */ template<typename T1, typename T2> class gzomanip2 { public: | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | * This class defines a two-argument manipulator for gzofstream. It is used * as base for the setcompression(int,int) manipulator. */ template<typename T1, typename T2> class gzomanip2 { public: // Allows insertor to peek at internals template <typename Ta, typename Tb> friend gzofstream& operator<<(gzofstream&, const gzomanip2<Ta,Tb>&); // Constructor gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2), |
︙ | ︙ | |||
448 449 450 451 452 453 454 | inline gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), T1 v1, T2 v2) : func(f), val1(v1), val2(v2) { } | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | inline gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), T1 v1, T2 v2) : func(f), val1(v1), val2(v2) { } // Insertor applies underlying manipulator function to stream template<typename T1, typename T2> inline gzofstream& operator<<(gzofstream& s, const gzomanip2<T1,T2>& m) { return (*m.func)(s, m.val1, m.val2); } // Insert this onto stream to simplify setting of compression level inline gzomanip2<int,int> setcompression(int l, int s = Z_DEFAULT_STRATEGY) { return gzomanip2<int,int>(&setcompression, l, s); } #endif // ZFSTREAM_H |
Added compat/zlib/contrib/masmx64/bld_ml64.bat.
> > | 1 2 | ml64.exe /Flinffasx64 /c /Zi inffasx64.asm ml64.exe /Flgvmat64 /c /Zi gvmat64.asm |
Added compat/zlib/contrib/masmx64/gvmat64.asm.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | ;uInt longest_match_x64( ; deflate_state *s, ; IPos cur_match); /* current match */ ; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86_64 ; (AMD64 on Athlon 64, Opteron, Phenom ; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) ; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. ; ; File written by Gilles Vollant, by converting to assembly the longest_match ; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. ; ; and by taking inspiration on asm686 with masm, optimised assembly code ; from Brian Raiter, written 1998 ; ; This software is provided 'as-is', without any express or implied ; warranty. In no event will the authors be held liable for any damages ; arising from the use of this software. ; ; Permission is granted to anyone to use this software for any purpose, ; including commercial applications, and to alter it and redistribute it ; freely, subject to the following restrictions: ; ; 1. The origin of this software must not be misrepresented; you must not ; claim that you wrote the original software. If you use this software ; in a product, an acknowledgment in the product documentation would be ; appreciated but is not required. ; 2. Altered source versions must be plainly marked as such, and must not be ; misrepresented as being the original software ; 3. This notice may not be removed or altered from any source distribution. ; ; ; ; http://www.zlib.net ; http://www.winimage.com/zLibDll ; http://www.muppetlabs.com/~breadbox/software/assembly.html ; ; to compile this file for infozip Zip, I use option: ; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm ; ; to compile this file for zLib, I use option: ; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm ; Be carrefull to adapt zlib1222add below to your version of zLib ; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change ; value of zlib1222add later) ; ; This file compile with Microsoft Macro Assembler (x64) for AMD64 ; ; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK ; ; (you can get Windows WDK with ml64 for AMD64 from ; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) ; ;uInt longest_match(s, cur_match) ; deflate_state *s; ; IPos cur_match; /* current match */ .code longest_match PROC ;LocalVarsSize equ 88 LocalVarsSize equ 72 ; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 ; free register : r14,r15 ; register can be saved : rsp chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len ; low word: s->wmask ;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10 ;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11 ;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w ;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx ;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13 ;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d ;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9 IFDEF INFOZIP ELSE nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size ENDIF save_rdi equ rsp + 24 - LocalVarsSize save_rsi equ rsp + 32 - LocalVarsSize save_rbx equ rsp + 40 - LocalVarsSize save_rbp equ rsp + 48 - LocalVarsSize save_r12 equ rsp + 56 - LocalVarsSize save_r13 equ rsp + 64 - LocalVarsSize ;save_r14 equ rsp + 72 - LocalVarsSize ;save_r15 equ rsp + 80 - LocalVarsSize ; summary of register usage ; scanend ebx ; scanendw bx ; chainlenwmask edx ; curmatch rsi ; curmatchd esi ; windowbestlen r8 ; scanalign r9 ; scanalignd r9d ; window r10 ; bestlen r11 ; bestlend r11d ; scanstart r12d ; scanstartw r12w ; scan r13 ; nicematch r14d ; limit r15 ; limitd r15d ; prev rcx ; all the +4 offsets are due to the addition of pending_buf_size (in zlib ; in the deflate_state structure since the asm code was first written ; (if you compile with zlib 1.0.4 or older, remove the +4). ; Note : these value are good with a 8 bytes boundary pack structure MAX_MATCH equ 258 MIN_MATCH equ 3 MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) ;;; Offsets for fields in the deflate_state structure. These numbers ;;; are calculated from the definition of deflate_state, with the ;;; assumption that the compiler will dword-align the fields. (Thus, ;;; changing the definition of deflate_state could easily cause this ;;; program to crash horribly, without so much as a warning at ;;; compile time. Sigh.) ; all the +zlib1222add offsets are due to the addition of fields ; in zlib in the deflate_state structure since the asm code was first written ; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). ; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). ; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). IFDEF INFOZIP _DATA SEGMENT COMM window_size:DWORD ; WMask ; 7fff COMM window:BYTE:010040H COMM prev:WORD:08000H ; MatchLen : unused ; PrevMatch : unused COMM strstart:DWORD COMM match_start:DWORD ; Lookahead : ignore COMM prev_length:DWORD ; PrevLen COMM max_chain_length:DWORD COMM good_match:DWORD COMM nice_match:DWORD prev_ad equ OFFSET prev window_ad equ OFFSET window nicematch equ nice_match _DATA ENDS WMask equ 07fffh ELSE IFNDEF zlib1222add zlib1222add equ 8 ENDIF dsWSize equ 56+zlib1222add+(zlib1222add/2) dsWMask equ 64+zlib1222add+(zlib1222add/2) dsWindow equ 72+zlib1222add dsPrev equ 88+zlib1222add dsMatchLen equ 128+zlib1222add dsPrevMatch equ 132+zlib1222add dsStrStart equ 140+zlib1222add dsMatchStart equ 144+zlib1222add dsLookahead equ 148+zlib1222add dsPrevLen equ 152+zlib1222add dsMaxChainLen equ 156+zlib1222add dsGoodMatch equ 172+zlib1222add dsNiceMatch equ 176+zlib1222add window_size equ [ rcx + dsWSize] WMask equ [ rcx + dsWMask] window_ad equ [ rcx + dsWindow] prev_ad equ [ rcx + dsPrev] strstart equ [ rcx + dsStrStart] match_start equ [ rcx + dsMatchStart] Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip prev_length equ [ rcx + dsPrevLen] max_chain_length equ [ rcx + dsMaxChainLen] good_match equ [ rcx + dsGoodMatch] nice_match equ [ rcx + dsNiceMatch] ENDIF ; parameter 1 in r8(deflate state s), param 2 in rdx (cur match) ; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and ; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp ; ; All registers must be preserved across the call, except for ; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. ;;; Save registers that the compiler may be using, and adjust esp to ;;; make room for our stack frame. ;;; Retrieve the function arguments. r8d will hold cur_match ;;; throughout the entire function. edx will hold the pointer to the ;;; deflate_state structure during the function's setup (before ;;; entering the main loop. ; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) ; this clear high 32 bits of r8, which can be garbage in both r8 and rdx mov [save_rdi],rdi mov [save_rsi],rsi mov [save_rbx],rbx mov [save_rbp],rbp IFDEF INFOZIP mov r8d,ecx ELSE mov r8d,edx ENDIF mov [save_r12],r12 mov [save_r13],r13 ; mov [save_r14],r14 ; mov [save_r15],r15 ;;; uInt wmask = s->w_mask; ;;; unsigned chain_length = s->max_chain_length; ;;; if (s->prev_length >= s->good_match) { ;;; chain_length >>= 2; ;;; } mov edi, prev_length mov esi, good_match mov eax, WMask mov ebx, max_chain_length cmp edi, esi jl LastMatchGood shr ebx, 2 LastMatchGood: ;;; chainlen is decremented once beforehand so that the function can ;;; use the sign flag instead of the zero flag for the exit test. ;;; It is then shifted into the high word, to make room for the wmask ;;; value, which it will always accompany. dec ebx shl ebx, 16 or ebx, eax ;;; on zlib only ;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; IFDEF INFOZIP mov [chainlenwmask], ebx ; on infozip nice_match = [nice_match] ELSE mov eax, nice_match mov [chainlenwmask], ebx mov r10d, Lookahead cmp r10d, eax cmovnl r10d, eax mov [nicematch],r10d ENDIF ;;; register Bytef *scan = s->window + s->strstart; mov r10, window_ad mov ebp, strstart lea r13, [r10 + rbp] ;;; Determine how many bytes the scan ptr is off from being ;;; dword-aligned. mov r9,r13 neg r13 and r13,3 ;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? ;;; s->strstart - (IPos)MAX_DIST(s) : NIL; IFDEF INFOZIP mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1)) ELSE mov eax, window_size sub eax, MIN_LOOKAHEAD ENDIF xor edi,edi sub ebp, eax mov r11d, prev_length cmovng ebp,edi ;;; int best_len = s->prev_length; ;;; Store the sum of s->window + best_len in esi locally, and in esi. lea rsi,[r10+r11] ;;; register ush scan_start = *(ushf*)scan; ;;; register ush scan_end = *(ushf*)(scan+best_len-1); ;;; Posf *prev = s->prev; movzx r12d,word ptr [r9] movzx ebx, word ptr [r9 + r11 - 1] mov rdi, prev_ad ;;; Jump into the main loop. mov edx, [chainlenwmask] cmp bx,word ptr [rsi + r8 - 1] jz LookupLoopIsZero LookupLoop1: and r8d, edx movzx r8d, word ptr [rdi + r8*2] cmp r8d, ebp jbe LeaveNow sub edx, 00010000h js LeaveNow LoopEntry1: cmp bx,word ptr [rsi + r8 - 1] jz LookupLoopIsZero LookupLoop2: and r8d, edx movzx r8d, word ptr [rdi + r8*2] cmp r8d, ebp jbe LeaveNow sub edx, 00010000h js LeaveNow LoopEntry2: cmp bx,word ptr [rsi + r8 - 1] jz LookupLoopIsZero LookupLoop4: and r8d, edx movzx r8d, word ptr [rdi + r8*2] cmp r8d, ebp jbe LeaveNow sub edx, 00010000h js LeaveNow LoopEntry4: cmp bx,word ptr [rsi + r8 - 1] jnz LookupLoop1 jmp LookupLoopIsZero ;;; do { ;;; match = s->window + cur_match; ;;; if (*(ushf*)(match+best_len-1) != scan_end || ;;; *(ushf*)match != scan_start) continue; ;;; [...] ;;; } while ((cur_match = prev[cur_match & wmask]) > limit ;;; && --chain_length != 0); ;;; ;;; Here is the inner loop of the function. The function will spend the ;;; majority of its time in this loop, and majority of that time will ;;; be spent in the first ten instructions. ;;; ;;; Within this loop: ;;; ebx = scanend ;;; r8d = curmatch ;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) ;;; esi = windowbestlen - i.e., (window + bestlen) ;;; edi = prev ;;; ebp = limit LookupLoop: and r8d, edx movzx r8d, word ptr [rdi + r8*2] cmp r8d, ebp jbe LeaveNow sub edx, 00010000h js LeaveNow LoopEntry: cmp bx,word ptr [rsi + r8 - 1] jnz LookupLoop1 LookupLoopIsZero: cmp r12w, word ptr [r10 + r8] jnz LookupLoop1 ;;; Store the current value of chainlen. mov [chainlenwmask], edx ;;; Point edi to the string under scrutiny, and esi to the string we ;;; are hoping to match it up with. In actuality, esi and edi are ;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is ;;; initialized to -(MAX_MATCH_8 - scanalign). lea rsi,[r8+r10] mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8) lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8] lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8] prefetcht1 [rsi+rdx] prefetcht1 [rdi+rdx] ;;; Test the strings for equality, 8 bytes at a time. At the end, ;;; adjust rdx so that it is offset to the exact byte that mismatched. ;;; ;;; We already know at this point that the first three bytes of the ;;; strings match each other, and they can be safely passed over before ;;; starting the compare loop. So what this code does is skip over 0-3 ;;; bytes, as much as necessary in order to dword-align the edi ;;; pointer. (rsi will still be misaligned three times out of four.) ;;; ;;; It should be confessed that this loop usually does not represent ;;; much of the total running time. Replacing it with a more ;;; straightforward "rep cmpsb" would not drastically degrade ;;; performance. LoopCmps: mov rax, [rsi + rdx] xor rax, [rdi + rdx] jnz LeaveLoopCmps mov rax, [rsi + rdx + 8] xor rax, [rdi + rdx + 8] jnz LeaveLoopCmps8 mov rax, [rsi + rdx + 8+8] xor rax, [rdi + rdx + 8+8] jnz LeaveLoopCmps16 add rdx,8+8+8 jnz short LoopCmps jmp short LenMaximum LeaveLoopCmps16: add rdx,8 LeaveLoopCmps8: add rdx,8 LeaveLoopCmps: test eax, 0000FFFFh jnz LenLower test eax,0ffffffffh jnz LenLower32 add rdx,4 shr rax,32 or ax,ax jnz LenLower LenLower32: shr eax,16 add rdx,2 LenLower: sub al, 1 adc rdx, 0 ;;; Calculate the length of the match. If it is longer than MAX_MATCH, ;;; then automatically accept it as the best possible match and leave. lea rax, [rdi + rdx] sub rax, r9 cmp eax, MAX_MATCH jge LenMaximum ;;; If the length of the match is not longer than the best match we ;;; have so far, then forget it and return to the lookup loop. ;/////////////////////////////////// cmp eax, r11d jg LongerMatch lea rsi,[r10+r11] mov rdi, prev_ad mov edx, [chainlenwmask] jmp LookupLoop ;;; s->match_start = cur_match; ;;; best_len = len; ;;; if (len >= nice_match) break; ;;; scan_end = *(ushf*)(scan+best_len-1); LongerMatch: mov r11d, eax mov match_start, r8d cmp eax, [nicematch] jge LeaveNow lea rsi,[r10+rax] movzx ebx, word ptr [r9 + rax - 1] mov rdi, prev_ad mov edx, [chainlenwmask] jmp LookupLoop ;;; Accept the current string, with the maximum possible length. LenMaximum: mov r11d,MAX_MATCH mov match_start, r8d ;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; ;;; return s->lookahead; LeaveNow: IFDEF INFOZIP mov eax,r11d ELSE mov eax, Lookahead cmp r11d, eax cmovng eax, r11d ENDIF ;;; Restore the stack and return from whence we came. mov rsi,[save_rsi] mov rdi,[save_rdi] mov rbx,[save_rbx] mov rbp,[save_rbp] mov r12,[save_r12] mov r13,[save_r13] ; mov r14,[save_r14] ; mov r15,[save_r15] ret 0 ; please don't remove this string ! ; Your can freely use gvmat64 in any free or commercial app ; but it is far better don't remove the string in the binary! db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 longest_match ENDP match_init PROC ret 0 match_init ENDP END |
Added compat/zlib/contrib/masmx64/inffas8664.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding * version for AMD64 on Windows using Microsoft C compiler * * Copyright (C) 1995-2003 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Copyright (C) 2003 Chris Anderson <christop@charm.net> * Please use the copyright conditions above. * * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant * * inffas8664.c call function inffas8664fnc in inffasx64.asm * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c * * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also * slightly quicker on x86 systems because, instead of using rep movsb to copy * data, it uses rep movsw, which moves data in 2-byte chunks instead of single * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates * from http://fedora.linux.duke.edu/fc1_x86_64 * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, * when decompressing mozilla-source-1.3.tar.gz. * * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at * the moment. I have successfully compiled and tested this code with gcc2.96, * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX * enabled. I will attempt to merge the MMX code into this version. Newer * versions of this and inffast.S can be found at * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ * */ #include <stdio.h> #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* Mark Adler's comments from inffast.c: */ /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ typedef struct inffast_ar { /* 64 32 x86 x86_64 */ /* ar offset register */ /* 0 0 */ void *esp; /* esp save */ /* 8 4 */ void *ebp; /* ebp save */ /* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ /* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ /* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ /* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ /* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ /* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ /* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ /* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ /* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */ /* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ /* 92 48 */ unsigned wsize; /* window size */ /* 96 52 */ unsigned write; /* window write index */ /*100 56 */ unsigned lmask; /* r12 mask for lcode */ /*104 60 */ unsigned dmask; /* r13 mask for dcode */ /*108 64 */ unsigned len; /* r14 match length */ /*112 68 */ unsigned dist; /* r15 match distance */ /*116 72 */ unsigned status; /* set when state chng*/ } type_ar; #ifdef ASMINF void inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; type_ar ar; void inffas8664fnc(struct inffast_ar * par); #if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64)) #define PAD_AVAIL_IN 6 #define PAD_AVAIL_OUT 258 #else #define PAD_AVAIL_IN 5 #define PAD_AVAIL_OUT 257 #endif /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; ar.in = strm->next_in; ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); ar.out = strm->next_out; ar.beg = ar.out - (start - strm->avail_out); ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); ar.wsize = state->wsize; ar.write = state->wnext; ar.window = state->window; ar.hold = state->hold; ar.bits = state->bits; ar.lcode = state->lencode; ar.dcode = state->distcode; ar.lmask = (1U << state->lenbits) - 1; ar.dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ /* align in on 1/2 hold size boundary */ while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { ar.hold += (unsigned long)*ar.in++ << ar.bits; ar.bits += 8; } inffas8664fnc(&ar); if (ar.status > 1) { if (ar.status == 2) strm->msg = "invalid literal/length code"; else if (ar.status == 3) strm->msg = "invalid distance code"; else strm->msg = "invalid distance too far back"; state->mode = BAD; } else if ( ar.status == 1 ) { state->mode = TYPE; } /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ ar.len = ar.bits >> 3; ar.in -= ar.len; ar.bits -= ar.len << 3; ar.hold &= (1U << ar.bits) - 1; /* update state and return */ strm->next_in = ar.in; strm->next_out = ar.out; strm->avail_in = (unsigned)(ar.in < ar.last ? PAD_AVAIL_IN + (ar.last - ar.in) : PAD_AVAIL_IN - (ar.in - ar.last)); strm->avail_out = (unsigned)(ar.out < ar.end ? PAD_AVAIL_OUT + (ar.end - ar.out) : PAD_AVAIL_OUT - (ar.out - ar.end)); state->hold = (unsigned long)ar.hold; state->bits = ar.bits; return; } #endif |
Added compat/zlib/contrib/masmx64/inffasx64.asm.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | ; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding ; version for AMD64 on Windows using Microsoft C compiler ; ; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c ; inffasx64.asm is called by inffas8664.c, which contain more info. ; to compile this file, I use option ; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm ; with Microsoft Macro Assembler (x64) for AMD64 ; ; This file compile with Microsoft Macro Assembler (x64) for AMD64 ; ; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK ; ; (you can get Windows WDK with ml64 for AMD64 from ; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) ; .code inffas8664fnc PROC ; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and ; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp ; ; All registers must be preserved across the call, except for ; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch. mov [rsp-8],rsi mov [rsp-16],rdi mov [rsp-24],r12 mov [rsp-32],r13 mov [rsp-40],r14 mov [rsp-48],r15 mov [rsp-56],rbx mov rax,rcx mov [rax+8], rbp ; /* save regs rbp and rsp */ mov [rax], rsp mov rsp, rax ; /* make rsp point to &ar */ mov rsi, [rsp+16] ; /* rsi = in */ mov rdi, [rsp+32] ; /* rdi = out */ mov r9, [rsp+24] ; /* r9 = last */ mov r10, [rsp+48] ; /* r10 = end */ mov rbp, [rsp+64] ; /* rbp = lcode */ mov r11, [rsp+72] ; /* r11 = dcode */ mov rdx, [rsp+80] ; /* rdx = hold */ mov ebx, [rsp+88] ; /* ebx = bits */ mov r12d, [rsp+100] ; /* r12d = lmask */ mov r13d, [rsp+104] ; /* r13d = dmask */ ; /* r14d = len */ ; /* r15d = dist */ cld cmp r10, rdi je L_one_time ; /* if only one decode left */ cmp r9, rsi jne L_do_loop L_one_time: mov r8, r12 ; /* r8 = lmask */ cmp bl, 32 ja L_get_length_code_one_time lodsd ; /* eax = *(uint *)in++ */ mov cl, bl ; /* cl = bits, needs it for shifting */ add bl, 32 ; /* bits += 32 */ shl rax, cl or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ jmp L_get_length_code_one_time ALIGN 4 L_while_test: cmp r10, rdi jbe L_break_loop cmp r9, rsi jbe L_break_loop L_do_loop: mov r8, r12 ; /* r8 = lmask */ cmp bl, 32 ja L_get_length_code ; /* if (32 < bits) */ lodsd ; /* eax = *(uint *)in++ */ mov cl, bl ; /* cl = bits, needs it for shifting */ add bl, 32 ; /* bits += 32 */ shl rax, cl or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ L_get_length_code: and r8, rdx ; /* r8 &= hold */ mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ mov cl, ah ; /* cl = this.bits */ sub bl, ah ; /* bits -= this.bits */ shr rdx, cl ; /* hold >>= this.bits */ test al, al jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ mov r8, r12 ; /* r8 = lmask */ shr eax, 16 ; /* output this.val char */ stosb L_get_length_code_one_time: and r8, rdx ; /* r8 &= hold */ mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ L_dolen: mov cl, ah ; /* cl = this.bits */ sub bl, ah ; /* bits -= this.bits */ shr rdx, cl ; /* hold >>= this.bits */ test al, al jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ shr eax, 16 ; /* output this.val char */ stosb jmp L_while_test ALIGN 4 L_test_for_length_base: mov r14d, eax ; /* len = this */ shr r14d, 16 ; /* len = this.val */ mov cl, al test al, 16 jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */ and cl, 15 ; /* op &= 15 */ jz L_decode_distance ; /* if (!op) */ L_add_bits_to_len: sub bl, cl xor eax, eax inc eax shl eax, cl dec eax and eax, edx ; /* eax &= hold */ shr rdx, cl add r14d, eax ; /* len += hold & mask[op] */ L_decode_distance: mov r8, r13 ; /* r8 = dmask */ cmp bl, 32 ja L_get_distance_code ; /* if (32 < bits) */ lodsd ; /* eax = *(uint *)in++ */ mov cl, bl ; /* cl = bits, needs it for shifting */ add bl, 32 ; /* bits += 32 */ shl rax, cl or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ L_get_distance_code: and r8, rdx ; /* r8 &= hold */ mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */ L_dodist: mov r15d, eax ; /* dist = this */ shr r15d, 16 ; /* dist = this.val */ mov cl, ah sub bl, ah ; /* bits -= this.bits */ shr rdx, cl ; /* hold >>= this.bits */ mov cl, al ; /* cl = this.op */ test al, 16 ; /* if ((op & 16) == 0) */ jz L_test_for_second_level_dist and cl, 15 ; /* op &= 15 */ jz L_check_dist_one L_add_bits_to_dist: sub bl, cl xor eax, eax inc eax shl eax, cl dec eax ; /* (1 << op) - 1 */ and eax, edx ; /* eax &= hold */ shr rdx, cl add r15d, eax ; /* dist += hold & ((1 << op) - 1) */ L_check_window: mov r8, rsi ; /* save in so from can use it's reg */ mov rax, rdi sub rax, [rsp+40] ; /* nbytes = out - beg */ cmp eax, r15d jb L_clip_window ; /* if (dist > nbytes) 4.2% */ mov ecx, r14d ; /* ecx = len */ mov rsi, rdi sub rsi, r15 ; /* from = out - dist */ sar ecx, 1 jnc L_copy_two ; /* if len % 2 == 0 */ rep movsw mov al, [rsi] mov [rdi], al inc rdi mov rsi, r8 ; /* move in back to %rsi, toss from */ jmp L_while_test L_copy_two: rep movsw mov rsi, r8 ; /* move in back to %rsi, toss from */ jmp L_while_test ALIGN 4 L_check_dist_one: cmp r15d, 1 ; /* if dist 1, is a memset */ jne L_check_window cmp [rsp+40], rdi ; /* if out == beg, outside window */ je L_check_window mov ecx, r14d ; /* ecx = len */ mov al, [rdi-1] mov ah, al sar ecx, 1 jnc L_set_two mov [rdi], al inc rdi L_set_two: rep stosw jmp L_while_test ALIGN 4 L_test_for_second_level_length: test al, 64 jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */ xor eax, eax inc eax shl eax, cl dec eax and eax, edx ; /* eax &= hold */ add eax, r14d ; /* eax += len */ mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/ jmp L_dolen ALIGN 4 L_test_for_second_level_dist: test al, 64 jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */ xor eax, eax inc eax shl eax, cl dec eax and eax, edx ; /* eax &= hold */ add eax, r15d ; /* eax += dist */ mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/ jmp L_dodist ALIGN 4 L_clip_window: mov ecx, eax ; /* ecx = nbytes */ mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */ neg ecx ; /* nbytes = -nbytes */ cmp eax, r15d jb L_invalid_distance_too_far ; /* if (dist > wsize) */ add ecx, r15d ; /* nbytes = dist - nbytes */ cmp dword ptr [rsp+96], 0 jne L_wrap_around_window ; /* if (write != 0) */ mov rsi, [rsp+56] ; /* from = window */ sub eax, ecx ; /* eax -= nbytes */ add rsi, rax ; /* from += wsize - nbytes */ mov eax, r14d ; /* eax = len */ cmp r14d, ecx jbe L_do_copy ; /* if (nbytes >= len) */ sub eax, ecx ; /* eax -= nbytes */ rep movsb mov rsi, rdi sub rsi, r15 ; /* from = &out[ -dist ] */ jmp L_do_copy ALIGN 4 L_wrap_around_window: mov eax, [rsp+96] ; /* eax = write */ cmp ecx, eax jbe L_contiguous_in_window ; /* if (write >= nbytes) */ mov esi, [rsp+92] ; /* from = wsize */ add rsi, [rsp+56] ; /* from += window */ add rsi, rax ; /* from += write */ sub rsi, rcx ; /* from -= nbytes */ sub ecx, eax ; /* nbytes -= write */ mov eax, r14d ; /* eax = len */ cmp eax, ecx jbe L_do_copy ; /* if (nbytes >= len) */ sub eax, ecx ; /* len -= nbytes */ rep movsb mov rsi, [rsp+56] ; /* from = window */ mov ecx, [rsp+96] ; /* nbytes = write */ cmp eax, ecx jbe L_do_copy ; /* if (nbytes >= len) */ sub eax, ecx ; /* len -= nbytes */ rep movsb mov rsi, rdi sub rsi, r15 ; /* from = out - dist */ jmp L_do_copy ALIGN 4 L_contiguous_in_window: mov rsi, [rsp+56] ; /* rsi = window */ add rsi, rax sub rsi, rcx ; /* from += write - nbytes */ mov eax, r14d ; /* eax = len */ cmp eax, ecx jbe L_do_copy ; /* if (nbytes >= len) */ sub eax, ecx ; /* len -= nbytes */ rep movsb mov rsi, rdi sub rsi, r15 ; /* from = out - dist */ jmp L_do_copy ; /* if (nbytes >= len) */ ALIGN 4 L_do_copy: mov ecx, eax ; /* ecx = len */ rep movsb mov rsi, r8 ; /* move in back to %esi, toss from */ jmp L_while_test L_test_for_end_of_block: test al, 32 jz L_invalid_literal_length_code mov dword ptr [rsp+116], 1 jmp L_break_loop_with_status L_invalid_literal_length_code: mov dword ptr [rsp+116], 2 jmp L_break_loop_with_status L_invalid_distance_code: mov dword ptr [rsp+116], 3 jmp L_break_loop_with_status L_invalid_distance_too_far: mov dword ptr [rsp+116], 4 jmp L_break_loop_with_status L_break_loop: mov dword ptr [rsp+116], 0 L_break_loop_with_status: ; /* put in, out, bits, and hold back into ar and pop esp */ mov [rsp+16], rsi ; /* in */ mov [rsp+32], rdi ; /* out */ mov [rsp+88], ebx ; /* bits */ mov [rsp+80], rdx ; /* hold */ mov rax, [rsp] ; /* restore rbp and rsp */ mov rbp, [rsp+8] mov rsp, rax mov rsi,[rsp-8] mov rdi,[rsp-16] mov r12,[rsp-24] mov r13,[rsp-32] mov r14,[rsp-40] mov r15,[rsp-48] mov rbx,[rsp-56] ret 0 ; : ; : "m" (ar) ; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", ; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" ; ); inffas8664fnc ENDP ;_TEXT ENDS END |
Added compat/zlib/contrib/masmx64/readme.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Summary ------- This directory contains ASM implementations of the functions longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t), for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits. gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits assembly optimized version from Jean-loup Gailly original longest_match function inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing original function from Mark Adler Use instructions ---------------- Assemble the .asm files using MASM and put the object files into the zlib source directory. You can also get object files here: http://www.winimage.com/zLibDll/zlib124_masm_obj.zip define ASMV and ASMINF in your project. Include inffas8664.c in your source tree, and inffasx64.obj and gvmat64.obj as object to link. Build instructions ------------------ run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe) ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK You can get Windows 2003 server DDK with ml64 and cl for AMD64 from http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) |
Added compat/zlib/contrib/masmx86/bld_ml32.bat.
> > | 1 2 | ml /coff /Zi /c /Flmatch686.lst match686.asm ml /coff /Zi /c /Flinffas32.lst inffas32.asm |
Added compat/zlib/contrib/masmx86/inffas32.asm.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | ;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding ; * ; * inffas32.asm is derivated from inffas86.c, with translation of assembly code ; * ; * Copyright (C) 1995-2003 Mark Adler ; * For conditions of distribution and use, see copyright notice in zlib.h ; * ; * Copyright (C) 2003 Chris Anderson <christop@charm.net> ; * Please use the copyright conditions above. ; * ; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from ; * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at ; * the moment. I have successfully compiled and tested this code with gcc2.96, ; * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S ; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX ; * enabled. I will attempt to merge the MMX code into this version. Newer ; * versions of this and inffast.S can be found at ; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ ; * ; * 2005 : modification by Gilles Vollant ; */ ; For Visual C++ 4.x and higher and ML 6.x and higher ; ml.exe is in directory \MASM611C of Win95 DDK ; ml.exe is also distributed in http://www.masm32.com/masmdl.htm ; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/ ; ; ; compile with command line option ; ml /coff /Zi /c /Flinffas32.lst inffas32.asm ; if you define NO_GZIP (see inflate.h), compile with ; ml /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm ; zlib122sup is 0 fort zlib 1.2.2.1 and lower ; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head ; in inflate_state in inflate.h) zlib1222sup equ 8 IFDEF GUNZIP INFLATE_MODE_TYPE equ 11 INFLATE_MODE_BAD equ 26 ELSE IFNDEF NO_GUNZIP INFLATE_MODE_TYPE equ 11 INFLATE_MODE_BAD equ 26 ELSE INFLATE_MODE_TYPE equ 3 INFLATE_MODE_BAD equ 17 ENDIF ENDIF ; 75 "inffast.S" ;FILE "inffast.S" ;;;GLOBAL _inflate_fast ;;;SECTION .text .586p .mmx name inflate_fast_x86 .MODEL FLAT _DATA segment inflate_fast_use_mmx: dd 1 _TEXT segment ALIGN 4 db 'Fast decoding Code from Chris Anderson' db 0 ALIGN 4 invalid_literal_length_code_msg: db 'invalid literal/length code' db 0 ALIGN 4 invalid_distance_code_msg: db 'invalid distance code' db 0 ALIGN 4 invalid_distance_too_far_msg: db 'invalid distance too far back' db 0 ALIGN 4 inflate_fast_mask: dd 0 dd 1 dd 3 dd 7 dd 15 dd 31 dd 63 dd 127 dd 255 dd 511 dd 1023 dd 2047 dd 4095 dd 8191 dd 16383 dd 32767 dd 65535 dd 131071 dd 262143 dd 524287 dd 1048575 dd 2097151 dd 4194303 dd 8388607 dd 16777215 dd 33554431 dd 67108863 dd 134217727 dd 268435455 dd 536870911 dd 1073741823 dd 2147483647 dd 4294967295 mode_state equ 0 ;/* state->mode */ wsize_state equ (32+zlib1222sup) ;/* state->wsize */ write_state equ (36+4+zlib1222sup) ;/* state->write */ window_state equ (40+4+zlib1222sup) ;/* state->window */ hold_state equ (44+4+zlib1222sup) ;/* state->hold */ bits_state equ (48+4+zlib1222sup) ;/* state->bits */ lencode_state equ (64+4+zlib1222sup) ;/* state->lencode */ distcode_state equ (68+4+zlib1222sup) ;/* state->distcode */ lenbits_state equ (72+4+zlib1222sup) ;/* state->lenbits */ distbits_state equ (76+4+zlib1222sup) ;/* state->distbits */ ;;SECTION .text ; 205 "inffast.S" ;GLOBAL inflate_fast_use_mmx ;SECTION .data ; GLOBAL inflate_fast_use_mmx:object ;.size inflate_fast_use_mmx, 4 ; 226 "inffast.S" ;SECTION .text ALIGN 4 _inflate_fast proc near .FPO (16, 4, 0, 0, 1, 0) push edi push esi push ebp push ebx pushfd sub esp,64 cld mov esi, [esp+88] mov edi, [esi+28] mov edx, [esi+4] mov eax, [esi+0] add edx,eax sub edx,11 mov [esp+44],eax mov [esp+20],edx mov ebp, [esp+92] mov ecx, [esi+16] mov ebx, [esi+12] sub ebp,ecx neg ebp add ebp,ebx sub ecx,257 add ecx,ebx mov [esp+60],ebx mov [esp+40],ebp mov [esp+16],ecx ; 285 "inffast.S" mov eax, [edi+lencode_state] mov ecx, [edi+distcode_state] mov [esp+8],eax mov [esp+12],ecx mov eax,1 mov ecx, [edi+lenbits_state] shl eax,cl dec eax mov [esp+0],eax mov eax,1 mov ecx, [edi+distbits_state] shl eax,cl dec eax mov [esp+4],eax mov eax, [edi+wsize_state] mov ecx, [edi+write_state] mov edx, [edi+window_state] mov [esp+52],eax mov [esp+48],ecx mov [esp+56],edx mov ebp, [edi+hold_state] mov ebx, [edi+bits_state] ; 321 "inffast.S" mov esi, [esp+44] mov ecx, [esp+20] cmp ecx,esi ja L_align_long add ecx,11 sub ecx,esi mov eax,12 sub eax,ecx lea edi, [esp+28] rep movsb mov ecx,eax xor eax,eax rep stosb lea esi, [esp+28] mov [esp+20],esi jmp L_is_aligned L_align_long: test esi,3 jz L_is_aligned xor eax,eax mov al, [esi] inc esi mov ecx,ebx add ebx,8 shl eax,cl or ebp,eax jmp L_align_long L_is_aligned: mov edi, [esp+60] ; 366 "inffast.S" L_check_mmx: cmp dword ptr [inflate_fast_use_mmx],2 je L_init_mmx ja L_do_loop push eax push ebx push ecx push edx pushfd mov eax, [esp] xor dword ptr [esp],0200000h popfd pushfd pop edx xor edx,eax jz L_dont_use_mmx xor eax,eax cpuid cmp ebx,0756e6547h jne L_dont_use_mmx cmp ecx,06c65746eh jne L_dont_use_mmx cmp edx,049656e69h jne L_dont_use_mmx mov eax,1 cpuid shr eax,8 and eax,15 cmp eax,6 jne L_dont_use_mmx test edx,0800000h jnz L_use_mmx jmp L_dont_use_mmx L_use_mmx: mov dword ptr [inflate_fast_use_mmx],2 jmp L_check_mmx_pop L_dont_use_mmx: mov dword ptr [inflate_fast_use_mmx],3 L_check_mmx_pop: pop edx pop ecx pop ebx pop eax jmp L_check_mmx ; 426 "inffast.S" ALIGN 4 L_do_loop: ; 437 "inffast.S" cmp bl,15 ja L_get_length_code xor eax,eax lodsw mov cl,bl add bl,16 shl eax,cl or ebp,eax L_get_length_code: mov edx, [esp+0] mov ecx, [esp+8] and edx,ebp mov eax, [ecx+edx*4] L_dolen: mov cl,ah sub bl,ah shr ebp,cl test al,al jnz L_test_for_length_base shr eax,16 stosb L_while_test: cmp [esp+16],edi jbe L_break_loop cmp [esp+20],esi ja L_do_loop jmp L_break_loop L_test_for_length_base: ; 502 "inffast.S" mov edx,eax shr edx,16 mov cl,al test al,16 jz L_test_for_second_level_length and cl,15 jz L_save_len cmp bl,cl jae L_add_bits_to_len mov ch,cl xor eax,eax lodsw mov cl,bl add bl,16 shl eax,cl or ebp,eax mov cl,ch L_add_bits_to_len: mov eax,1 shl eax,cl dec eax sub bl,cl and eax,ebp shr ebp,cl add edx,eax L_save_len: mov [esp+24],edx L_decode_distance: ; 549 "inffast.S" cmp bl,15 ja L_get_distance_code xor eax,eax lodsw mov cl,bl add bl,16 shl eax,cl or ebp,eax L_get_distance_code: mov edx, [esp+4] mov ecx, [esp+12] and edx,ebp mov eax, [ecx+edx*4] L_dodist: mov edx,eax shr edx,16 mov cl,ah sub bl,ah shr ebp,cl ; 584 "inffast.S" mov cl,al test al,16 jz L_test_for_second_level_dist and cl,15 jz L_check_dist_one cmp bl,cl jae L_add_bits_to_dist mov ch,cl xor eax,eax lodsw mov cl,bl add bl,16 shl eax,cl or ebp,eax mov cl,ch L_add_bits_to_dist: mov eax,1 shl eax,cl dec eax sub bl,cl and eax,ebp shr ebp,cl add edx,eax jmp L_check_window L_check_window: ; 625 "inffast.S" mov [esp+44],esi mov eax,edi sub eax, [esp+40] cmp eax,edx jb L_clip_window mov ecx, [esp+24] mov esi,edi sub esi,edx sub ecx,3 mov al, [esi] mov [edi],al mov al, [esi+1] mov dl, [esi+2] add esi,3 mov [edi+1],al mov [edi+2],dl add edi,3 rep movsb mov esi, [esp+44] jmp L_while_test ALIGN 4 L_check_dist_one: cmp edx,1 jne L_check_window cmp [esp+40],edi je L_check_window dec edi mov ecx, [esp+24] mov al, [edi] sub ecx,3 mov [edi+1],al mov [edi+2],al mov [edi+3],al add edi,4 rep stosb jmp L_while_test ALIGN 4 L_test_for_second_level_length: test al,64 jnz L_test_for_end_of_block mov eax,1 shl eax,cl dec eax and eax,ebp add eax,edx mov edx, [esp+8] mov eax, [edx+eax*4] jmp L_dolen ALIGN 4 L_test_for_second_level_dist: test al,64 jnz L_invalid_distance_code mov eax,1 shl eax,cl dec eax and eax,ebp add eax,edx mov edx, [esp+12] mov eax, [edx+eax*4] jmp L_dodist ALIGN 4 L_clip_window: ; 721 "inffast.S" mov ecx,eax mov eax, [esp+52] neg ecx mov esi, [esp+56] cmp eax,edx jb L_invalid_distance_too_far add ecx,edx cmp dword ptr [esp+48],0 jne L_wrap_around_window sub eax,ecx add esi,eax ; 749 "inffast.S" mov eax, [esp+24] cmp eax,ecx jbe L_do_copy1 sub eax,ecx rep movsb mov esi,edi sub esi,edx jmp L_do_copy1 cmp eax,ecx jbe L_do_copy1 sub eax,ecx rep movsb mov esi,edi sub esi,edx jmp L_do_copy1 L_wrap_around_window: ; 793 "inffast.S" mov eax, [esp+48] cmp ecx,eax jbe L_contiguous_in_window add esi, [esp+52] add esi,eax sub esi,ecx sub ecx,eax mov eax, [esp+24] cmp eax,ecx jbe L_do_copy1 sub eax,ecx rep movsb mov esi, [esp+56] mov ecx, [esp+48] cmp eax,ecx jbe L_do_copy1 sub eax,ecx rep movsb mov esi,edi sub esi,edx jmp L_do_copy1 L_contiguous_in_window: ; 836 "inffast.S" add esi,eax sub esi,ecx mov eax, [esp+24] cmp eax,ecx jbe L_do_copy1 sub eax,ecx rep movsb mov esi,edi sub esi,edx L_do_copy1: ; 862 "inffast.S" mov ecx,eax rep movsb mov esi, [esp+44] jmp L_while_test ; 878 "inffast.S" ALIGN 4 L_init_mmx: emms movd mm0,ebp mov ebp,ebx ; 896 "inffast.S" movd mm4,dword ptr [esp+0] movq mm3,mm4 movd mm5,dword ptr [esp+4] movq mm2,mm5 pxor mm1,mm1 mov ebx, [esp+8] jmp L_do_loop_mmx ALIGN 4 L_do_loop_mmx: psrlq mm0,mm1 cmp ebp,32 ja L_get_length_code_mmx movd mm6,ebp movd mm7,dword ptr [esi] add esi,4 psllq mm7,mm6 add ebp,32 por mm0,mm7 L_get_length_code_mmx: pand mm4,mm0 movd eax,mm4 movq mm4,mm3 mov eax, [ebx+eax*4] L_dolen_mmx: movzx ecx,ah movd mm1,ecx sub ebp,ecx test al,al jnz L_test_for_length_base_mmx shr eax,16 stosb L_while_test_mmx: cmp [esp+16],edi jbe L_break_loop cmp [esp+20],esi ja L_do_loop_mmx jmp L_break_loop L_test_for_length_base_mmx: mov edx,eax shr edx,16 test al,16 jz L_test_for_second_level_length_mmx and eax,15 jz L_decode_distance_mmx psrlq mm0,mm1 movd mm1,eax movd ecx,mm0 sub ebp,eax and ecx, [inflate_fast_mask+eax*4] add edx,ecx L_decode_distance_mmx: psrlq mm0,mm1 cmp ebp,32 ja L_get_dist_code_mmx movd mm6,ebp movd mm7,dword ptr [esi] add esi,4 psllq mm7,mm6 add ebp,32 por mm0,mm7 L_get_dist_code_mmx: mov ebx, [esp+12] pand mm5,mm0 movd eax,mm5 movq mm5,mm2 mov eax, [ebx+eax*4] L_dodist_mmx: movzx ecx,ah mov ebx,eax shr ebx,16 sub ebp,ecx movd mm1,ecx test al,16 jz L_test_for_second_level_dist_mmx and eax,15 jz L_check_dist_one_mmx L_add_bits_to_dist_mmx: psrlq mm0,mm1 movd mm1,eax movd ecx,mm0 sub ebp,eax and ecx, [inflate_fast_mask+eax*4] add ebx,ecx L_check_window_mmx: mov [esp+44],esi mov eax,edi sub eax, [esp+40] cmp eax,ebx jb L_clip_window_mmx mov ecx,edx mov esi,edi sub esi,ebx sub ecx,3 mov al, [esi] mov [edi],al mov al, [esi+1] mov dl, [esi+2] add esi,3 mov [edi+1],al mov [edi+2],dl add edi,3 rep movsb mov esi, [esp+44] mov ebx, [esp+8] jmp L_while_test_mmx ALIGN 4 L_check_dist_one_mmx: cmp ebx,1 jne L_check_window_mmx cmp [esp+40],edi je L_check_window_mmx dec edi mov ecx,edx mov al, [edi] sub ecx,3 mov [edi+1],al mov [edi+2],al mov [edi+3],al add edi,4 rep stosb mov ebx, [esp+8] jmp L_while_test_mmx ALIGN 4 L_test_for_second_level_length_mmx: test al,64 jnz L_test_for_end_of_block and eax,15 psrlq mm0,mm1 movd ecx,mm0 and ecx, [inflate_fast_mask+eax*4] add ecx,edx mov eax, [ebx+ecx*4] jmp L_dolen_mmx ALIGN 4 L_test_for_second_level_dist_mmx: test al,64 jnz L_invalid_distance_code and eax,15 psrlq mm0,mm1 movd ecx,mm0 and ecx, [inflate_fast_mask+eax*4] mov eax, [esp+12] add ecx,ebx mov eax, [eax+ecx*4] jmp L_dodist_mmx ALIGN 4 L_clip_window_mmx: mov ecx,eax mov eax, [esp+52] neg ecx mov esi, [esp+56] cmp eax,ebx jb L_invalid_distance_too_far add ecx,ebx cmp dword ptr [esp+48],0 jne L_wrap_around_window_mmx sub eax,ecx add esi,eax cmp edx,ecx jbe L_do_copy1_mmx sub edx,ecx rep movsb mov esi,edi sub esi,ebx jmp L_do_copy1_mmx cmp edx,ecx jbe L_do_copy1_mmx sub edx,ecx rep movsb mov esi,edi sub esi,ebx jmp L_do_copy1_mmx L_wrap_around_window_mmx: mov eax, [esp+48] cmp ecx,eax jbe L_contiguous_in_window_mmx add esi, [esp+52] add esi,eax sub esi,ecx sub ecx,eax cmp edx,ecx jbe L_do_copy1_mmx sub edx,ecx rep movsb mov esi, [esp+56] mov ecx, [esp+48] cmp edx,ecx jbe L_do_copy1_mmx sub edx,ecx rep movsb mov esi,edi sub esi,ebx jmp L_do_copy1_mmx L_contiguous_in_window_mmx: add esi,eax sub esi,ecx cmp edx,ecx jbe L_do_copy1_mmx sub edx,ecx rep movsb mov esi,edi sub esi,ebx L_do_copy1_mmx: mov ecx,edx rep movsb mov esi, [esp+44] mov ebx, [esp+8] jmp L_while_test_mmx ; 1174 "inffast.S" L_invalid_distance_code: mov ecx, invalid_distance_code_msg mov edx,INFLATE_MODE_BAD jmp L_update_stream_state L_test_for_end_of_block: test al,32 jz L_invalid_literal_length_code mov ecx,0 mov edx,INFLATE_MODE_TYPE jmp L_update_stream_state L_invalid_literal_length_code: mov ecx, invalid_literal_length_code_msg mov edx,INFLATE_MODE_BAD jmp L_update_stream_state L_invalid_distance_too_far: mov esi, [esp+44] mov ecx, invalid_distance_too_far_msg mov edx,INFLATE_MODE_BAD jmp L_update_stream_state L_update_stream_state: mov eax, [esp+88] test ecx,ecx jz L_skip_msg mov [eax+24],ecx L_skip_msg: mov eax, [eax+28] mov [eax+mode_state],edx jmp L_break_loop ALIGN 4 L_break_loop: ; 1243 "inffast.S" cmp dword ptr [inflate_fast_use_mmx],2 jne L_update_next_in mov ebx,ebp L_update_next_in: ; 1266 "inffast.S" mov eax, [esp+88] mov ecx,ebx mov edx, [eax+28] shr ecx,3 sub esi,ecx shl ecx,3 sub ebx,ecx mov [eax+12],edi mov [edx+bits_state],ebx mov ecx,ebx lea ebx, [esp+28] cmp [esp+20],ebx jne L_buf_not_used sub esi,ebx mov ebx, [eax+0] mov [esp+20],ebx add esi,ebx mov ebx, [eax+4] sub ebx,11 add [esp+20],ebx L_buf_not_used: mov [eax+0],esi mov ebx,1 shl ebx,cl dec ebx cmp dword ptr [inflate_fast_use_mmx],2 jne L_update_hold psrlq mm0,mm1 movd ebp,mm0 emms L_update_hold: and ebp,ebx mov [edx+hold_state],ebp mov ebx, [esp+20] cmp ebx,esi jbe L_last_is_smaller sub ebx,esi add ebx,11 mov [eax+4],ebx jmp L_fixup_out L_last_is_smaller: sub esi,ebx neg esi add esi,11 mov [eax+4],esi L_fixup_out: mov ebx, [esp+16] cmp ebx,edi jbe L_end_is_smaller sub ebx,edi add ebx,257 mov [eax+16],ebx jmp L_done L_end_is_smaller: sub edi,ebx neg edi add edi,257 mov [eax+16],edi L_done: add esp,64 popfd pop ebx pop ebp pop esi pop edi ret _inflate_fast endp _TEXT ends end |
Added compat/zlib/contrib/masmx86/match686.asm.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | ; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86 ; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant. ; File written by Gilles Vollant, by converting match686.S from Brian Raiter ; for MASM. This is as assembly version of longest_match ; from Jean-loup Gailly in deflate.c ; ; http://www.zlib.net ; http://www.winimage.com/zLibDll ; http://www.muppetlabs.com/~breadbox/software/assembly.html ; ; For Visual C++ 4.x and higher and ML 6.x and higher ; ml.exe is distributed in ; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 ; ; this file contain two implementation of longest_match ; ; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro ; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom) ; ; for using an assembly version of longest_match, you need define ASMV in project ; ; compile the asm file running ; ml /coff /Zi /c /Flmatch686.lst match686.asm ; and do not include match686.obj in your project ; ; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for ; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor ; with autoselect (with cpu detection code) ; if you want support the old pentium optimization, you can still use these version ; ; this file is not optimized for old pentium, but it compatible with all x86 32 bits ; processor (starting 80386) ; ; ; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2 ;uInt longest_match(s, cur_match) ; deflate_state *s; ; IPos cur_match; /* current match */ NbStack equ 76 cur_match equ dword ptr[esp+NbStack-0] str_s equ dword ptr[esp+NbStack-4] ; 5 dword on top (ret,ebp,esi,edi,ebx) adrret equ dword ptr[esp+NbStack-8] pushebp equ dword ptr[esp+NbStack-12] pushedi equ dword ptr[esp+NbStack-16] pushesi equ dword ptr[esp+NbStack-20] pushebx equ dword ptr[esp+NbStack-24] chain_length equ dword ptr [esp+NbStack-28] limit equ dword ptr [esp+NbStack-32] best_len equ dword ptr [esp+NbStack-36] window equ dword ptr [esp+NbStack-40] prev equ dword ptr [esp+NbStack-44] scan_start equ word ptr [esp+NbStack-48] wmask equ dword ptr [esp+NbStack-52] match_start_ptr equ dword ptr [esp+NbStack-56] nice_match equ dword ptr [esp+NbStack-60] scan equ dword ptr [esp+NbStack-64] windowlen equ dword ptr [esp+NbStack-68] match_start equ dword ptr [esp+NbStack-72] strend equ dword ptr [esp+NbStack-76] NbStackAdd equ (NbStack-24) .386p name gvmatch .MODEL FLAT ; all the +zlib1222add offsets are due to the addition of fields ; in zlib in the deflate_state structure since the asm code was first written ; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). ; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). ; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). zlib1222add equ 8 ; Note : these value are good with a 8 bytes boundary pack structure dep_chain_length equ 74h+zlib1222add dep_window equ 30h+zlib1222add dep_strstart equ 64h+zlib1222add dep_prev_length equ 70h+zlib1222add dep_nice_match equ 88h+zlib1222add dep_w_size equ 24h+zlib1222add dep_prev equ 38h+zlib1222add dep_w_mask equ 2ch+zlib1222add dep_good_match equ 84h+zlib1222add dep_match_start equ 68h+zlib1222add dep_lookahead equ 6ch+zlib1222add _TEXT segment IFDEF NOUNDERLINE public longest_match public match_init ELSE public _longest_match public _match_init ENDIF MAX_MATCH equ 258 MIN_MATCH equ 3 MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) MAX_MATCH equ 258 MIN_MATCH equ 3 MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1) MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h) ;;; stack frame offsets chainlenwmask equ esp + 0 ; high word: current chain len ; low word: s->wmask window equ esp + 4 ; local copy of s->window windowbestlen equ esp + 8 ; s->window + bestlen scanstart equ esp + 16 ; first two bytes of string scanend equ esp + 12 ; last two bytes of string scanalign equ esp + 20 ; dword-misalignment of string nicematch equ esp + 24 ; a good enough match size bestlen equ esp + 28 ; size of best match so far scan equ esp + 32 ; ptr to string wanting match LocalVarsSize equ 36 ; saved ebx byte esp + 36 ; saved edi byte esp + 40 ; saved esi byte esp + 44 ; saved ebp byte esp + 48 ; return address byte esp + 52 deflatestate equ esp + 56 ; the function arguments curmatch equ esp + 60 ;;; Offsets for fields in the deflate_state structure. These numbers ;;; are calculated from the definition of deflate_state, with the ;;; assumption that the compiler will dword-align the fields. (Thus, ;;; changing the definition of deflate_state could easily cause this ;;; program to crash horribly, without so much as a warning at ;;; compile time. Sigh.) dsWSize equ 36+zlib1222add dsWMask equ 44+zlib1222add dsWindow equ 48+zlib1222add dsPrev equ 56+zlib1222add dsMatchLen equ 88+zlib1222add dsPrevMatch equ 92+zlib1222add dsStrStart equ 100+zlib1222add dsMatchStart equ 104+zlib1222add dsLookahead equ 108+zlib1222add dsPrevLen equ 112+zlib1222add dsMaxChainLen equ 116+zlib1222add dsGoodMatch equ 132+zlib1222add dsNiceMatch equ 136+zlib1222add ;;; match686.asm -- Pentium-Pro-optimized version of longest_match() ;;; Written for zlib 1.1.2 ;;; Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com> ;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html ;;; ;; ;; This software is provided 'as-is', without any express or implied ;; warranty. In no event will the authors be held liable for any damages ;; arising from the use of this software. ;; ;; Permission is granted to anyone to use this software for any purpose, ;; including commercial applications, and to alter it and redistribute it ;; freely, subject to the following restrictions: ;; ;; 1. The origin of this software must not be misrepresented; you must not ;; claim that you wrote the original software. If you use this software ;; in a product, an acknowledgment in the product documentation would be ;; appreciated but is not required. ;; 2. Altered source versions must be plainly marked as such, and must not be ;; misrepresented as being the original software ;; 3. This notice may not be removed or altered from any source distribution. ;; ;GLOBAL _longest_match, _match_init ;SECTION .text ;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch) ;_longest_match: IFDEF NOUNDERLINE longest_match proc near ELSE _longest_match proc near ENDIF .FPO (9, 4, 0, 0, 1, 0) ;;; Save registers that the compiler may be using, and adjust esp to ;;; make room for our stack frame. push ebp push edi push esi push ebx sub esp, LocalVarsSize ;;; Retrieve the function arguments. ecx will hold cur_match ;;; throughout the entire function. edx will hold the pointer to the ;;; deflate_state structure during the function's setup (before ;;; entering the main loop. mov edx, [deflatestate] mov ecx, [curmatch] ;;; uInt wmask = s->w_mask; ;;; unsigned chain_length = s->max_chain_length; ;;; if (s->prev_length >= s->good_match) { ;;; chain_length >>= 2; ;;; } mov eax, [edx + dsPrevLen] mov ebx, [edx + dsGoodMatch] cmp eax, ebx mov eax, [edx + dsWMask] mov ebx, [edx + dsMaxChainLen] jl LastMatchGood shr ebx, 2 LastMatchGood: ;;; chainlen is decremented once beforehand so that the function can ;;; use the sign flag instead of the zero flag for the exit test. ;;; It is then shifted into the high word, to make room for the wmask ;;; value, which it will always accompany. dec ebx shl ebx, 16 or ebx, eax mov [chainlenwmask], ebx ;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; mov eax, [edx + dsNiceMatch] mov ebx, [edx + dsLookahead] cmp ebx, eax jl LookaheadLess mov ebx, eax LookaheadLess: mov [nicematch], ebx ;;; register Bytef *scan = s->window + s->strstart; mov esi, [edx + dsWindow] mov [window], esi mov ebp, [edx + dsStrStart] lea edi, [esi + ebp] mov [scan], edi ;;; Determine how many bytes the scan ptr is off from being ;;; dword-aligned. mov eax, edi neg eax and eax, 3 mov [scanalign], eax ;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? ;;; s->strstart - (IPos)MAX_DIST(s) : NIL; mov eax, [edx + dsWSize] sub eax, MIN_LOOKAHEAD sub ebp, eax jg LimitPositive xor ebp, ebp LimitPositive: ;;; int best_len = s->prev_length; mov eax, [edx + dsPrevLen] mov [bestlen], eax ;;; Store the sum of s->window + best_len in esi locally, and in esi. add esi, eax mov [windowbestlen], esi ;;; register ush scan_start = *(ushf*)scan; ;;; register ush scan_end = *(ushf*)(scan+best_len-1); ;;; Posf *prev = s->prev; movzx ebx, word ptr [edi] mov [scanstart], ebx movzx ebx, word ptr [edi + eax - 1] mov [scanend], ebx mov edi, [edx + dsPrev] ;;; Jump into the main loop. mov edx, [chainlenwmask] jmp short LoopEntry align 4 ;;; do { ;;; match = s->window + cur_match; ;;; if (*(ushf*)(match+best_len-1) != scan_end || ;;; *(ushf*)match != scan_start) continue; ;;; [...] ;;; } while ((cur_match = prev[cur_match & wmask]) > limit ;;; && --chain_length != 0); ;;; ;;; Here is the inner loop of the function. The function will spend the ;;; majority of its time in this loop, and majority of that time will ;;; be spent in the first ten instructions. ;;; ;;; Within this loop: ;;; ebx = scanend ;;; ecx = curmatch ;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) ;;; esi = windowbestlen - i.e., (window + bestlen) ;;; edi = prev ;;; ebp = limit LookupLoop: and ecx, edx movzx ecx, word ptr [edi + ecx*2] cmp ecx, ebp jbe LeaveNow sub edx, 00010000h js LeaveNow LoopEntry: movzx eax, word ptr [esi + ecx - 1] cmp eax, ebx jnz LookupLoop mov eax, [window] movzx eax, word ptr [eax + ecx] cmp eax, [scanstart] jnz LookupLoop ;;; Store the current value of chainlen. mov [chainlenwmask], edx ;;; Point edi to the string under scrutiny, and esi to the string we ;;; are hoping to match it up with. In actuality, esi and edi are ;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is ;;; initialized to -(MAX_MATCH_8 - scanalign). mov esi, [window] mov edi, [scan] add esi, ecx mov eax, [scanalign] mov edx, 0fffffef8h; -(MAX_MATCH_8) lea edi, [edi + eax + 0108h] ;MAX_MATCH_8] lea esi, [esi + eax + 0108h] ;MAX_MATCH_8] ;;; Test the strings for equality, 8 bytes at a time. At the end, ;;; adjust edx so that it is offset to the exact byte that mismatched. ;;; ;;; We already know at this point that the first three bytes of the ;;; strings match each other, and they can be safely passed over before ;;; starting the compare loop. So what this code does is skip over 0-3 ;;; bytes, as much as necessary in order to dword-align the edi ;;; pointer. (esi will still be misaligned three times out of four.) ;;; ;;; It should be confessed that this loop usually does not represent ;;; much of the total running time. Replacing it with a more ;;; straightforward "rep cmpsb" would not drastically degrade ;;; performance. LoopCmps: mov eax, [esi + edx] xor eax, [edi + edx] jnz LeaveLoopCmps mov eax, [esi + edx + 4] xor eax, [edi + edx + 4] jnz LeaveLoopCmps4 add edx, 8 jnz LoopCmps jmp short LenMaximum LeaveLoopCmps4: add edx, 4 LeaveLoopCmps: test eax, 0000FFFFh jnz LenLower add edx, 2 shr eax, 16 LenLower: sub al, 1 adc edx, 0 ;;; Calculate the length of the match. If it is longer than MAX_MATCH, ;;; then automatically accept it as the best possible match and leave. lea eax, [edi + edx] mov edi, [scan] sub eax, edi cmp eax, MAX_MATCH jge LenMaximum ;;; If the length of the match is not longer than the best match we ;;; have so far, then forget it and return to the lookup loop. mov edx, [deflatestate] mov ebx, [bestlen] cmp eax, ebx jg LongerMatch mov esi, [windowbestlen] mov edi, [edx + dsPrev] mov ebx, [scanend] mov edx, [chainlenwmask] jmp LookupLoop ;;; s->match_start = cur_match; ;;; best_len = len; ;;; if (len >= nice_match) break; ;;; scan_end = *(ushf*)(scan+best_len-1); LongerMatch: mov ebx, [nicematch] mov [bestlen], eax mov [edx + dsMatchStart], ecx cmp eax, ebx jge LeaveNow mov esi, [window] add esi, eax mov [windowbestlen], esi movzx ebx, word ptr [edi + eax - 1] mov edi, [edx + dsPrev] mov [scanend], ebx mov edx, [chainlenwmask] jmp LookupLoop ;;; Accept the current string, with the maximum possible length. LenMaximum: mov edx, [deflatestate] mov dword ptr [bestlen], MAX_MATCH mov [edx + dsMatchStart], ecx ;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; ;;; return s->lookahead; LeaveNow: mov edx, [deflatestate] mov ebx, [bestlen] mov eax, [edx + dsLookahead] cmp ebx, eax jg LookaheadRet mov eax, ebx LookaheadRet: ;;; Restore the stack and return from whence we came. add esp, LocalVarsSize pop ebx pop esi pop edi pop ebp ret ; please don't remove this string ! ; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary! db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah IFDEF NOUNDERLINE longest_match endp ELSE _longest_match endp ENDIF IFDEF NOUNDERLINE match_init proc near ret match_init endp ELSE _match_init proc near ret _match_init endp ENDIF _TEXT ends end |
Added compat/zlib/contrib/masmx86/readme.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Summary ------- This directory contains ASM implementations of the functions longest_match() and inflate_fast(). Use instructions ---------------- Assemble using MASM, and copy the object files into the zlib source directory, then run the appropriate makefile, as suggested below. You can donwload MASM from here: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 You can also get objects files here: http://www.winimage.com/zLibDll/zlib124_masm_obj.zip Build instructions ------------------ * With Microsoft C and MASM: nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" * With Borland C and TASM: make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" OBJPA="+match686c.obj+match686.obj+inffas32.obj" |
Changes to compat/zlib/contrib/minizip/Makefile.
|
| | | < < | | < < | | 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 | CC=cc CFLAGS=-O -I../.. UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a .c.o: $(CC) -c $(CFLAGS) $*.c all: miniunz minizip miniunz: $(UNZ_OBJS) $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) minizip: $(ZIP_OBJS) $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) test: miniunz minizip ./minizip test readme.txt ./miniunz -l test.zip mv readme.txt readme.old ./miniunz test.zip clean: /bin/rm -f *.o *~ minizip miniunz |
Changes to compat/zlib/contrib/minizip/MiniZip64_Changes.txt.
1 |
| | | 1 2 3 4 5 6 | MiniZip 1.1 was derrived from MiniZip at version 1.01f Change in 1.0 (Okt 2009) - **TODO - Add history** |
Changes to compat/zlib/contrib/minizip/configure.ac.
1 2 3 | # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. | | | 1 2 3 4 5 6 7 8 9 10 11 | # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_INIT([minizip], [1.2.11], [bugzilla.redhat.com]) AC_CONFIG_SRCDIR([minizip.c]) AM_INIT_AUTOMAKE([foreign]) LT_INIT AC_MSG_CHECKING([whether to build example programs]) AC_ARG_ENABLE([demos], AC_HELP_STRING([--enable-demos], [build example programs])) AM_CONDITIONAL([COND_DEMOS], [test "$enable_demos" = yes]) |
︙ | ︙ |
Changes to compat/zlib/contrib/minizip/crypt.h.
︙ | ︙ | |||
28 29 30 31 32 33 34 | */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ | | > < | > | > | | | | | | | | > | | 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 | */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != '\0') { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead(const char* passwd, /* password string */ unsigned char* buf, /* where to write header */ int bufSize, unsigned long* pkeys, const z_crc_t* pcrc_32_tab, unsigned long crcForCrypting) { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize<RAND_HEAD_LEN) return 0; |
︙ | ︙ |
Changes to compat/zlib/contrib/minizip/ioapi.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | */ #if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) #define _CRT_SECURE_NO_WARNINGS #endif | | | > | > | > | | > > > > > > > > > > | > < | > < | > < | > < | > < | > < | | > < | | > < | | > < | > < > | > | > | 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 | */ #if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) #define _CRT_SECURE_NO_WARNINGS #endif #if defined(__APPLE__) || defined(IOAPI_NO_64) // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) #else #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) #define FTELLO_FUNC(stream) ftello64(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) #endif #include "ioapi.h" voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); else { return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); } } long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else { uLong offsetTruncated = (uLong)offset; if (offsetTruncated != offset) return -1; else return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); } } ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else { uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == MAXU32) return (ZPOS64_T)-1; else return tell_uLong; } } void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; p_filefunc64_32->zfile_func64.zseek64_file = NULL; p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; } static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = fopen(filename, mode_fopen); return file; } static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = FOPEN_FUNC((const char*)filename, mode_fopen); return file; } static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) { long ret; ret = ftell((FILE *)stream); return ret; } static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) { ZPOS64_T ret; ret = FTELLO_FUNC((FILE *)stream); return ret; } static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if (fseek((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; } static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; } static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) { int ret; ret = fclose((FILE *)stream); return ret; } static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) { int ret; ret = ferror((FILE *)stream); return ret; } void fill_fopen_filefunc (pzlib_filefunc_def) zlib_filefunc_def* pzlib_filefunc_def; { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell_file = ftell_file_func; pzlib_filefunc_def->zseek_file = fseek_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell64_file = ftell64_file_func; pzlib_filefunc_def->zseek64_file = fseek64_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } |
Changes to compat/zlib/contrib/minizip/ioapi.h.
︙ | ︙ | |||
46 47 48 49 50 51 52 | #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else #ifdef __FreeBSD__ #define fopen64 fopen #define ftello64 ftello #define fseeko64 fseeko #endif #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) |
︙ | ︙ | |||
78 79 80 81 82 83 84 | #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif | | | > | < < < | 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 | #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif /* a type choosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else #ifdef HAS_STDINT_H #include "stdint.h" typedef uint64_t ZPOS64_T; #else /* Maximum unsigned 32-bit value used as placeholder for zip64 */ #define MAXU32 0xffffffff #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; #else typedef unsigned long long int ZPOS64_T; #endif #endif #endif #ifdef __cplusplus extern "C" { #endif #define ZLIB_FILEFUNC_SEEK_CUR (1) |
︙ | ︙ | |||
130 131 132 133 134 135 136 | #define ZCALLBACK #endif #endif | | | | | | | | | | | | | | | | | | | 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 | #define ZCALLBACK #endif #endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); /* here is the "old" 32 bits structure structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); typedef struct zlib_filefunc64_def_s { open64_file_func zopen64_file; read_file_func zread_file; write_file_func zwrite_file; tell64_file_func ztell64_file; seek64_file_func zseek64_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc64_def; void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s { zlib_filefunc64_def zfile_func64; open_file_func zopen32_file; tell_file_func ztell32_file; seek_file_func zseek32_file; } zlib_filefunc64_32_def; #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) #ifdef __cplusplus } #endif #endif |
Changes to compat/zlib/contrib/minizip/iowin32.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif // see Include/shared/winapifamily.h in the Windows Kit #if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API))) | < < < < < > > > > > > > > | > | > | > | 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 | #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif // see Include/shared/winapifamily.h in the Windows Kit #if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API))) #if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP) #define IOWIN32_USING_WINRT_API 1 #endif #endif voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); typedef struct { HANDLE hf; int error; } WIN32FILE_IOWIN; static void win32_translate_open_mode(int mode, DWORD* lpdwDesiredAccess, DWORD* lpdwCreationDisposition, DWORD* lpdwShareMode, DWORD* lpdwFlagsAndAttributes) { *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) { *lpdwDesiredAccess = GENERIC_READ; *lpdwCreationDisposition = OPEN_EXISTING; *lpdwShareMode = FILE_SHARE_READ; } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) { *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; *lpdwCreationDisposition = OPEN_EXISTING; } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) { *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; *lpdwCreationDisposition = CREATE_ALWAYS; } } static voidpf win32_build_iowin(HANDLE hFile) { voidpf ret=NULL; if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) { WIN32FILE_IOWIN w32fiow; w32fiow.hf = hFile; w32fiow.error = 0; ret = malloc(sizeof(WIN32FILE_IOWIN)); if (ret==NULL) CloseHandle(hFile); else *((WIN32FILE_IOWIN*)ret) = w32fiow; } return ret; } voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) { const char* mode_fopen = NULL; DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; HANDLE hFile = NULL; win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); #ifdef IOWIN32_USING_WINRT_API |
︙ | ︙ | |||
112 113 114 115 116 117 118 | hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } | | > | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) { const char* mode_fopen = NULL; DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; HANDLE hFile = NULL; win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); #ifdef IOWIN32_USING_WINRT_API |
︙ | ︙ | |||
135 136 137 138 139 140 141 | hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } | | > | > | 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 | hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) { const char* mode_fopen = NULL; DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; HANDLE hFile = NULL; win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); #ifdef IOWIN32_USING_WINRT_API if ((filename!=NULL) && (dwDesiredAccess != 0)) hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL); #else if ((filename!=NULL) && (dwDesiredAccess != 0)) hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) { const char* mode_fopen = NULL; DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; HANDLE hFile = NULL; win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); #ifdef IOWIN32_USING_WINRT_API |
︙ | ︙ | |||
182 183 184 185 186 187 188 | hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } | | > | > | > | > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); #endif return win32_build_iowin(hFile); } uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) { uLong ret=0; HANDLE hFile = NULL; if (stream!=NULL) hFile = ((WIN32FILE_IOWIN*)stream) -> hf; if (hFile != NULL) { if (!ReadFile(hFile, buf, size, &ret, NULL)) { DWORD dwErr = GetLastError(); if (dwErr == ERROR_HANDLE_EOF) dwErr = 0; ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; } } return ret; } uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) { uLong ret=0; HANDLE hFile = NULL; if (stream!=NULL) hFile = ((WIN32FILE_IOWIN*)stream) -> hf; if (hFile != NULL) { if (!WriteFile(hFile, buf, size, &ret, NULL)) { DWORD dwErr = GetLastError(); if (dwErr == ERROR_HANDLE_EOF) dwErr = 0; ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; } } return ret; } static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos, DWORD dwMoveMethod) { #ifdef IOWIN32_USING_WINRT_API return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod); #else LONG lHigh = pos.HighPart; DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, dwMoveMethod); BOOL fOk = TRUE; if (dwNewPos == 0xFFFFFFFF) if (GetLastError() != NO_ERROR) fOk = FALSE; if ((newPos != NULL) && (fOk)) { newPos->LowPart = dwNewPos; newPos->HighPart = lHigh; } return fOk; #endif } long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) { long ret=-1; HANDLE hFile = NULL; if (stream!=NULL) hFile = ((WIN32FILE_IOWIN*)stream) -> hf; if (hFile != NULL) { LARGE_INTEGER pos; |
︙ | ︙ | |||
264 265 266 267 268 269 270 | } else ret=(long)pos.LowPart; } return ret; } | | > | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | } else ret=(long)pos.LowPart; } return ret; } ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) { ZPOS64_T ret= (ZPOS64_T)-1; HANDLE hFile = NULL; if (stream!=NULL) hFile = ((WIN32FILE_IOWIN*)stream)->hf; if (hFile) { |
︙ | ︙ | |||
288 289 290 291 292 293 294 | else ret=pos.QuadPart; } return ret; } | | > | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | else ret=pos.QuadPart; } return ret; } long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) { DWORD dwMoveMethod=0xFFFFFFFF; HANDLE hFile = NULL; long ret=-1; if (stream!=NULL) hFile = ((WIN32FILE_IOWIN*)stream) -> hf; switch (origin) |
︙ | ︙ | |||
325 326 327 328 329 330 331 | } else ret=0; } return ret; } | | > | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | } else ret=0; } return ret; } long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) { DWORD dwMoveMethod=0xFFFFFFFF; HANDLE hFile = NULL; long ret=-1; if (stream!=NULL) hFile = ((WIN32FILE_IOWIN*)stream)->hf; |
︙ | ︙ | |||
363 364 365 366 367 368 369 | } else ret=0; } return ret; } | | > | > | > | > | > | > | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | } else ret=0; } return ret; } int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) { int ret=-1; if (stream!=NULL) { HANDLE hFile; hFile = ((WIN32FILE_IOWIN*)stream) -> hf; if (hFile != NULL) { CloseHandle(hFile); ret=0; } free(stream); } return ret; } int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) { int ret=-1; if (stream!=NULL) { ret = ((WIN32FILE_IOWIN*)stream) -> error; } return ret; } void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = win32_open_file_func; pzlib_filefunc_def->zread_file = win32_read_file_func; pzlib_filefunc_def->zwrite_file = win32_write_file_func; pzlib_filefunc_def->ztell_file = win32_tell_file_func; pzlib_filefunc_def->zseek_file = win32_seek_file_func; pzlib_filefunc_def->zclose_file = win32_close_file_func; pzlib_filefunc_def->zerror_file = win32_error_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = win32_open64_file_func; pzlib_filefunc_def->zread_file = win32_read_file_func; pzlib_filefunc_def->zwrite_file = win32_write_file_func; pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; pzlib_filefunc_def->zclose_file = win32_close_file_func; pzlib_filefunc_def->zerror_file = win32_error_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; pzlib_filefunc_def->zread_file = win32_read_file_func; pzlib_filefunc_def->zwrite_file = win32_write_file_func; pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; pzlib_filefunc_def->zclose_file = win32_close_file_func; pzlib_filefunc_def->zerror_file = win32_error_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; pzlib_filefunc_def->zread_file = win32_read_file_func; pzlib_filefunc_def->zwrite_file = win32_write_file_func; pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; pzlib_filefunc_def->zclose_file = win32_close_file_func; pzlib_filefunc_def->zerror_file = win32_error_file_func; pzlib_filefunc_def->opaque = NULL; } |
Changes to compat/zlib/contrib/minizip/iowin32.h.
︙ | ︙ | |||
14 15 16 17 18 19 20 | #include <windows.h> #ifdef __cplusplus extern "C" { #endif | | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <windows.h> #ifdef __cplusplus extern "C" { #endif void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); #ifdef __cplusplus } #endif |
Changes to compat/zlib/contrib/minizip/miniunz.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif | | < | 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 | #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #ifdef __APPLE__ // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) #else #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) #define FTELLO_FUNC(stream) ftello64(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <errno.h> #include <fcntl.h> #ifdef _WIN32 # include <direct.h> # include <io.h> #else # include <unistd.h> # include <utime.h> |
︙ | ︙ | |||
75 76 77 78 79 80 81 | list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT if it exists */ /* change_file_date : change the date/time of a file filename : the filename of the file where date/time must be modified | | > | > > > | < < < < < > | > < < > | > | | | 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 | list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT if it exists */ /* change_file_date : change the date/time of a file filename : the filename of the file where date/time must be modified dosdate : the new date at the MSDos format (4 bytes) tmu_date : the SAME new date at the tm_unz format */ void change_file_date(filename,dosdate,tmu_date) const char *filename; uLong dosdate; tm_unz tmu_date; { #ifdef _WIN32 HANDLE hFile; FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, 0,NULL,OPEN_EXISTING,0,NULL); GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); LocalFileTimeToFileTime(&ftLocal,&ftm); SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); CloseHandle(hFile); #else #ifdef unix || __APPLE__ struct utimbuf ut; struct tm newdate; newdate.tm_sec = tmu_date.tm_sec; newdate.tm_min=tmu_date.tm_min; newdate.tm_hour=tmu_date.tm_hour; newdate.tm_mday=tmu_date.tm_mday; newdate.tm_mon=tmu_date.tm_mon; if (tmu_date.tm_year > 1900) newdate.tm_year=tmu_date.tm_year - 1900; else newdate.tm_year=tmu_date.tm_year ; newdate.tm_isdst=-1; ut.actime=ut.modtime=mktime(&newdate); utime(filename,&ut); #endif #endif } /* mymkdir and change_file_date are not 100 % portable As I don't know well Unix, I wait feedback for the unix portion */ int mymkdir(dirname) const char* dirname; { int ret=0; #ifdef _WIN32 ret = _mkdir(dirname); #elif unix ret = mkdir (dirname,0775); #elif __APPLE__ ret = mkdir (dirname,0775); #endif return ret; } int makedir (newdir) char *newdir; { char *buffer ; char *p; int len = (int)strlen(newdir); if (len <= 0) return 0; buffer = (char*)malloc(len+1); if (buffer==NULL) { printf("Error allocating memory\n"); return UNZ_INTERNALERROR; |
︙ | ︙ | |||
181 182 183 184 185 186 187 | break; *p++ = hold; } free(buffer); return 1; } | | > | | > | | > | 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 | break; *p++ = hold; } free(buffer); return 1; } void do_banner() { printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); } void do_help() { printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ " -e Extract without pathname (junk paths)\n" \ " -x Extract with pathname\n" \ " -v list files\n" \ " -l list files\n" \ " -d directory to extract into\n" \ " -o overwrite files without prompting\n" \ " -p extract crypted file using password\n\n"); } void Display64BitsSize(ZPOS64_T n, int size_char) { /* to avoid compatibility problem , we do here the conversion */ char number[21]; int offset=19; int pos_string = 19; number[20]=0; for (;;) { number[offset]=(char)((n%10)+'0'); |
︙ | ︙ | |||
224 225 226 227 228 229 230 | printf(" "); } } printf("%s",&number[pos_string]); } | | > > | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | printf(" "); } } printf("%s",&number[pos_string]); } int do_list(uf) unzFile uf; { uLong i; unz_global_info64 gi; int err; err = unzGetGlobalInfo64(uf,&gi); if (err!=UNZ_OK) printf("error %d with zipfile in unzGetGlobalInfo \n",err); printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); for (i=0;i<gi.number_entry;i++) { char filename_inzip[256]; unz_file_info64 file_info; uLong ratio=0; const char *string_method; char charCrypt=' '; err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0); if (err!=UNZ_OK) { printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); break; } if (file_info.uncompressed_size>0) ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); /* display a '*' if the file is crypted */ if ((file_info.flag & 1) != 0) charCrypt='*'; if (file_info.compression_method==0) string_method="Stored"; else if (file_info.compression_method==Z_DEFLATED) |
︙ | ︙ | |||
300 301 302 303 304 305 306 | } } return 0; } | > > | > > > > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | } } return 0; } int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password) unzFile uf; const int* popt_extract_without_path; int* popt_overwrite; const char* password; { char filename_inzip[256]; char* filename_withoutpath; char* p; int err=UNZ_OK; FILE *fout=NULL; void* buf; uInt size_buf; unz_file_info64 file_info; uLong ratio=0; err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0); if (err!=UNZ_OK) { printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); return err; } |
︙ | ︙ | |||
352 353 354 355 356 357 358 | int skip=0; if ((*popt_extract_without_path)==0) write_filename = filename_inzip; else write_filename = filename_withoutpath; | < < < < < < < < < < < < < < | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | int skip=0; if ((*popt_extract_without_path)==0) write_filename = filename_inzip; else write_filename = filename_withoutpath; err = unzOpenCurrentFilePassword(uf,password); if (err!=UNZ_OK) { printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err); } if (((*popt_overwrite)==0) && (err==UNZ_OK)) |
︙ | ︙ | |||
438 439 440 441 442 443 444 | err = unzReadCurrentFile(uf,buf,size_buf); if (err<0) { printf("error %d with zipfile in unzReadCurrentFile\n",err); break; } if (err>0) | | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | err = unzReadCurrentFile(uf,buf,size_buf); if (err<0) { printf("error %d with zipfile in unzReadCurrentFile\n",err); break; } if (err>0) if (fwrite(buf,err,1,fout)!=1) { printf("error in writing extracted file\n"); err=UNZ_ERRNO; break; } } while (err>0); |
︙ | ︙ | |||
471 472 473 474 475 476 477 | } free(buf); return err; } | > > | > > > > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | } free(buf); return err; } int do_extract(uf,opt_extract_without_path,opt_overwrite,password) unzFile uf; int opt_extract_without_path; int opt_overwrite; const char* password; { uLong i; unz_global_info64 gi; int err; FILE* fout=NULL; err = unzGetGlobalInfo64(uf,&gi); if (err!=UNZ_OK) printf("error %d with zipfile in unzGetGlobalInfo \n",err); for (i=0;i<gi.number_entry;i++) { |
︙ | ︙ | |||
501 502 503 504 505 506 507 | } } } return 0; } | > > > | > > > > > > | > | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | } } } return 0; } int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite,password) unzFile uf; const char* filename; int opt_extract_without_path; int opt_overwrite; const char* password; { int err = UNZ_OK; if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK) { printf("file %s not found in the zipfile\n",filename); return 2; } if (do_extract_currentfile(uf,&opt_extract_without_path, &opt_overwrite, password) == UNZ_OK) return 0; else return 1; } int main(argc,argv) int argc; char *argv[]; { const char *zipfilename=NULL; const char *filename_to_extract=NULL; const char *password=NULL; char filename_try[MAXFILENAME+16] = ""; int i; int ret_value=0; int opt_do_list=0; |
︙ | ︙ | |||
548 549 550 551 552 553 554 | { if ((*argv[i])=='-') { const char *p=argv[i]+1; while ((*p)!='\0') { | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | { if ((*argv[i])=='-') { const char *p=argv[i]+1; while ((*p)!='\0') { char c=*(p++);; if ((c=='l') || (c=='L')) opt_do_list = 1; if ((c=='v') || (c=='V')) opt_do_list = 1; if ((c=='x') || (c=='X')) opt_do_extract = 1; if ((c=='e') || (c=='E')) |
︙ | ︙ | |||
590 591 592 593 594 595 596 | { # ifdef USEWIN32IOAPI zlib_filefunc64_def ffunc; # endif strncpy(filename_try, zipfilename,MAXFILENAME-1); | | | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | { # ifdef USEWIN32IOAPI zlib_filefunc64_def ffunc; # endif strncpy(filename_try, zipfilename,MAXFILENAME-1); /* strncpy doesnt append the trailing NULL, of the string is too long. */ filename_try[ MAXFILENAME ] = '\0'; # ifdef USEWIN32IOAPI fill_win32_filefunc64A(&ffunc); uf = unzOpen2_64(zipfilename,&ffunc); # else uf = unzOpen64(zipfilename); |
︙ | ︙ |
Changes to compat/zlib/contrib/minizip/minizip.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #ifdef __APPLE__ // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) #else #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) #define FTELLO_FUNC(stream) ftello64(stream) |
︙ | ︙ | |||
67 68 69 70 71 72 73 | #define WRITEBUFFERSIZE (16384) #define MAXFILENAME (256) #ifdef _WIN32 | > | | | > | > | < | | > | | | 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 | #define WRITEBUFFERSIZE (16384) #define MAXFILENAME (256) #ifdef _WIN32 uLong filetime(f, tmzip, dt) char *f; /* name of file to get info on */ tm_zip *tmzip; /* return value: access, modific. and creation times */ uLong *dt; /* dostime */ { int ret = 0; { FILETIME ftLocal; HANDLE hFind; WIN32_FIND_DATAA ff32; hFind = FindFirstFileA(f,&ff32); if (hFind != INVALID_HANDLE_VALUE) { FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); FindClose(hFind); ret = 1; } } return ret; } #else #ifdef unix || __APPLE__ uLong filetime(f, tmzip, dt) char *f; /* name of file to get info on */ tm_zip *tmzip; /* return value: access, modific. and creation times */ uLong *dt; /* dostime */ { int ret=0; struct stat s; /* results of stat() */ struct tm* filedate; time_t tm_t=0; if (strcmp(f,"-")!=0) { char name[MAXFILENAME+1]; int len = strlen(f); if (len > MAXFILENAME) len = MAXFILENAME; strncpy(name, f,MAXFILENAME-1); /* strncpy doesnt append the trailing NULL, of the string is too long. */ name[ MAXFILENAME ] = '\0'; if (name[len - 1] == '/') name[len - 1] = '\0'; /* not all systems allow stat'ing a file with / appended */ if (stat(name,&s)==0) { |
︙ | ︙ | |||
130 131 132 133 134 135 136 | tmzip->tm_mday = filedate->tm_mday; tmzip->tm_mon = filedate->tm_mon ; tmzip->tm_year = filedate->tm_year; return ret; } #else | > | < | < < | > > | > | > | > | > | | | | | > | | | > > | > | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | tmzip->tm_mday = filedate->tm_mday; tmzip->tm_mon = filedate->tm_mon ; tmzip->tm_year = filedate->tm_year; return ret; } #else uLong filetime(f, tmzip, dt) char *f; /* name of file to get info on */ tm_zip *tmzip; /* return value: access, modific. and creation times */ uLong *dt; /* dostime */ { return 0; } #endif #endif int check_exist_file(filename) const char* filename; { FILE* ftestexist; int ret = 1; ftestexist = FOPEN_FUNC(filename,"rb"); if (ftestexist==NULL) ret = 0; else fclose(ftestexist); return ret; } void do_banner() { printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); } void do_help() { printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ " -o Overwrite existing file.zip\n" \ " -a Append to existing file.zip\n" \ " -0 Store only\n" \ " -1 Compress faster\n" \ " -9 Compress better\n\n" \ " -j exclude path. store only the file name.\n\n"); } /* calculate the CRC32 of a file, because to encrypt a file, we need known the CRC32 of the file before */ int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) { unsigned long calculate_crc=0; int err=ZIP_OK; FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); unsigned long size_read = 0; unsigned long total_read = 0; if (fin==NULL) { err = ZIP_ERRNO; } if (err == ZIP_OK) do { err = ZIP_OK; size_read = (int)fread(buf,1,size_buf,fin); if (size_read < size_buf) if (feof(fin)==0) { printf("error in reading %s\n",filenameinzip); err = ZIP_ERRNO; } if (size_read>0) calculate_crc = crc32(calculate_crc,buf,size_read); total_read += size_read; } while ((err == ZIP_OK) && (size_read>0)); if (fin) fclose(fin); *result_crc=calculate_crc; printf("file %s crc %lx\n", filenameinzip, calculate_crc); return err; } int isLargeFile(const char* filename) { int largeFile = 0; ZPOS64_T pos = 0; FILE* pFile = FOPEN_FUNC(filename, "rb"); if(pFile != NULL) { int n = FSEEKO_FUNC(pFile, 0, SEEK_END); pos = FTELLO_FUNC(pFile); printf("File : %s is %lld bytes\n", filename, pos); if(pos >= 0xffffffff) largeFile = 1; fclose(pFile); } return largeFile; } int main(argc,argv) int argc; char *argv[]; { int i; int opt_overwrite=0; int opt_compress_level=Z_DEFAULT_COMPRESSION; int opt_exclude_path=0; int zipfilenamearg = 0; char filename_try[MAXFILENAME+16]; int zipok; int err=0; int size_buf=0; void* buf=NULL; const char* password=NULL; do_banner(); if (argc==1) { do_help(); return 0; } else { for (i=1;i<argc;i++) { if ((*argv[i])=='-') { const char *p=argv[i]+1; while ((*p)!='\0') { char c=*(p++);; if ((c=='o') || (c=='O')) opt_overwrite = 1; if ((c=='a') || (c=='A')) opt_overwrite = 2; if ((c>='0') && (c<='9')) opt_compress_level = c-'0'; if ((c=='j') || (c=='J')) |
︙ | ︙ | |||
307 308 309 310 311 312 313 | else { int i,len; int dot_found=0; zipok = 1 ; strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1); | | | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | else { int i,len; int dot_found=0; zipok = 1 ; strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1); /* strncpy doesnt append the trailing NULL, of the string is too long. */ filename_try[ MAXFILENAME ] = '\0'; len=(int)strlen(filename_try); for (i=0;i<len;i++) if (filename_try[i]=='.') dot_found=1; |
︙ | ︙ | |||
377 378 379 380 381 382 383 | for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++) { if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) && ((argv[i][1]=='o') || (argv[i][1]=='O') || (argv[i][1]=='a') || (argv[i][1]=='A') || (argv[i][1]=='p') || (argv[i][1]=='P') || | | | | | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++) { if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) && ((argv[i][1]=='o') || (argv[i][1]=='O') || (argv[i][1]=='a') || (argv[i][1]=='A') || (argv[i][1]=='p') || (argv[i][1]=='P') || ((argv[i][1]>='0') || (argv[i][1]<='9'))) && (strlen(argv[i]) == 2))) { FILE * fin; int size_read; const char* filenameinzip = argv[i]; const char *savefilenameinzip; zip_fileinfo zi; unsigned long crcFile=0; int zip64 = 0; zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = |
︙ | ︙ | |||
457 458 459 460 461 462 463 | } } if (err == ZIP_OK) do { err = ZIP_OK; | | | | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | } } if (err == ZIP_OK) do { err = ZIP_OK; size_read = (int)fread(buf,1,size_buf,fin); if (size_read < size_buf) if (feof(fin)==0) { printf("error in reading %s\n",filenameinzip); err = ZIP_ERRNO; } if (size_read>0) { err = zipWriteInFileInZip (zf,buf,size_read); if (err<0) { printf("error in writing %s in the zipfile\n", filenameinzip); } } |
︙ | ︙ |
Changes to compat/zlib/contrib/minizip/mztools.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ } while(0) #define WRITE_32(buff, n) do { \ WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ } while(0) | > > > | > > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ } while(0) #define WRITE_32(buff, n) do { \ WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ } while(0) extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) const char* file; const char* fileOut; const char* fileOutTmp; uLong* nRecovered; uLong* bytesRecovered; { int err = Z_OK; FILE* fpZip = fopen(file, "rb"); FILE* fpOut = fopen(fileOut, "wb"); FILE* fpOutCD = fopen(fileOutTmp, "wb"); if (fpZip != NULL && fpOut != NULL) { int entries = 0; uLong totalBytes = 0; |
︙ | ︙ |
Changes to compat/zlib/contrib/minizip/unzip.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* 2007-2008 - Even Rouault - Remove old C style function prototypes 2007-2008 - Even Rouault - Add unzip support for ZIP64 Copyright (C) 2007-2008 Even Rouault | | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* 2007-2008 - Even Rouault - Remove old C style function prototypes 2007-2008 - Even Rouault - Add unzip support for ZIP64 Copyright (C) 2007-2008 Even Rouault Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson */ |
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 | #endif #include "zlib.h" #include "unzip.h" #ifdef STDC # include <stddef.h> #endif #ifdef NO_ERRNO_H extern int errno; #else # include <errno.h> #endif | > > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | #endif #include "zlib.h" #include "unzip.h" #ifdef STDC # include <stddef.h> # include <string.h> # include <stdlib.h> #endif #ifdef NO_ERRNO_H extern int errno; #else # include <errno.h> #endif |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; | > > > | | 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 | #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ } unz_file_info64_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, |
︙ | ︙ | |||
144 145 146 147 148 149 150 | ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; | | | | 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 | ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip64_read_info_s; /* unz64_s contain internal information about the zipfile */ typedef struct { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; voidpf filestream; /* io structore of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ ZPOS64_T central_pos; /* position of the beginning of the central dir*/ |
︙ | ︙ | |||
188 189 190 191 192 193 194 | } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif | < | > > > > | | | < < < | < < < < < < | < < < < < | < < < | | | < > < > > > > | | > > > > | > > > > | | > > | > > | > > > > > > | > > > > | > > > > > > > > > > > | > > | > > > > > > > > > > > > > | > > > > > > > > > > > | > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < | > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been successfully opened for reading. */ local int unz64local_getByte OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unz64local_getShort OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<24; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<32; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<40; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<48; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<56; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) |
︙ | ︙ | |||
288 289 290 291 292 293 294 | #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* | | | | | | | > > < < < < > | > | | | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackRead<uMaxBack) { uLong uReadSize; ZPOS64_T uReadPos ; int i; |
︙ | ︙ | |||
364 365 366 367 368 369 370 | if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { | | | | > > > > | > | | | | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackRead<uMaxBack) { uLong uReadSize; ZPOS64_T uReadPos; int i; |
︙ | ︙ | |||
427 428 429 430 431 432 433 | if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { | | | | | | | | | | | | | | | | | | | | > | | | | | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) return 0; /* total number of disks */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 1) return 0; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0x06064b50) return 0; return relativeOffset; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ local unzFile unzOpenInternal (const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def, int is64bitOpenFunction) { unz64_s us; unz64_s *s; ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') |
︙ | ︙ | |||
524 525 526 527 528 529 530 | path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); | | | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); if (central_pos) { uLong uS; ZPOS64_T uL64; us.isZip64 = 1; if (ZSEEK64(us.z_filefunc, us.filestream, |
︙ | ︙ | |||
586 587 588 589 590 591 592 | err=UNZ_ERRNO; us.gi.size_comment = 0; } else { central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); | | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | err=UNZ_ERRNO; us.gi.size_comment = 0; } else { central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==0) err=UNZ_ERRNO; us.isZip64 = 0; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; |
︙ | ︙ | |||
665 666 667 668 669 670 671 | *s=us; unzGoToFirstFile((unzFile)s); } return (unzFile)s; } | | | > | | > | > | > | > | | > | > | | > | | | | | | | | | | | | | | | | > > > > > > > > > > > > | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 | *s=us; unzGoToFirstFile((unzFile)s); } return (unzFile)s; } extern unzFile ZEXPORT unzOpen2 (const char *path, zlib_filefunc_def* pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0); } else return unzOpenInternal(path, NULL, 0); } extern unzFile ZEXPORT unzOpen2_64 (const void *path, zlib_filefunc64_def* pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1); } else return unzOpenInternal(path, NULL, 1); } extern unzFile ZEXPORT unzOpen (const char *path) { return unzOpenInternal(path, NULL, 0); } extern unzFile ZEXPORT unzOpen64 (const void *path) { return unzOpenInternal(path, NULL, 1); } /* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzClose (unzFile file) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (s->pfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE64(s->z_filefunc, s->filestream); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; *pglobal_info=s->gi; return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* to do : check if number_entry is not truncated */ pglobal_info32->number_entry = (uLong)s->gi.number_entry; pglobal_info32->size_comment = s->gi.size_comment; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unz64local_GetCurrentFileInfoInternal (unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; uLong uL; |
︙ | ︙ | |||
876 877 878 879 880 881 882 | if (file_info.size_file_extra<extraFieldBufferSize) uSizeRead = file_info.size_file_extra; else uSizeRead = extraFieldBufferSize; if (lSeek!=0) { | | | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 | if (file_info.size_file_extra<extraFieldBufferSize) uSizeRead = file_info.size_file_extra; else uSizeRead = extraFieldBufferSize; if (lSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) |
︙ | ︙ | |||
901 902 903 904 905 906 907 | uLong acc = 0; // since lSeek now points to after the extra field we need to move back lSeek -= file_info.size_file_extra; if (lSeek!=0) { | | > > | | | | | | | | | | | | | | | | | | | | | | | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | uLong acc = 0; // since lSeek now points to after the extra field we need to move back lSeek -= file_info.size_file_extra; if (lSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } while(acc < file_info.size_file_extra) { uLong headerId; uLong dataSize; if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) err=UNZ_ERRNO; /* ZIP64 extra fields */ if (headerId == 0x0001) { uLong uL; if(file_info.uncompressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.compressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info_internal.offset_curfile == MAXU32) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.disk_num_start == MAXU32) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; } } else { if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) err=UNZ_ERRNO; } |
︙ | ︙ | |||
971 972 973 974 975 976 977 | uSizeRead = file_info.size_file_comment; } else uSizeRead = commentBufferSize; if (lSeek!=0) { | | | 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | uSizeRead = file_info.size_file_comment; } else uSizeRead = commentBufferSize; if (lSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) |
︙ | ︙ | |||
1002 1003 1004 1005 1006 1007 1008 | /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ | | | | | | > | | | | | | | | > | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, unz_file_info64 * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, unz_file_info * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); if ((err==UNZ_OK) && (pfile_info != NULL)) |
︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 | pfile_info->size_file_extra = file_info64.size_file_extra; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; | | | > | > | 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 | pfile_info->size_file_extra = file_info64.size_file_extra; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; pfile_info->tmu_date = file_info64.tmu_date, pfile_info->compressed_size = (uLong)file_info64.compressed_size; pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; } return err; } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (unzFile file) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 | Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ | | > | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 | Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info64 cur_file_infoSaved; |
︙ | ︙ | |||
1181 1182 1183 1184 1185 1186 1187 | typedef struct unz_file_pos_s { ZPOS64_T pos_in_zip_directory; // offset in file ZPOS64_T num_of_file; // # of file } unz_file_pos; */ | | > | > > > | > | > > > | 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 | typedef struct unz_file_pos_s { ZPOS64_T pos_in_zip_directory; // offset in file ZPOS64_T num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) { file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; file_pos->num_of_file = (uLong)file_pos64.num_of_file; } return err; } extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; file_pos64.num_of_file = file_pos->num_of_file; return unzGoToFilePos64(file,&file_pos64); |
︙ | ︙ | |||
1250 1251 1252 1253 1254 1255 1256 | /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ | | | | > | 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 | /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, ZPOS64_T * poffset_local_extrafield, uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; |
︙ | ︙ | |||
1336 1337 1338 1339 1340 1341 1342 | return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ | | | > | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 | return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { | | | 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; |
︙ | ︙ | |||
1432 1433 1434 1435 1436 1437 1438 | pfile_in_zip_read_info->stream.avail_in = 0; err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { | < | < | | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 | pfile_in_zip_read_info->stream.avail_in = 0; err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { TRYFREE(pfile_in_zip_read_info); return err; } #else pfile_in_zip_read_info->raw=1; #endif } else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = 0; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the |
︙ | ︙ | |||
1506 1507 1508 1509 1510 1511 1512 | } # endif return UNZ_OK; } | | > | > | > | > | | > | 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 | } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile (unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; if (file==NULL) return 0; //UNZ_PARAMERROR; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return 0; //UNZ_PARAMERROR; return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; } /** Addition for GDAL : END */ /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; |
︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 | if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) | | | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; |
︙ | ︙ | |||
1720 1721 1722 1723 1724 1725 1726 | */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; | < < < | | | > | > | > | 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 | */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } extern ZPOS64_T ZEXPORT unztell64 (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return (ZPOS64_T)-1; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return (ZPOS64_T)-1; return pfile_in_zip_read_info->total_out_64; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; |
︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 | if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ | | > | 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 | if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; ZPOS64_T size_to_read; if (file==NULL) return UNZ_PARAMERROR; |
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 | return (int)read_now; } /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ | | > | 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 | return (int)read_now; } /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; |
︙ | ︙ | |||
1885 1886 1887 1888 1889 1890 1891 | (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } | | | | > | 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 | (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); #ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); #endif pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) return (int)UNZ_PARAMERROR; s=(unz64_s*)file; uReadThis = uSizeBuf; |
︙ | ︙ | |||
1936 1937 1938 1939 1940 1941 1942 | if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ | | > | > | > | > | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 | if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) return 0; //UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern uLong ZEXPORT unzGetOffset (unzFile file) { ZPOS64_T offset64; if (file==NULL) return 0; //UNZ_PARAMERROR; offset64 = unzGetOffset64(file); return (uLong)offset64; } extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } |
Changes to compat/zlib/contrib/minizip/unzip.h.
︙ | ︙ | |||
79 80 81 82 83 84 85 | #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { | | | | | | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info64_s { ZPOS64_T number_entry; /* total number of entries in |
︙ | ︙ | |||
146 147 148 149 150 151 152 | uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((const char *path)); extern unzFile ZEXPORT unzOpen64 OF((const void *path)); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. the "64" function take a const void* pointer, because the path is just the value passed to the open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found |
︙ | ︙ | |||
281 282 283 284 285 286 287 | extern int ZEXPORT unzGoToFilePos64( unzFile file, const unz64_file_pos* file_pos); /* ****************************************** */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | extern int ZEXPORT unzGoToFilePos64( unzFile file, const unz64_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); /** Addition for GDAL : END */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field |
︙ | ︙ |
Changes to compat/zlib/contrib/minizip/zip.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | For more info read MiniZip_info.txt Changes Oct-2009 - Mathias Svensson - Remove old C style function prototypes Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data | | < > > | > > > | 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 | For more info read MiniZip_info.txt Changes Oct-2009 - Mathias Svensson - Remove old C style function prototypes Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data It is used when recreting zip archive with RAW when deleting items from a zip. ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "zlib.h" #include "zip.h" #ifdef STDC # include <stddef.h> # include <string.h> # include <stdlib.h> #endif #ifdef NO_ERRNO_H extern int errno; #else # include <errno.h> #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x0) /* platform depedent */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (64*1024) //(16384) #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ |
︙ | ︙ | |||
130 131 132 133 134 135 136 | bz_stream bstream; /* bzLib stream structure for bziped */ #endif int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file | | | | | | | | > | > | | > | > | > | | 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 | bz_stream bstream; /* bzLib stream structure for bziped */ #endif int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file currenty writing */ char* central_header; /* central header data for the current file */ uLong size_centralExtra; uLong size_centralheader; /* size of the central header for cur file */ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currenty wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; int zip64; /* Add ZIP64 extened information in the extra field */ ZPOS64_T pos_zip64extrainfo; ZPOS64_T totalCompressedData; ZPOS64_T totalUncompressedData; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t* pcrc_32_tab; int crypt_header_size; #endif } curfile64_info; typedef struct { zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile64_info ci; /* info on the file curretly writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ ZPOS64_T add_position_when_writing_offset; ZPOS64_T number_entry; #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif } zip64_internal; #ifndef NOCRYPT #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED #include "crypt.h" #endif local linkedlist_datablock_internal* allocate_new_datablock() { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(linkedlist_datablock_internal* ldi) { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } local void init_linkedlist(linkedlist_data* ll) { ll->first_block = ll->last_block = NULL; } local void free_linkedlist(linkedlist_data* ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; |
︙ | ︙ | |||
270 271 272 273 274 275 276 | #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ | > | > | > | > | > | | > > | > > > | > > > | > | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) { unsigned char buf[8]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } /****************************************************************************/ local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) { uLong year = (uLong)ptm->tm_year; if (year>=1980) year-=1980; else if (year>=80) year-=80; return (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return ZIP_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return ZIP_ERRNO; else return ZIP_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; |
︙ | ︙ | |||
393 394 395 396 397 398 399 400 | if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } | > > | > | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; |
︙ | ︙ | |||
445 446 447 448 449 450 451 | #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ | > > | > | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) |
︙ | ︙ | |||
489 490 491 492 493 494 495 | if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { | | | | | > > | > | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; |
︙ | ︙ | |||
550 551 552 553 554 555 556 | break; for (i=(int)uReadSize-3; (i--)>0;) { // Signature "0x07064b50" Zip64 end of central directory locater if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { | | | | | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | break; for (i=(int)uReadSize-3; (i--)>0;) { // Signature "0x07064b50" Zip64 end of central directory locater if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) |
︙ | ︙ | |||
601 602 603 604 605 606 607 | if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' return 0; return relativeOffset; } | | > | | | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' return 0; return relativeOffset; } int LoadCentralDirectoryRecord(zip64_internal* pziinit) { int err=ZIP_OK; ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory */ ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry; ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ uLong VersionMadeBy; uLong VersionNeeded; uLong size_comment; |
︙ | ︙ | |||
793 794 795 796 797 798 799 | err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } | | | > | 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } TRYFREE(buf_read); } pziinit->begin_pos = byte_before_the_zipfile; pziinit->number_entry = number_entry_CD; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; return err; } #endif /* !NO_ADDFILEINEXISTINGZIP*/ /************************************************************/ extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) { zip64_internal ziinit; zip64_internal* zi; int err=ZIP_OK; ziinit.z_filefunc.zseek32_file = NULL; ziinit.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) |
︙ | ︙ | |||
867 868 869 870 871 872 873 | *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP | | | | > | > | > | > | > | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 | *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ TRYFREE(zi); return NULL; } else { *zi = ziinit; return (zipFile)zi; } } extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(pathname, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(pathname, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen (const char* pathname, int append) { return zipOpen3((const void*)pathname,append,NULL,NULL); } extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) { return zipOpen3(pathname,append,NULL,NULL); } int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) { /* write the local header */ int err; uInt size_filename = (uInt)strlen(filename); uInt size_extrafield = size_extrafield_local; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); |
︙ | ︙ | |||
991 992 993 994 995 996 997 | short DataSize = 16; ZPOS64_T CompressedSize = 0; ZPOS64_T UncompressedSize = 0; // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); | | | | | | | | | | > | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | short DataSize = 16; ZPOS64_T CompressedSize = 0; ZPOS64_T UncompressedSize = 0; // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); } return err; } /* NOTE. When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped before calling this function it can be done with zipRemoveExtraInfoBlock It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize unnecessary allocations. */ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) { zip64_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; # ifdef NOCRYPT |
︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 | if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) return ZIP_PARAMERROR; #else if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; #endif | < < < < < < < < < < < | 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 | if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) return ZIP_PARAMERROR; #else if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; #endif zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; |
︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 | # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } | | | | | | | | > | | | | | | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | | | > | | | | | | | | | | > | | | | | | | | | | > | | | | | | | > | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 | # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); } extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } local int zip64FlushWriteBuffer(zip64_internal* zi) { int err=ZIP_OK; if (zi->ci.encrypt != 0) { #ifndef NOCRYPT uInt i; int t; |
︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 | zi->ci.pos_in_buffered_data = 0; return err; } | | > | 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 | zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) { zip64_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; |
︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 | if(err == BZ_RUN_OK) err = ZIP_OK; } else #endif { | | > > > > > | 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 | if(err == BZ_RUN_OK) err = ZIP_OK; } else #endif { zi->ci.stream.next_in = (Bytef*)buf; zi->ci.stream.avail_in = len; while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if(err != ZIP_OK) break; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); if(uTotalOutBefore > zi->ci.stream.total_out) { int bBreak = 0; bBreak++; } zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) |
︙ | ︙ | |||
1459 1460 1461 1462 1463 1464 1465 | } }// while(...) } return err; } | | > | > | | 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 | } }// while(...) } return err; } extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) { return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); } extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) { zip64_internal* zi; ZPOS64_T compressed_size; uLong invalidValue = 0xffffffff; short datasize = 0; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) |
︙ | ︙ | |||
1604 1605 1606 1607 1608 1609 1610 | if(datasize > 0) { char* p = NULL; if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) { | | | 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 | if(datasize > 0) { char* p = NULL; if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) { // we can not write more data to the buffer that we have room for. return ZIP_BADZIPFILE; } p = zi->ci.central_header + zi->ci.size_centralheader; // Add Extra Information Header for 'ZIP64 information' zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID |
︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 | zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } | | > | > | > | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 | zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip (zipFile file) { return zipCloseFileInZipRaw (file,0,0); } int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) { int err = ZIP_OK; ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); /*num disks*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /*relative offset*/ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); return err; } int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; uLong Zip64DataSize = 44; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ |
︙ | ︙ | |||
1761 1762 1763 1764 1765 1766 1767 | if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); } return err; } | > | < | 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 | if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); } return err; } int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; /*signature*/ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); |
︙ | ︙ | |||
1809 1810 1811 1812 1813 1814 1815 | else err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); } return err; } | | > | > | 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 | else err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); } return err; } int Write_GlobalComment(zip64_internal* zi, const char* global_comment) { int err = ZIP_OK; uInt size_global_comment = 0; if(global_comment != NULL) size_global_comment = (uInt)strlen(global_comment); err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); if (err == ZIP_OK && size_global_comment > 0) { if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) err = ZIP_ERRNO; } return err; } extern int ZEXPORT zipClose (zipFile file, const char* global_comment) { zip64_internal* zi; int err = 0; uLong size_centraldir = 0; ZPOS64_T centraldir_pos_inzip; ZPOS64_T pos; if (file == NULL) |
︙ | ︙ | |||
1868 1869 1870 1871 1872 1873 1874 | size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; | | | | | > | | | 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 | size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) { ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); } if (err==ZIP_OK) err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); if(err == ZIP_OK) err = Write_GlobalComment(zi, global_comment); if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(zi->globalcomment); #endif TRYFREE(zi); return err; } extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) { char* p = pData; int size = 0; char* pNewHeader; char* pTmp; short header; short dataSize; int retVal = ZIP_OK; if(pData == NULL || *dataLen < 4) return ZIP_PARAMERROR; pNewHeader = (char*)ALLOC(*dataLen); pTmp = pNewHeader; while(p < (pData + *dataLen)) { header = *(short*)p; dataSize = *(((short*)p)+1); |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 | *dataLen = size; retVal = ZIP_OK; } else retVal = ZIP_ERRNO; | | | 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 | *dataLen = size; retVal = ZIP_OK; } else retVal = ZIP_ERRNO; TRYFREE(pNewHeader); return retVal; } |
Changes to compat/zlib/contrib/minizip/zip.h.
︙ | ︙ | |||
84 85 86 87 88 89 90 | # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { | | | | | | | | | | | | | | | | < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); /* Create a zipfile. pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another Of couse, you can use RAW reading and writing to copy the file you did not want delte */ extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) zip64 is set to 1 if a zip64 extended information block should be added to the local file header. this MUST be '1' if the uncompressed size is >= 0xffffffff. */ extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw)); extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting)); extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64 )); /* Same than zipOpenNewFileInZip2, except windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCrypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase )); extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64 )); /* Same than zipOpenNewFileInZip4, except versionMadeBy : value for Version made by field flag : value for flag field (compression level info will be added) */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); /* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); /* zipRemoveExtraInfoBlock - Added by Mathias Svensson Remove extra information block from a extra information data for the local file header or central directory header It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. |
︙ | ︙ |
Changes to compat/zlib/contrib/pascal/zlibpas.pas.
1 2 3 4 5 6 7 8 9 10 11 12 | (* zlibpas -- Pascal interface to the zlib data compression library * * Copyright (C) 2003 Cosmin Truta. * Derived from original sources by Bob Dellaca. * For conditions of distribution and use, see copyright notice in readme.txt *) unit zlibpas; interface const | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | (* zlibpas -- Pascal interface to the zlib data compression library * * Copyright (C) 2003 Cosmin Truta. * Derived from original sources by Bob Dellaca. * For conditions of distribution and use, see copyright notice in readme.txt *) unit zlibpas; interface const ZLIB_VERSION = '1.2.11'; ZLIB_VERNUM = $12a0; type alloc_func = function(opaque: Pointer; items, size: Integer): Pointer; cdecl; free_func = procedure(opaque, address: Pointer); cdecl; |
︙ | ︙ |
Changes to compat/zlib/contrib/puff/README.
︙ | ︙ | |||
34 35 36 37 38 39 40 | unsigned char *source, /* pointer to source data pointer */ unsigned long *sourcelen); /* amount of input available */ Then you can call puff() to decompress a deflate stream that is in memory in its entirety at source, to a sufficiently sized block of memory for the decompressed data at dest. puff() is the only external symbol in puff.c The only C library functions that puff.c needs are setjmp() and longjmp(), which | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | unsigned char *source, /* pointer to source data pointer */ unsigned long *sourcelen); /* amount of input available */ Then you can call puff() to decompress a deflate stream that is in memory in its entirety at source, to a sufficiently sized block of memory for the decompressed data at dest. puff() is the only external symbol in puff.c The only C library functions that puff.c needs are setjmp() and longjmp(), which are used to simplify error checking in the code to improve readabilty. puff.c does no memory allocation, and uses less than 2K bytes off of the stack. If destlen is not enough space for the uncompressed data, then inflate will return an error without writing more than destlen bytes. Note that this means that in order to decompress the deflate data successfully, you need to know the size of the uncompressed data ahead of time. |
︙ | ︙ |
Changes to compat/zlib/contrib/puff/puff.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | * - Simplify offs[] index in construct() * - Add input size and checking, using longjmp() to * maintain easy readability * - Use short data type for large arrays * - Use pointers instead of long to specify source and * destination sizes to avoid arbitrary 4 GB limits * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | * - Simplify offs[] index in construct() * - Add input size and checking, using longjmp() to * maintain easy readability * - Use short data type for large arrays * - Use pointers instead of long to specify source and * destination sizes to avoid arbitrary 4 GB limits * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), * but leave simple version for readabilty * - Make sure invalid distances detected if pointers * are 16 bits * - Fix fixed codes table error * - Provide a scanning mode for determining size of * uncompressed data * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] * - Add a puff.h file for the interface |
︙ | ︙ | |||
589 590 591 592 593 594 595 | * from the number of bits in each code. Therefore the code descriptions * are simply a list of code lengths for each symbol. * * - The code lengths are stored in order for the symbols, so lengths are * provided for each of the literal/length symbols, and for each of the * distance symbols. * | | | | | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | * from the number of bits in each code. Therefore the code descriptions * are simply a list of code lengths for each symbol. * * - The code lengths are stored in order for the symbols, so lengths are * provided for each of the literal/length symbols, and for each of the * distance symbols. * * - If a symbol is not used in the block, this is represented by a zero as * as the code length. This does not mean a zero-length code, but rather * that no code should be created for this symbol. There is no way in the * deflate format to represent a zero-length code. * * - The maximum number of bits in a code is 15, so the possible lengths for * any code are 1..15. * * - The fact that a length of zero is not permitted for a code has an * interesting consequence. Normally if only one symbol is used for a given * code, then in fact that code could be represented with zero bits. However |
︙ | ︙ | |||
620 621 622 623 624 625 626 | * - If there are only literal codes and no lengths, then there are no distance * codes. This is represented by one distance code with zero bits. * * - The list of up to 286 length/literal lengths and up to 30 distance lengths * are themselves compressed using Huffman codes and run-length encoding. In * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means * that length, and the symbols 16, 17, and 18 are run-length instructions. | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | * - If there are only literal codes and no lengths, then there are no distance * codes. This is represented by one distance code with zero bits. * * - The list of up to 286 length/literal lengths and up to 30 distance lengths * are themselves compressed using Huffman codes and run-length encoding. In * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means * that length, and the symbols 16, 17, and 18 are run-length instructions. * Each of 16, 17, and 18 are follwed by extra bits to define the length of * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols * are common, hence the special coding for zero lengths. * * - The symbols for 0..18 are Huffman coded, and so that code must be * described first. This is simply a sequence of up to 19 three-bit values * representing no code (0) or the code length for that symbol (1..7). |
︙ | ︙ |
Changes to compat/zlib/contrib/puff/pufftest.c.
︙ | ︙ | |||
139 140 141 142 143 144 145 | fprintf(stderr, "puff() failed with return code %d\n", ret); else { fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen); if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n", len - sourcelen); } | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | fprintf(stderr, "puff() failed with return code %d\n", ret); else { fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen); if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n", len - sourcelen); } /* if requested, inflate again and write decompressd data to stdout */ if (put && ret == 0) { if (fail) destlen >>= 1; dest = malloc(destlen); if (dest == NULL) { fprintf(stderr, "memory allocation failure\n"); free(source); |
︙ | ︙ |
Changes to compat/zlib/contrib/testzlib/testzlib.c.
︙ | ︙ | |||
165 166 167 168 169 170 171 | } if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) { printf("error reading %s\n",argv[1]); return 1; } | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | } if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) { printf("error reading %s\n",argv[1]); return 1; } else printf("file %s read, %u bytes\n",argv[1],lFileSize); if (argc>=3) BlockSizeCompress=atol(argv[2]); if (argc>=4) BlockSizeUncompress=atol(argv[3]); |
︙ | ︙ |
Changes to compat/zlib/contrib/untgz/untgz.c.
1 2 3 4 5 6 | /* * untgz.c -- Display contents and extract files from a gzip'd TAR file * * written by Pedro A. Aranda Gutierrez <paag@tid.es> * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> | < < < < < < < < < < < < < < < < | > > > > > | < < | 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 | /* * untgz.c -- Display contents and extract files from a gzip'd TAR file * * written by Pedro A. Aranda Gutierrez <paag@tid.es> * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <errno.h> #include "zlib.h" #ifdef unix # include <unistd.h> #else # include <direct.h> # include <io.h> #endif #ifdef WIN32 #include <windows.h> # ifndef F_OK # define F_OK 0 # endif # define mkdir(dirname,mode) _mkdir(dirname) # ifdef _MSC_VER # define access(path,mode) _access(path,mode) # define chmod(path,mode) _chmod(path,mode) # define strdup(str) _strdup(str) # endif #else # include <utime.h> #endif /* values used in typeflag field */ #define REGTYPE '0' /* regular file */ |
︙ | ︙ | |||
111 112 113 114 115 116 117 | char *fname; int mode; time_t time; }; enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; | | > > > > > > | > | > > | > > | > > | > | 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 | char *fname; int mode; time_t time; }; enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; char *TGZfname OF((const char *)); void TGZnotfound OF((const char *)); int getoct OF((char *, int)); char *strtime OF((time_t *)); int setfiletime OF((char *, time_t)); void push_attr OF((struct attr_item **, char *, int, time_t)); void restore_attr OF((struct attr_item **)); int ExprMatch OF((char *, char *)); int makedir OF((char *)); int matchname OF((int, int, char **, char *)); void error OF((const char *)); int tar OF((gzFile, int, int, int, char **)); void help OF((int)); int main OF((int, char **)); char *prog; const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL }; /* return the file name of the TGZ archive */ /* or NULL if it does not exist */ char *TGZfname (const char *arcname) { |
︙ | ︙ | |||
200 201 202 203 204 205 206 | } /* set file time */ int setfiletime (char *fname,time_t ftime) { | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | } /* set file time */ int setfiletime (char *fname,time_t ftime) { #ifdef WIN32 static int isWinNT = -1; SYSTEMTIME st; FILETIME locft, modft; struct tm *loctm; HANDLE hFile; int result; |
︙ | ︙ | |||
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | printf("Usage: untgz file.tgz extract all files\n" " untgz file.tgz fname ... extract selected files\n" " untgz -l file.tgz list archive contents\n" " untgz -h display this help\n"); exit(exitval); } /* ============================================================ */ #if defined(WIN32) && defined(__GNUC__) int _CRT_glob = 0; /* disable argument globbing in MinGW */ #endif int main(int argc,char **argv) { int action = TGZ_EXTRACT; int arg = 1; char *TGZfile; | > > > > > > | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | printf("Usage: untgz file.tgz extract all files\n" " untgz file.tgz fname ... extract selected files\n" " untgz -l file.tgz list archive contents\n" " untgz -h display this help\n"); exit(exitval); } void error(const char *msg) { fprintf(stderr, "%s: %s\n", prog, msg); exit(1); } /* ============================================================ */ #if defined(WIN32) && defined(__GNUC__) int _CRT_glob = 0; /* disable argument globbing in MinGW */ #endif int main(int argc,char **argv) { int action = TGZ_EXTRACT; int arg = 1; char *TGZfile; gzFile *f; prog = strrchr(argv[0],'\\'); if (prog == NULL) { prog = strrchr(argv[0],'/'); if (prog == NULL) { |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/readme.txt.
|
| | > > > | 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 | Building instructions for the DLL versions of Zlib 1.2.11 ======================================================== This directory contains projects that build zlib and minizip using Microsoft Visual C++ 9.0/10.0. You don't need to build these projects yourself. You can download the binaries from: http://www.winimage.com/zLibDll More information can be found at this site. Build instructions for Visual Studio 2008 (32 bits or 64 bits) -------------------------------------------------------------- - Decompress current zlib, including all contrib/* files - Compile assembly code (with Visual Studio Command Prompt) by running: bld_ml64.bat (in contrib\masmx64) bld_ml32.bat (in contrib\masmx86) - Open contrib\vstudio\vc9\zlibvc.sln with Microsoft Visual C++ 2008 - Or run: vcbuild /rebuild contrib\vstudio\vc9\zlibvc.sln "Release|Win32" Build instructions for Visual Studio 2010 (32 bits or 64 bits) -------------------------------------------------------------- - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc10\zlibvc.sln with Microsoft Visual C++ 2010 |
︙ | ︙ | |||
35 36 37 38 39 40 41 | - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc12\zlibvc.sln with Microsoft Visual C++ 2013 Build instructions for Visual Studio 2015 (32 bits or 64 bits) -------------------------------------------------------------- - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc14\zlibvc.sln with Microsoft Visual C++ 2015 | < < < < < < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc12\zlibvc.sln with Microsoft Visual C++ 2013 Build instructions for Visual Studio 2015 (32 bits or 64 bits) -------------------------------------------------------------- - Decompress current zlib, including all contrib/* files - Open contrib\vstudio\vc14\zlibvc.sln with Microsoft Visual C++ 2015 Important --------- - To use zlibwapi.dll in your application, you must define the macro ZLIB_WINAPI when compiling your application's source files. |
︙ | ︙ | |||
73 74 75 76 77 78 79 | has a slightly different effect. To avoid compatibility problems, do not define it here. Gilles Vollant info@winimage.com | | | 70 71 72 73 74 75 76 77 78 | has a slightly different effect. To avoid compatibility problems, do not define it here. Gilles Vollant info@winimage.com Visual Studio 2013 and 2015 Projects from Sean Hunt seandhunt_7@yahoo.com |
Changes to compat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters.
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{048af943-022b-4db6-beeb-a54c34774ee2}</UniqueIdentifier> | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{048af943-022b-4db6-beeb-a54c34774ee2}</UniqueIdentifier> <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm</Extensions> </Filter> <Filter Include="Header Files"> <UniqueIdentifier>{c1d600d2-888f-4aea-b73e-8b0dd9befa0c}</UniqueIdentifier> <Extensions>h;hpp;hxx;hm;inl;inc</Extensions> </Filter> <Filter Include="Resource Files"> <UniqueIdentifier>{0844199a-966b-4f19-81db-1e0125e141b9}</UniqueIdentifier> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters.
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{c0419b40-bf50-40da-b153-ff74215b79de}</UniqueIdentifier> | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{c0419b40-bf50-40da-b153-ff74215b79de}</UniqueIdentifier> <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm</Extensions> </Filter> <Filter Include="Header Files"> <UniqueIdentifier>{bb87b070-735b-478e-92ce-7383abb2f36c}</UniqueIdentifier> <Extensions>h;hpp;hxx;hm;inl;inc</Extensions> </Filter> <Filter Include="Resource Files"> <UniqueIdentifier>{f46ab6a6-548f-43cb-ae96-681abb5bd5db}</UniqueIdentifier> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.
︙ | ︙ | |||
177 178 179 180 181 182 183 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 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 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeader> </PrecompiledHeader> <AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile> <SubSystem>Console</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> |
︙ | ︙ | |||
237 238 239 240 241 242 243 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | | | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeader> </PrecompiledHeader> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <OptimizeReferences>true</OptimizeReferences> <EnableCOMDATFolding>true</EnableCOMDATFolding> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <TargetMachine>MachineX86</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
348 349 350 351 352 353 354 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> | > > > > > > > > | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> |
Changes to compat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters.
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{c1f6a2e3-5da5-4955-8653-310d3efe05a9}</UniqueIdentifier> | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{c1f6a2e3-5da5-4955-8653-310d3efe05a9}</UniqueIdentifier> <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm</Extensions> </Filter> <Filter Include="Header Files"> <UniqueIdentifier>{c2aaffdc-2c95-4d6f-8466-4bec5890af2c}</UniqueIdentifier> <Extensions>h;hpp;hxx;hm;inl;inc</Extensions> </Filter> <Filter Include="Resource Files"> <UniqueIdentifier>{c274fe07-05f2-461c-964b-f6341e4e7eb5}</UniqueIdentifier> |
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\deflate.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\infback.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inflate.c"> <Filter>Source Files</Filter> </ClCompile> | > > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\deflate.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\infback.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\masmx64\inffas8664.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inflate.c"> <Filter>Source Files</Filter> </ClCompile> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters.
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{fa61a89f-93fc-4c89-b29e-36224b7592f4}</UniqueIdentifier> | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{fa61a89f-93fc-4c89-b29e-36224b7592f4}</UniqueIdentifier> <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm</Extensions> </Filter> <Filter Include="Header Files"> <UniqueIdentifier>{d4b85da0-2ba2-4934-b57f-e2584e3848ee}</UniqueIdentifier> <Extensions>h;hpp;hxx;hm;inl;inc</Extensions> </Filter> <Filter Include="Resource Files"> <UniqueIdentifier>{e573e075-00bd-4a7d-bd67-a8cc9bfc5aca}</UniqueIdentifier> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE FILEVERSION 1, 2, 11, 0 PRODUCTVERSION 1, 2, 11, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_DOS_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0 // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" VALUE "FileVersion", "1.2.11\0" VALUE "InternalName", "zlib\0" VALUE "OriginalFilename", "zlibwapi.dll\0" VALUE "ProductName", "ZLib.DLL\0" VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END |
Changes to compat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.
︙ | ︙ | |||
156 157 158 159 160 161 162 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 | <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | > > > > | | | > > > > | | 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 | <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
240 241 242 243 244 245 246 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
262 263 264 265 266 267 268 269 270 271 272 273 274 275 | <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | > > > > | | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
298 299 300 301 302 303 304 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | > > > > | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
359 360 361 362 363 364 365 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
389 390 391 392 393 394 395 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
423 424 425 426 427 428 429 430 431 432 433 434 435 436 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> | > > > > > > > > | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\gzwrite.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\infback.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inflate.c"> <Filter>Source Files</Filter> </ClCompile> | > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\gzwrite.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\infback.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\masmx64\inffas8664.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inflate.c"> <Filter>Source Files</Filter> </ClCompile> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 | LIBRARY ; zlib data compression and ZIP file I/O library VERSION 1.2 EXPORTS adler32 @1 compress @2 crc32 @3 deflate @4 deflateCopy @5 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 | < < < < < | 147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 |
Changes to compat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.
︙ | ︙ | |||
193 194 195 196 197 198 199 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | | > > > > | | 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 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <GenerateMapFile>true</GenerateMapFile> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
280 281 282 283 284 285 286 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
304 305 306 307 308 309 310 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> | | > > > > | | | > > > > | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateMapFile>true</GenerateMapFile> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <GenerateMapFile>true</GenerateMapFile> <SubSystem>Windows</SubSystem> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
408 409 410 411 412 413 414 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
449 450 451 452 453 454 455 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
494 495 496 497 498 499 500 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
517 518 519 520 521 522 523 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> | | > > > > | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateMapFile>true</GenerateMapFile> <SubSystem>Windows</SubSystem> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
581 582 583 584 585 586 587 588 589 590 591 592 593 594 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> | > > > > > > > > | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters.
︙ | ︙ | |||
37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\gzwrite.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\infback.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inflate.c"> <Filter>Source Files</Filter> </ClCompile> | > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\gzwrite.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\infback.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\masmx64\inffas8664.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\..\..\inflate.c"> <Filter>Source Files</Filter> </ClCompile> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc11/testzlib.vcxproj.
︙ | ︙ | |||
183 184 185 186 187 188 189 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 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 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeader> </PrecompiledHeader> <AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile> <SubSystem>Console</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> |
︙ | ︙ | |||
243 244 245 246 247 248 249 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeader> </PrecompiledHeader> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <OptimizeReferences>true</OptimizeReferences> <EnableCOMDATFolding>true</EnableCOMDATFolding> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <TargetMachine>MachineX86</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
354 355 356 357 358 359 360 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> | > > > > > > > > | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> |
Changes to compat/zlib/contrib/vstudio/vc11/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE FILEVERSION 1, 2, 11, 0 PRODUCTVERSION 1, 2, 11, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_DOS_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0 // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" VALUE "FileVersion", "1.2.11\0" VALUE "InternalName", "zlib\0" VALUE "OriginalFilename", "zlibwapi.dll\0" VALUE "ProductName", "ZLib.DLL\0" VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END |
Changes to compat/zlib/contrib/vstudio/vc11/zlibstat.vcxproj.
︙ | ︙ | |||
163 164 165 166 167 168 169 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
189 190 191 192 193 194 195 | <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | | | 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 | <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
247 248 249 250 251 252 253 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
276 277 278 279 280 281 282 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
305 306 307 308 309 310 311 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
366 367 368 369 370 371 372 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
396 397 398 399 400 401 402 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
430 431 432 433 434 435 436 437 438 439 440 441 442 443 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> | > > > > > > > > | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc11/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 | LIBRARY ; zlib data compression and ZIP file I/O library VERSION 1.2 EXPORTS adler32 @1 compress @2 crc32 @3 deflate @4 deflateCopy @5 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 | < < < < < | 147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 |
Changes to compat/zlib/contrib/vstudio/vc11/zlibvc.vcxproj.
︙ | ︙ | |||
200 201 202 203 204 205 206 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | | > > > > | | 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 256 257 258 259 260 261 262 263 264 265 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
295 296 297 298 299 300 301 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
319 320 321 322 323 324 325 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> | | > > > > | | | > > > > | | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\contrib\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
431 432 433 434 435 436 437 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
476 477 478 479 480 481 482 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
521 522 523 524 525 526 527 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
544 545 546 547 548 549 550 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> | | > > > > | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
612 613 614 615 616 617 618 619 620 621 622 623 624 625 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> | > > > > > > > > | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc12/testzlib.vcxproj.
︙ | ︙ | |||
186 187 188 189 190 191 192 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 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 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeader> </PrecompiledHeader> <AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile> <SubSystem>Console</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> |
︙ | ︙ | |||
246 247 248 249 250 251 252 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeader> </PrecompiledHeader> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <OptimizeReferences>true</OptimizeReferences> <EnableCOMDATFolding>true</EnableCOMDATFolding> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <TargetMachine>MachineX86</TargetMachine> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
358 359 360 361 362 363 364 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> | > > > > > > > > | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> |
Changes to compat/zlib/contrib/vstudio/vc12/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE FILEVERSION 1, 2, 11, 0 PRODUCTVERSION 1, 2, 11, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_DOS_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0 // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" VALUE "FileVersion", "1.2.11\0" VALUE "InternalName", "zlib\0" VALUE "OriginalFilename", "zlibwapi.dll\0" VALUE "ProductName", "ZLib.DLL\0" VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END |
Changes to compat/zlib/contrib/vstudio/vc12/zlibstat.vcxproj.
︙ | ︙ | |||
166 167 168 169 170 171 172 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
192 193 194 195 196 197 198 | <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | | | 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 | <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
250 251 252 253 254 255 256 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
279 280 281 282 283 284 285 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
308 309 310 311 312 313 314 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
369 370 371 372 373 374 375 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
399 400 401 402 403 404 405 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
433 434 435 436 437 438 439 440 441 442 443 444 445 446 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> | > > > > > > > > | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc12/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 | LIBRARY ; zlib data compression and ZIP file I/O library VERSION 1.2 EXPORTS adler32 @1 compress @2 crc32 @3 deflate @4 deflateCopy @5 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 | < < < < < | 147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 |
Changes to compat/zlib/contrib/vstudio/vc12/zlibvc.vcxproj.
︙ | ︙ | |||
203 204 205 206 207 208 209 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | | > > > > | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
298 299 300 301 302 303 304 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
322 323 324 325 326 327 328 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> | | > > > > | | | > > > > | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\contrib\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
435 436 437 438 439 440 441 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
480 481 482 483 484 485 486 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
525 526 527 528 529 530 531 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
548 549 550 551 552 553 554 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> | | > > > > | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
616 617 618 619 620 621 622 623 624 625 626 627 628 629 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> | > > > > > > > > | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc14/testzlib.vcxproj.
︙ | ︙ | |||
186 187 188 189 190 191 192 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 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 | <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeader> </PrecompiledHeader> <AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)testzlib.pdb</ProgramDatabaseFile> <SubSystem>Console</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> |
︙ | ︙ | |||
246 247 248 249 250 251 252 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <OmitFramePointers>true</OmitFramePointers> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeader> </PrecompiledHeader> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)testzlib.exe</OutputFile> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <OptimizeReferences>true</OptimizeReferences> <EnableCOMDATFolding>true</EnableCOMDATFolding> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <TargetMachine>MachineX86</TargetMachine> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
358 359 360 361 362 363 364 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | | | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineIA64</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <AdditionalIncludeDirectories>..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <BasicRuntimeChecks>Default</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> </ClCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> |
︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> | > > > > > > > > | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\..\adler32.c" /> <ClCompile Include="..\..\..\compress.c" /> <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\testzlib\testzlib.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\..\zutil.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> |
Changes to compat/zlib/contrib/vstudio/vc14/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE FILEVERSION 1, 2, 11, 0 PRODUCTVERSION 1, 2, 11, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_DOS_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0 // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" VALUE "FileVersion", "1.2.11\0" VALUE "InternalName", "zlib\0" VALUE "OriginalFilename", "zlibwapi.dll\0" VALUE "ProductName", "ZLib.DLL\0" VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END |
Changes to compat/zlib/contrib/vstudio/vc14/zlibstat.vcxproj.
︙ | ︙ | |||
166 167 168 169 170 171 172 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
192 193 194 195 196 197 198 | <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | | | 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 | <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
250 251 252 253 254 255 256 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
279 280 281 282 283 284 285 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
308 309 310 311 312 313 314 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibstat.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <Culture>0x040c</Culture> </ResourceCompile> <Lib> <AdditionalOptions>/MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibstat.lib</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
369 370 371 372 373 374 375 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|x64'"> <Midl> <TargetEnvironment>X64</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
399 400 401 402 403 404 405 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'"> <Midl> <TargetEnvironment>Itanium</TargetEnvironment> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
433 434 435 436 437 438 439 440 441 442 443 444 445 446 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> | > > > > > > > > | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> <ClCompile Include="..\..\minizip\unzip.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc14/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 | LIBRARY ; zlib data compression and ZIP file I/O library VERSION 1.2 EXPORTS adler32 @1 compress @2 crc32 @3 deflate @4 deflateCopy @5 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 | < < < < < | 147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 |
Changes to compat/zlib/contrib/vstudio/vc14/zlibvc.vcxproj.
︙ | ︙ | |||
203 204 205 206 207 208 209 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> | | | | > > > > | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
298 299 300 301 302 303 304 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Win32</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
322 323 324 325 326 327 328 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> | | > > > > | | | > > > > | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions> <AdditionalDependencies>..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <RandomizedBaseAddress>false</RandomizedBaseAddress> <DataExecutionPrevention> </DataExecutionPrevention> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> <PreBuildEvent> <Command>cd ..\..\masmx86 bld_ml32.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> <ObjectFileName>$(IntDir)</ObjectFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <BrowseInformation> </BrowseInformation> <WarningLevel>Level3</WarningLevel> <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\contrib\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'"> <Midl> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> |
︙ | ︙ | |||
435 436 437 438 439 440 441 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
480 481 482 483 484 485 486 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
525 526 527 528 529 530 531 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> | | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>X64</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile> |
︙ | ︙ | |||
548 549 550 551 552 553 554 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> | | > > > > | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | <SuppressStartupBanner>true</SuppressStartupBanner> </ClCompile> <ResourceCompile> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <Culture>0x040c</Culture> </ResourceCompile> <Link> <AdditionalDependencies>..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies)</AdditionalDependencies> <OutputFile>$(OutDir)zlibwapi.dll</OutputFile> <SuppressStartupBanner>true</SuppressStartupBanner> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile> <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile> <GenerateMapFile>true</GenerateMapFile> <MapFileName>$(OutDir)zlibwapi.map</MapFileName> <SubSystem>Windows</SubSystem> <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> </Link> <PreBuildEvent> <Command>cd ..\..\masmx64 bld_ml64.bat</Command> </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'"> <Midl> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MkTypLibCompatible>true</MkTypLibCompatible> <SuppressStartupBanner>true</SuppressStartupBanner> <TargetEnvironment>Itanium</TargetEnvironment> <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName> </Midl> <ClCompile> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <AdditionalIncludeDirectories>..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <ExceptionHandling> </ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <BufferSecurityCheck>false</BufferSecurityCheck> <FunctionLevelLinking>true</FunctionLevelLinking> |
︙ | ︙ | |||
616 617 618 619 620 621 622 623 624 625 626 627 628 629 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> | > > > > > > > > | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | <ClCompile Include="..\..\..\crc32.c" /> <ClCompile Include="..\..\..\deflate.c" /> <ClCompile Include="..\..\..\gzclose.c" /> <ClCompile Include="..\..\..\gzlib.c" /> <ClCompile Include="..\..\..\gzread.c" /> <ClCompile Include="..\..\..\gzwrite.c" /> <ClCompile Include="..\..\..\infback.c" /> <ClCompile Include="..\..\masmx64\inffas8664.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseWithoutAsm|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Itanium'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\..\inffast.c" /> <ClCompile Include="..\..\..\inflate.c" /> <ClCompile Include="..\..\..\inftrees.c" /> <ClCompile Include="..\..\minizip\ioapi.c" /> <ClCompile Include="..\..\minizip\iowin32.c" /> <ClCompile Include="..\..\..\trees.c" /> <ClCompile Include="..\..\..\uncompr.c" /> |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/miniunz.vcproj.
︙ | ︙ | |||
538 539 540 541 542 543 544 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > <File RelativePath="..\..\minizip\miniunz.c" > </File> </Filter> <Filter |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/minizip.vcproj.
︙ | ︙ | |||
535 536 537 538 539 540 541 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > <File RelativePath="..\..\minizip\minizip.c" > </File> </Filter> <Filter |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/testzlib.vcproj.
︙ | ︙ | |||
44 45 46 47 48 49 50 | <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" MinimalRebuild="true" BasicRuntimeChecks="0" RuntimeLibrary="1" BufferSecurityCheck="false" UsePrecompiledHeader="0" AssemblerOutput="4" AssemblerListingLocation="$(IntDir)\" |
︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)/testzlib.exe" LinkIncremental="2" GenerateManifest="false" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/testzlib.pdb" SubSystem="1" RandomizedBaseAddress="1" | > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="..\..\masmx86\match686.obj ..\..\masmx86\inffas32.obj" OutputFile="$(OutDir)/testzlib.exe" LinkIncremental="2" GenerateManifest="false" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/testzlib.pdb" SubSystem="1" RandomizedBaseAddress="1" |
︙ | ︙ | |||
123 124 125 126 127 128 129 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." | | > | 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 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" BasicRuntimeChecks="0" RuntimeLibrary="3" BufferSecurityCheck="false" AssemblerListingLocation="$(IntDir)\" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj" GenerateManifest="false" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" |
︙ | ︙ | |||
511 512 513 514 515 516 517 | /> <Tool Name="VCCLCompilerTool" Optimization="2" InlineFunctionExpansion="1" OmitFramePointers="true" AdditionalIncludeDirectories="..\..\.." | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | /> <Tool Name="VCCLCompilerTool" Optimization="2" InlineFunctionExpansion="1" OmitFramePointers="true" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" StringPooling="true" BasicRuntimeChecks="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" AssemblerListingLocation="$(IntDir)\" |
︙ | ︙ | |||
534 535 536 537 538 539 540 541 542 543 544 545 546 547 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)/testzlib.exe" LinkIncremental="1" GenerateManifest="false" GenerateDebugInformation="true" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" | > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="..\..\masmx86\match686.obj ..\..\masmx86\inffas32.obj" OutputFile="$(OutDir)/testzlib.exe" LinkIncremental="1" GenerateManifest="false" GenerateDebugInformation="true" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" |
︙ | ︙ | |||
593 594 595 596 597 598 599 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." | | > | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="..\..\.." PreprocessorDefinitions="ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" BasicRuntimeChecks="0" RuntimeLibrary="0" BufferSecurityCheck="false" AssemblerListingLocation="$(IntDir)\" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj" GenerateManifest="false" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" |
︙ | ︙ | |||
725 726 727 728 729 730 731 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > <File RelativePath="..\..\..\adler32.c" > </File> <File RelativePath="..\..\..\compress.c" |
︙ | ︙ | |||
747 748 749 750 751 752 753 754 755 756 757 758 759 760 | RelativePath="..\..\..\deflate.c" > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | RelativePath="..\..\..\deflate.c" > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\masmx64\inffas8664.c" > <FileConfiguration Name="Debug|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Debug|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="ReleaseWithoutAsm|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="ReleaseWithoutAsm|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Release|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/testzlibdll.vcproj.
︙ | ︙ | |||
538 539 540 541 542 543 544 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" | | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > <File RelativePath="..\..\testzlib\testzlib.c" > </File> </Filter> <Filter |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/zlib.rc.
1 2 3 4 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE | | | | | | 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 | #include <windows.h> #define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE FILEVERSION 1, 2, 11, 0 PRODUCTVERSION 1, 2, 11, 0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_DOS_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0 // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" VALUE "FileVersion", "1.2.11\0" VALUE "InternalName", "zlib\0" VALUE "OriginalFilename", "zlibwapi.dll\0" VALUE "ProductName", "ZLib.DLL\0" VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END |
Changes to compat/zlib/contrib/vstudio/vc9/zlibstat.vcproj.
︙ | ︙ | |||
43 44 45 46 47 48 49 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" ExceptionHandling="0" RuntimeLibrary="1" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
︙ | ︙ | |||
117 118 119 120 121 122 123 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
︙ | ︙ | |||
191 192 193 194 195 196 197 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
︙ | ︙ | |||
264 265 266 267 268 269 270 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" |
︙ | ︙ | |||
291 292 293 294 295 296 297 298 299 300 301 302 303 304 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB" OutputFile="$(OutDir)\zlibstat.lib" SuppressStartupBanner="true" /> <Tool Name="VCALinkTool" /> <Tool | > | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:X86 /NODEFAULTLIB" AdditionalDependencies="..\..\masmx86\match686.obj ..\..\masmx86\inffas32.obj " OutputFile="$(OutDir)\zlibstat.lib" SuppressStartupBanner="true" /> <Tool Name="VCALinkTool" /> <Tool |
︙ | ︙ | |||
338 339 340 341 342 343 344 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" AssemblerListingLocation="$(IntDir)\" |
︙ | ︙ | |||
365 366 367 368 369 370 371 372 373 374 375 376 377 378 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB" OutputFile="$(OutDir)\zlibstat.lib" SuppressStartupBanner="true" /> <Tool Name="VCALinkTool" /> <Tool | > | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLibrarianTool" AdditionalOptions="/MACHINE:AMD64 /NODEFAULTLIB" AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj " OutputFile="$(OutDir)\zlibstat.lib" SuppressStartupBanner="true" /> <Tool Name="VCALinkTool" /> <Tool |
︙ | ︙ | |||
412 413 414 415 416 417 418 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
︙ | ︙ | |||
485 486 487 488 489 490 491 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
︙ | ︙ | |||
559 560 561 562 563 564 565 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | <Tool Name="VCMIDLTool" TargetEnvironment="3" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
︙ | ︙ | |||
633 634 635 636 637 638 639 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | <Tool Name="VCMIDLTool" TargetEnvironment="2" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibstat.pch" |
︙ | ︙ | |||
726 727 728 729 730 731 732 733 734 735 736 737 738 739 | RelativePath="..\..\..\gzwrite.c" > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | RelativePath="..\..\..\gzwrite.c" > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\masmx64\inffas8664.c" > <FileConfiguration Name="Debug|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Debug|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Release|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="ReleaseWithoutAsm|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="ReleaseWithoutAsm|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > |
︙ | ︙ |
Changes to compat/zlib/contrib/vstudio/vc9/zlibvc.def.
1 2 3 | LIBRARY ; zlib data compression and ZIP file I/O library | | | 1 2 3 4 5 6 7 8 9 10 11 | LIBRARY ; zlib data compression and ZIP file I/O library VERSION 1.2 EXPORTS adler32 @1 compress @2 crc32 @3 deflate @4 deflateCopy @5 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 | < < < < < | 147 148 149 150 151 152 153 | inflateValidate @169 uncompress2 @170 gzfread @171 gzfwrite @172 deflateGetDictionary @173 adler32_z @174 crc32_z @175 |
Changes to compat/zlib/contrib/vstudio/vc9/zlibvc.vcproj.
︙ | ︙ | |||
49 50 51 52 53 54 55 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF" ExceptionHandling="0" RuntimeLibrary="1" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" ProgramDataBaseFileName="$(OutDir)\" |
︙ | ︙ | |||
77 78 79 80 81 82 83 84 85 86 87 88 89 90 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="2" SuppressStartupBanner="true" GenerateManifest="false" ModuleDefinitionFile=".\zlibvc.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" | > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" AdditionalDependencies="..\..\masmx86\match686.obj ..\..\masmx86\inffas32.obj" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="2" SuppressStartupBanner="true" GenerateManifest="false" ModuleDefinitionFile=".\zlibvc.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
︙ | ︙ | |||
145 146 147 148 149 150 151 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" ProgramDataBaseFileName="$(OutDir)\" |
︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 181 182 183 184 185 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="2" SuppressStartupBanner="true" GenerateManifest="false" ModuleDefinitionFile=".\zlibvc.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" | > | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj " OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="2" SuppressStartupBanner="true" GenerateManifest="false" ModuleDefinitionFile=".\zlibvc.def" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
︙ | ︙ | |||
239 240 241 242 243 244 245 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" ExceptionHandling="0" RuntimeLibrary="3" BufferSecurityCheck="false" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerListingLocation="$(IntDir)\" ObjectFile="$(IntDir)\" |
︙ | ︙ | |||
334 335 336 337 338 339 340 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
︙ | ︙ | |||
434 435 436 437 438 439 440 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
︙ | ︙ | |||
532 533 534 535 536 537 538 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
︙ | ︙ | |||
630 631 632 633 634 635 636 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | SuppressStartupBanner="true" TargetEnvironment="1" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="0" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerOutput="2" |
︙ | ︙ | |||
660 661 662 663 664 665 666 667 668 669 670 671 672 673 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="1" SuppressStartupBanner="true" GenerateManifest="false" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile=".\zlibvc.def" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" | > | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386" AdditionalDependencies="..\..\masmx86\match686.obj ..\..\masmx86\inffas32.obj " OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="1" SuppressStartupBanner="true" GenerateManifest="false" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile=".\zlibvc.def" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
︙ | ︙ | |||
730 731 732 733 734 735 736 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | SuppressStartupBanner="true" TargetEnvironment="3" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" AssemblerOutput="2" |
︙ | ︙ | |||
759 760 761 762 763 764 765 766 767 768 769 770 771 772 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="1" SuppressStartupBanner="true" GenerateManifest="false" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile=".\zlibvc.def" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" | > | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | Culture="1036" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="..\..\masmx64\gvmat64.obj ..\..\masmx64\inffasx64.obj " OutputFile="$(OutDir)\zlibwapi.dll" LinkIncremental="1" SuppressStartupBanner="true" GenerateManifest="false" IgnoreAllDefaultLibraries="false" ModuleDefinitionFile=".\zlibvc.def" ProgramDatabaseFile="$(OutDir)/zlibwapi.pdb" |
︙ | ︙ | |||
828 829 830 831 832 833 834 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" | | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 | SuppressStartupBanner="true" TargetEnvironment="2" TypeLibraryName="$(OutDir)/zlibvc.tlb" /> <Tool Name="VCCLCompilerTool" InlineFunctionExpansion="1" AdditionalIncludeDirectories="..\..\..;..\..\masmx86" PreprocessorDefinitions="_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64" StringPooling="true" ExceptionHandling="0" RuntimeLibrary="2" BufferSecurityCheck="false" EnableFunctionLevelLinking="true" PrecompiledHeaderFile="$(IntDir)/zlibvc.pch" |
︙ | ︙ | |||
941 942 943 944 945 946 947 948 949 950 951 952 953 954 | RelativePath="..\..\..\gzwrite.c" > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | RelativePath="..\..\..\gzwrite.c" > </File> <File RelativePath="..\..\..\infback.c" > </File> <File RelativePath="..\..\masmx64\inffas8664.c" > <FileConfiguration Name="Debug|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Debug|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="ReleaseWithoutAsm|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="ReleaseWithoutAsm|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> <FileConfiguration Name="Release|Itanium" ExcludedFromBuild="true" > <Tool Name="VCCLCompilerTool" /> </FileConfiguration> </File> <File RelativePath="..\..\..\inffast.c" > </File> <File RelativePath="..\..\..\inflate.c" > |
︙ | ︙ |
Changes to compat/zlib/crc32.c.
1 | /* crc32.c -- compute the CRC-32 of a data stream | | | | | > > | | < | < < < < < < < < < < < | < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < | < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < | < < < < | < < < < < < < < < < < < | | < < < < | | | | | | | | | | | > > | > | > > > > > > | > > > > > | > > > | | | | | | | > > | > > > | > > > > > > > | | > | < | > | < < | < < < < > > < < < < < < < < < < < < < < < | | < | < > | < < < < < < | < < < < < < | < | < | < < < < < < < < < < | < < < < < | < < < < < < < < < < < < < < < < < < < | < < < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < | < < < < < < | < < < < < < < < < < < < < < | | | < < | < < < < < < | < < > > < < < < < < < < < < < < < < | | < | > > | | | < < | < < < < < < < < < < < < | | < < | | < < | | < | > > > > > > > > > < < | | < | > > | | > | > | < < | < < > | | | < < < < < < < < < < < < < | > > | | | < < | < < < < < | < < < < < < < < | < < < < < | | < < < < | < | < | < < < < < | < < < | < | < | < < < < > > > > < < < < < | | < | < < > | < < | < > > | | < < | < < < | < < | < < < < < < < < < > > | > | < | < > | > | < | < < < < | < > | | < < < < < < > | < | | | | < < < < < < < < < < > | | > > | < | < < < < < < < < < < > | > > > > | < | < < < < < | > | < | < | < > | < < < < | < < < < < | < < < | | | < | < < < < < | > | > | < < > | | | | < < < < < < < < | > > > | < | < | > | | > | < < < < < < < < < < < < < < < < < < < < < < | | < > < < < < < < < < < < < < < < < < < < | > | | | < < < < < > > | > | > > > > > | | | > | | < < < < < > | < | < | < < < < < < | < < < < < | < | < < > > > | | < | | | > | | | < < < < < | < | > | < < < < < < < < > | < < < < | > > | | < < < | < < < < < < < < < < < | > | | | | < < | | < < < < > > | | < | < | > | < < < < < < < < | > | < < | | < > | < < < < < < < | < | < | < | < > | < < | < | < < < < < | < | | < | < | < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | /* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH # include <stdio.h> # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, z_size_t)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, z_size_t)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { z_crc_t c; int n, k; z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0; for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const z_crc_t FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32_z(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { return crc32_z(crc, buf, len); } #ifdef BYFOUR /* This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit integer pointer type. This violates the strict aliasing rule, where a compiler can assume, for optimization purposes, that two pointers to fundamentally different types won't ever point to the same memory. This can manifest as a problem only if one of the pointers is written to. This code only reads from those pointers. So long as this code remains isolated in this compilation unit, there won't be a problem. For this reason, this code should not be copied and pasted into a compilation unit in which other code writes to the buffer that is passed to these routines. */ /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *buf4++; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times(mat, vec) unsigned long *mat; unsigned long vec; { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square(square, mat) unsigned long *square; unsigned long *mat; { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { return crc32_combine_(crc1, crc2, len2); } |
Changes to compat/zlib/crc32.h.
1 2 3 4 | /* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | < < | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < < < < < < < < < < < < < < < < < < < < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | | < < < < < < < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | /* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; |
Changes to compat/zlib/deflate.c.
1 | /* deflate.c -- compress data using the deflation algorithm | | | 1 2 3 4 5 6 7 8 9 | /* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions |
︙ | ︙ | |||
48 49 50 51 52 53 54 | */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = | | > > > | > > > | | | | | > > > > > > > > > > > > > > > > | 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 | */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local int deflateStateCheck OF((z_streamp strm)); local void slide_hash OF((deflate_state *s)); local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV # pragma message("Assembler code may have bugs -- use at your own risk") void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif #ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ |
︙ | ︙ | |||
134 135 136 137 138 139 140 | /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced |
︙ | ︙ | |||
164 165 166 167 168 169 170 | #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ | < | | < < < < < < < | > > | 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 | #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* =========================================================================== * Slide the hash table when sliding the window down (could be avoided with 32 * bit values at the expense of memory usage). We slide even when level == 0 to * keep the hash table consistent if we switch back to level > 0 later. */ local void slide_hash(s) deflate_state *s; { unsigned n, m; Posf *p; uInt wsize = s->w_size; n = s->hash_size; p = &s->head[n]; do { |
︙ | ︙ | |||
204 205 206 207 208 209 210 | /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif } | | < < < < < < < < | < < | < | < < < < < < < < < < < | < < | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > | > > | > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 | /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif } /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; int method; int windowBits; int memLevel; int strategy; const char *version; int stream_size; { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; |
︙ | ︙ | |||
409 410 411 412 413 414 415 | if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; | < < | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } |
︙ | ︙ | |||
440 441 442 443 444 445 446 | s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | < < < < < < < < < | > > | > > | > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ local int deflateStateCheck (strm) z_streamp strm; { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; s = strm->state; if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && #ifdef GZIP s->status != GZIP_STATE && #endif s->status != EXTRA_STATE && s->status != NAME_STATE && s->status != COMMENT_STATE && s->status != HCRC_STATE && s->status != BUSY_STATE && s->status != FINISH_STATE)) return 1; return 0; } /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { deflate_state *s; uInt str, n; int wrap; unsigned avail; z_const unsigned char *next; if (deflateStateCheck(strm) || dictionary == Z_NULL) |
︙ | ︙ | |||
609 610 611 612 613 614 615 | strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ | | > > | > | > > | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { deflate_state *s; uInt len; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) len = s->w_size; if (dictionary != Z_NULL && len) zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); if (dictLength != Z_NULL) *dictLength = len; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s; if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; |
︙ | ︙ | |||
650 651 652 653 654 655 656 | if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif | | | | < < < < | < | < < < < < < | < < < < < < < < < < < | > > > | > > > > | > > > > < < < < < < | < | > > > > | | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset (strm) z_streamp strm; { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePending (strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; { deflate_state *s; int put; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; { deflate_state *s; compress_func func; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && s->high_water) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; if (strm->avail_out == 0) return Z_BUF_ERROR; } if (s->level != level) { if (s->level == 0 && s->matches != 0) { if (s->matches == 1) slide_hash(s); else |
︙ | ︙ | |||
790 791 792 793 794 795 796 | s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return Z_OK; } /* ========================================================================= */ | > > | > | > > | | | > > | | < < | | < < < > | < < | < < > < < | > > > | | < < < | | < < < < | | | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) z_streamp strm; int good_length; int max_lazy; int nice_length; int max_chain; { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; s->good_match = (uInt)good_length; s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; s->max_chain_length = (uInt)max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; uLong complen, wraplen; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (deflateStateCheck(strm)) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; |
︙ | ︙ | |||
881 882 883 884 885 886 887 | } break; #endif default: /* for compiler happiness */ wraplen = 6; } | | < | | < | > > > | > > | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | } break; #endif default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB (s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output, except for * some deflate_stored() output, goes through this function so some * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; |
︙ | ︙ | |||
939 940 941 942 943 944 945 | do { \ if (s->gzhead->hcrc && s->pending > (beg)) \ strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ s->pending - (beg)); \ } while (0) /* ========================================================================= */ | | > > > | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | do { \ if (s->gzhead->hcrc && s->pending > (beg)) \ strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ s->pending - (beg)); \ } while (0) /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; int flush; { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; |
︙ | ︙ | |||
987 988 989 990 991 992 993 | /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Write the header */ | < < | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Write the header */ if (s->status == INIT_STATE) { /* zlib header */ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) |
︙ | ︙ | |||
1251 1252 1253 1254 1255 1256 1257 | * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ | | > > | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd (strm) z_streamp strm; { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; /* Deallocate in reverse order of allocations: */ |
︙ | ︙ | |||
1275 1276 1277 1278 1279 1280 1281 | } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ | | > > > < < > > | | < | | < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | < | | | | | | | | | < | | | | | | | | < | | > | > > > | < | | | | > > > > | < < < < < < < < | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 | } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy (dest, source) z_streamp dest; z_streamp source; { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local unsigned read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init (s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #ifndef ASMV /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef ZLIB_DEBUG #define EQUAL 0 /* result of memcmp for equal strings */ /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(s, start, match, length) deflate_state *s; IPos start, match; int length; { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(s) deflate_state *s; { unsigned n; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; slide_hash(s); more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ |
︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 | * of hash table slides to perform. If s->matches is 1, then one hash table * slide will be done when switching. If s->matches is 2, the maximum value * allowed here, then the hash table will be cleared, since two or more slides * is the same as a clear. * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which | | | > > > | 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 | * of hash table slides to perform. If s->matches is 1, then one hash table * slide will be done when switching. If s->matches is 2, the maximum value * allowed here, then the hash table will be cleared, since two or more slides * is the same as a clear. * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which * maximizes the opportunites to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. */ unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); /* Copy as many min_block or larger stored blocks directly to next_out as |
︙ | ︙ | |||
1719 1720 1721 1722 1723 1724 1725 | /* If any input was used, then no unused input remains in the window, * therefore s->block_start == s->strstart. */ if (used >= s->w_size) { /* supplant the previous history */ s->matches = 2; /* clear hash */ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); s->strstart = s->w_size; | < < < < > | < < < | 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 | /* If any input was used, then no unused input remains in the window, * therefore s->block_start == s->strstart. */ if (used >= s->w_size) { /* supplant the previous history */ s->matches = 2; /* clear hash */ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); s->strstart = s->w_size; } else { if (s->window_size - s->strstart <= used) { /* Slide the window down. */ s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ } zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); s->strstart += used; } s->block_start = s->strstart; s->insert += MIN(used, s->w_size - s->insert); } if (s->high_water < s->strstart) s->high_water = s->strstart; /* If the last block was written to next_out, then done. */ if (last) return finish_done; /* If flushing and all input has been consumed, then done. */ if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (long)s->strstart == s->block_start) return block_done; /* Fill the window with any remaining input. */ have = s->window_size - s->strstart - 1; if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { /* Slide the window down. */ s->block_start -= s->w_size; s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ have += s->w_size; /* more space now */ } if (have > s->strm->avail_in) have = s->strm->avail_in; if (have) { read_buf(s->strm, s->window + s->strstart, have); s->strstart += have; } if (s->high_water < s->strstart) s->high_water = s->strstart; /* There was not enough avail_out to write a complete worthy or flushed * stored block to next_out. Write a stored block to pending instead, if we * have enough input for a worthy block, or if flushing and there is enough |
︙ | ︙ | |||
1804 1805 1806 1807 1808 1809 1810 | /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ | | > > > | | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 | /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } |
︙ | ︙ | |||
1870 1871 1872 1873 1874 1875 1876 | s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; | | | | | > > > | | 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } |
︙ | ︙ | |||
1964 1965 1966 1967 1968 1969 1970 | /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ | | | | | | | | | | | > > > | 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 | /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes |
︙ | ︙ | |||
2066 2067 2068 2069 2070 2071 2072 | prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } | | < | | | > > > | | | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 | prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } |
Changes to compat/zlib/deflate.h.
1 | /* deflate.h -- internal compression state | | | 1 2 3 4 5 6 7 8 9 | /* deflate.h -- internal compression state * Copyright (C) 1995-2016 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ |
︙ | ︙ | |||
19 20 21 22 23 24 25 | trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif | < < < < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ |
︙ | ︙ | |||
217 218 219 220 221 222 223 | * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ | < < < | < < < < | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even |
︙ | ︙ | |||
246 247 248 249 250 251 252 | * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ | | | > > > > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef ZLIB_DEBUG |
︙ | ︙ | |||
298 299 300 301 302 303 304 | */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ | | | | | | | | | < | | | | | | < < < < < < < < < < < < < < < < < < < < < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ |
Changes to compat/zlib/examples/README.examples.
︙ | ︙ | |||
30 31 32 33 34 35 36 | gzlog.c gzlog.h efficiently and robustly maintain a message log file in gzip format - illustrates use of raw deflate, Z_PARTIAL_FLUSH, deflatePrime(), and deflateSetDictionary() - illustrates use of a gzip header extra field | < < < < < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | gzlog.c gzlog.h efficiently and robustly maintain a message log file in gzip format - illustrates use of raw deflate, Z_PARTIAL_FLUSH, deflatePrime(), and deflateSetDictionary() - illustrates use of a gzip header extra field zlib_how.html painfully comprehensive description of zpipe.c (see below) - describes in excruciating detail the use of deflate() and inflate() zpipe.c reads and writes zlib streams from stdin to stdout - illustrates the proper use of deflate() and inflate() - deeply commented in zlib_how.html (see above) zran.c index a zlib or gzip stream and randomly access it - illustrates the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary() to provide random access |
Changes to compat/zlib/examples/enough.c.
1 | /* enough.c -- determine the maximum size of inflate's Huffman code tables over | | | | < < | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | | < | | | | | | | | | | | | | > | | | | | | | | | | > < < < < < < < < < < < < < | | | | | | > > | > > | | < < < < < | < < < < < | < < < < < < < < < < < | > > | > > | | < | < | | < < < < < < < | < < < < < | < < < < < < < < < < < < < < < | | | | > | > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > | | | | < < | | | | | | | | | < | | | | | | > | > > > > > | | | | | | | | | > | > > > > > | | | | | < < | < | | < < | < < | < | | < < < | < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > | | | | < | | | | > | | | | | | | | | | > > > | | > > > > > > > > > > | > > | > > | > > > > > > | | | < < < < < < < < | | < < | | | | | | < | | | | | | | | | | | < | < | > | | | | | > > > > > > > < < < < | | | | | | < | < < | | | > > | | > | | | | | > > > | > > | | | | | | | | > > | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | /* enough.c -- determine the maximum size of inflate's Huffman code tables over * all possible valid and complete Huffman codes, subject to a length limit. * Copyright (C) 2007, 2008, 2012 Mark Adler * Version 1.4 18 August 2012 Mark Adler */ /* Version history: 1.0 3 Jan 2007 First version (derived from codecount.c version 1.4) 1.1 4 Jan 2007 Use faster incremental table usage computation Prune examine() search on previously visited states 1.2 5 Jan 2007 Comments clean up As inflate does, decrease root for short codes Refuse cases where inflate would increase root 1.3 17 Feb 2008 Add argument for initial root table size Fix bug for initial root table size == max - 1 Use a macro to compute the history index 1.4 18 Aug 2012 Avoid shifts more than bits in type (caused endless loop!) Clean up comparisons of different types Clean up code indentation */ /* Examine all possible Huffman codes for a given number of symbols and a maximum code length in bits to determine the maximum table size for zilb's inflate. Only complete Huffman codes are counted. Two codes are considered distinct if the vectors of the number of codes per length are not identical. So permutations of the symbol assignments result in the same code for the counting, as do permutations of the assignments of the bit values to the codes (i.e. only canonical codes are counted). We build a code from shorter to longer lengths, determining how many symbols are coded at each length. At each step, we have how many symbols remain to be coded, what the last code length used was, and how many bit patterns of that length remain unused. Then we add one to the code length and double the number of unused patterns to graduate to the next code length. We then assign all portions of the remaining symbols to that code length that preserve the properties of a correct and eventually complete code. Those properties are: we cannot use more bit patterns than are available; and when all the symbols are used, there are exactly zero possible bit patterns remaining. The inflate Huffman decoding algorithm uses two-level lookup tables for speed. There is a single first-level table to decode codes up to root bits in length (root == 9 in the current inflate implementation). The table has 1 << root entries and is indexed by the next root bits of input. Codes shorter than root bits have replicated table entries, so that the correct entry is pointed to regardless of the bits that follow the short code. If the code is longer than root bits, then the table entry points to a second- level table. The size of that table is determined by the longest code with that root-bit prefix. If that longest code has length len, then the table has size 1 << (len - root), to index the remaining bits in that set of codes. Each subsequent root-bit prefix then has its own sub-table. The total number of table entries required by the code is calculated incrementally as the number of codes at each bit length is populated. When all of the codes are shorter than root bits, then root is reduced to the longest code length, resulting in a single, smaller, one-level table. The inflate algorithm also provides for small values of root (relative to the log2 of the number of symbols), where the shortest code has more bits than root. In that case, root is increased to the length of the shortest code. This program, by design, does not handle that case, so it is verified that the number of symbols is less than 2^(root + 1). In order to speed up the examination (by about ten orders of magnitude for the default arguments), the intermediate states in the build-up of a code are remembered and previously visited branches are pruned. The memory required for this will increase rapidly with the total number of symbols and the maximum code length in bits. However this is a very small price to pay for the vast speedup. First, all of the possible Huffman codes are counted, and reachable intermediate states are noted by a non-zero count in a saved-results array. Second, the intermediate states that lead to (root + 1) bit or longer codes are used to look at all sub-codes from those junctures for their inflate memory usage. (The amount of memory used is not affected by the number of codes of root bits or less in length.) Third, the visited states in the construction of those sub-codes and the associated calculation of the table size is recalled in order to avoid recalculating from the same juncture. Beginning the code examination at (root + 1) bit codes, which is enabled by identifying the reachable nodes, accounts for about six of the orders of magnitude of improvement for the default arguments. About another four orders of magnitude come from not revisiting previous states. Out of approximately 2x10^16 possible Huffman codes, only about 2x10^6 sub-codes need to be examined to cover all of the possible table memory usage cases for the default arguments of 286 symbols limited to 15-bit codes. Note that an unsigned long long type is used for counting. It is quite easy to exceed the capacity of an eight-byte integer with a large number of symbols and a large maximum code length, so multiple-precision arithmetic would need to replace the unsigned long long arithmetic in that case. This program will abort if an overflow occurs. The big_t type identifies where the counting takes place. An unsigned long long type is also used for calculating the number of possible codes remaining at the maximum length. This limits the maximum code length to the number of bits in a long long minus the number of bits needed to represent the symbols in a flat code. The code_t type identifies where the bit pattern counting takes place. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #define local static /* special data types */ typedef unsigned long long big_t; /* type for code counting */ typedef unsigned long long code_t; /* type for bit pattern counting */ struct tab { /* type for been here check */ size_t len; /* length of bit vector in char's */ char *vec; /* allocated bit vector */ }; /* The array for saving results, num[], is indexed with this triplet: syms: number of symbols remaining to code left: number of available bit patterns at length len len: number of bits in the codes currently being assigned Those indices are constrained thusly when saving results: syms: 3..totsym (totsym == total symbols to code) left: 2..syms - 1, but only the evens (so syms == 8 -> 2, 4, 6) len: 1..max - 1 (max == maximum code length in bits) syms == 2 is not saved since that immediately leads to a single code. left must be even, since it represents the number of available bit patterns at the current length, which is double the number at the previous length. left ends at syms-1 since left == syms immediately results in a single code. (left > sym is not allowed since that would result in an incomplete code.) len is less than max, since the code completes immediately when len == max. The offset into the array is calculated for the three indices with the first one (syms) being outermost, and the last one (len) being innermost. We build the array with length max-1 lists for the len index, with syms-3 of those for each symbol. There are totsym-2 of those, with each one varying in length as a function of sym. See the calculation of index in count() for the index, and the calculation of size in main() for the size of the array. For the deflate example of 286 symbols limited to 15-bit codes, the array has 284,284 entries, taking up 2.17 MB for an 8-byte big_t. More than half of the space allocated for saved results is actually used -- not all possible triplets are reached in the generation of valid Huffman codes. */ /* The array for tracking visited states, done[], is itself indexed identically to the num[] array as described above for the (syms, left, len) triplet. Each element in the array is further indexed by the (mem, rem) doublet, where mem is the amount of inflate table space used so far, and rem is the remaining unused entries in the current inflate sub-table. Each indexed element is simply one bit indicating whether the state has been visited or not. Since the ranges for mem and rem are not known a priori, each bit vector is of a variable size, and grows as needed to accommodate the visited states. mem and rem are used to calculate a single index in a triangular array. Since the range of mem is expected in the default case to be about ten times larger than the range of rem, the array is skewed to reduce the memory usage, with eight times the range for mem than for rem. See the calculations for offset and bit in beenhere() for the details. For the deflate example of 286 symbols limited to 15-bit codes, the bit vectors grow to total approximately 21 MB, in addition to the 4.3 MB done[] array itself. */ /* Globals to avoid propagating constants or constant pointers recursively */ local int max; /* maximum allowed bit length for the codes */ local int root; /* size of base code table in bits */ local int large; /* largest code table so far */ local size_t size; /* number of elements in num and done */ local int *code; /* number of symbols assigned to each bit length */ local big_t *num; /* saved results array for code counting */ local struct tab *done; /* states already evaluated array */ /* Index function for num[] and done[] */ #define INDEX(i,j,k) (((size_t)((i-1)>>1)*((i-2)>>1)+(j>>1)-1)*(max-1)+k-1) /* Free allocated space. Uses globals code, num, and done. */ local void cleanup(void) { size_t n; if (done != NULL) { for (n = 0; n < size; n++) if (done[n].len) free(done[n].vec); free(done); } if (num != NULL) free(num); if (code != NULL) free(code); } /* Return the number of possible Huffman codes using bit patterns of lengths len through max inclusive, coding syms symbols, with left bit patterns of length len unused -- return -1 if there is an overflow in the counting. Keep a record of previous results in num to prevent repeating the same calculation. Uses the globals max and num. */ local big_t count(int syms, int len, int left) { big_t sum; /* number of possible codes from this juncture */ big_t got; /* value returned from count() */ int least; /* least number of syms to use at this juncture */ int most; /* most number of syms to use at this juncture */ int use; /* number of bit patterns to use in next call */ size_t index; /* index of this case in *num */ /* see if only one possible code */ if (syms == left) return 1; /* note and verify the expected state */ assert(syms > left && left > 0 && len < max); /* see if we've done this one already */ index = INDEX(syms, left, len); got = num[index]; if (got) return got; /* we have -- return the saved result */ /* we need to use at least this many bit patterns so that the code won't be incomplete at the next length (more bit patterns than symbols) */ least = (left << 1) - syms; if (least < 0) least = 0; /* we can use at most this many bit patterns, lest there not be enough available for the remaining symbols at the maximum length (if there were no limit to the code length, this would become: most = left - 1) */ most = (((code_t)left << (max - len)) - syms) / (((code_t)1 << (max - len)) - 1); /* count all possible codes from this juncture and add them up */ sum = 0; for (use = least; use <= most; use++) { got = count(syms - use, len + 1, (left - use) << 1); sum += got; if (got == (big_t)0 - 1 || sum < got) /* overflow */ return (big_t)0 - 1; } /* verify that all recursive calls are productive */ assert(sum != 0); /* save the result and return it */ num[index] = sum; return sum; } /* Return true if we've been here before, set to true if not. Set a bit in a bit vector to indicate visiting this state. Each (syms,len,left) state has a variable size bit vector indexed by (mem,rem). The bit vector is lengthened if needed to allow setting the (mem,rem) bit. */ local int beenhere(int syms, int len, int left, int mem, int rem) { size_t index; /* index for this state's bit vector */ size_t offset; /* offset in this state's bit vector */ int bit; /* mask for this state's bit */ size_t length; /* length of the bit vector in bytes */ char *vector; /* new or enlarged bit vector */ /* point to vector for (syms,left,len), bit in vector for (mem,rem) */ index = INDEX(syms, left, len); mem -= 1 << root; offset = (mem >> 3) + rem; offset = ((offset * (offset + 1)) >> 1) + rem; bit = 1 << (mem & 7); /* see if we've been here */ length = done[index].len; if (offset < length && (done[index].vec[offset] & bit) != 0) return 1; /* done this! */ /* we haven't been here before -- set the bit to show we have now */ /* see if we need to lengthen the vector in order to set the bit */ if (length <= offset) { /* if we have one already, enlarge it, zero out the appended space */ if (length) { do { length <<= 1; } while (length <= offset); vector = realloc(done[index].vec, length); if (vector != NULL) memset(vector + done[index].len, 0, length - done[index].len); } /* otherwise we need to make a new vector and zero it out */ else { length = 1 << (len - root); while (length <= offset) length <<= 1; vector = calloc(length, sizeof(char)); } /* in either case, bail if we can't get the memory */ if (vector == NULL) { fputs("abort: unable to allocate enough memory\n", stderr); cleanup(); exit(1); } /* install the new vector */ done[index].len = length; done[index].vec = vector; } /* set the bit */ done[index].vec[offset] |= bit; return 0; } /* Examine all possible codes from the given node (syms, len, left). Compute the amount of memory required to build inflate's decoding tables, where the number of code structures used so far is mem, and the number remaining in the current sub-table is rem. Uses the globals max, code, root, large, and done. */ local void examine(int syms, int len, int left, int mem, int rem) { int least; /* least number of syms to use at this juncture */ int most; /* most number of syms to use at this juncture */ int use; /* number of bit patterns to use in next call */ /* see if we have a complete code */ if (syms == left) { /* set the last code entry */ code[len] = left; /* complete computation of memory used by this code */ while (rem < left) { left -= rem; rem = 1 << (len - root); mem += rem; } assert(rem == left); /* if this is a new maximum, show the entries used and the sub-code */ if (mem > large) { large = mem; printf("max %d: ", mem); for (use = root + 1; use <= max; use++) if (code[use]) printf("%d[%d] ", code[use], use); putchar('\n'); fflush(stdout); } /* remove entries as we drop back down in the recursion */ code[len] = 0; return; } /* prune the tree if we can */ if (beenhere(syms, len, left, mem, rem)) return; /* we need to use at least this many bit patterns so that the code won't be incomplete at the next length (more bit patterns than symbols) */ least = (left << 1) - syms; if (least < 0) least = 0; /* we can use at most this many bit patterns, lest there not be enough available for the remaining symbols at the maximum length (if there were no limit to the code length, this would become: most = left - 1) */ most = (((code_t)left << (max - len)) - syms) / (((code_t)1 << (max - len)) - 1); /* occupy least table spaces, creating new sub-tables as needed */ use = least; while (rem < use) { use -= rem; rem = 1 << (len - root); mem += rem; } rem -= use; /* examine codes from here, updating table space as we go */ for (use = least; use <= most; use++) { code[len] = use; examine(syms - use, len + 1, (left - use) << 1, mem + (rem ? 1 << (len - root) : 0), rem << 1); if (rem == 0) { rem = 1 << (len - root); mem += rem; } rem--; } /* remove entries as we drop back down in the recursion */ code[len] = 0; } /* Look at all sub-codes starting with root + 1 bits. Look at only the valid intermediate code states (syms, left, len). For each completed code, calculate the amount of memory required by inflate to build the decoding tables. Find the maximum amount of memory required and show the code that requires that maximum. Uses the globals max, root, and num. */ local void enough(int syms) { int n; /* number of remaing symbols for this node */ int left; /* number of unused bit patterns at this length */ size_t index; /* index of this case in *num */ /* clear code */ for (n = 0; n <= max; n++) code[n] = 0; /* look at all (root + 1) bit and longer codes */ large = 1 << root; /* base table */ if (root < max) /* otherwise, there's only a base table */ for (n = 3; n <= syms; n++) for (left = 2; left < n; left += 2) { /* look at all reachable (root + 1) bit nodes, and the resulting codes (complete at root + 2 or more) */ index = INDEX(n, left, root + 1); if (root + 1 < max && num[index]) /* reachable node */ examine(n, root + 1, left, 1 << root, 0); /* also look at root bit codes with completions at root + 1 bits (not saved in num, since complete), just in case */ if (num[index - 1] && n <= left << 1) examine((n - left) << 1, root + 1, (n - left) << 1, 1 << root, 0); } /* done */ printf("done: maximum of %d table entries\n", large); } /* Examine and show the total number of possible Huffman codes for a given maximum number of symbols, initial root table size, and maximum code length in bits -- those are the command arguments in that order. The default values are 286, 9, and 15 respectively, for the deflate literal/length code. The possible codes are counted for each number of coded symbols from two to the maximum. The counts for each of those and the total number of codes are shown. The maximum number of inflate table entires is then calculated across all possible codes. Each new maximum number of table entries and the associated sub-code (starting at root + 1 == 10 bits) is shown. To count and examine Huffman codes that are not length-limited, provide a maximum length equal to the number of symbols minus one. For the deflate literal/length code, use "enough". For the deflate distance code, use "enough 30 6". This uses the %llu printf format to print big_t numbers, which assumes that big_t is an unsigned long long. If the big_t type is changed (for example to a multiple precision type), the method of printing will also need to be updated. */ int main(int argc, char **argv) { int syms; /* total number of symbols to code */ int n; /* number of symbols to code for this run */ big_t got; /* return value of count() */ big_t sum; /* accumulated number of codes over n */ code_t word; /* for counting bits in code_t */ /* set up globals for cleanup() */ code = NULL; num = NULL; done = NULL; /* get arguments -- default to the deflate literal/length code */ syms = 286; root = 9; max = 15; if (argc > 1) { syms = atoi(argv[1]); if (argc > 2) { root = atoi(argv[2]); if (argc > 3) max = atoi(argv[3]); } } if (argc > 4 || syms < 2 || root < 1 || max < 1) { fputs("invalid arguments, need: [sym >= 2 [root >= 1 [max >= 1]]]\n", stderr); return 1; } /* if not restricting the code length, the longest is syms - 1 */ if (max > syms - 1) max = syms - 1; /* determine the number of bits in a code_t */ for (n = 0, word = 1; word; n++, word <<= 1) ; /* make sure that the calculation of most will not overflow */ if (max > n || (code_t)(syms - 2) >= (((code_t)0 - 1) >> (max - 1))) { fputs("abort: code length too long for internal types\n", stderr); return 1; } /* reject impossible code requests */ if ((code_t)(syms - 1) > ((code_t)1 << max) - 1) { fprintf(stderr, "%d symbols cannot be coded in %d bits\n", syms, max); return 1; } /* allocate code vector */ code = calloc(max + 1, sizeof(int)); if (code == NULL) { fputs("abort: unable to allocate enough memory\n", stderr); return 1; } /* determine size of saved results array, checking for overflows, allocate and clear the array (set all to zero with calloc()) */ if (syms == 2) /* iff max == 1 */ num = NULL; /* won't be saving any results */ else { size = syms >> 1; if (size > ((size_t)0 - 1) / (n = (syms - 1) >> 1) || (size *= n, size > ((size_t)0 - 1) / (n = max - 1)) || (size *= n, size > ((size_t)0 - 1) / sizeof(big_t)) || (num = calloc(size, sizeof(big_t))) == NULL) { fputs("abort: unable to allocate enough memory\n", stderr); cleanup(); return 1; } } /* count possible codes for all numbers of symbols, add up counts */ sum = 0; for (n = 2; n <= syms; n++) { got = count(n, 1, 2); sum += got; if (got == (big_t)0 - 1 || sum < got) { /* overflow */ fputs("abort: can't count that high!\n", stderr); cleanup(); return 1; } printf("%llu %d-codes\n", got, n); } printf("%llu total codes for 2 to %d symbols", sum, syms); if (max < syms - 1) printf(" (%d-bit length limit)\n", max); else puts(" (no length limit)"); /* allocate and clear done array for beenhere() */ if (syms == 2) done = NULL; else if (size > ((size_t)0 - 1) / sizeof(struct tab) || (done = calloc(size, sizeof(struct tab))) == NULL) { fputs("abort: unable to allocate enough memory\n", stderr); cleanup(); return 1; } /* find and show maximum inflate table usage */ if (root > max) /* reduce root to max length */ root = max; if ((code_t)syms < ((code_t)1 << (root + 1))) enough(syms); else puts("cannot handle minimum code lengths > root"); /* done */ cleanup(); return 0; } |
Changes to compat/zlib/examples/fitblk.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | /* Approach to just fitting a requested compressed size: fitblk performs three compression passes on a portion of the input data in order to determine how much of that input will compress to nearly the requested output block size. The first pass generates enough deflate blocks to produce output to fill the requested | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /* Approach to just fitting a requested compressed size: fitblk performs three compression passes on a portion of the input data in order to determine how much of that input will compress to nearly the requested output block size. The first pass generates enough deflate blocks to produce output to fill the requested output size plus a specfied excess amount (see the EXCESS define below). The last deflate block may go quite a bit past that, but is discarded. The second pass decompresses and recompresses just the compressed data that fit in the requested plus excess sized buffer. The deflate process is terminated after that amount of input, which is less than the amount consumed on the first pass. The last deflate block of the result will be of a comparable size to the final product, so that the header for that deflate block and |
︙ | ︙ | |||
105 106 107 108 109 110 111 | inf->next_out = raw; ret = inflate(inf, Z_NO_FLUSH); assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && ret != Z_NEED_DICT); if (ret == Z_MEM_ERROR) return ret; | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | inf->next_out = raw; ret = inflate(inf, Z_NO_FLUSH); assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && ret != Z_NEED_DICT); if (ret == Z_MEM_ERROR) return ret; /* compress what was decompresed until done or no room */ def->avail_in = RAWLEN - inf->avail_out; def->next_in = raw; if (inf->avail_out != 0) flush = Z_FINISH; ret = deflate(def, flush); assert(ret != Z_STREAM_ERROR); } while (ret != Z_STREAM_END && def->avail_out != 0); |
︙ | ︙ | |||
194 195 196 197 198 199 200 | inf.next_in = blk; def.avail_out = size + EXCESS; def.next_out = tmp; ret = recompress(&inf, &def); if (ret == Z_MEM_ERROR) quit("out of memory"); | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | inf.next_in = blk; def.avail_out = size + EXCESS; def.next_out = tmp; ret = recompress(&inf, &def); if (ret == Z_MEM_ERROR) quit("out of memory"); /* set up for next reocmpression */ ret = inflateReset(&inf); assert(ret != Z_STREAM_ERROR); ret = deflateReset(&def); assert(ret != Z_STREAM_ERROR); /* do second and final recompression (third compression) */ inf.avail_in = size - MARGIN; /* assure stream will complete */ |
︙ | ︙ |
Changes to compat/zlib/examples/gun.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | writing all of the uncompressed data to the output. Unlike gzip, gun allows an empty file on input, and will produce no error writing an empty output file. gun will also decompress files made by Unix compress, which uses LZW compression. These files are automatically detected by virtue of their magic header bytes. Since the end of Unix compress stream is marked by the | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | writing all of the uncompressed data to the output. Unlike gzip, gun allows an empty file on input, and will produce no error writing an empty output file. gun will also decompress files made by Unix compress, which uses LZW compression. These files are automatically detected by virtue of their magic header bytes. Since the end of Unix compress stream is marked by the end-of-file, they cannot be concantenated. If a Unix compress stream is encountered in an input file, it is the last stream in that file. Like gunzip and uncompress, the file attributes of the original compressed file are maintained in the final uncompressed file, to the extent that the user permissions allow it. On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version |
︙ | ︙ |
Changes to compat/zlib/examples/gzappend.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | * 1.1 4 Nov 2003 - Expand and clarify some comments and notes * - Add version and copyright to help * - Send help to stdout instead of stderr * - Add some preemptive typecasts * - Add L to constants in lseek() calls * - Remove some debugging information in error messages * - Use new data_type definition for zlib 1.2.1 | | | | 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 | * 1.1 4 Nov 2003 - Expand and clarify some comments and notes * - Add version and copyright to help * - Send help to stdout instead of stderr * - Add some preemptive typecasts * - Add L to constants in lseek() calls * - Remove some debugging information in error messages * - Use new data_type definition for zlib 1.2.1 * - Simplfy and unify file operations * - Finish off gzip file in gztack() * - Use deflatePrime() instead of adding empty blocks * - Keep gzip file clean on appended file read errors * - Use in-place rotate instead of auxiliary buffer * (Why you ask? Because it was fun to write!) * 1.2 11 Oct 2012 - Fix for proper z_const usage * - Check for input buffer malloc failure */ /* gzappend takes a gzip file and appends to it, compressing files from the command line or data from stdin. The gzip file is written to directly, to avoid copying that file, in case it's large. Note that this results in the unfriendly behavior that if gzappend fails, the gzip file is corrupted. This program was written to illustrate the use of the new Z_BLOCK option of zlib 1.2.x's inflate() function. This option returns from inflate() at each block boundary to facilitate locating and modifying the last block bit at the start of the final deflate block. Also whether using Z_BLOCK or not, another required feature of zlib 1.2.x is that inflate() now provides the number of unusued bits in the last input byte used. gzappend will not work with versions of zlib earlier than 1.2.1. gzappend first decompresses the gzip file internally, discarding all but the last 32K of uncompressed data, and noting the location of the last block bit and the number of unused bits in the last byte of the compressed data. The gzip trailer containing the CRC-32 and length of the uncompressed data is verified. This trailer will be later overwritten. |
︙ | ︙ | |||
133 134 135 136 137 138 139 | /* pointer to last entry in list */ last = list + (len - 1); /* do simple left shift by one */ if (rot == 1) { tmp = *list; | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /* pointer to last entry in list */ last = list + (len - 1); /* do simple left shift by one */ if (rot == 1) { tmp = *list; memcpy(list, list + 1, len - 1); *last = tmp; return; } /* do simple right shift by one */ if (rot == len - 1) { tmp = *last; |
︙ | ︙ |
Changes to compat/zlib/examples/gzlog.c.
1 2 | /* * gzlog.c | | | | 1 2 3 4 5 6 7 8 9 10 11 12 | /* * gzlog.c * Copyright (C) 2004, 2008, 2012, 2016 Mark Adler, all rights reserved * For conditions of distribution and use, see copyright notice in gzlog.h * version 2.2, 14 Aug 2012 */ /* gzlog provides a mechanism for frequently appending short strings to a gzip file that is efficient both in execution time and compression ratio. The strategy is to write the short strings in an uncompressed form to the end of the gzip file, only compressing when the amount of uncompressed data has |
︙ | ︙ | |||
208 209 210 211 212 213 214 | - Write over the extra field, marking foo.gz as complete. Recovery procedure: - If not a replace recovery, read in the foo.add file, and provide that data to the appropriate recovery below. If there is no foo.add file, provide a zero data length to the recovery. In that case, the append recovery restores the foo.gz to the previous compressed + uncompressed data state. | | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | - Write over the extra field, marking foo.gz as complete. Recovery procedure: - If not a replace recovery, read in the foo.add file, and provide that data to the appropriate recovery below. If there is no foo.add file, provide a zero data length to the recovery. In that case, the append recovery restores the foo.gz to the previous compressed + uncompressed data state. For the the compress recovery, a missing foo.add file results in foo.gz being restored to the previous compressed-only data state. - Append recovery: - Pick up append at + step above - Compress recovery: - Pick up compress at * step above - Replace recovery: - Pick up compress at @ step above - Log the repair with a date stamp in foo.repairs |
︙ | ︙ | |||
752 753 754 755 756 757 758 | len = (size_t)(st.st_size); if ((off_t)len != st.st_size || (data = malloc(st.st_size)) == NULL) { log_log(log, op, "allocation failure"); return -2; } if ((fd = open(log->path, O_RDONLY, 0)) < 0) { | < < | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | len = (size_t)(st.st_size); if ((off_t)len != st.st_size || (data = malloc(st.st_size)) == NULL) { log_log(log, op, "allocation failure"); return -2; } if ((fd = open(log->path, O_RDONLY, 0)) < 0) { log_log(log, op, ".add file read failure"); return -1; } ret = (size_t)read(fd, data, len) != len; close(fd); if (ret) { log_log(log, op, ".add file read failure"); return -1; } log_log(log, op, "loaded .add file"); } else log_log(log, op, "missing .add file!"); |
︙ | ︙ |
Changes to compat/zlib/examples/gzlog.h.
︙ | ︙ | |||
36 37 38 39 40 41 42 | opening the log file locked for small bursts, and then closing it. The log object works by appending stored (uncompressed) data to the gzip file until 1 MB has been accumulated. At that time, the stored data is compressed, and replaces the uncompressed data in the file. The log file is truncated to its new size at that time. After each write operation, the log file is a valid gzip file that can decompressed to recover what was written. | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | opening the log file locked for small bursts, and then closing it. The log object works by appending stored (uncompressed) data to the gzip file until 1 MB has been accumulated. At that time, the stored data is compressed, and replaces the uncompressed data in the file. The log file is truncated to its new size at that time. After each write operation, the log file is a valid gzip file that can decompressed to recover what was written. The gzlog operations can be interupted at any point due to an application or system crash, and the log file will be recovered the next time the log is opened with gzlog_open(). */ #ifndef GZLOG_H #define GZLOG_H |
︙ | ︙ |
Deleted compat/zlib/examples/gznorm.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to compat/zlib/examples/zlib_how.html.
|
| | | | | | 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 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>zlib Usage Example</title> <!-- Copyright (c) 2004, 2005 Mark Adler. --> </head> <body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#00A000"> <h2 align="center"> zlib Usage Example </h2> We often get questions about how the <tt>deflate()</tt> and <tt>inflate()</tt> functions should be used. Users wonder when they should provide more input, when they should use more output, what to do with a <tt>Z_BUF_ERROR</tt>, how to make sure the process terminates properly, and so on. So for those who have read <tt>zlib.h</tt> (a few times), and would like further edification, below is an annotated example in C of simple routines to compress and decompress from an input file to an output file using <tt>deflate()</tt> and <tt>inflate()</tt> respectively. The annotations are interspersed between lines of the code. So please read between the lines. We hope this helps explain some of the intricacies of <em>zlib</em>. <p> Without further adieu, here is the program <a href="zpipe.c"><tt>zpipe.c</tt></a>: <pre><b> /* zpipe.c: example of proper use of zlib's inflate() and deflate() Not copyrighted -- provided to the public domain Version 1.4 11 December 2005 Mark Adler */ /* Version history: 1.0 30 Oct 2004 First version |
︙ | ︙ | |||
151 152 153 154 155 156 157 | before we fall out of the loop at the bottom. <pre><b> /* compress until end of file */ do { </b></pre> We start off by reading data from the input file. The number of bytes read is put directly into <tt>avail_in</tt>, and a pointer to those bytes is put into <tt>next_in</tt>. We also | | < | > > > | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | before we fall out of the loop at the bottom. <pre><b> /* compress until end of file */ do { </b></pre> We start off by reading data from the input file. The number of bytes read is put directly into <tt>avail_in</tt>, and a pointer to those bytes is put into <tt>next_in</tt>. We also check to see if end-of-file on the input has been reached. If we are at the end of file, then <tt>flush</tt> is set to the <em>zlib</em> constant <tt>Z_FINISH</tt>, which is later passed to <tt>deflate()</tt> to indicate that this is the last chunk of input data to compress. We need to use <tt>feof()</tt> to check for end-of-file as opposed to seeing if fewer than <tt>CHUNK</tt> bytes have been read. The reason is that if the input file length is an exact multiple of <tt>CHUNK</tt>, we will miss the fact that we got to the end-of-file, and not know to tell <tt>deflate()</tt> to finish up the compressed stream. If we are not yet at the end of the input, then the <em>zlib</em> constant <tt>Z_NO_FLUSH</tt> will be passed to <tt>deflate</tt> to indicate that we are still in the middle of the uncompressed data. <p> If there is an error in reading from the input file, the process is aborted with <tt>deflateEnd()</tt> being called to free the allocated <em>zlib</em> state before returning the error. We wouldn't want a memory leak, now would we? <tt>deflateEnd()</tt> can be called at any time after the state has been initialized. Once that's done, <tt>deflateInit()</tt> (or |
︙ | ︙ | |||
534 535 536 537 538 539 540 | else { fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); return 1; } } </b></pre> <hr> | | < < < < < < | 536 537 538 539 540 541 542 543 544 545 | else { fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); return 1; } } </b></pre> <hr> <i>Copyright (c) 2004, 2005 by Mark Adler<br>Last modified 11 December 2005</i> </body> </html> |
Changes to compat/zlib/examples/zran.c.
|
| | | | < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > | | | | | | | | | | > < | > > | | > > > > > > > | > > > > > > | > > > | | < < | | > > | > < | | < < < | > > > | < | | | | | < < < < < | | > | | | | | > > > > > | | > > | < | | | < < < < < < | | | | | < | < < < < < < < < < < < < < < < | | | | < | < | > | > | < < < < < < < < | | | > | | > > > | | | | | < < | | | < | < < | | < > | < < < > | | | < | < | | < < | | < | < < < < < < < < < | > > > > > > > > > > > > > | | | | | < < < | < | < < < < < < < | < < < < < < < < < < < < | > > > > > > | > > > > > > | < < < < < < < < < < < < < < > > > > > > | > | < < < | < < > > > | < < < < < > < < | > | < < < > < > > | > > | < < < < < < | | | | > | > | < | | < | | | | | < < | | < < < > | < < > < < < < < < < | < < < < < < < < < < < < < < < < < | < < | > | > | < | | > < | | | > > > > > | < < < < < < < | < < < < < | < < < < < | < < < < < | < < < < < < | < | < | < > | < < < < < < | < < | | | | | < < | | > > > | | | | > > > | | < < | | > > | > > | < | < < < < | | < < | > > > > > > > | | | | < < < < < < < < < < < | < | < < < | < | < | | | | | | | < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | /* zran.c -- example of zlib/gzip stream indexing and random access * Copyright (C) 2005, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h Version 1.1 29 Sep 2012 Mark Adler */ /* Version History: 1.0 29 May 2005 First version 1.1 29 Sep 2012 Fix memory reallocation error */ /* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary() for random access of a compressed file. A file containing a zlib or gzip stream is provided on the command line. The compressed stream is decoded in its entirety, and an index built with access points about every SPAN bytes in the uncompressed output. The compressed file is left open, and can then be read randomly, having to decompress on the average SPAN/2 uncompressed bytes before getting to the desired block of data. An access point can be created at the start of any deflate block, by saving the starting file offset and bit of that block, and the 32K bytes of uncompressed data that precede that block. Also the uncompressed offset of that block is saved to provide a referece for locating a desired starting point in the uncompressed stream. build_index() works by decompressing the input zlib or gzip stream a block at a time, and at the end of each block deciding if enough uncompressed data has gone by to justify the creation of a new access point. If so, that point is saved in a data structure that grows as needed to accommodate the points. To use the index, an offset in the uncompressed data is provided, for which the latest access point at or preceding that offset is located in the index. The input file is positioned to the specified location in the index, and if necessary the first few bits of the compressed data is read from the file. inflate is initialized with those bits and the 32K of uncompressed data, and the decompression then proceeds until the desired offset in the file is reached. Then the decompression continues to read the desired uncompressed data from the file. Another approach would be to generate the index on demand. In that case, requests for random access reads from the compressed data would try to use the index, but if a read far enough past the end of the index is required, then further index entries would be generated and added. There is some fair bit of overhead to starting inflation for the random access, mainly copying the 32K byte dictionary. So if small pieces of the file are being accessed, it would make sense to implement a cache to hold some lookahead and avoid many calls to extract() for small lengths. Another way to build an index would be to use inflateCopy(). That would not be constrained to have access points at block boundaries, but requires more memory per access point, and also cannot be saved to file due to the use of pointers in the state. The approach here allows for storage of the index in a file. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "zlib.h" #define local static #define SPAN 1048576L /* desired distance between access points */ #define WINSIZE 32768U /* sliding window size */ #define CHUNK 16384 /* file input buffer size */ /* access point entry */ struct point { off_t out; /* corresponding offset in uncompressed data */ off_t in; /* offset in input file of first full byte */ int bits; /* number of bits (1-7) from byte at in - 1, or 0 */ unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */ }; /* access point list */ struct access { int have; /* number of list entries filled in */ int size; /* number of list entries allocated */ struct point *list; /* allocated list */ }; /* Deallocate an index built by build_index() */ local void free_index(struct access *index) { if (index != NULL) { free(index->list); free(index); } } /* Add an entry to the access point list. If out of memory, deallocate the existing list and return NULL. */ local struct access *addpoint(struct access *index, int bits, off_t in, off_t out, unsigned left, unsigned char *window) { struct point *next; /* if list is empty, create it (start with eight points) */ if (index == NULL) { index = malloc(sizeof(struct access)); if (index == NULL) return NULL; index->list = malloc(sizeof(struct point) << 3); if (index->list == NULL) { free(index); return NULL; } index->size = 8; index->have = 0; } /* if list is full, make it bigger */ else if (index->have == index->size) { index->size <<= 1; next = realloc(index->list, sizeof(struct point) * index->size); if (next == NULL) { free_index(index); return NULL; } index->list = next; } /* fill in entry and increment how many we have */ next = index->list + index->have; next->bits = bits; next->in = in; next->out = out; if (left) memcpy(next->window, window + WINSIZE - left, left); if (left < WINSIZE) memcpy(next->window + left, window, WINSIZE - left); index->have++; /* return list, possibly reallocated */ return index; } /* Make one entire pass through the compressed stream and build an index, with access points about every span bytes of uncompressed output -- span is chosen to balance the speed of random access against the memory requirements of the list, about 32K bytes per access point. Note that data after the end of the first zlib or gzip stream in the file is ignored. build_index() returns the number of access points on success (>= 1), Z_MEM_ERROR for out of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a file read error. On success, *built points to the resulting index. */ local int build_index(FILE *in, off_t span, struct access **built) { int ret; off_t totin, totout; /* our own total counters to avoid 4GB limit */ off_t last; /* totout value of last access point */ struct access *index; /* access points being generated */ z_stream strm; unsigned char input[CHUNK]; unsigned char window[WINSIZE]; /* initialize inflate */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */ if (ret != Z_OK) return ret; /* inflate the input, maintain a sliding window, and build an index -- this also validates the integrity of the compressed data using the check information at the end of the gzip or zlib stream */ totin = totout = last = 0; index = NULL; /* will be allocated by first addpoint() */ strm.avail_out = 0; do { /* get some compressed data from input file */ strm.avail_in = fread(input, 1, CHUNK, in); if (ferror(in)) { ret = Z_ERRNO; goto build_index_error; } if (strm.avail_in == 0) { ret = Z_DATA_ERROR; goto build_index_error; } strm.next_in = input; /* process all of that, or until end of stream */ do { /* reset sliding window if necessary */ if (strm.avail_out == 0) { strm.avail_out = WINSIZE; strm.next_out = window; } /* inflate until out of input, output, or at end of block -- update the total input and output counters */ totin += strm.avail_in; totout += strm.avail_out; ret = inflate(&strm, Z_BLOCK); /* return at end of block */ totin -= strm.avail_in; totout -= strm.avail_out; if (ret == Z_NEED_DICT) ret = Z_DATA_ERROR; if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) goto build_index_error; if (ret == Z_STREAM_END) break; /* if at end of block, consider adding an index entry (note that if data_type indicates an end-of-block, then all of the uncompressed data from that block has been delivered, and none of the compressed data after that block has been consumed, except for up to seven bits) -- the totout == 0 provides an entry point after the zlib or gzip header, and assures that the index always has at least one access point; we avoid creating an access point after the last block by checking bit 6 of data_type */ if ((strm.data_type & 128) && !(strm.data_type & 64) && (totout == 0 || totout - last > span)) { index = addpoint(index, strm.data_type & 7, totin, totout, strm.avail_out, window); if (index == NULL) { ret = Z_MEM_ERROR; goto build_index_error; } last = totout; } } while (strm.avail_in != 0); } while (ret != Z_STREAM_END); /* clean up and return index (release unused entries in list) */ (void)inflateEnd(&strm); index->list = realloc(index->list, sizeof(struct point) * index->have); index->size = index->have; *built = index; return index->size; /* return error */ build_index_error: (void)inflateEnd(&strm); if (index != NULL) free_index(index); return ret; } /* Use the index to read len bytes from offset into buf, return bytes read or negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past the end of the uncompressed data, then extract() will return a value less than len, indicating how much as actually read into buf. This function should not return a data error unless the file was modified since the index was generated. extract() may also return Z_ERRNO if there is an error on reading or seeking the input file. */ local int extract(FILE *in, struct access *index, off_t offset, unsigned char *buf, int len) { int ret, skip; z_stream strm; struct point *here; unsigned char input[CHUNK]; unsigned char discard[WINSIZE]; /* proceed only if something reasonable to do */ if (len < 0) return 0; /* find where in stream to start */ here = index->list; ret = index->have; while (--ret && here[1].out <= offset) here++; /* initialize file and inflate state to start there */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit2(&strm, -15); /* raw inflate */ if (ret != Z_OK) return ret; ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET); if (ret == -1) goto extract_ret; if (here->bits) { ret = getc(in); if (ret == -1) { ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR; goto extract_ret; } (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits)); } (void)inflateSetDictionary(&strm, here->window, WINSIZE); /* skip uncompressed bytes until offset reached, then satisfy request */ offset -= here->out; strm.avail_in = 0; skip = 1; /* while skipping to offset */ do { /* define where to put uncompressed data, and how much */ if (offset == 0 && skip) { /* at offset now */ strm.avail_out = len; strm.next_out = buf; skip = 0; /* only do this once */ } if (offset > WINSIZE) { /* skip WINSIZE bytes */ strm.avail_out = WINSIZE; strm.next_out = discard; offset -= WINSIZE; } else if (offset != 0) { /* last skip */ strm.avail_out = (unsigned)offset; strm.next_out = discard; offset = 0; } /* uncompress until avail_out filled, or end of stream */ do { if (strm.avail_in == 0) { strm.avail_in = fread(input, 1, CHUNK, in); if (ferror(in)) { ret = Z_ERRNO; goto extract_ret; } if (strm.avail_in == 0) { ret = Z_DATA_ERROR; goto extract_ret; } strm.next_in = input; } ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */ if (ret == Z_NEED_DICT) ret = Z_DATA_ERROR; if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) goto extract_ret; if (ret == Z_STREAM_END) break; } while (strm.avail_out != 0); /* if reach end of stream, then don't keep trying to get more */ if (ret == Z_STREAM_END) break; /* do until offset reached and requested data read, or stream ends */ } while (skip); /* compute number of uncompressed bytes read after offset */ ret = skip ? 0 : len - strm.avail_out; /* clean up and return bytes read or error */ extract_ret: (void)inflateEnd(&strm); return ret; } /* Demonstrate the use of build_index() and extract() by processing the file provided on the command line, and the extracting 16K from about 2/3rds of the way through the uncompressed output, and writing that to stdout. */ int main(int argc, char **argv) { int len; off_t offset; FILE *in; struct access *index = NULL; unsigned char buf[CHUNK]; /* open input file */ if (argc != 2) { fprintf(stderr, "usage: zran file.gz\n"); return 1; } in = fopen(argv[1], "rb"); if (in == NULL) { fprintf(stderr, "zran: could not open %s for reading\n", argv[1]); return 1; } /* build index */ len = build_index(in, SPAN, &index); if (len < 0) { fclose(in); switch (len) { case Z_MEM_ERROR: fprintf(stderr, "zran: out of memory\n"); break; case Z_DATA_ERROR: fprintf(stderr, "zran: compressed data error in %s\n", argv[1]); break; case Z_ERRNO: fprintf(stderr, "zran: read error on %s\n", argv[1]); break; default: fprintf(stderr, "zran: error %d while building index\n", len); } return 1; } fprintf(stderr, "zran: built index with %d access points\n", len); /* use index by reading some bytes from an arbitrary offset */ offset = (index->list[index->have - 1].out << 1) / 3; len = extract(in, index, offset, buf, CHUNK); if (len < 0) fprintf(stderr, "zran: extraction failed: %s error\n", len == Z_MEM_ERROR ? "out of memory" : "input corrupted"); else { fwrite(buf, 1, len, stdout); fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset); } /* clean up and exit */ free_index(index); fclose(in); return 0; } |
Deleted compat/zlib/examples/zran.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to compat/zlib/gzclose.c.
1 2 3 4 5 6 7 8 9 10 | /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose(file) gzFile file; { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; |
︙ | ︙ |
Changes to compat/zlib/gzguts.h.
1 | /* gzguts.h -- zlib internal header definitions for gz* operations | | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS # endif #endif #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif |
︙ | ︙ | |||
34 35 36 37 38 39 40 | # include <stddef.h> #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include <io.h> #endif | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # include <stddef.h> #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include <io.h> #endif #if defined(_WIN32) || defined(__CYGWIN__) # define WIDECHAR #endif #ifdef WINAPI_FAMILY # define open _open # define read _read # define write _write |
︙ | ︙ | |||
114 115 116 117 118 119 120 | #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC | | | | | | | | 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 | #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include <windows.h> # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifndef NO_STRERROR # include <errno.h> # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL |
︙ | ︙ | |||
185 186 187 188 189 190 191 | int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ | < | | > > > | | > | 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 | int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else unsigned ZLIB_INTERNAL gz_intmax OF((void)); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif |
Changes to compat/zlib/gzlib.c.
1 | /* gzlib.c -- zlib functions common to reading and writing gzip files | | | > > > > | > > | 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 | /* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif /* Local functions */ local void gz_reset OF((gz_statep)); local gzFile gz_open OF((const void *, int, const char *)); #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror (error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, |
︙ | ︙ | |||
62 63 64 65 66 67 68 | SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ | | > > < < | > > > > | 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 | SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset(state) gz_statep state; { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(path, fd, mode) const void *path; int fd; const char *mode; { gz_statep state; z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; #endif #ifdef O_EXCL |
︙ | ︙ | |||
253 254 255 256 257 258 259 | gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ | | > > > | > > > | > > > | > > > | > > > | | | > > | > > > > | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen(fd, mode) int fd; const char *mode; { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); #else sprintf(path, "<fd:%d>", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef WIDECHAR gzFile ZEXPORT gzopen_w(path, mode) const wchar_t *path; const char *mode; { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ int ZEXPORT gzbuffer(file, size) gzFile file; unsigned size; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if ((size << 1) < size) return -1; /* need to be able to double it */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64(file, offset, whence) gzFile file; z_off64_t offset; int whence; { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; |
︙ | ︙ | |||
362 363 364 365 366 367 368 | else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { | | | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); |
︙ | ︙ | |||
405 406 407 408 409 410 411 | state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ | | > > > > | > > | > > | > > | > > | > > | > > > | > > | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek(file, offset, whence) gzFile file; z_off_t offset; int whence; { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell(file) gzFile file; { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64(file) gzFile file; { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset(file) gzFile file; { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror(file, errnum) gzFile file; int *errnum; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ void ZEXPORT gzclearerr(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
︙ | ︙ | |||
522 523 524 525 526 527 528 | /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ | | > > > > | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error(state, err, msg) gz_statep state; int err; const char *msg; { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } |
︙ | ︙ | |||
559 560 561 562 563 564 565 566 567 568 569 | #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif } /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ | > | < < < > | > > < > | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax() { unsigned p, q; p = 1; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; } #endif |
Changes to compat/zlib/gzread.c.
1 | /* gzread.c -- zlib functions for reading gzip files | | > > > > > > > > > > > | > | > | 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 | /* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load(state, buf, len, have) gz_statep state; unsigned char *buf; unsigned len; unsigned *have; { int ret; unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { get = len - *have; if (get > max) |
︙ | ︙ | |||
36 37 38 39 40 41 42 | /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ | | > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ local int gz_avail(state) gz_statep state; { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ |
︙ | ︙ | |||
69 70 71 72 73 74 75 | left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ | | > > | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ local int gz_look(state) gz_statep state; { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); |
︙ | ︙ | |||
136 137 138 139 140 141 142 | return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; | > | | | > | > > | 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 | return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; if (strm->avail_in) { memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; } state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ local int gz_decomp(state) gz_statep state; { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { |
︙ | ︙ | |||
201 202 203 204 205 206 207 | /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ | | > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_fetch(state) gz_statep state; { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; |
︙ | ︙ | |||
229 230 231 232 233 234 235 | return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ | | > > > | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip(state, len) gz_statep state; z_off64_t len; { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? |
︙ | ︙ | |||
261 262 263 264 265 266 267 | return 0; } /* Read len bytes into buf from file, or less than len up to the end of the input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ | | > > > > | | | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | return 0; } /* Read len bytes into buf from file, or less than len up to the end of the input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ local z_size_t gz_read(state, buf, len) gz_statep state; voidp buf; z_size_t len; { z_size_t got; unsigned n; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return 0; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* set n to the maximum amount of len that fits in an unsigned int */ n = -1; if (n > len) n = len; /* first just try copying data from the output buffer */ if (state->x.have) { if (state->x.have < n) n = state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; |
︙ | ︙ | |||
338 339 340 341 342 343 344 | } while (len); /* return number of bytes read into user buffer */ return got; } /* -- see zlib.h -- */ | | > > > > | | > > > > > | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | } while (len); /* return number of bytes read into user buffer */ return got; } /* -- see zlib.h -- */ int ZEXPORT gzread(file, buf, len) gzFile file; voidp buf; unsigned len; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); return -1; } /* read len or fewer bytes to buf */ len = gz_read(state, buf, len); /* check for an error */ if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* return the number of bytes read (this is assured to fit in an int) */ return (int)len; } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfread(buf, size, nitems, file) voidp buf; z_size_t size; z_size_t nitems; gzFile file; { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; |
︙ | ︙ | |||
401 402 403 404 405 406 407 | /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif | | > > > | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif int ZEXPORT gzgetc(file) gzFile file; { int ret; unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; |
︙ | ︙ | |||
423 424 425 426 427 428 429 | if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gz_read() */ | | > | > > | > > > < < < < | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gz_read() */ ret = gz_read(state, buf, 1); return ret < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_(file) gzFile file; { return gzgetc(file); } /* -- see zlib.h -- */ int ZEXPORT gzungetc(c, file) int c; gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { |
︙ | ︙ | |||
492 493 494 495 496 497 498 | state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ | | > > > > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets(file, buf, len) gzFile file; char *buf; int len; { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) |
︙ | ︙ | |||
552 553 554 555 556 557 558 | if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ | | > > | > > | 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r(file) gzFile file; { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; |
︙ | ︙ |
Changes to compat/zlib/gzwrite.c.
1 | /* gzwrite.c -- zlib functions for writing gzip files | | > > > > > > | > > | 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 | /* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on a memory allocation failure, or 0 on success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); /* allocate input buffer (double size for gzprintf) */ state->in = (unsigned char *)malloc(state->want << 1); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); |
︙ | ︙ | |||
58 59 60 61 62 63 64 | /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ | | > > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; { int ret, writ; unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; |
︙ | ︙ | |||
82 83 84 85 86 87 88 | } strm->avail_in -= (unsigned)writ; strm->next_in += writ; } return 0; } | < < < < < < < < < | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | } strm->avail_in -= (unsigned)writ; strm->next_in += writ; } return 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { |
︙ | ︙ | |||
128 129 130 131 132 133 134 | return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) | | | > > > | 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 | return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) deflateReset(strm); /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on a write error or memory allocation failure by gz_comp(), or 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; |
︙ | ︙ | |||
166 167 168 169 170 171 172 | len -= n; } return 0; } /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ | | > > > > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | len -= n; } return 0; } /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ local z_size_t gz_write(state, buf, len) gz_statep state; voidpc buf; z_size_t len; { z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ |
︙ | ︙ | |||
196 197 198 199 200 201 202 | if (state->strm.avail_in == 0) state->strm.next_in = state->in; have = (unsigned)((state->strm.next_in + state->strm.avail_in) - state->in); copy = state->size - have; if (copy > len) | | | | > > > > | 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 256 257 | if (state->strm.avail_in == 0) state->strm.next_in = state->in; have = (unsigned)((state->strm.next_in + state->strm.avail_in) - state->in); copy = state->size - have; if (copy > len) copy = len; memcpy(state->in + have, buf, copy); state->strm.avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ state->strm.next_in = (z_const Bytef *)buf; do { unsigned n = (unsigned)-1; if (n > len) n = len; state->strm.avail_in = n; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; len -= n; } while (len); } /* input was all buffered or compressed */ return put; } /* -- see zlib.h -- */ int ZEXPORT gzwrite(file, buf, len) gzFile file; voidpc buf; unsigned len; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; |
︙ | ︙ | |||
254 255 256 257 258 259 260 | } /* write len bytes from buf (the return value will fit in an int) */ return (int)gz_write(state, buf, len); } /* -- see zlib.h -- */ | | > > > | > | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | } /* write len bytes from buf (the return value will fit in an int) */ return (int)gz_write(state, buf, len); } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) voidpc buf; z_size_t size; z_size_t nitems; gzFile file; { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; |
︙ | ︙ | |||
280 281 282 283 284 285 286 | } /* write len bytes to buf, return the number of full items written */ return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ | | > > > | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | } /* write len bytes to buf, return the number of full items written */ return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ int ZEXPORT gzputc(file, c) gzFile file; int c; { unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) |
︙ | ︙ | |||
325 326 327 328 329 330 331 | buf[0] = (unsigned char)c; if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ | | > > > > | | < < < < | | | > | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | buf[0] = (unsigned char)c; if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs(file, str) gzFile file; const char *str; { int ret; z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* write string */ len = strlen(str); ret = gz_write(state, str, len); return ret == 0 && len != 0 ? -1 : ret; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) #include <stdarg.h> /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int len; unsigned left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ |
︙ | ︙ | |||
416 417 418 419 420 421 422 | strm->avail_in += (unsigned)len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; | | | > > > > | | < | > | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | strm->avail_in += (unsigned)len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memcpy(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return len; } int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; va_start(va, format); ret = gzvprintf(file, format, va); va_end(va); return ret; } #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { unsigned len, left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) |
︙ | ︙ | |||
511 512 513 514 515 516 517 | strm->avail_in += len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; | | | > > > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | strm->avail_in += len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memcpy(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return (int)len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush(file, flush) gzFile file; int flush; { gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; |
︙ | ︙ | |||
550 551 552 553 554 555 556 | /* compress remaining data with requested flush */ (void)gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ | | > > > > | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | /* compress remaining data with requested flush */ (void)gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams(file, level, strategy) gzFile file; int level; int strategy; { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ |
︙ | ︙ | |||
588 589 590 591 592 593 594 | } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ | | > > | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w(file) gzFile file; { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; |
︙ | ︙ |
Changes to compat/zlib/infback.c.
1 | /* infback.c -- inflate using a call-back interface | | > > > | > > | > | > | 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 | /* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; int stream_size; { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) |
︙ | ︙ | |||
55 56 57 58 59 60 61 | strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; | < | > > | 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 | strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { |
︙ | ︙ | |||
235 236 237 238 239 240 241 | Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ | | > > > | > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) z_streamp strm; in_func in; void FAR *in_desc; out_func out; void FAR *out_desc; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ |
︙ | ︙ | |||
460 461 462 463 464 465 466 | if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; | < | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; |
︙ | ︙ | |||
588 589 590 591 592 593 594 | do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: | | > > > > < | | < < < < < | > > | 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly -- write leftover output */ ret = Z_STREAM_END; if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left)) ret = Z_BUF_ERROR; } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd(strm) z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } |
Changes to compat/zlib/inffast.c.
︙ | ︙ | |||
43 44 45 46 47 48 49 | checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ | | > > > | | 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 | checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ |
︙ | ︙ | |||
100 101 102 103 104 105 106 | do { if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } | | | | | | | | | | | | | 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 | do { if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); *out++ = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; |
︙ | ︙ | |||
257 258 259 260 261 262 263 | *out++ = *from++; if (len > 1) *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ | | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | *out++ = *from++; if (len > 1) *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } |
︙ | ︙ |
Changes to compat/zlib/inffast.h.
1 2 3 4 5 6 7 8 9 10 | /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ | | | 1 2 3 4 5 6 7 8 9 10 11 | /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); |
Changes to compat/zlib/inflate.c.
1 | /* inflate.c -- zlib decompression | | | 1 2 3 4 5 6 7 8 9 | /* inflate.c -- zlib decompression * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 |
︙ | ︙ | |||
87 88 89 90 91 92 93 | #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif | > > > > > > > > > > > | > > | > > < | > > | > > > < < | 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 | #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local int inflateStateCheck OF((z_streamp strm)); local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); local int inflateStateCheck(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; state = (struct inflate_state FAR *)strm->state; if (state == Z_NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) return 1; return 0; } int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) |
︙ | ︙ | |||
171 172 173 174 175 176 177 | /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } | | > > | > > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; |
︙ | ︙ | |||
211 212 213 214 215 216 217 | if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } | > > | | > | > > > > < < | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; |
︙ | ︙ | |||
245 246 247 248 249 250 251 | If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ | | > > | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { |
︙ | ︙ | |||
307 308 309 310 311 312 313 | return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ | | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); |
︙ | ︙ | |||
361 362 363 364 365 366 367 | Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ | | > > > > | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, end, copy) z_streamp strm; const Bytef *end; unsigned copy; { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { |
︙ | ︙ | |||
411 412 413 414 415 416 417 | return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP | | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ |
︙ | ︙ | |||
583 584 585 586 587 588 589 | the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ | | > > > | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ |
︙ | ︙ | |||
631 632 633 634 635 636 637 638 639 640 641 642 643 644 | state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { | > | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { |
︙ | ︙ | |||
657 658 659 660 661 662 663 | state->wbits = len; if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; | < | 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | state->wbits = len; if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: |
︙ | ︙ | |||
683 684 685 686 687 688 689 | } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; | < < < < | | < < | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && |
︙ | ︙ | |||
763 764 765 766 767 768 769 | next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; | < < | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; |
︙ | ︙ | |||
808 809 810 811 812 813 814 | break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; | < < < | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); |
︙ | ︙ | |||
870 871 872 873 874 875 876 | } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; | < < | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); |
︙ | ︙ | |||
909 910 911 912 913 914 915 | state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; | < | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 | state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) |
︙ | ︙ | |||
931 932 933 934 935 936 937 | strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; | < | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 | strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } |
︙ | ︙ | |||
1015 1016 1017 1018 1019 1020 1021 | strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; | < < | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; | < < | 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { |
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 | strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; | < < | 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 | strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { |
︙ | ︙ | |||
1184 1185 1186 1187 1188 1189 1190 | if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = | | < | < < | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer |
︙ | ︙ | |||
1250 1251 1252 1253 1254 1255 1256 | in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = | | | > > | > > | > | > > | > | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; |
︙ | ︙ | |||
1323 1324 1325 1326 1327 1328 1329 | return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } | | > > > | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 | return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; |
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 | state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ | | > > | > | > > < | < < < < < < | > > | > > > | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 | state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; const unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (inflateStateCheck(source) || dest == Z_NULL) |
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 | zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } | | > > > | > > > | | > > | > > | 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 | zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = !subvert; return Z_OK; #else (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } int ZEXPORT inflateValidate(strm, check) z_streamp strm; int check; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (check) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return -(1L << 16); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } unsigned long ZEXPORT inflateCodesUsed(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } |
Changes to compat/zlib/inflate.h.
1 | /* inflate.h -- internal inflate state definition | | | 1 2 3 4 5 6 7 8 9 | /* inflate.h -- internal inflate state definition * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ |
︙ | ︙ | |||
82 83 84 85 86 87 88 | struct inflate_state { z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ | | < | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | struct inflate_state { z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ |
︙ | ︙ |
Changes to compat/zlib/inftrees.c.
1 | /* inftrees.c -- generate Huffman trees for efficient decoding | | | > > | | > | > > | 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 | /* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ |
︙ | ︙ | |||
53 54 55 56 57 58 59 | unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, |
︙ | ︙ |
Changes to compat/zlib/inftrees.h.
︙ | ︙ | |||
34 35 36 37 38 39 40 | 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program | | | | | | | | 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 | 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); |
Changes to compat/zlib/make_vms.com.
︙ | ︙ | |||
10 11 12 13 14 15 16 | $!------------------------------------------------------------------------------ $! Version history $! 0.01 20060120 First version to receive a number $! 0.02 20061008 Adapt to new Makefile.in $! 0.03 20091224 Add support for large file check $! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite $! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in | | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | $!------------------------------------------------------------------------------ $! Version history $! 0.01 20060120 First version to receive a number $! 0.02 20061008 Adapt to new Makefile.in $! 0.03 20091224 Add support for large file check $! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite $! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in $! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new exmples $! subdir path, update module search in makefile.in $! 0.07 20120115 Triggered by work done by Alexey Chupahin completly redesigned $! shared image creation $! 0.08 20120219 Make it work on VAX again, pre-load missing symbols to shared $! image $! 0.09 20120305 SMS. P1 sets builder ("MMK", "MMS", " " (built-in)). $! "" -> automatic, preference: MMK, MMS, built-in. $! $ on error then goto err_exit |
︙ | ︙ |
Changes to compat/zlib/old/visual-basic.txt.
︙ | ︙ | |||
111 112 113 114 115 116 117 | ReDim bytaryCpr(lngCprSiz - 1) If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) = SUCCESS Then lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100 ReDim Preserve bytaryCpr(lngCprSiz - 1) Open strCprPth For Binary Access Write As #1 Put #1, , bytaryCpr() | | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | ReDim bytaryCpr(lngCprSiz - 1) If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) = SUCCESS Then lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100 ReDim Preserve bytaryCpr(lngCprSiz - 1) Open strCprPth For Binary Access Write As #1 Put #1, , bytaryCpr() Put #1, , lngOriSiz 'Add the the original size value to the end (last 4 bytes) Close #1 Else MsgBox "Compression error" End If Erase bytaryCpr Erase bytaryOri |
︙ | ︙ |
Changes to compat/zlib/os400/README400.
|
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ZLIB version 1.2.11 for OS/400 installation instructions 1) Download and unpack the zlib tarball to some IFS directory. (i.e.: /path/to/the/zlib/ifs/source/directory) If the installed IFS command suppors gzip format, this is straightforward, else you have to unpack first to some directory on a system supporting it, then move the whole directory to the IFS via the network (via SMB or FTP). 2) Edit the configuration parameters in the compilation script. EDTF STMF('/path/to/the/zlib/ifs/source/directory/os400/make.sh') |
︙ | ︙ | |||
39 40 41 42 43 44 45 | In the ILE environment, the same definitions are available from file zlib.inc located in the same IFS include directory as the C/C++ header files. Please read comments in this member for more information. Remember that most foreign textual data are ASCII coded: this implementation does not handle conversion from/to ASCII, so | | | 39 40 41 42 43 44 45 46 47 48 | In the ILE environment, the same definitions are available from file zlib.inc located in the same IFS include directory as the C/C++ header files. Please read comments in this member for more information. Remember that most foreign textual data are ASCII coded: this implementation does not handle conversion from/to ASCII, so text data code conversions must be done explicitely. Mainly for the reason above, always open zipped files in binary mode. |
Changes to compat/zlib/os400/bndsrc.
︙ | ︙ | |||
112 113 114 115 116 117 118 | EXPORT SYMBOL("deflateGetDictionary") EXPORT SYMBOL("gzfread") EXPORT SYMBOL("gzfwrite") EXPORT SYMBOL("inflateCodesUsed") EXPORT SYMBOL("inflateValidate") EXPORT SYMBOL("uncompress2") | < < < < < < < < | 112 113 114 115 116 117 118 119 | EXPORT SYMBOL("deflateGetDictionary") EXPORT SYMBOL("gzfread") EXPORT SYMBOL("gzfwrite") EXPORT SYMBOL("inflateCodesUsed") EXPORT SYMBOL("inflateValidate") EXPORT SYMBOL("uncompress2") ENDPGMEXP |
Changes to compat/zlib/os400/zlib.inc.
1 2 3 | * ZLIB.INC - Interface to the general purpose compression library * * ILE RPG400 version by Patrick Monnerat, DATASPHERE. | | | | | | 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 | * ZLIB.INC - Interface to the general purpose compression library * * ILE RPG400 version by Patrick Monnerat, DATASPHERE. * Version 1.2.11 * * * WARNING: * Procedures inflateInit(), inflateInit2(), deflateInit(), * deflateInit2() and inflateBackInit() need to be called with * two additional arguments: * the package version string and the stream control structure. * size. This is needed because RPG lacks some macro feature. * Call these procedures as: * inflateInit(...: ZLIB_VERSION: %size(z_stream)) * /if not defined(ZLIB_H_) /define ZLIB_H_ * ************************************************************************** * Constants ************************************************************************** * * Versioning information. * D ZLIB_VERSION C '1.2.11' D ZLIB_VERNUM C X'12a0' D ZLIB_VER_MAJOR C 1 D ZLIB_VER_MINOR C 2 D ZLIB_VER_REVISION... D C 11 D ZLIB_VER_SUBREVISION... D C 0 * * Other equates. * D Z_NO_FLUSH C 0 D Z_PARTIAL_FLUSH... |
︙ | ︙ |
Changes to compat/zlib/qnx/package.qpg.
︙ | ︙ | |||
21 22 23 24 25 26 27 | <QPG:EmailAddress></QPG:EmailAddress> </QPG:Responsible> <QPG:Values> <QPG:Files> <QPG:Add file="../zconf.h" install="/opt/include/" user="root:sys" permission="644"/> <QPG:Add file="../zlib.h" install="/opt/include/" user="root:sys" permission="644"/> | | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <QPG:EmailAddress></QPG:EmailAddress> </QPG:Responsible> <QPG:Values> <QPG:Files> <QPG:Add file="../zconf.h" install="/opt/include/" user="root:sys" permission="644"/> <QPG:Add file="../zlib.h" install="/opt/include/" user="root:sys" permission="644"/> <QPG:Add file="../libz.so.1.2.11" install="/opt/lib/" user="root:bin" permission="644"/> <QPG:Add file="libz.so" install="/opt/lib/" component="dev" filetype="symlink" linkto="libz.so.1.2.11"/> <QPG:Add file="libz.so.1" install="/opt/lib/" filetype="symlink" linkto="libz.so.1.2.11"/> <QPG:Add file="../libz.so.1.2.11" install="/opt/lib/" component="slib"/> </QPG:Files> <QPG:PackageFilter> <QPM:PackageManifest> <QPM:PackageDescription> <QPM:PackageType>Library</QPM:PackageType> <QPM:PackageReleaseNotes></QPM:PackageReleaseNotes> |
︙ | ︙ | |||
59 60 61 62 63 64 65 | <QPM:ProductDescriptionShort>A massively spiffy yet delicately unobtrusive compression library.</QPM:ProductDescriptionShort> <QPM:ProductDescriptionLong>zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system.</QPM:ProductDescriptionLong> <QPM:ProductDescriptionURL>http://www.gzip.org/zlib</QPM:ProductDescriptionURL> <QPM:ProductDescriptionEmbedURL></QPM:ProductDescriptionEmbedURL> </QPM:ProductDescription> <QPM:ReleaseDescription> | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | <QPM:ProductDescriptionShort>A massively spiffy yet delicately unobtrusive compression library.</QPM:ProductDescriptionShort> <QPM:ProductDescriptionLong>zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system.</QPM:ProductDescriptionLong> <QPM:ProductDescriptionURL>http://www.gzip.org/zlib</QPM:ProductDescriptionURL> <QPM:ProductDescriptionEmbedURL></QPM:ProductDescriptionEmbedURL> </QPM:ProductDescription> <QPM:ReleaseDescription> <QPM:ReleaseVersion>1.2.11</QPM:ReleaseVersion> <QPM:ReleaseUrgency>Medium</QPM:ReleaseUrgency> <QPM:ReleaseStability>Stable</QPM:ReleaseStability> <QPM:ReleaseNoteMinor></QPM:ReleaseNoteMinor> <QPM:ReleaseNoteMajor></QPM:ReleaseNoteMajor> <QPM:ExcludeCountries> <QPM:Country></QPM:Country> </QPM:ExcludeCountries> |
︙ | ︙ |
Changes to compat/zlib/test/example.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 | static z_const char hello[] = "hello, hello!"; /* "hello world" would be more standard, but the repeated "hello" * stresses the compression code better, sorry... */ static const char dictionary[] = "hello"; static uLong dictId; /* Adler32 value of the dictionary */ #ifdef Z_SOLO | > > > > > > > > > > > > > > > > > > > | > > > | > > > > > > | | > > | 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 | static z_const char hello[] = "hello, hello!"; /* "hello world" would be more standard, but the repeated "hello" * stresses the compression code better, sorry... */ static const char dictionary[] = "hello"; static uLong dictId; /* Adler32 value of the dictionary */ void test_deflate OF((Byte *compr, uLong comprLen)); void test_inflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_large_deflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_large_inflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_flush OF((Byte *compr, uLong *comprLen)); void test_sync OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_dict_deflate OF((Byte *compr, uLong comprLen)); void test_dict_inflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); int main OF((int argc, char *argv[])); #ifdef Z_SOLO void *myalloc OF((void *, unsigned, unsigned)); void myfree OF((void *, void *)); void *myalloc(q, n, m) void *q; unsigned n, m; { (void)q; return calloc(n, m); } void myfree(void *q, void *p) { (void)q; free(p); } static alloc_func zalloc = myalloc; static free_func zfree = myfree; #else /* !Z_SOLO */ static alloc_func zalloc = (alloc_func)0; static free_func zfree = (free_func)0; void test_compress OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_gzio OF((const char *fname, Byte *uncompr, uLong uncomprLen)); /* =========================================================================== * Test compress() and uncompress() */ void test_compress(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; uLong len = (uLong)strlen(hello)+1; err = compress(compr, &comprLen, (const Bytef*)hello, len); CHECK_ERR(err, "compress"); strcpy((char*)uncompr, "garbage"); |
︙ | ︙ | |||
77 78 79 80 81 82 83 | printf("uncompress(): %s\n", (char *)uncompr); } } /* =========================================================================== * Test read/write of .gz files */ | > > > | > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | printf("uncompress(): %s\n", (char *)uncompr); } } /* =========================================================================== * Test read/write of .gz files */ void test_gzio(fname, uncompr, uncomprLen) const char *fname; /* compressed file name */ Byte *uncompr; uLong uncomprLen; { #ifdef NO_GZCOMPRESS fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); #else int err; int len = (int)strlen(hello)+1; gzFile file; z_off_t pos; |
︙ | ︙ | |||
159 160 161 162 163 164 165 | } #endif /* Z_SOLO */ /* =========================================================================== * Test deflate() with small buffers */ | | > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | } #endif /* Z_SOLO */ /* =========================================================================== * Test deflate() with small buffers */ void test_deflate(compr, comprLen) Byte *compr; uLong comprLen; { z_stream c_stream; /* compression stream */ int err; uLong len = (uLong)strlen(hello)+1; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; |
︙ | ︙ | |||
194 195 196 197 198 199 200 | err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with small buffers */ | | | > > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with small buffers */ void test_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; |
︙ | ︙ | |||
233 234 235 236 237 238 239 | printf("inflate(): %s\n", (char *)uncompr); } } /* =========================================================================== * Test deflate() with large buffers and dynamic change of compression level */ | | | > > | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | printf("inflate(): %s\n", (char *)uncompr); } } /* =========================================================================== * Test deflate() with large buffers and dynamic change of compression level */ void test_large_deflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { z_stream c_stream; /* compression stream */ int err; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; |
︙ | ︙ | |||
263 264 265 266 267 268 269 | fprintf(stderr, "deflate not greedy\n"); exit(1); } /* Feed in already compressed data and switch to no compression: */ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); c_stream.next_in = compr; | | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | fprintf(stderr, "deflate not greedy\n"); exit(1); } /* Feed in already compressed data and switch to no compression: */ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); c_stream.next_in = compr; c_stream.avail_in = (uInt)comprLen/2; err = deflate(&c_stream, Z_NO_FLUSH); CHECK_ERR(err, "deflate"); /* Switch back to compressing mode: */ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); c_stream.next_in = uncompr; c_stream.avail_in = (uInt)uncomprLen; |
︙ | ︙ | |||
286 287 288 289 290 291 292 | err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with large buffers */ | | | > > | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with large buffers */ void test_large_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; |
︙ | ︙ | |||
314 315 316 317 318 319 320 | if (err == Z_STREAM_END) break; CHECK_ERR(err, "large inflate"); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); | | > > | > | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | if (err == Z_STREAM_END) break; CHECK_ERR(err, "large inflate"); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); if (d_stream.total_out != 2*uncomprLen + comprLen/2) { fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); exit(1); } else { printf("large_inflate(): OK\n"); } } /* =========================================================================== * Test deflate() with full flush */ void test_flush(compr, comprLen) Byte *compr; uLong *comprLen; { z_stream c_stream; /* compression stream */ int err; uInt len = (uInt)strlen(hello)+1; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; |
︙ | ︙ | |||
360 361 362 363 364 365 366 | *comprLen = c_stream.total_out; } /* =========================================================================== * Test inflateSync() */ | > | | > | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | *comprLen = c_stream.total_out; } /* =========================================================================== * Test inflateSync() */ void test_sync(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; |
︙ | ︙ | |||
388 389 390 391 392 393 394 | CHECK_ERR(err, "inflate"); d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ err = inflateSync(&d_stream); /* but skip the damaged part */ CHECK_ERR(err, "inflateSync"); err = inflate(&d_stream, Z_FINISH); | | | > | > > > | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | CHECK_ERR(err, "inflate"); d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ err = inflateSync(&d_stream); /* but skip the damaged part */ CHECK_ERR(err, "inflateSync"); err = inflate(&d_stream, Z_FINISH); if (err != Z_DATA_ERROR) { fprintf(stderr, "inflate should report DATA_ERROR\n"); /* Because of incorrect adler32 */ exit(1); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); printf("after inflateSync(): hel%s\n", (char *)uncompr); } /* =========================================================================== * Test deflate() with preset dictionary */ void test_dict_deflate(compr, comprLen) Byte *compr; uLong comprLen; { z_stream c_stream; /* compression stream */ int err; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; |
︙ | ︙ | |||
435 436 437 438 439 440 441 | err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with a preset dictionary */ | | | > > | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with a preset dictionary */ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; |
︙ | ︙ | |||
484 485 486 487 488 489 490 | } } /* =========================================================================== * Usage: example [output.gz [input.gz]] */ | > > | > > | < | < | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | } } /* =========================================================================== * Usage: example [output.gz [input.gz]] */ int main(argc, argv) int argc; char *argv[]; { Byte *compr, *uncompr; uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ uLong uncomprLen = comprLen; static const char* myVersion = ZLIB_VERSION; if (zlibVersion()[0] != myVersion[0]) { fprintf(stderr, "incompatible zlib version\n"); exit(1); } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { fprintf(stderr, "warning: different zlib version\n"); } printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); compr = (Byte*)calloc((uInt)comprLen, 1); uncompr = (Byte*)calloc((uInt)uncomprLen, 1); |
︙ | ︙ | |||
530 531 532 533 534 535 536 | test_inflate(compr, comprLen, uncompr, uncomprLen); test_large_deflate(compr, comprLen, uncompr, uncomprLen); test_large_inflate(compr, comprLen, uncompr, uncomprLen); test_flush(compr, &comprLen); test_sync(compr, comprLen, uncompr, uncomprLen); | | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | test_inflate(compr, comprLen, uncompr, uncomprLen); test_large_deflate(compr, comprLen, uncompr, uncomprLen); test_large_inflate(compr, comprLen, uncompr, uncomprLen); test_flush(compr, &comprLen); test_sync(compr, comprLen, uncompr, uncomprLen); comprLen = uncomprLen; test_dict_deflate(compr, comprLen); test_dict_inflate(compr, comprLen, uncompr, uncomprLen); free(compr); free(uncompr); return 0; } |
Changes to compat/zlib/test/infcover.c.
︙ | ︙ | |||
369 370 371 372 373 374 375 | inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK); inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END); inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR); mem_setup(&strm); strm.avail_in = 0; strm.next_in = Z_NULL; | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK); inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END); inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR); mem_setup(&strm); strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream)); assert(ret == Z_VERSION_ERROR); mem_done(&strm, "wrong version"); strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit(&strm); assert(ret == Z_OK); ret = inflateEnd(&strm); assert(ret == Z_OK); |
︙ | ︙ | |||
458 459 460 461 462 463 464 | if (state != Z_NULL) state->mode = SYNC; /* force an otherwise impossible situation */ return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0; } local int push(void *desc, unsigned char *buf, unsigned len) { | < | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | if (state != Z_NULL) state->mode = SYNC; /* force an otherwise impossible situation */ return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0; } local int push(void *desc, unsigned char *buf, unsigned len) { buf += len; return desc != Z_NULL; /* force error if desc not null */ } /* cover inflateBack() up to common deflate data cases and after those */ local void cover_back(void) { int ret; |
︙ | ︙ |
Changes to compat/zlib/test/minigzip.c.
︙ | ︙ | |||
55 56 57 58 59 60 61 | #endif #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include <unix.h> /* for fileno */ #endif #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | #endif #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include <unix.h> /* for fileno */ #endif #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ extern int unlink OF((const char *)); #endif #endif #if defined(UNDER_CE) # include <windows.h> # define perror(s) pwinerror(s) |
︙ | ︙ | |||
145 146 147 148 149 150 151 | #ifdef Z_SOLO /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) # include <unistd.h> /* for unlink() */ #endif | > > > | > > > | > > > > > > > | > > > > > > > > > > > > > > > > > | 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 | #ifdef Z_SOLO /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) # include <unistd.h> /* for unlink() */ #endif void *myalloc OF((void *, unsigned, unsigned)); void myfree OF((void *, void *)); void *myalloc(q, n, m) void *q; unsigned n, m; { (void)q; return calloc(n, m); } void myfree(q, p) void *q, *p; { (void)q; free(p); } typedef struct gzFile_s { FILE *file; int write; int err; char *msg; z_stream strm; } *gzFile; gzFile gzopen OF((const char *, const char *)); gzFile gzdopen OF((int, const char *)); gzFile gz_open OF((const char *, int, const char *)); gzFile gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } gzFile gzdopen(fd, mode) int fd; const char *mode; { return gz_open(NULL, fd, mode); } gzFile gz_open(path, fd, mode) const char *path; int fd; const char *mode; { gzFile gz; int ret; gz = malloc(sizeof(struct gzFile_s)); if (gz == NULL) return NULL; gz->write = strchr(mode, 'w') != NULL; |
︙ | ︙ | |||
197 198 199 200 201 202 203 | return NULL; } gz->err = 0; gz->msg = ""; return gz; } | | < | | | > | < | < > > > > > | > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | return NULL; } gz->err = 0; gz->msg = ""; return gz; } int gzwrite OF((gzFile, const void *, unsigned)); int gzwrite(gz, buf, len) gzFile gz; const void *buf; unsigned len; { z_stream *strm; unsigned char out[BUFLEN]; if (gz == NULL || !gz->write) return 0; strm = &(gz->strm); strm->next_in = (void *)buf; strm->avail_in = len; do { strm->next_out = out; strm->avail_out = BUFLEN; (void)deflate(strm, Z_NO_FLUSH); fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); } while (strm->avail_out == 0); return len; } int gzread OF((gzFile, void *, unsigned)); int gzread(gz, buf, len) gzFile gz; void *buf; unsigned len; { int ret; unsigned got; unsigned char in[1]; z_stream *strm; if (gz == NULL || gz->write) return 0; |
︙ | ︙ | |||
254 255 256 257 258 259 260 | } if (ret == Z_STREAM_END) inflateReset(strm); } while (strm->avail_out); return len - strm->avail_out; } | > > | > > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | } if (ret == Z_STREAM_END) inflateReset(strm); } while (strm->avail_out); return len - strm->avail_out; } int gzclose OF((gzFile)); int gzclose(gz) gzFile gz; { z_stream *strm; unsigned char out[BUFLEN]; if (gz == NULL) return Z_STREAM_ERROR; strm = &(gz->strm); if (gz->write) { |
︙ | ︙ | |||
279 280 281 282 283 284 285 | else inflateEnd(strm); fclose(gz->file); free(gz); return Z_OK; } | > > | > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | else inflateEnd(strm); fclose(gz->file); free(gz); return Z_OK; } const char *gzerror OF((gzFile, int *)); const char *gzerror(gz, err) gzFile gz; int *err; { *err = gz->err; return gz->msg; } #endif static char *prog; void error OF((const char *msg)); void gz_compress OF((FILE *in, gzFile out)); #ifdef USE_MMAP int gz_compress_mmap OF((FILE *in, gzFile out)); #endif void gz_uncompress OF((gzFile in, FILE *out)); void file_compress OF((char *file, char *mode)); void file_uncompress OF((char *file)); int main OF((int argc, char *argv[])); /* =========================================================================== * Display error message and exit */ void error(msg) const char *msg; { fprintf(stderr, "%s: %s\n", prog, msg); exit(1); } /* =========================================================================== * Compress input to output then close both files. */ void gz_compress(in, out) FILE *in; gzFile out; { local char buf[BUFLEN]; int len; int err; #ifdef USE_MMAP /* Try first compressing with mmap. If mmap fails (minigzip used in a * pipe), use the normal fread loop. */ if (gz_compress_mmap(in, out) == Z_OK) return; #endif for (;;) { len = (int)fread(buf, 1, sizeof(buf), in); if (ferror(in)) { perror("fread"); exit(1); } if (len == 0) break; if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); } fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); } #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ /* Try compressing the input file at once using mmap. Return Z_OK if * if success, Z_ERRNO otherwise. */ int gz_compress_mmap(in, out) FILE *in; gzFile out; { int len; int err; int ifd = fileno(in); caddr_t buf; /* mmap'ed buffer for the entire input file */ off_t buf_len; /* length of the input file */ struct stat sb; |
︙ | ︙ | |||
330 331 332 333 334 335 336 337 | munmap(buf, buf_len); fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); return Z_OK; } #endif /* USE_MMAP */ /* =========================================================================== | | | < < < < | < < < < < < < < < < < < < | < < < < < | < < < < | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | munmap(buf, buf_len); fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); return Z_OK; } #endif /* USE_MMAP */ /* =========================================================================== * Uncompress input to output then close both files. */ void gz_uncompress(in, out) gzFile in; FILE *out; { local char buf[BUFLEN]; int len; int err; for (;;) { len = gzread(in, buf, sizeof(buf)); if (len < 0) error (gzerror(in, &err)); |
︙ | ︙ | |||
386 387 388 389 390 391 392 | } /* =========================================================================== * Compress the given file: create a corresponding .gz file and remove the * original. */ | | > > > | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | } /* =========================================================================== * Compress the given file: create a corresponding .gz file and remove the * original. */ void file_compress(file, mode) char *file; char *mode; { local char outfile[MAX_NAME_LEN]; FILE *in; gzFile out; if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { fprintf(stderr, "%s: filename too long\n", prog); exit(1); |
︙ | ︙ | |||
422 423 424 425 426 427 428 | unlink(file); } /* =========================================================================== * Uncompress the given file and remove the original. */ | | > > | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | unlink(file); } /* =========================================================================== * Uncompress the given file and remove the original. */ void file_uncompress(file) char *file; { local char buf[MAX_NAME_LEN]; char *infile, *outfile; FILE *out; gzFile in; unsigned len = strlen(file); if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { fprintf(stderr, "%s: filename too long\n", prog); exit(1); } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) |
︙ | ︙ | |||
480 481 482 483 484 485 486 | * -d : decompress * -f : compress with Z_FILTERED * -h : compress with Z_HUFFMAN_ONLY * -r : compress with Z_RLE * -1 to -9 : compression level */ | > > | > | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | * -d : decompress * -f : compress with Z_FILTERED * -h : compress with Z_HUFFMAN_ONLY * -r : compress with Z_RLE * -1 to -9 : compression level */ int main(argc, argv) int argc; char *argv[]; { int copyout = 0; int uncompr = 0; gzFile file; char *bname, outmode[20]; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(outmode, sizeof(outmode), "%s", "wb6 "); |
︙ | ︙ |
Changes to compat/zlib/treebuild.xml.
1 | <?xml version="1.0" ?> | | | | 1 2 3 4 5 6 7 8 9 10 | <?xml version="1.0" ?> <package name="zlib" version="1.2.11"> <library name="zlib" dlversion="1.2.11" dlname="z"> <property name="description"> zip compression library </property> <property name="include-target-dir" value="$(@PACKAGE/install-includedir)" /> <!-- fixme: not implemented yet --> <property name="compiler/c/inline" value="yes" /> <include-file name="zlib.h" scope="public" mode="644" /> |
︙ | ︙ |
Changes to compat/zlib/trees.c.
1 | /* trees.c -- output deflated data using Huffman coding | | | 1 2 3 4 5 6 7 8 9 | /* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2017 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * |
︙ | ︙ | |||
118 119 120 121 122 123 124 | const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; | < < < < < | < | | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < < | < < < < < < | < | < < < < | < < < < < < < < < < < < | | < > > | > | > | < | < < < < > | > > > > > > > > > > > | > > > > | | 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 | const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local const static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local const static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local const static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; |
︙ | ︙ | |||
287 288 289 290 291 292 293 | /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ | | > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ |
︙ | ︙ | |||
313 314 315 316 317 318 319 | static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; | | | | | | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1<<extra_lbits[code]); n++) { _length_code[length++] = (uch)code; } } Assert (length == 256, "tr_static_init: length != 256"); /* Note that the length 255 (match length 258) can be represented * in two different ways: code 284 + 5 bits or code 285, so we * overwrite length_code[255] to use the best encoding: */ _length_code[length-1] = (uch)code; /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<<extra_dbits[code]); n++) { _dist_code[dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: dist != 256"); dist >>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; |
︙ | ︙ | |||
369 370 371 372 373 374 375 | # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== | | | | > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG # include <stdio.h> # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); |
︙ | ︙ | |||
429 430 431 432 433 434 435 | SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ | < < < < < < < < < < < < < < < < | > > | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(s) deflate_state *s; { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; |
︙ | ︙ | |||
470 471 472 473 474 475 476 477 478 479 480 481 482 483 | s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with | > > > > > > > > > > > > > > > > > > | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with |
︙ | ︙ | |||
500 501 502 503 504 505 506 | /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ | | > > > > | | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; |
︙ | ︙ | |||
531 532 533 534 535 536 537 | * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ | | > > > | | | | | | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); |
︙ | ︙ | |||
606 607 608 609 610 611 612 | tree[m].Len = (ush)bits; } n--; } } } | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | > > > > > | > > > > | > > > | | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes (tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ unsigned code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { code = (code + bl_count[bits-1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, "inconsistent bit counts"); Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); for (n = 0; n <= max_code; n++) { int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ tree[n].Code = (ush)bi_reverse(next_code[len]++, len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); } } /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. * Update the total bit length for the current block. * IN assertion: the field freq is set for all tree elements. * OUT assertions: the fields len and code are set to the optimal bit length * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ local void build_tree(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; |
︙ | ︙ | |||
655 656 657 658 659 660 661 | tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ |
︙ | ︙ | |||
703 704 705 706 707 708 709 | gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ | | > > > > | | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; |
︙ | ︙ | |||
744 745 746 747 748 749 750 | } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ | | > > > > | | | | | | > > | | | | > | > | | | | | | > > | > > | < | | | > > | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | > > | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 | } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); s->pending += stored_len; #ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; s->bits_sent += stored_len<<3; #endif } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void ZLIB_INTERNAL _tr_flush_bits(s) deflate_state *s; { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s; { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ |
︙ | ︙ | |||
1018 1019 1020 1021 1022 1023 1024 | /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ | | | | < | < < | > | > > > | | | | | | | | > > > | | < < < < < | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 | /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally (s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(s, ltree, dtree) deflate_state *s; const ct_data *ltree; /* literal tree */ const ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= (unsigned)base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(s) deflate_state *s; { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(s) deflate_state *s; { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } |
Changes to compat/zlib/uncompr.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | first unused input byte. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ | > > > | | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | first unused input byte. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong *sourceLen; { z_stream stream; int err; const uInt max = (uInt)-1; uLong len, left; Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ len = *sourceLen; |
︙ | ︙ | |||
75 76 77 78 79 80 81 | inflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : err; } | > > > | | > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | inflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : err; } int ZEXPORT uncompress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return uncompress2(dest, destLen, source, &sourceLen); } |
Changes to compat/zlib/win32/DLL_FAQ.txt.
1 2 3 4 5 | Frequently Asked Questions about ZLIB1.DLL This document describes the design, the rationale, and the usage | | | > > > > | 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 | Frequently Asked Questions about ZLIB1.DLL This document describes the design, the rationale, and the usage of the official DLL build of zlib, named ZLIB1.DLL. If you have general questions about zlib, you should see the file "FAQ" found in the zlib distribution, or at the following location: http://www.gzip.org/zlib/zlib_faq.html 1. What is ZLIB1.DLL, and how can I get it? - ZLIB1.DLL is the official build of zlib as a DLL. (Please remark the character '1' in the name.) Pointers to a precompiled ZLIB1.DLL can be found in the zlib web site at: http://www.zlib.net/ Applications that link to ZLIB1.DLL can rely on the following specification: * The exported symbols are exclusively defined in the source files "zlib.h" and "zlib.def", found in an official zlib source distribution. |
︙ | ︙ | |||
371 372 373 374 375 376 377 378 379 380 381 | macros like NO_GZCOMPRESS or NO_GZIP at compile time? - No. A legitimate build of ZLIB1.DLL must provide the complete zlib functionality, as implemented in the official zlib source code. But you can make your own private DLL build, under a different file name, as suggested in the previous answer. ** This document is written and maintained by Cosmin Truta <cosmint@cs.ubbcluj.ro> | > > > > > > > > > > > > | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | macros like NO_GZCOMPRESS or NO_GZIP at compile time? - No. A legitimate build of ZLIB1.DLL must provide the complete zlib functionality, as implemented in the official zlib source code. But you can make your own private DLL build, under a different file name, as suggested in the previous answer. 17. I made my own ZLIB1.DLL build. Can I test it for compliance? - We prefer that you download the official DLL from the zlib web site. If you need something peculiar from this DLL, you can send your suggestion to the zlib mailing list. However, in case you do rebuild the DLL yourself, you can run it with the test programs found in the DLL distribution. Running these test programs is not a guarantee of compliance, but a failure can imply a detected problem. ** This document is written and maintained by Cosmin Truta <cosmint@cs.ubbcluj.ro> |
Changes to compat/zlib/win32/Makefile.bor.
1 2 3 4 5 6 7 8 9 10 11 12 | # Makefile for zlib # Borland C++ for Win32 # # Usage: # make -f win32/Makefile.bor # ------------ Borland C++ ------------ # Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) # should be added to the environment via "set LOCAL_ZLIB=-DFOO" or # added to the declaration of LOC here: LOC = $(LOCAL_ZLIB) | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # Makefile for zlib # Borland C++ for Win32 # # Usage: # make -f win32/Makefile.bor # make -f win32/Makefile.bor LOCAL_ZLIB=-DASMV OBJA=match.obj OBJPA=+match.obj # ------------ Borland C++ ------------ # Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) # should be added to the environment via "set LOCAL_ZLIB=-DFOO" or # added to the declaration of LOC here: LOC = $(LOCAL_ZLIB) |
︙ | ︙ |
Changes to compat/zlib/win32/Makefile.gcc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Makefile for zlib, derived from Makefile.dj2. # Modified for mingw32 by C. Spieler, 6/16/98. # Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003. # Last updated: Mar 2012. # Tested under Cygwin and MinGW. # Copyright (C) 1995-2003 Jean-loup Gailly. # For conditions of distribution and use, see copyright notice in zlib.h # To compile, or to compile and test, type from the top level zlib directory: # # make -fwin32/Makefile.gcc; make test testdll -fwin32/Makefile.gcc # # To install libz.a, zconf.h and zlib.h in the system directories, type: # # make install -fwin32/Makefile.gcc # # BINARY_PATH, INCLUDE_PATH and LIBRARY_PATH must be set. # # To install the shared lib, append SHARED_MODE=1 to the make command : | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Makefile for zlib, derived from Makefile.dj2. # Modified for mingw32 by C. Spieler, 6/16/98. # Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003. # Last updated: Mar 2012. # Tested under Cygwin and MinGW. # Copyright (C) 1995-2003 Jean-loup Gailly. # For conditions of distribution and use, see copyright notice in zlib.h # To compile, or to compile and test, type from the top level zlib directory: # # make -fwin32/Makefile.gcc; make test testdll -fwin32/Makefile.gcc # # To use the asm code, type: # cp contrib/asm?86/match.S ./match.S # make LOC=-DASMV OBJA=match.o -fwin32/Makefile.gcc # # To install libz.a, zconf.h and zlib.h in the system directories, type: # # make install -fwin32/Makefile.gcc # # BINARY_PATH, INCLUDE_PATH and LIBRARY_PATH must be set. # # To install the shared lib, append SHARED_MODE=1 to the make command : |
︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 | IMPLIB = libz.dll.a # # Set to 1 if shared object needs to be installed # SHARED_MODE=0 #LOC = -DZLIB_DEBUG -g PREFIX = CC = $(PREFIX)gcc CFLAGS = $(LOC) -O3 -Wall AS = $(CC) | > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | IMPLIB = libz.dll.a # # Set to 1 if shared object needs to be installed # SHARED_MODE=0 #LOC = -DASMV #LOC = -DZLIB_DEBUG -g PREFIX = CC = $(PREFIX)gcc CFLAGS = $(LOC) -O3 -Wall AS = $(CC) |
︙ | ︙ |
Changes to compat/zlib/win32/Makefile.msc.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # Makefile for zlib using Microsoft (Visual) C # zlib is copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler # # Usage: # nmake -f win32/Makefile.msc (standard build) # nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) # The toplevel directory of the source tree. # TOP = . # optional build flags LOC = | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Makefile for zlib using Microsoft (Visual) C # zlib is copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler # # Usage: # nmake -f win32/Makefile.msc (standard build) # nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) # nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" \ # OBJA="inffas32.obj match686.obj" (use ASM code, x86) # nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." \ # OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" (use ASM code, x64) # The toplevel directory of the source tree. # TOP = . # optional build flags LOC = |
︙ | ︙ |
Changes to compat/zlib/win32/README-WIN32.txt.
1 2 | ZLIB DATA COMPRESSION LIBRARY | | | | | | 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 | ZLIB DATA COMPRESSION LIBRARY zlib 1.2.11 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). Two compiled examples are distributed in this package, example and minigzip. The example_d and minigzip_d flavors validate that the zlib1.dll file is working correctly. Questions about zlib should be sent to <zlib@gzip.org>. The zlib home page is http://zlib.net/ . Before reporting a problem, please check this site to verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read DLL_FAQ.txt, and the the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Manifest: The package zlib-1.2.11-win32-x86.zip will contain the following files: README-WIN32.txt This document ChangeLog Changes since previous zlib packages DLL_FAQ.txt Frequently asked questions about zlib1.dll zlib.3.pdf Documentation of this library in Adobe Acrobat format example.exe A statically-bound example (using zlib.lib, not the dll) |
︙ | ︙ |
Changes to compat/zlib/win32/zlib.def.
︙ | ︙ | |||
65 66 67 68 69 70 71 | ; large file functions gzopen64 gzseek64 gztell64 gzoffset64 adler32_combine64 crc32_combine64 | < < < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | ; large file functions gzopen64 gzseek64 gztell64 gzoffset64 adler32_combine64 crc32_combine64 ; checksum functions adler32 adler32_z crc32 crc32_z adler32_combine crc32_combine ; various hacks, don't look :) deflateInit_ deflateInit2_ inflateInit_ inflateInit2_ inflateBackInit_ gzgetc_ |
︙ | ︙ |
Changes to compat/zlib/win32/zlib1.rc.
︙ | ︙ | |||
22 23 24 25 26 27 28 | BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression library\0" VALUE "FileVersion", ZLIB_VERSION "\0" VALUE "InternalName", "zlib1.dll\0" | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "zlib data compression library\0" VALUE "FileVersion", ZLIB_VERSION "\0" VALUE "InternalName", "zlib1.dll\0" VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" VALUE "OriginalFilename", "zlib1.dll\0" VALUE "ProductName", "zlib\0" VALUE "ProductVersion", ZLIB_VERSION "\0" VALUE "Comments", "For more information visit http://www.zlib.net/\0" END END BLOCK "VarFileInfo" |
︙ | ︙ |
Changes to compat/zlib/zconf.h.
1 | /* zconf.h -- configuration of the zlib compression library | | | 1 2 3 4 5 6 7 8 9 | /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H |
︙ | ︙ | |||
34 35 36 37 38 39 40 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 | < < < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit |
︙ | ︙ | |||
237 238 239 240 241 242 243 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO | < < < | < | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO typedef unsigned long z_size_t; #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include <stddef.h> typedef size_t z_size_t; |
︙ | ︙ | |||
295 296 297 298 299 300 301 302 303 304 305 306 307 308 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ | > > > > > > > > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ |
︙ | ︙ | |||
344 345 346 347 348 349 350 | * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif | < < < | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include <windows.h> /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else |
︙ | ︙ | |||
465 466 467 468 469 470 471 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif | | < | < < < < < < | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif |
︙ | ︙ | |||
512 513 514 515 516 517 518 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else | | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ |
︙ | ︙ |
Changes to compat/zlib/zconf.h.cmakein.
1 | /* zconf.h -- configuration of the zlib compression library | | | 1 2 3 4 5 6 7 8 9 | /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H |
︙ | ︙ | |||
36 37 38 39 40 41 42 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 | < < < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit |
︙ | ︙ | |||
239 240 241 242 243 244 245 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO | < < < | < | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO typedef unsigned long z_size_t; #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include <stddef.h> typedef size_t z_size_t; |
︙ | ︙ | |||
297 298 299 300 301 302 303 304 305 306 307 308 309 310 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ | > > > > > > > > | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ |
︙ | ︙ | |||
346 347 348 349 350 351 352 | * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif | < < < | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include <windows.h> /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else |
︙ | ︙ | |||
467 468 469 470 471 472 473 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif | | < | < < < < < < | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif |
︙ | ︙ | |||
514 515 516 517 518 519 520 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else | | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ |
︙ | ︙ |
Changes to compat/zlib/zconf.h.in.
1 | /* zconf.h -- configuration of the zlib compression library | | | 1 2 3 4 5 6 7 8 9 | /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H |
︙ | ︙ | |||
34 35 36 37 38 39 40 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 | < < < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit |
︙ | ︙ | |||
237 238 239 240 241 242 243 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO | < < < | < | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO typedef unsigned long z_size_t; #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include <stddef.h> typedef size_t z_size_t; |
︙ | ︙ | |||
295 296 297 298 299 300 301 302 303 304 305 306 307 308 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ | > > > > > > > > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ |
︙ | ︙ | |||
344 345 346 347 348 349 350 | * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif | < < < | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include <windows.h> /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else |
︙ | ︙ | |||
465 466 467 468 469 470 471 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif | | < | < < < < < < | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif |
︙ | ︙ | |||
512 513 514 515 516 517 518 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else | | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ |
︙ | ︙ |
Changes to compat/zlib/zlib.3.
|
| | | 1 2 3 4 5 6 7 8 | .TH ZLIB 3 "15 Jan 2017" .SH NAME zlib \- compression/decompression library .SH SYNOPSIS [see .I zlib.h for full description] .SH DESCRIPTION |
︙ | ︙ | |||
101 102 103 104 105 106 107 | .IP http://zlib.net/zlib_faq.html .LP before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS AND LICENSE | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | .IP http://zlib.net/zlib_faq.html .LP before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS AND LICENSE Version 1.2.11 .LP Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler .LP This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. .LP Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it |
︙ | ︙ |
Changes to compat/zlib/zlib.3.pdf.
cannot compute difference between binary files
Changes to compat/zlib/zlib.h.
1 | /* zlib.h -- interface of the 'zlib' general purpose compression library | | | | 1 2 3 4 5 6 7 8 9 10 11 | /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.11, January 15th, 2017 Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it |
︙ | ︙ | |||
33 34 35 36 37 38 39 | #include "zconf.h" #ifdef __cplusplus extern "C" { #endif | | | | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.11" #define ZLIB_VERNUM 0x12b0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 11 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream |
︙ | ︙ | |||
74 75 76 77 78 79 80 | directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. */ | | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ |
︙ | ︙ | |||
213 214 215 216 217 218 219 | #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ | | | | | | 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 256 257 | #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the |
︙ | ︙ | |||
272 273 274 275 276 277 278 | one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), which can be used if desired to determine whether or not there is more ouput in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is |
︙ | ︙ | |||
316 317 318 319 320 321 322 | random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that | | | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations |
︙ | ︙ | |||
356 357 358 359 360 361 362 | by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ | | | | < | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. In the current version of inflate, the provided input is not read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression. Actual decompression will be done by inflate(). So next_in, and avail_in, next_out, and avail_out are unused and unchanged. The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the |
︙ | ︙ | |||
514 515 516 517 518 519 520 | inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ | | | | | | | | | > | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state was inconsistent. */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better |
︙ | ︙ | |||
604 605 606 607 608 609 610 | memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ | | | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been |
︙ | ︙ | |||
648 649 650 651 652 653 654 | deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | < | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up to 258 bytes less in that case, due to how zlib's implementation of deflate manages the sliding window and lookahead for matches, where matches can be up to 258 bytes long. If the application needs the last window-size bytes of input, then that would need to be saved by the application outside of zlib. deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been set unchanged. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the strategy is changed, and if any input has been consumed in a previous deflate() call, then the input available so far is compressed with the old level and strategy using deflate(strm, Z_BLOCK). There are three approaches for the compression levels 0, 1..3, and 4..9 respectively. The new level and strategy will take effect at the next call of deflate(). If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not take effect. In this case, deflateParams() can be called again with the same parameters and more output space to try again. In order to assure a change in the parameters on the first try, the deflate stream should be flushed using deflate() with Z_BLOCK or other flush request until strm.avail_out is not zero, before calling deflateParams(). Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be applied to the the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach. Note that in the case of a Z_BUF_ERROR, the parameters are not changed. A return value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be retried with more output space. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, unsigned *pending, int *bits)); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for |
︙ | ︙ | |||
863 864 865 866 867 868 869 | above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see | | | | < < | | | | | | | | | | | | | | | < | | | | | | | 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 | above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see below), inflate() will not automatically decode concatenated gzip streams. inflate() will return Z_STREAM_END at the end of the gzip stream. The state would need to be reset to continue decoding a subsequent gzip stream. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. If the window size is changed, then the memory allocated for the window is freed, and the window will be reallocated by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of |
︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 | location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ | | | | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 | retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* | | | | | | | | | | 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 | retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output |
︙ | ︙ | |||
1164 1165 1166 1167 1168 1169 1170 | using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ | | | | 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ | | | | | | | | | | | | < | | | | | | | > | 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress() is equivalent to compress2() with a level parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen)); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of source bytes consumed. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. |
︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 | gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ | | | | | | | | | | | | | | | | | | | | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Three times that size in buffer space is allocated. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. Previously provided data is flushed before the parameter change. gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not opened for writing, Z_ERRNO if there is an error writing the flushed data, or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, |
︙ | ︙ | |||
1418 1419 1420 1421 1422 1423 1424 | gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. If len is too large to fit in an int, then nothing is read, -1 is returned, and the error state is set to Z_STREAM_ERROR. */ | | | | | | | | | | | > | | > | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | < | | | | | | < < | < < < < < < < < < < < < | | | | | | | | | | | | | | | 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. If len is too large to fit in an int, then nothing is read, -1 is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, gzFile file)); /* Read up to nitems items of size size from file to buf, otherwise operating as gzread() does. This duplicates the interface of stdio's fread(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfread() returns the number of full items read of size size, or zero if the end of the file was reached and a full item could not be read, or if there was an error. gzerror() must be consulted if zero is returned in order to determine if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is read, zero is returned, and the error state is set to Z_STREAM_ERROR. In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a multiple of size, then the final partial item is nevetheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written file, reseting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, z_size_t nitems, gzFile file)); /* gzfwrite() writes nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfwrite() returns the number of full items written of size size, or zero if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is written, zero is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or a negative zlib error code in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as adler32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as crc32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ |
︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 | * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; | | | | | | | < | < < | | | | | < | | | | | | < | | < | | | | | | | | | | | | | | | | 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 | * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* !Z_SOLO */ /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, const char *format, va_list va)); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ |
Changes to compat/zlib/zlib.map.
︙ | ︙ | |||
88 89 90 91 92 93 94 | uncompress2; gzfread; gzfwrite; deflateGetDictionary; adler32_z; crc32_z; } ZLIB_1.2.7.1; | < < < < < < | 88 89 90 91 92 93 94 | uncompress2; gzfread; gzfwrite; deflateGetDictionary; adler32_z; crc32_z; } ZLIB_1.2.7.1; |
Added compat/zlib/zlib2ansi.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/perl # Transform K&R C function definitions into ANSI equivalent. # # Author: Paul Marquess # Version: 1.0 # Date: 3 October 2006 # TODO # # Asumes no function pointer parameters. unless they are typedefed. # Assumes no literal strings that look like function definitions # Assumes functions start at the beginning of a line use strict; use warnings; local $/; $_ = <>; my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments my $d1 = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ; my $decl = qr{ $sp (?: \w+ $sp )+ $d1 }xo ; my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ; while (s/^ ( # Start $1 ( # Start $2 .*? # Minimal eat content ( ^ \w [\w\s\*]+ ) # $3 -- function name \s* # optional whitespace ) # $2 - Matched up to before parameter list \( \s* # Literal "(" + optional whitespace ( [^\)]+ ) # $4 - one or more anythings except ")" \s* \) # optional whitespace surrounding a Literal ")" ( (?: $dList )+ ) # $5 $sp ^ { # literal "{" at start of line ) # Remember to $1 //xsom ) { my $all = $1 ; my $prefix = $2; my $param_list = $4 ; my $params = $5; StripComments($params); StripComments($param_list); $param_list =~ s/^\s+//; $param_list =~ s/\s+$//; my $i = 0 ; my %pList = map { $_ => $i++ } split /\s*,\s*/, $param_list; my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ; my @params = split /\s*;\s*/, $params; my @outParams = (); foreach my $p (@params) { if ($p =~ /,/) { my @bits = split /\s*,\s*/, $p; my $first = shift @bits; $first =~ s/^\s*//; push @outParams, $first; $first =~ /^(\w+\s*)/; my $type = $1 ; push @outParams, map { $type . $_ } @bits; } else { $p =~ s/^\s+//; push @outParams, $p; } } my %tmp = map { /$pMatch/; $_ => $pList{$1} } @outParams ; @outParams = map { " $_" } sort { $tmp{$a} <=> $tmp{$b} } @outParams ; print $prefix ; print "(\n" . join(",\n", @outParams) . ")\n"; print "{" ; } # Output any trailing code. print ; exit 0; sub StripComments { no warnings; # Strip C & C++ coments # From the perlfaq $_[0] =~ s{ /\* ## Start of /* ... */ comment [^*]*\*+ ## Non-* followed by 1-or-more *'s ( [^/*][^*]*\*+ )* ## 0-or-more things which don't start with / ## but do end with '*' / ## End of /* ... */ comment | ## OR C++ Comment // ## Start of C++ comment // [^\n]* ## followed by 0-or-more non end of line characters | ## OR various things which aren't comments: ( " ## Start of " ... " string ( \\. ## Escaped char | ## OR [^"\\] ## Non "\ )* " ## End of " ... " string | ## OR ' ## Start of ' ... ' string ( \\. ## Escaped char | ## OR [^'\\] ## Non '\ )* ' ## End of ' ... ' string | ## OR . ## Anything other char [^/"'\\]* ## Chars which doesn't start a comment, string or escape ) }{$2}gxs; } |
Changes to compat/zlib/zutil.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"" }; | | > | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"" }; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; |
︙ | ︙ | |||
55 56 57 58 59 60 61 | case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef ZLIB_DEBUG flags += 1 << 8; #endif | < < | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef ZLIB_DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE |
︙ | ︙ | |||
115 116 117 118 119 120 121 | #ifdef ZLIB_DEBUG #include <stdlib.h> # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; | | > > | > > | | | > > > > | > > > > | > > > | 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 | #ifdef ZLIB_DEBUG #include <stdlib.h> # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error (m) char *m; { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(err) int err; { return ERR_MSG(err); } #if defined(_WIN32_WCE) /* The Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(dest, source, len) Bytef* dest; const Bytef* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(s1, s2, len) const Bytef* s1; const Bytef* s2; uInt len; { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(dest, len) Bytef* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif |
︙ | ︙ | |||
195 196 197 198 199 200 201 | /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ | | > | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; (void)opaque; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. |
︙ | ︙ | |||
220 221 222 223 224 225 226 | /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } | | > | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; (void)opaque; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; |
︙ | ︙ | |||
256 257 258 259 260 261 262 | # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif | | > | > | | | | > > > > | > > > | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) voidpf opaque; unsigned items; unsigned size; { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { (void)opaque; free(ptr); } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ |
Changes to compat/zlib/zutil.h.
1 | /* zutil.h -- internal interface and configuration of the compression library | | | 1 2 3 4 5 6 7 8 9 | /* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ |
︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include <stddef.h> # endif # include <string.h> # include <stdlib.h> #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; | > > > > < < < < < < < < < < < | | 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 | #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include <stddef.h> # endif # include <string.h> # include <stdlib.h> #endif #ifdef Z_SOLO typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ |
︙ | ︙ | |||
133 134 135 136 137 138 139 | #ifdef OS2 # define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include <malloc.h> # endif #endif | | > > > > > > > > > | 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 | #ifdef OS2 # define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include <malloc.h> # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 7 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include <unix.h> /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif # endif #endif #ifdef __acorn # define OS_CODE 13 #endif #if defined(WIN32) && !defined(__CYGWIN__) |
︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | #ifdef __TOS_OS400__ # define OS_CODE 18 #endif #ifdef __APPLE__ # define OS_CODE 19 #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) | > > > > > > > > > > > > > > > > | < | | 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 | #ifdef __TOS_OS400__ # define OS_CODE 18 #endif #ifdef __APPLE__ # define OS_CODE 19 #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # ifndef _PTRDIFF_T_DEFINED typedef int ptrdiff_t; # define _PTRDIFF_T_DEFINED # endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 3 /* assume Unix */ #endif |
︙ | ︙ | |||
207 208 209 210 211 212 213 | # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include <stdio.h> extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ |
Changes to configure.
1 2 | #!/bin/sh dir="`dirname "$0"`/autosetup" | | | 1 2 3 | #!/bin/sh dir="`dirname "$0"`/autosetup" WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" |
Changes to debian/makedeb.sh.
︙ | ︙ | |||
55 56 57 58 59 60 61 | COPYRIGHT=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright cat <<EOF > ${COPYRIGHT} This package was created by fossil-scm <fossil-dev@lists.fossil-scm.org> on ${PACKAGE_TIME}. The original sources for fossil can be downloaded for free from: | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | COPYRIGHT=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright cat <<EOF > ${COPYRIGHT} This package was created by fossil-scm <fossil-dev@lists.fossil-scm.org> on ${PACKAGE_TIME}. The original sources for fossil can be downloaded for free from: http://www.fossil-scm.org/ fossil is released under the terms of the 2-clause BSD License. EOF } true && { |
︙ | ︙ |
Deleted extsrc/cson_amalgamation.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/cson_amalgamation.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/linenoise.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/linenoise.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/pikchr-worker.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/pikchr.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/pikchr.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted extsrc/pikchr.wasm.
cannot compute difference between binary files
Deleted extsrc/shell.c.
more than 10,000 changes
Deleted extsrc/sqlite3.c.
more than 10,000 changes
Deleted extsrc/sqlite3.h.
more than 10,000 changes
Changes to fossil.1.
|
| | | | | | | | | | > > > > > | 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 | .TH FOSSIL "1" "September 2018" "http://fossil-scm.org" "User Commands" .SH NAME fossil \- Distributed Version Control System .SH SYNOPSIS .B fossil \fIhelp\fR .br .B fossil \fIhelp COMMAND\fR .br .B fossil \fICOMMAND [OPTIONS]\fR .SH DESCRIPTION Fossil is a distributed version control system (DVCS) with built-in forum, wiki, ticket tracker, CGI/HTTP interface, and HTTP server. .SH Common COMMANDs: add clean help push timeline .br addremove clone import rebuild ui .br all commit info remote-url undo .br amend delete init revert unpublished .br annotate diff ls rm unversioned .br bisect export merge settings update .br blame extras mv sql version .br branch finfo open stash .br bundle fusefs praise status .br cat gdiff publish sync .br changes grep pull tag .SH FEATURES Features as described on the fossil home page. .HP 1. |
︙ | ︙ | |||
92 93 94 95 96 97 98 | .HP 8. .B Free and Open-Source - Uses the 2-clause BSD license. .SH DOCUMENTATION | | | 97 98 99 100 101 102 103 104 105 106 107 | .HP 8. .B Free and Open-Source - Uses the 2-clause BSD license. .SH DOCUMENTATION http://www.fossil-scm.org/ .br .B fossil \fIui\fR |
Changes to setup/fossil.iss.
︙ | ︙ | |||
17 18 19 20 21 22 23 | [Setup] ArchitecturesAllowed=x86 x64 AlwaysShowComponentsList=false AppCopyright=Copyright (c) D. Richard Hipp. All rights reserved. AppID={{f1c25a1f-3954-4e1a-ac36-4314c52f057c} AppName=Fossil AppPublisher=Fossil Development Team | | | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | [Setup] ArchitecturesAllowed=x86 x64 AlwaysShowComponentsList=false AppCopyright=Copyright (c) D. Richard Hipp. All rights reserved. AppID={{f1c25a1f-3954-4e1a-ac36-4314c52f057c} AppName=Fossil AppPublisher=Fossil Development Team AppPublisherURL=https://www.fossil-scm.org/ AppSupportURL=https://www.fossil-scm.org/ AppUpdatesURL=https://www.fossil-scm.org/ AppVerName=Fossil v{#AppVersion} AppVersion={#AppVersion} AppComments=Simple, high-reliability, distributed software configuration management system. AppReadmeFile=https://www.fossil-scm.org/index.html/doc/tip/www/quickstart.wiki DefaultDirName={pf}\Fossil DefaultGroupName=Fossil OutputBaseFilename=fossil-win32-{#AppVersion} OutputManifestFile=fossil-win32-{#AppVersion}-manifest.txt SetupLogging=true UninstallFilesDir={app}\uninstall VersionInfoVersion={#AppVersion} |
︙ | ︙ |
Changes to skins/README.md.
1 2 3 4 | Built-in Skins ============== Each subdirectory under this folder describes a built-in "skin". | | | < < < < < | | | < < < | | < | > | | | 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 | Built-in Skins ============== Each subdirectory under this folder describes a built-in "skin". There are four files in each subdirectory for the CSS, the "details" file, the footer, and the header for that skin. To improve an existing built-in skin, simply edit the appropriate files and recompile. To add a new skin: 1. Create a new subdirectory under skins/. (The new directory is called "skins/newskin" below but you should use a new original name, of course.) 2. Add files skins/newskin/css.txt, skins/newskin/details.txt, skins/newskin/footer.txt and skins/newskin/header.txt. Be sure to "fossil add" these files. 3. Go to the src/ directory and rerun "tclsh makemake.tcl". This step rebuilds the various makefiles so that they have dependencies on the skin files you just installed. 4. Edit the BuiltinSkin[] array near the top of the src/skins.c source file so that it describes and references the "newskin" skin. 5. Type "make" to rebuild. Development Hints ----------------- One way to develop a new skin is to copy the baseline files (css.txt, details.txt, footer.txt, and header.txt) into a working directory $WORKDIR then launch Fossil with a command-line option "--skin $WORKDIR". Example: cp -r skins/default newskin fossil ui --skin ./newskin When the argument to --skin contains one or more '/' characters, the appropriate skin files are read from disk from the directory specified. So after launching fossil as shown above, you can edit the newskin/css.txt, newskin/details.txt, newskin/footer.txt, and newskin/header.txt files using your favorite text editor, then press Reload on your browser to see immediate results. |
Added skins/aht/details.txt.
> > > > | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 0 white-foreground: 0 |
Changes to skins/ardoise/css.txt.
1 2 3 4 5 6 7 8 9 10 11 12 13 | @charset "UTF-8"; /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ hr, input[type=search] { box-sizing: content-box } img, legend, table.login_out, table.login_out td, tr.timelineCurrent, tr.timelineCurrent td.timelineTableCell, tr.timelineSelected { | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @charset "UTF-8"; /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ hr, input[type=search] { box-sizing: content-box } img, legend, table.login_out, table.login_out td, tr.timelineCurrent, tr.timelineCurrent td.timelineTableCell, tr.timelineSelected { border: 0 } ol, p, ul { margin-top: 0 } |
︙ | ︙ | |||
47 48 49 50 51 52 53 | .filetree ul ul, .mainmenu ul, sub, sup { position: relative } .filetree .dir > div.filetreeline > a, | | > > | 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 | .filetree ul ul, .mainmenu ul, sub, sup { position: relative } .filetree .dir > div.filetreeline > a, ul.browser li.dir { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDUuMjkyIDQuMjMzIj48cGF0aCBkPSJNLjc5NC41M3YzLjE3NGgzLjcwNFYxLjMyM0gyLjkxVi41Mjl6IiBmaWxsPSIjMWQyMDIxIiBzdHJva2U9IiNmZjgwMDAiIHN0cm9rZS13aWR0aD0iLjUyOSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+) } dfn, span.modpending { font-style: italic } html { font-family: sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100% } audio, canvas, progress, video { display: inline-block; vertical-align: baseline |
︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 | a { background-color: transparent; color: #ff8000; text-decoration: unset } a:active, a:hover, abbr[title] { border-bottom: 1px dotted } b, optgroup, strong, td.usetupEditLabel { | > > > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | a { background-color: transparent; color: #ff8000; text-decoration: unset } a:active, a:hover, pre.udiff:focus, table.sbsdiffcols:focus { outline: 0 } abbr[title] { border-bottom: 1px dotted } b, optgroup, strong, td.usetupEditLabel { |
︙ | ︙ | |||
155 156 157 158 159 160 161 162 163 164 165 166 167 168 | select { text-transform: none } button, html input[type=button], input[type=reset], input[type=submit] { cursor: pointer } button[disabled], html input[disabled] { cursor: default } button::-moz-focus-inner, | > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | select { text-transform: none } button, html input[type=button], input[type=reset], input[type=submit] { -webkit-appearance: button; cursor: pointer } button[disabled], html input[disabled] { cursor: default } button::-moz-focus-inner, |
︙ | ︙ | |||
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | padding: 0; display: inline } input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { height: auto } input[type=search]::-webkit-search-cancel-button, fieldset { border: 1px solid silver; margin: 0 2px } legend { padding: 0 } | > > > > > > | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | padding: 0; display: inline } input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { height: auto } input[type=search] { -webkit-appearance: textfield } input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration { -webkit-appearance: none } fieldset { border: 1px solid silver; margin: 0 2px } legend { padding: 0 } |
︙ | ︙ | |||
277 278 279 280 281 282 283 | max-width: 1200px; margin: 0 auto; box-sizing: border-box } .column, .columns { width: 100%; | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | max-width: 1200px; margin: 0 auto; box-sizing: border-box } .column, .columns { width: 100%; float: left; box-sizing: border-box } @media (min-width:400px) { .container { width: 95%; padding: 0 } |
︙ | ︙ | |||
305 306 307 308 309 310 311 | display: inline-block; box-sizing: border-box; text-decoration: none; text-align: center; white-space: nowrap; cursor: pointer } | < < < < < | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | display: inline-block; box-sizing: border-box; text-decoration: none; text-align: center; white-space: nowrap; cursor: pointer } @media (min-width:550px) { .container { width: 95% } .column, .columns { margin-left: 4% |
︙ | ︙ | |||
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | input[type=password], input[type=search], input[type=tel], input[type=text], input[type=url] { box-shadow: none; box-sizing: border-box; } input[type=email], input[type=number], input[type=password], input[type=search], input[type=tel], input[type=text], input[type=url], select, textarea { height: 32px; padding: 6px 10px; color: #bbb; background-color: #303536; border: 0; border-radius: 5px; box-shadow: none; box-sizing: border-box } | > > > < < < > > > | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | input[type=password], input[type=search], input[type=tel], input[type=text], input[type=url] { box-shadow: none; box-sizing: border-box; -webkit-appearance: none; -moz-appearance: none; appearance: none } input[type=email], input[type=number], input[type=password], input[type=search], input[type=tel], input[type=text], input[type=url], select, textarea { height: 32px; padding: 6px 10px; color: #bbb; background-color: #303536; border: 0; border-radius: 5px; box-shadow: none; box-sizing: border-box } input[type=email]:hover, input[type=number]:hover, input[type=password]:hover, input[type=search]:hover, input[type=tel]:hover, input[type=text]:hover, input[type=url]:hover, select:hover, textarea:hover { color: #eef8ff; background-color: #555 } textarea { overflow: auto; -webkit-appearance: none; -moz-appearance: none; appearance: none; min-height: 65px; padding-top: 6px; padding-bottom: 6px } input[type=email]:focus, input[type=number]:focus, input[type=password]:focus, |
︙ | ︙ | |||
572 573 574 575 576 577 578 | margin: 0 .2rem; font-size: 90%; white-space: nowrap; background: #000; border: 2px solid #bbb; border-radius: 5px } | < < < < < < < < < | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 | margin: 0 .2rem; font-size: 90%; white-space: nowrap; background: #000; border: 2px solid #bbb; border-radius: 5px } pre > code { padding: 1rem 1.5rem; white-space: pre } td, th { padding: 1px 5px; |
︙ | ︙ | |||
614 615 616 617 618 619 620 | ol, p, pre, table, ul { margin-bottom: 1.5rem } | | | | | | | | | | | < < | | | < > > > < < < < < < < < | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | ol, p, pre, table, ul { margin-bottom: 1.5rem } .header { color: #888; font-weight: 400; padding-top: 10px; border-width: 0 } .filetree li > ul:before, .filetree li li:before { border-left: 2px solid #888; content: ''; position: absolute } .filetree>ul, .header .logo, .header .logo h1 { display: inline-block } .header .login { padding-top: 2px; text-align: right } .header .login .button { margin: 0 } .header h1 { margin: 0; color: #888; display: inline-block } .header .title h1 { padding-bottom: 10px } .header .login, .header h1 small, .header h2 small { color: #777 } .middle { background-color: #1d2021; padding-bottom: 20px; max-width: 100%; box-sizing: border-box } .content { padding-top: 8px; padding-left: 8px; padding-right: 8px } .content a { color: #8cf } .content a:hover, .submenu a:hover, .submenu label:hover { color: #fff } .artifact_content hr:first-of-type { margin: 0; border: 0 } .artifact_content blockquote:first-of-type { padding: 1px 20px; margin: 0 0 20px; background: #000; border-radius: 5px } .footer { padding: 10px 0 60px; border-top: 0; color: #888 } .footer a { color: #527b8f; background-repeat: no-repeat; background-position: center top 10px } .footer a:hover { color: #eef8ff } .mainmenu { background-color: #161819; border-top-right-radius: 15px; border-top-left-radius: 15px; clear: both } .mainmenu ul { list-style: none; display: block; border-top: 1px solid transparent; padding: 0 } .mainmenu li { outline: 0; display: block; float: left; margin: 0 } .mainmenu li.active { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNyIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgNC40OTggMi4zODEiPjxwYXRoIGQ9Ik00LjIzMyAyLjM4MUguMjY1bC45OTgtMS4wNTguOTg2LTEuMDU4Ljk5OCAxLjA2MnoiIGZpbGw9IiNmZjgwMDAiLz48L3N2Zz4=); background-repeat: no-repeat; background-position: center bottom } .mainmenu li a { color: #66a8c7; display: block; padding: 10px 15px } .mainmenu li.active a { text-shadow: 0 0 1px #b1d2e2 } .mainmenu li:hover { background-color: #ff8000; border-radius: 5px } .mainmenu li:hover a { color: #000 } .submenu { padding: 4px 0; background-color: #000; border-bottom-right-radius: 15px; border-bottom-left-radius: 15px; line-height: 2.5 } |
︙ | ︙ | |||
793 794 795 796 797 798 799 | list-style: none; line-height: 1.6 } ul.browser li.dir { background-repeat: no-repeat } .filetree a, | | < < < < < < | 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | list-style: none; line-height: 1.6 } ul.browser li.dir { background-repeat: no-repeat } .filetree a, ul.browser li.file { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDUuMjkyIDQuMjMzIj48cGF0aCBkPSJNMS4zMjMuMjY1djMuNzA0aDIuNjQ2VjEuMzIzTDIuOTEuMjY1eiIgZmlsbD0iIzFkMjAyMSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMi42NDYuMjY1aC4yNjR2MS4zMjNoMS4wNiIgZmlsbD0iIzFkMjAyMSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=); background-repeat: no-repeat } div.filetreeline:hover *, ul.browser li.dir:hover, ul.browser li.dir:hover *, ul.browser li.file:hover, ul.browser li.file:hover * { background-color: #333 } td.browser, td.tktDescLabel { vertical-align: top } div.filetreeline { display: table; width: 100%; white-space: nowrap } .filetree { margin: 1em 0; |
︙ | ︙ | |||
959 960 961 962 963 964 965 | padding: .75em; border-radius: 5px; border: solid #ff8000; vertical-align: top; text-align: left; background: #442800 } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 946 947 948 949 950 951 952 953 954 955 956 957 958 959 | padding: .75em; border-radius: 5px; border: solid #ff8000; vertical-align: top; text-align: left; background: #442800 } .timelineCurrent > .timelineColumnarCell, .timelineCurrent > .timelineCompactCell, .timelineCurrent > .timelineDetailCell, .timelineCurrent > .timelineModernCell, .timelineCurrent > .timelineVerboseCell { vertical-align: top; text-align: left; |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 | position: absolute; top: 3px; left: 3px; width: 4px; height: 4px; background: #bbb } | < < < < < < < < | 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 | position: absolute; top: 3px; left: 3px; width: 4px; height: 4px; background: #bbb } .tl-node.sel:after { content: ''; position: absolute; top: 1px; left: 1px; width: 8px; height: 8px; |
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 | } .tl-arrow.merge.r { border-left: 3px solid #bbb } .tl-line.merge { width: 1px } | < < < < < < < < < < < < < < < < < < < < < < < | 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 | } .tl-arrow.merge.r { border-left: 3px solid #bbb } .tl-line.merge { width: 1px } .intLink[title="Add indentation"], .intLink[title="Center align"], .intLink[title="Dotted list"], .intLink[title="Left align"], .intLink[title="Numbered list"], .intLink[title="Remove formatting"], .intLink[title="Right align"], |
︙ | ︙ | |||
1132 1133 1134 1135 1136 1137 1138 | .tl-line.warp { background: #600000 } table.login_out .login_out_label { font-weight: 700; text-align: right } | > | > | > | > | < | | | < < < | < | | | < | | | | | < | > | < | > | | < | < | < < < < | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 | .tl-line.warp { background: #600000 } table.login_out .login_out_label { font-weight: 700; text-align: right } pre.udiff, table.sbsdiffcols { width: 100%; overflow: auto; padding: 0 5px; font-size: 1rem; background: #000; border-radius: 5px } pre.udiff, pre.udiff pre, table.sbsdiffcols pre { font-size: 1.15rem } pre.udiff { padding: 10px 0 } div.difftxtcol { width: 52rem; overflow-x: auto } span.diffchng { background-color: #8080e8; color: #000 } span.diffadd { background-color: #559855; color: #000 } span.diffrm { background-color: #c55; color: #000 } div.diffmkrcol { padding: 0 1em; background: #111 } span.diffhr { display: inline-block; margin: .5em 0 1em; color: #555 } span.diffln { color: #666 } table.report { width: 100%; cursor: auto; margin: 0 0 1em; color: #000 } table.report thead { |
︙ | ︙ | |||
1393 1394 1395 1396 1397 1398 1399 | .intLink[title=Hyperlink] { background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cGF0aCBkPSJNMS43NTIgMy45NjloLjc5M20tLjc5My0yLjExN2guNzkzTTEuNzUyIDMuOTdjLS4zNDMgMC0uNjU5LS4xMTktLjgzLS40MTUtLjE3MS0uMjk3LS4xNzEtLjk5IDAtMS4yODcuMTcxLS4yOTYuNDg3LS40MTUuODMtLjQxNW0yLjIxNyAyLjExNmgtLjc5NG0uNzk0LTIuMTE3aC0uNzk0bS43OTQgMi4xMTdjLjM0MiAwIC42NTgtLjExOS44My0uNDE1LjE3LS4yOTcuMTctLjk5IDAtMS4yODctLjE3Mi0uMjk2LS40ODgtLjQxNS0uODMtLjQxNU0yLjExNyAyLjkxaDEuNTg3IiBmaWxsPSJub25lIiBzdHJva2U9IiNhYWEiIHN0cm9rZS13aWR0aD0iLjUyOSIvPjwvc3ZnPg==) } .intLink[title=Hyperlink]:hover { background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cmVjdCByeT0iLjI2NSIgcng9Ii4yNjUiIHk9Ii0uMDAxIiBoZWlnaHQ9IjUuODIxIiB3aWR0aD0iNS44MjEiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNMS43NTIgMy45NjhoLjc5M20tLjc5My0yLjExN2guNzkzbS0uNzkzIDIuMTE3Yy0uMzQzIDAtLjY1OS0uMTE5LS44My0uNDE1LS4xNzEtLjI5Ny0uMTcxLS45OSAwLTEuMjg3LjE3MS0uMjk2LjQ4Ny0uNDE1LjgzLS40MTVtMi4yMTcgMi4xMTdoLS43OTRtLjc5NC0yLjExN2gtLjc5NG0uNzk0IDIuMTE3Yy4zNDIgMCAuNjU4LS4xMTkuODMtLjQxNS4xNy0uMjk3LjE3LS45OSAwLTEuMjg3LS4xNzItLjI5Ni0uNDg4LS40MTUtLjgzLS40MTVNMi4xMTcgMi45MWgxLjU4NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiLz48L3N2Zz4=) } .statistics-report-graph-line { | < | < < < < | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | .intLink[title=Hyperlink] { background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cGF0aCBkPSJNMS43NTIgMy45NjloLjc5M20tLjc5My0yLjExN2guNzkzTTEuNzUyIDMuOTdjLS4zNDMgMC0uNjU5LS4xMTktLjgzLS40MTUtLjE3MS0uMjk3LS4xNzEtLjk5IDAtMS4yODcuMTcxLS4yOTYuNDg3LS40MTUuODMtLjQxNW0yLjIxNyAyLjExNmgtLjc5NG0uNzk0LTIuMTE3aC0uNzk0bS43OTQgMi4xMTdjLjM0MiAwIC42NTgtLjExOS44My0uNDE1LjE3LS4yOTcuMTctLjk5IDAtMS4yODctLjE3Mi0uMjk2LS40ODgtLjQxNS0uODMtLjQxNU0yLjExNyAyLjkxaDEuNTg3IiBmaWxsPSJub25lIiBzdHJva2U9IiNhYWEiIHN0cm9rZS13aWR0aD0iLjUyOSIvPjwvc3ZnPg==) } .intLink[title=Hyperlink]:hover { background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDUuODIxIDUuODIxIj48cmVjdCByeT0iLjI2NSIgcng9Ii4yNjUiIHk9Ii0uMDAxIiBoZWlnaHQ9IjUuODIxIiB3aWR0aD0iNS44MjEiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNMS43NTIgMy45NjhoLjc5M20tLjc5My0yLjExN2guNzkzbS0uNzkzIDIuMTE3Yy0uMzQzIDAtLjY1OS0uMTE5LS44My0uNDE1LS4xNzEtLjI5Ny0uMTcxLS45OSAwLTEuMjg3LjE3MS0uMjk2LjQ4Ny0uNDE1LjgzLS40MTVtMi4yMTcgMi4xMTdoLS43OTRtLjc5NC0yLjExN2gtLjc5NG0uNzk0IDIuMTE3Yy4zNDIgMCAuNjU4LS4xMTkuODMtLjQxNS4xNy0uMjk3LjE3LS45OSAwLTEuMjg3LS4xNzItLjI5Ni0uNDg4LS40MTUtLjgzLS40MTVNMi4xMTcgMi45MWgxLjU4NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZGRkIiBzdHJva2Utd2lkdGg9Ii41MjkiLz48L3N2Zz4=) } .statistics-report-graph-line { background-color: #ff8000 } mark, p.noMoreShun, p.shunned, span.modpending { color: #ff8000 } |
︙ | ︙ | |||
1420 1421 1422 1423 1424 1425 1426 | .mainmenu:after, .row:after, .u-cf { content: ""; display: table; clear: both } | < < < < < < < < < < < < < < < < < < < < < < < < | 1333 1334 1335 1336 1337 1338 1339 | .mainmenu:after, .row:after, .u-cf { content: ""; display: table; clear: both } |
Changes to skins/ardoise/details.txt.
1 2 3 4 | timeline-arrowheads: 0 timeline-circle-nodes: 1 timeline-color-graph-lines: 1 white-foreground: 1 | < | 1 2 3 4 | timeline-arrowheads: 0 timeline-circle-nodes: 1 timeline-color-graph-lines: 1 white-foreground: 1 |
Changes to skins/ardoise/footer.txt.
|
| | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <th1> if {[string first artifact $current_page] == 0 || [string first hexdump $current_page] == 0} { html "</div>" } </th1> </div> <!-- end div container --> </div> <!-- end div middle max-full-width --> <div class="footer"> <div class="container"> <div class="pull-right"> <a href="https://www.fossil-scm.org/">Fossil $release_version $manifest_version $manifest_date</a> </div> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s </div> </div> |
Changes to skins/ardoise/header.txt.
|
| | | 1 2 3 4 5 6 7 8 | <div class="header"> <div class="container"> <div class="login pull-right"> <th1> if {[info exists login]} { html "<b>$login</b> — <a class='button' href='$home/login'>Logout</a>\n" } else { html "<a class='button' href='$home/login'>Login</a>\n" |
︙ | ︙ | |||
16 17 18 19 20 21 22 | html "<a class='rss' href='$home/timeline.rss'></a>" } </th1> <small> $<title></small></h1> </div> <!-- Main Menu --> | | < | | | < | | | > | < < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | | | | | | | | | | 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 | html "<a class='rss' href='$home/timeline.rss'></a>" } </th1> <small> $<title></small></h1> </div> <!-- Main Menu --> <div class="mainmenu"> <ul> <th1> proc menulink {url name} { upvar current_page current upvar home home if {[string range $url 0 [string length $current]] eq "/$current"} { html "<li class='active'>" } else { html "<li>" } html "<a href='$home$url'>$name</a></li>\n" } menulink $index_page Home if {[anycap jor]} { menulink /timeline Timeline } if {[hascap oh]} { menulink /dir?ci=tip Files } if {[hascap o]} { menulink /brlist Branches menulink /taglist Tags } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } if {[hascap r]} { menulink /ticket Tickets } if {[hascap j]} { menulink /wiki Wiki } if {[hascap o]} { menulink /help Help } if {[hascap s]} { menulink /setup Admin } elseif {[hascap a]} { menulink /setup_ulist Users } </th1> </ul> </div> <!-- end div mainmenu --> </div> <!-- end div container --> </div> <!-- end div header --> <div class="middle max-full-width"> <div class="container"> <th1> if {[string first artifact $current_page] == 0 || [string first hexdump $current_page] == 0} { html "<div class=\"artifact_content\">" } </th1> |
Changes to skins/black_and_white/css.txt.
1 2 3 4 5 6 7 | /* General settings for the entire page */ body { margin:0px 0px 0px 0px; padding:0px; font-family:verdana, arial, helvetica, "sans serif"; color:#333; background-color:white; | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* General settings for the entire page */ body { margin:0px 0px 0px 0px; padding:0px; font-family:verdana, arial, helvetica, "sans serif"; color:#333; background-color:white; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } /* consistent colours */ h2 { color: #333; } h3 { |
︙ | ︙ | |||
47 48 49 50 51 52 53 | color: #333; font-size: 0.8em; font-weight: bold; white-space: nowrap; } /* The header across the top of the page */ | | | | | | | | | 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 | color: #333; font-size: 0.8em; font-weight: bold; white-space: nowrap; } /* The header across the top of the page */ div.header { margin:10px 0px 10px 0px; padding:1px 0px 0px 20px; border-style:solid; border-color:black; border-width:1px 0px; background-color:#eee; } /* The main menu bar that appears at the top left of the page beneath ** the header. Width must be co-ordinated with the container below */ div.mainmenu { float: left; margin-left: 10px; margin-right: 10px; font-size: 0.9em; font-weight: bold; padding:5px; background-color:#eee; border:1px solid #999; width:8em; } /* Main menu is now a list */ div.mainmenu ul { padding: 0; list-style:none; } div.mainmenu a, div.mainmenu a:visited{ padding: 1px 10px 1px 10px; color: #333; text-decoration: none; } div.mainmenu a:hover { color: #eee; background-color: #333; } /* Container for the sub-menu and content so they don't spread ** out underneath the main menu */ #container { |
︙ | ︙ | |||
147 148 149 150 151 152 153 | float: left; clear: left; color: #333; white-space: nowrap; } /* The footer at the very bottom of the page */ | | | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | float: left; clear: left; color: #333; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { font-size: 0.8em; margin-top: 12px; padding: 5px 10px 5px 10px; text-align: right; background-color: #eee; color: #555; } |
︙ | ︙ |
Changes to skins/black_and_white/footer.txt.
|
| | | | 1 2 3 | <div class="footer"> Fossil $release_version $manifest_version $manifest_date </div> |
Changes to skins/black_and_white/header.txt.
|
| | | | | | | | | | > | < > > | > > | > | > > > > | > | > > > | | > > | > > > > > | < | 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 | <div class="header"> <div class="logo"> <img src="$logo_image_url" alt="logo"> <br />$<project_name> </div> <div class="title">$<title></div> <div class="status"><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></div> </div> <div class="mainmenu"> <th1> html "<a href='$home$index_page'>Home</a>\n" if {[anycap jor]} { html "<a href='$home/timeline'>Timeline</a>\n" } if {[anoncap oh]} { html "<a href='$home/tree?ci=tip'>Files</a>\n" } if {[anoncap o]} { html "<a href='$home/brlist'>Branches</a>\n" html "<a href='$home/taglist'>Tags</a>\n" } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { html "<a href='$home/forum'>Forum</a>\n" } if {[anoncap r]} { html "<a href='$home/ticket'>Tickets</a>\n" } if {[anoncap j]} { html "<a href='$home/wiki'>Wiki</a>\n" } if {[hascap s]} { html "<a href='$home/setup'>Admin</a>\n" } elseif {[hascap a]} { html "<a href='$home/setup_ulist'>Users</a>\n" } if {[info exists login]} { html "<a href='$home/login'>Logout</a>\n" } else { html "<a href='$home/login'>Login</a>\n" } </th1></ul></div> |
Changes to skins/blitz/css.txt.
︙ | ︙ | |||
561 562 563 564 565 566 567 | input[type="submit"]:hover, input[type="submit"]:focus { color: white !important; background-color: #648898; border-color: #648898; } | < < < < < | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | input[type="submit"]:hover, input[type="submit"]:focus { color: white !important; background-color: #648898; border-color: #648898; } /* Forms ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ input[type="email"], input[type="number"], input[type="search"], input[type="text"], |
︙ | ︙ | |||
753 754 755 756 757 758 759 | box-sizing: border-box; } /* Header * Div displayed at the top of every page. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ | | | | | | | | | | | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | box-sizing: border-box; } /* Header * Div displayed at the top of every page. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .header { color: #666; font-weight: 400; padding-top: 10px; border-width: 0px; border-top: 4px solid #446979; border-bottom: 1px solid #ccc; } .header .logo { display: inline-block; } .header .login { padding-top: 2px; text-align: right; } .header .login .button { margin: 0; } .header h1 { margin: 0px; color: #666; display: inline-block; } .header .logo h1 { display: inline-block; } .header .title h1 { padding-bottom: 10px; } .header h1 small, .header h2 small { color: #888; } .header a.rss { display: inline-block; padding: 10px 15px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMNDhwn05VjawAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAGlSURBVDjLrdPfb8xREAXwT7tIl+paVNaPJghCKC8kXv0XXvyNXsRfwYPQJqVKiqykWFVZXd12vcxNJtduUtJJvrm7984998ycMxxwNGI9jPs4j7nY+/U/gIdiPYO71dk21rCE7r8ybOHGmMfmcRNnsbEf1gXwNzqYSXs5WljEMXzAaBLg1Ji9Js7hOi6OeeAznqC/X8AcMyHWYpX7E4/Rm1QyHMdefCWGeI/VcMDR2D8S7Fci5y/AeTzCPVyLi1sYJAut4BTaiX0n9kc14MmkcjPY3I5LXezGtxqKtyJ3Lir6VAM2AmCq6m8Hl6PsQTB5hyvxmMhZxk4G3MZLfAwLtdNZM9rwOs528TVVNB3ga7UoQ2wGmyWciFaU0VwIJiP8iL6Xfp7GK+w0JthliDep8UKonTSGvbBTaU8f3QzYxgPcCsBvWK9E6OBFCNGPVjTTqC430p+H6fLVGLGtmIw7SbwevqT+XkgVPJ9Otpmtyl6I9XswLXEp/d6oPN0ugJu14xMLob4kgPRYjtkCOMDTUG+AZ3ibEtfDLorfEmAB3UuTdXDxBzUUZV+B82aLAAAAAElFTkSuQmCC); background-position: center center; background-repeat: no-repeat; } |
︙ | ︙ | |||
828 829 830 831 832 833 834 | color: #002060; } /* Footer * Displayed after the middle div and forms the page bottom. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ | | | > > | < > | < < < < < < < < < < < | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | color: #002060; } /* Footer * Displayed after the middle div and forms the page bottom. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .footer { padding: 10px 0 60px; border-top: 1px solid #ccc; background-color: #f8f8f8; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABGCAQAAADxl9ugAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAwkQBRPw+yfrAAAAPHRFWHRDb21tZW50ACBJbWFnZSBnZW5lcmF0ZWQgYnkgRVNQIEdob3N0c2NyaXB0IChkZXZpY2U9cG5tcmF3KQqV01S1AAANg0lEQVRo3s2aa3RVRZbH/3tXnftIbhJCeJMXyEsNCsgrSBzAYXyt0YVj2zSOonbLqNNO+25FB2kdoBVdrp6l09P2NNpOL/ExSrtUdGRU5JEQgggCggIhQIBAIIGQ5N57TlXt+ZAICY+AGCT76zlV91dVe+/a+38uDQ7dYmrxw41QocJuni28vWTedEa7Gd9iatplos7Y2mfDRED6A2G0I2At6AdPIiA84HgbLhx1o9QX9Zoh7QjYHpOkYJYrfNyOKH0O/f2FJpfkSRmMCNqDk9rDXwTAuxK7h3uFf7vXxC6QVO8w19taNOT4Y0wu1sCdW0AA6IZ73bCUaI/GHuqnsJqcEqVrzSo+wNtLdgAPsz6jeVURtQ9gA8bQT8xztW7X2u3I4G6UdA0cohxcSAN7nt939/zDQzl0LnfwaLpxqFT/i7w7XLYXhoUQ+YFW3pJlC0/nt6jZZb4zjXY2AaGXvQOz/gMY09NM4C6ixRL7OU3PTm4ORdiIjyLsJvq1Z28Hj5rBM82xMTqPuhHznmU72vq12W5M3+LykQWUW9pirzXOmmk8wjE87kb8HPmSKlY+wY62R9jhI69xf/AmYiEfiXs+e4CCAZiDUc9wP6cRIJn8tq23PQClbwap9Ivk7usiGj/CDs5xl3Qe/EiQCEWsgXLlq8sfamM73osMna43ef/pfm731Hsxv+Z00ozFzaJpF+gMrsNB2BwL3cGpSsNRWHbmvTQNiTbev9q4xXszMLzqpdgDNjxv/YjmvHlSQIc5brl8nrqT5pllMpHM9wRc4gU3oC8JyDLt8P78ZLyM2lrmAeTg5YrKdf1S1N9QTs6At1YM49DJo1gwWy7uE5kKBQHbler9K8R+L8API2qmFoDY7ejxpxGJxtMctyZcfYvJDYX4i5LXp/MJAS2edkM6edNUDuLNOdMDmz913bIw8RidKO/1w+3NQfePbHQjdbd/NKOjbq7UqQOmYtXb/+BdbGc4AJjPX53CXe6UGweYWxUR8N8rNkzn4wAFc9yYPvGbI+mttoycpo14fWbD0hZv+njOAcBl6Yl8jiEMbSKhqGPypZ5N0B2kDxrjOjF0QuI2oRqj2z6rAebx5pNiRrEo0jhV9wFkP//xpkPHAU6UGdnBLyR8jMOQs6xwcMAznVys+Uqa5YCCnilFkuVSkeKlGKfDED8JaI+VifMWR9LPC/u+UkoZA6edOezVu83pny4yD6qQnCxhDzk/MhUED+8PWHJMkAgWROvvQoxOcEdayynVY9/5tIgAwsfIvaD3XaFx6M6ddMx3WlurCGICiAIhMLxB1VM+wQRMDOeYjHCUMum85OW909/acOlJgqaI3qrulU9dYGlgzVI1tsVrETzlOt3MeUGCudVoCgJmAhFU78F+6Usu0V39iylSHCRZMROM0do5pUDWQamEPZTy5oqyXVt77bG94HGEyTkCE8BsjLOcl11Uvf7V+qvIP86jgWH8zhc9LpKYU7qRhH5NTRknwFw3+jpMQCIItG69PCLfZ1YKAMlS/7PQDCc2qbRzSjET4slINBAvhsPxjarKKy/9FhjZG8Ol4tINi/uFzkcfl8sEnwExATGRY73Ze2VpAHxHoPFki7r2iljN3a6LqqOxnZ+vXUBNwTF6uL0e0Nr3tSYWpqNhQtaIaA0A1oZftuf5Y1xmCMRO2IM1VXqf3aYr5IDXODTx7+43PAjPFcit1MANeHfFxuFpSFW9TbbORpaNEqt6/5tIoxuBOO049NHXNTN5lFwlE3o09JUMlWKdSmJ/UC8TvRwqjNzoVwNIw3upcluyq4hSAq3Idyt5HOyRIDGuGdA42un+6wv/Cq7sFA1F/B4N/5MEgL/yOsSPlFSMOzD5JhkMEQ8l8u41Job7hVoExsiRNMU1Biac4oqD92Np8Xt0BgUiEOeIHLyobbQb9U/8fSAItsFdJv1wECASB5L92xb2yefcE3Q+jgsof//m3+PO2i7YhgV0HisAK48UnE03EaT67axMyjMNXpFkf/za8r3VPP2I46Ri+aYDW0z3SMT6NJb62wPiJEFhEoFCYIhNoyS4VF1CBKArPu6MKWysBZhFVFrD7yri2VkuR4QZAIkTMAOAiDIY9KvFQ3gVPqXVFD9JSbSS3vP7b/QzKY8SlO6G5e2fv/dozvDxciKvCqOYrIURT/XU2+0SKrdVqtpVojz4Sq1Vi1duV0UE+PSEy33AhRRZAzDDc4vXrB1xKU0gRUR0LCCRi/be8XZ12/0M41Ka5K/5JjA80PlQKMjfeVVN9ZG0NZbmH8xf5Y8nJxIKmYC7SmLlexeVp2wKb+y++f6KZ3c/03g+qSISPONGDqHRZOk7QGde6XsrjTP+kXTTCpCVGErZteZUDRdhD3Ls65tz64J85ZGyQ0tXDAzckadFlOtv+ZQLoYMgHHaGcrJ7fb56inR3WVJJRVTdVM3kQSh5r1hjlbIGIKVX6ammE1vnmImh4Y4BZHGcvmvx5XQ6BcRIfnPHxV82ZnFUYsh+bWXLzMuwquGwCnvdBUTkqHcPmb+l5cJZcKervlwc8N04sbYwSJC1tsnneemJqh32LksZflr1SUh+pT6q+/ov/krztitDq1s4hP1p7mbfuFfkEKJgSejLh/Wa7Y5GJsdQmEYDoVocDCvnLCvnwPDMzOK/uiVoPS8IxoQi409D2xAU4Hd2xE2DZ3gjvcpVZY+0iqgAbFh7F9grp84xf5D6QFOE/rYo1vto4z6ZVg/COHKAiGJrACaljNHaiaqTp0NeXlr37Ydz/ahSLY9YzLIPMzlxSrxMzM/ochfnO8UHvJJpgTnm+UE5GKMeOu3LrLJPd32+Z1FamfczKli36jzTtHplvPg46o2WgNwEaOqoTk8Jxsu4+vGUruDkCCCJkg171g2ntqMkjrmuYUBwG7LglIq/U7Zr1HEjJrtiay9imIzsqt37gb4/RSZlSsP88iZf5T3kX2xOuBEck2yp13F32NbDuZbHqSjwFrzJbeP5eN6NHOJuoQyXRIZ7Y+3Gh08wohjpW/VOkFMyqagHILnOSAOuflh1bqKggew524Zs1ex+R6cmz1W7Z6clvzzF8T7rLsvnSfBgJVO9cN+ax4/IRwazZLZrqmOSWJjAR0hCdFc/F2AtToTos34POQHAkVw2Sp2m7EKwOEyLVj59w6EtpyjdFYSCCYhaC0n9fcmmr5pb8QBrQl0wqn/hNc82J8Rfc8lWVwVGwLeNDVPTdW30+KZN0Sab5JTBqOBBowIHzeZVJcBjXHdKXfQp93+DgwuIgy9QtqJ8evPhOtRRzZi30iKfBZPxQVNhofDP6sUXh05zA5MH+WKdpAgAJ/lAChqhyQmd5HgFChFoMvar0AaKq8qSGmA6o03lVFCEqx1Q0Ce0075hkgvW93EPNeMZ3Cl93eRl5Q8GVjoBs1tUN1l/rvkn1VOuNXUIAyATv6zz3bXPEo3t7N/L6bBirfV0MimktOclgnDUJHiTWxo9oJOZQT/TDUk0nIYfFODFaMMN4WFqbnEl8BzXtlBX++ATr2KW3eC9kbg/9d2l6/qmdxrq9bdRkBwMtrgd+lpkpxwyWSwAkvRKSfl0phf4l+6acGVeak6QQbCJYH/Gwci+zPi/+oMFEJpLdTDfQ8IpTTl8r/lkQuniX3oR98mjX65sJQZ0wYNu1NU0wZ8RjSUf0Qo22aCU1oAoCazTFe5bdZ1pVIqcv2B12XSm6awxCFNaichCr1I1auDOQFvKxzQHFD4mexGXNfds/PoYB+iMhxzwIC8vcJe7HKVIrBEoLRQkuVL+Ii70lDlMUOR/uHrJdNaAwXo82orksR8gfVUAGFkgy5JfhKdEKncelwhq8SinwMeidX+303VHuvOgCGSRRF2o6vb6FyKmQTGRNTraQt1qJ6EaAPA4V22MYH20wXx+aCyfKFvFAcymiYfCh/YhSQZACFHpBB/l6On2l0s/AgTBWdIHHbpIulzfWDbvAW4r3gPUIwWZ0lW6SoaE0AgDYG6Six0R4OjgWRMwGUAVHuUz+SS2iNQ+XSMAvKqzrLCemdtUo3ifWhpoTi7b/RSfVRH9zBc2y43umXVgtImf3R08c7zCIeYpVoPOtoh+ZjYEhd3kWtV4IHSldEjAV7U/ATHxig89Tx0QUFCtvUJisxnNknuHArSY4+xtNuk4ZQWai4wOBThJRqZJvhYXtptnNTVAHQnQYbT4k7QI6/Vd6w6f/U9h39cUgEg+BCG3rk/AHQ9wlhsz1IUCI3tRPrDVtdlhzO9rxPNke+nuXR0TUIdAMOrDlkJshwEM4QId98C8vKTmUUJHAwww03VNT8ny9hd/cJ9qCaU7QnrpjXvcsKuT6W7VdcvHc+sq95wDCuZILxp9t+TZJWVL/56PPdJzDhjDhG75UyUrsXXtBw9z/PjAObd3729leA++mTOldO07dyl9ghbmnALmYpjybndhO3/VV/dx9IQdlj53YQEAo2din3p1cv1VfDIF8EfvSdJQSZvU3ljGJJOvNuH94kOPs22jwWq3P5edTryG8G/OdtsxOPiZd6O1ppTeK0n43Hb/9yPuYBhPuFFXumEq3231S+ibL/e+yhtP2Zz+iD74hCu83vblr+W1yJ5LgguxmzedRu/8//AUSaqMTR1xAAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: center top 10px; } .footer a { color: #3b5c6b; } /* Main Menu * Displayed in header, contains repository links. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .mainmenu { clear:both; } .mainmenu ul { list-style: none outside; display: block; position: relative; border-top: 1px solid #ccc; padding: 0; } .mainmenu li { outline: 0; display: block; float: left; margin: 0; } .mainmenu li.active { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: center bottom; } .mainmenu li a { color: #3b5c6b; display: block; padding: 10px 15px; } .mainmenu li.active a { font-weight: bold; } .mainmenu li:hover { background-color: #eee; } /* Submenu * Displayed in the middle div. Contains page-specific form controls. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .submenu { padding: 10px 0px; |
︙ | ︙ | |||
959 960 961 962 963 964 965 | * Repository tree navigation. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ ul.browser { list-style: none; } ul.browser li.dir { | < < < < < < < | > | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 | * Repository tree navigation. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ ul.browser { list-style: none; } ul.browser li.dir { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: 0px center; padding-left: 22px; padding-top: 2px; } ul.browser li.file { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: 0px center; padding-left: 22px; padding-top: 2px; } div.filetreeline { display: table; width: 100%; white-space: nowrap; } |
︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 | tr.timelineCurrent { border-left: 2px solid orange; background-color: #ffc; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; } | | < < < | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 | tr.timelineCurrent { border-left: 2px solid orange; background-color: #ffc; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; } tr.timelineSelected { border-left: 2px solid orange; background-color: #ffffe8; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; } tr.timelineCurrent td.timelineTableCell { } tr.timelineBottom td { border-bottom: 0; } |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | } span.timelineComment { padding: 0px 5px; } | | | | | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 | } span.timelineComment { padding: 0px 5px; } /* Login/Loguot ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ table.login_out { } table.login_out .login_out_label { font-weight: 700; text-align: right; } table.login_out td { border: 0; } /* Diff displays ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ pre.udiff, table.sbsdiffcols { width: 100%; overflow: auto; border: 1px solid #ccc; padding: 5px; font-size: 1rem; } pre.udiff:focus, table.sbsdiffcols:focus { outline: none; } /* Ticket Reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ table.report { |
︙ | ︙ | |||
1275 1276 1277 1278 1279 1280 1281 | .mainmenu:after, .row:after, .u-cf { content: ""; display: table; clear: both; } | < < < < | 1252 1253 1254 1255 1256 1257 1258 | .mainmenu:after, .row:after, .u-cf { content: ""; display: table; clear: both; } |
Changes to skins/blitz/footer.txt.
1 2 | </div> <!-- end div container --> </div> <!-- end div middle max-full-width --> | | | | 1 2 3 4 5 6 7 8 9 10 | </div> <!-- end div container --> </div> <!-- end div middle max-full-width --> <div class="footer"> <div class="container"> <div class="pull-right"> <a href="https://www.fossil-scm.org/">Fossil $release_version $manifest_version $manifest_date</a> </div> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s </div> </div> |
Changes to skins/blitz/header.txt.
|
| | > > | > < > < | < | | | < | | | > | < < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | | | | | 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 | <div class="header"> <div class="container"> <!-- Header --> <div class="login pull-right"> <th1> if {[info exists login]} { html "<b>$login</b> — <a class='button' href='$home/login'>Logout</a>\n" } else { html "<a class='button' href='$home/login'>Login</a>\n" } </th1> <div> <h2><small>$title</small></h2> </div> </div> <div class='logo'> <img src='$logo_image_url' /> <th1> if {[anycap jor]} { html "<a class='rss' href='$home/timeline.rss'></a>" } </th1> </div> <!-- Main Menu --> <div class="mainmenu"> <ul> <th1> proc menulink {url name} { upvar current_page current upvar home home if {[string range $url 0 [string length $current]] eq "/$current"} { html "<li class='active'>" } else { html "<li>" } html "<a href='$home$url'>$name</a></li>\n" } menulink $index_page Home if {[anycap jor]} { menulink /timeline Timeline } if {[hascap oh]} { menulink /dir?ci=tip Files } if {[hascap o]} { menulink /brlist Branches menulink /taglist Tags } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } if {[hascap r]} { menulink /ticket Tickets } if {[hascap j]} { menulink /wiki Wiki } if {[hascap o]} { menulink /help Help } if {[hascap s]} { menulink /setup Admin } elseif {[hascap a]} { menulink /setup_ulist Users } </th1> </ul> </div> <!-- end div mainmenu --> </div> <!-- end div container --> </div> <!-- end div header --> <div class="middle max-full-width"> <div class="container"> |
Changes to skins/blitz/ticket.txt.
1 2 | <h4>$<title></h4> <table class="tktDsp"> | | | 1 2 3 4 5 6 7 8 9 10 | <h4>$<title></h4> <table class="tktDsp"> <tr><td class="tktDspLabel">Ticket UUID</td> <th1> if {[info exists tkt_uuid]} { if {[hascap s]} { html "<td class='tktDspValue' colspan='3'>$tkt_uuid " html "($tkt_id)</td></tr>\n" } else { html "<td class='tktDspValue' colspan='3'>$tkt_uuid</td></tr>\n" |
︙ | ︙ |
Added skins/blitz_no_logo/README.md.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ## Blitz Theme (no logo) Contributed by James Moger (james.moger@gitblit.com) This theme is inspired by my own project, [Gitblit](http://gitblit.com), and offered to the Fossil project. This theme embeds & uses an unmodified copy of [Normalize 3.0.2](https://necolas.github.io/normalize.css/) which is distributed under an [MIT license](https://github.com/necolas/normalize.css/blob/master/LICENSE.md). This theme uses half of a heavily-modified version of [Skeleton](http://getskeleton.com) which is distributed under an [MIT license](https://github.com/dhg/Skeleton/blob/master/LICENSE.md). None of the responsive elements (media queries) are included at this time. The font used in the included Fossil logo image is [Trillium Web Light](http://www.google.com/fonts/specimen/Titillium+Web) @ 48px HTML color code #456a7a. The RSS feed icon is sourced from [Font-Awesome](https://fortawesome.github.io/Font-Awesome/icons) by Dave Gandy and is distributed under the [SIL OFL 1.1 ](http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) license. |
Added skins/blitz_no_logo/css.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ /** * 1. Set default font family to sans-serif. * 2. Prevent iOS text size adjust after orientation change, without disabling * user zoom. */ html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /** * Remove default margin. */ body { margin: 0; } /* HTML5 display definitions ========================================================================== */ /** * Correct `block` display not defined for any HTML5 element in IE 8/9. * Correct `block` display not defined for `details` or `summary` in IE 10/11 * and Firefox. * Correct `block` display not defined for `main` in IE 11. */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } /** * 1. Correct `inline-block` display not defined in IE 8/9. * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. */ audio, canvas, progress, video { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } /** * Prevent modern browsers from displaying `audio` without controls. * Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /** * Address `[hidden]` styling not present in IE 8/9/10. * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. */ [hidden], template { display: none; } /* Links ========================================================================== */ /** * Remove the gray background color from active links in IE 10. */ a { background-color: transparent; } /** * Improve readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* Text-level semantics ========================================================================== */ /** * Address styling not present in IE 8/9/10/11, Safari, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /** * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. */ b, strong { font-weight: bold; } /** * Address styling not present in Safari and Chrome. */ dfn { font-style: italic; } /** * Address variable `h1` font-size and margin within `section` and `article` * contexts in Firefox 4+, Safari, and Chrome. */ h1 { font-size: 2em; margin: 0.67em 0; } /** * Address styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /** * Address inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* Embedded content ========================================================================== */ /** * Remove border when inside `a` element in IE 8/9/10. */ img { border: 0; } /** * Correct overflow not hidden in IE 9/10/11. */ svg:not(:root) { overflow: hidden; } /* Grouping content ========================================================================== */ /** * Address margin not present in IE 8/9 and Safari. */ figure { margin: 1em 40px; } /** * Address differences between Firefox and other browsers. */ hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } /** * Contain overflow in all browsers. */ pre { overflow: auto; } /** * Address odd `em`-unit font size rendering in all browsers. */ code, kbd, pre, samp { font-family: monospace, monospace; font-size: 1em; } /* Forms ========================================================================== */ /** * Known limitation: by default, Chrome and Safari on OS X allow very limited * styling of `select`, unless a `border` property is set. */ /** * 1. Correct color not being inherited. * Known issue: affects color of disabled elements. * 2. Correct font properties not being inherited. * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. */ button, input, optgroup, select, textarea { color: inherit; /* 1 */ font: inherit; /* 2 */ margin: 0; /* 3 */ } /** * Address `overflow` set to `hidden` in IE 8/9/10/11. */ button { overflow: visible; } /** * Address inconsistent `text-transform` inheritance for `button` and `select`. * All other form control elements do not inherit `text-transform` values. * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. * Correct `select` style inheritance in Firefox. */ button, select { text-transform: none; } /** * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` * and `video` controls. * 2. Correct inability to style clickable `input` types in iOS. * 3. Improve usability and consistency of cursor style between image-type * `input` and others. */ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /** * Re-set default cursor for disabled elements. */ button[disabled], html input[disabled] { cursor: default; } /** * Remove inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /** * Address Firefox 4+ setting `line-height` on `input` using `!important` in * the UA stylesheet. */ input { line-height: normal; } /** * It's recommended that you don't attempt to style these elements. * Firefox's implementation doesn't respect box-sizing, padding, or width. * * 1. Address box sizing set to `content-box` in IE 8/9/10. * 2. Remove excess padding in IE 8/9/10. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Fix the cursor style for Chrome's increment/decrement buttons. For certain * `font-size` values of the `input`, it causes the cursor style of the * decrement button to change from `default` to `text`. */ input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Address `appearance` set to `searchfield` in Safari and Chrome. * 2. Address `box-sizing` set to `border-box` in Safari and Chrome * (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /** * Remove inner padding and search cancel button in Safari and Chrome on OS X. * Safari (but not Chrome) clips the cancel button when the search input has * padding (and `textfield` appearance). */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /** * 1. Correct `color` not being inherited in IE 8/9/10/11. * 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /** * Remove default vertical scrollbar in IE 8/9/10/11. */ textarea { overflow: auto; } /** * Don't inherit the `font-weight` (applied by a rule above). * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. */ optgroup { font-weight: bold; } /* Tables ========================================================================== */ /** * Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; } td, th { padding: 0; } /* * Blitz * * Skin inspired by Gitblit with heavily-modified excerpts from Skeleton 2.0.4. * Blitz is authored by james.moger@gitblit.com. * * Skeleton is authored by Dave Gamache and is distributed under the MIT license. * http://getskeleton.com * ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ html { /* 62.5% so that the REM values are base 10px. */ /* 1.5rem = 15px */ font-size: 62.5%; } /* Typography ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ h1, h2, h3, h4, h5, h6 { margin: 0; margin-bottom: 1rem; font-weight: 700; } h1 { font-size: 3.0rem; line-height: 1.2; } h2 { font-size: 2.6rem; line-height: 1.25; } h3 { font-size: 2.4rem; line-height: 1.3; } h4 { font-size: 2.0rem; line-height: 1.35; } h5 { font-size: 1.6rem; line-height: 1.5; } h6 { font-size: 1.4rem; line-height: 1.6; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 0.75em; font-weight: 400; color: #ccc; } pre, code { font-size: 1.2rem; } body { font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ line-height: 1.5; font-weight: 400; font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; color: #333; background-color: #f8f8f8; } /* Spacing ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ button, .button { margin-bottom: 1rem; } input, textarea, select, fieldset, pre, blockquote, dl, figure, table, p, ul, ol { margin-bottom: 1rem; } p { margin-top: 0; } hr { margin-top: 3rem; margin-bottom: 3.5rem; border-width: 0; border-top: 1px solid #ccc; } /* Buttons ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .button, button, input[type="button"], input[type="reset"], input[type="submit"] { display: inline-block; height: 3.3rem; padding: 0 2.2rem; color: #555 !important; text-align: center; font-size: 1.1rem; font-weight: 700; line-height: 3.3rem; letter-spacing: .08rem; text-transform: uppercase; text-decoration: none; white-space: nowrap; background-color: transparent; border-radius: 4px; border: 1px solid #ccc; cursor: pointer; box-sizing: border-box; } .button:hover, button:hover, input[type="button"]:hover, input[type="reset"]:hover, .button:focus, button:focus, input[type="button"]:focus, input[type="reset"]:focus { color: #444 !important; background-color: #eee; border-color: #aaa; outline: 0; } input[type="submit"] { color: white !important; background-color: #446979; border-color: #446979; } input[type="submit"]:hover, input[type="submit"]:focus { color: white !important; background-color: #648898; border-color: #648898; } /* Forms ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ input[type="email"], input[type="number"], input[type="search"], input[type="text"], input[type="tel"], input[type="url"], input[type="password"], textarea, select { height: 3.3rem; padding: 6px 10px; background-color: #fff; border: 1px solid #ddd; border-radius: 4px; box-shadow: none; box-sizing: border-box; } /* Removes awkward default styles on some inputs for iOS */ input[type="email"], input[type="number"], input[type="search"], input[type="text"], input[type="tel"], input[type="url"], input[type="password"], textarea { -webkit-appearance: none; -moz-appearance: none; appearance: none; } textarea { height: inherit; min-height: 65px; padding-top: 6px; padding-bottom: 6px; } input[type="email"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="text"]:focus, input[type="tel"]:focus, input[type="url"]:focus, input[type="password"]:focus, textarea:focus, select:focus { border: 1px solid #aaa; outline: 0; } label, legend { display: block; margin-bottom: .5rem; font-weight: 700; } fieldset { padding: 0; border-width: 0; } input[type="checkbox"], input[type="radio"] { display: inline; } /* Links ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ a { color: #446979; text-decoration: none; } a:hover { text-decoration: underline; } /* Lists ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ ul { list-style: square; } ol { list-style: decimal; } ol, ul { padding-left: 3rem; margin-top: 0; } li { margin-bottom: 0.5rem; } /* Nested Lists ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ ul ul, ul ol, ol ol, ol ul { margin: 1rem 0 1rem 2rem; } /* Code ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ code, kbd { padding: .2rem .5rem; margin: 0 .2rem; white-space: nowrap; background: #f8f8f8; border: 1px solid #ccc; border-radius: 4px; } pre > code { display: block; padding: 1rem 1.5rem; white-space: pre; } pre.verbatim { background-color: inherit; white-space: pre-wrap; } /* Blockquote ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ blockquote { padding: 0px 20px; margin: 0 0 20px; border-left: 4px solid #ccc; } /* Tables ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ th, td { padding: 6px 5px; text-align: left; border-bottom: 1px solid #ddd; } th:first-child, td:first-child { padding-left: 0; } th:last-child, td:last-child { padding-right: 0; } /* * Blitz Page Layout Design * * html > body > header > container > mainmenu * middle > container > submenu & content * footer > container > generation stats, fossil logo, version * ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ /* Container * Represents the usable layout space for header, middle, and footer. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .container { position: relative; width: 100%; max-width: 900px; margin: 0 auto; box-sizing: border-box; } /* Header * Div displayed at the top of every page. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .header { color: #666; font-weight: 400; padding-top: 10px; border-width: 0px; border-top: 4px solid #446979; border-bottom: 1px solid #ccc; } .header .logo { display: inline-block; } .header .login { padding-top: 2px; text-align: right; } .header .login .button { margin: 0; } .header h1 { margin: 0px; color: #666; display: inline-block; } .header .logo h1 { display: inline-block; } .header .title h1 { padding-bottom: 10px; } .header h1 small, .header h2 small, .header .login { color: #888; } .header a.rss { display: inline-block; padding: 10px 15px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMNDhwn05VjawAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAGlSURBVDjLrdPfb8xREAXwT7tIl+paVNaPJghCKC8kXv0XXvyNXsRfwYPQJqVKiqykWFVZXd12vcxNJtduUtJJvrm7984998ycMxxwNGI9jPs4j7nY+/U/gIdiPYO71dk21rCE7r8ybOHGmMfmcRNnsbEf1gXwNzqYSXs5WljEMXzAaBLg1Ji9Js7hOi6OeeAznqC/X8AcMyHWYpX7E4/Rm1QyHMdefCWGeI/VcMDR2D8S7Fci5y/AeTzCPVyLi1sYJAut4BTaiX0n9kc14MmkcjPY3I5LXezGtxqKtyJ3Lir6VAM2AmCq6m8Hl6PsQTB5hyvxmMhZxk4G3MZLfAwLtdNZM9rwOs528TVVNB3ga7UoQ2wGmyWciFaU0VwIJiP8iL6Xfp7GK+w0JthliDep8UKonTSGvbBTaU8f3QzYxgPcCsBvWK9E6OBFCNGPVjTTqC430p+H6fLVGLGtmIw7SbwevqT+XkgVPJ9Otpmtyl6I9XswLXEp/d6oPN0ugJu14xMLob4kgPRYjtkCOMDTUG+AZ3ibEtfDLorfEmAB3UuTdXDxBzUUZV+B82aLAAAAAElFTkSuQmCC); background-position: center center; background-repeat: no-repeat; } /* Middle * Center div displayed between header and footer. Contains per-page content. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .middle { background-color: white; padding-bottom: 20px; max-width: 100%; box-sizing: border-box; } /* Content * Displayed below submenu within the middle div. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .content { padding-top: 15px; } .content a { color: #002060; } /* Footer * Displayed after the middle div and forms the page bottom. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .footer { padding: 10px 0 60px; border-top: 1px solid #ccc; background-color: #f8f8f8; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABGCAQAAADxl9ugAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAwkQBRPw+yfrAAAAPHRFWHRDb21tZW50ACBJbWFnZSBnZW5lcmF0ZWQgYnkgRVNQIEdob3N0c2NyaXB0IChkZXZpY2U9cG5tcmF3KQqV01S1AAANg0lEQVRo3s2aa3RVRZbH/3tXnftIbhJCeJMXyEsNCsgrSBzAYXyt0YVj2zSOonbLqNNO+25FB2kdoBVdrp6l09P2NNpOL/ExSrtUdGRU5JEQgggCggIhQIBAIIGQ5N57TlXt+ZAICY+AGCT76zlV91dVe+/a+38uDQ7dYmrxw41QocJuni28vWTedEa7Gd9iatplos7Y2mfDRED6A2G0I2At6AdPIiA84HgbLhx1o9QX9Zoh7QjYHpOkYJYrfNyOKH0O/f2FJpfkSRmMCNqDk9rDXwTAuxK7h3uFf7vXxC6QVO8w19taNOT4Y0wu1sCdW0AA6IZ73bCUaI/GHuqnsJqcEqVrzSo+wNtLdgAPsz6jeVURtQ9gA8bQT8xztW7X2u3I4G6UdA0cohxcSAN7nt939/zDQzl0LnfwaLpxqFT/i7w7XLYXhoUQ+YFW3pJlC0/nt6jZZb4zjXY2AaGXvQOz/gMY09NM4C6ixRL7OU3PTm4ORdiIjyLsJvq1Z28Hj5rBM82xMTqPuhHznmU72vq12W5M3+LykQWUW9pirzXOmmk8wjE87kb8HPmSKlY+wY62R9jhI69xf/AmYiEfiXs+e4CCAZiDUc9wP6cRIJn8tq23PQClbwap9Ivk7usiGj/CDs5xl3Qe/EiQCEWsgXLlq8sfamM73osMna43ef/pfm731Hsxv+Z00ozFzaJpF+gMrsNB2BwL3cGpSsNRWHbmvTQNiTbev9q4xXszMLzqpdgDNjxv/YjmvHlSQIc5brl8nrqT5pllMpHM9wRc4gU3oC8JyDLt8P78ZLyM2lrmAeTg5YrKdf1S1N9QTs6At1YM49DJo1gwWy7uE5kKBQHbler9K8R+L8API2qmFoDY7ejxpxGJxtMctyZcfYvJDYX4i5LXp/MJAS2edkM6edNUDuLNOdMDmz913bIw8RidKO/1w+3NQfePbHQjdbd/NKOjbq7UqQOmYtXb/+BdbGc4AJjPX53CXe6UGweYWxUR8N8rNkzn4wAFc9yYPvGbI+mttoycpo14fWbD0hZv+njOAcBl6Yl8jiEMbSKhqGPypZ5N0B2kDxrjOjF0QuI2oRqj2z6rAebx5pNiRrEo0jhV9wFkP//xpkPHAU6UGdnBLyR8jMOQs6xwcMAznVys+Uqa5YCCnilFkuVSkeKlGKfDED8JaI+VifMWR9LPC/u+UkoZA6edOezVu83pny4yD6qQnCxhDzk/MhUED+8PWHJMkAgWROvvQoxOcEdayynVY9/5tIgAwsfIvaD3XaFx6M6ddMx3WlurCGICiAIhMLxB1VM+wQRMDOeYjHCUMum85OW909/acOlJgqaI3qrulU9dYGlgzVI1tsVrETzlOt3MeUGCudVoCgJmAhFU78F+6Usu0V39iylSHCRZMROM0do5pUDWQamEPZTy5oqyXVt77bG94HGEyTkCE8BsjLOcl11Uvf7V+qvIP86jgWH8zhc9LpKYU7qRhH5NTRknwFw3+jpMQCIItG69PCLfZ1YKAMlS/7PQDCc2qbRzSjET4slINBAvhsPxjarKKy/9FhjZG8Ol4tINi/uFzkcfl8sEnwExATGRY73Ze2VpAHxHoPFki7r2iljN3a6LqqOxnZ+vXUBNwTF6uL0e0Nr3tSYWpqNhQtaIaA0A1oZftuf5Y1xmCMRO2IM1VXqf3aYr5IDXODTx7+43PAjPFcit1MANeHfFxuFpSFW9TbbORpaNEqt6/5tIoxuBOO049NHXNTN5lFwlE3o09JUMlWKdSmJ/UC8TvRwqjNzoVwNIw3upcluyq4hSAq3Idyt5HOyRIDGuGdA42un+6wv/Cq7sFA1F/B4N/5MEgL/yOsSPlFSMOzD5JhkMEQ8l8u41Job7hVoExsiRNMU1Biac4oqD92Np8Xt0BgUiEOeIHLyobbQb9U/8fSAItsFdJv1wECASB5L92xb2yefcE3Q+jgsof//m3+PO2i7YhgV0HisAK48UnE03EaT67axMyjMNXpFkf/za8r3VPP2I46Ri+aYDW0z3SMT6NJb62wPiJEFhEoFCYIhNoyS4VF1CBKArPu6MKWysBZhFVFrD7yri2VkuR4QZAIkTMAOAiDIY9KvFQ3gVPqXVFD9JSbSS3vP7b/QzKY8SlO6G5e2fv/dozvDxciKvCqOYrIURT/XU2+0SKrdVqtpVojz4Sq1Vi1duV0UE+PSEy33AhRRZAzDDc4vXrB1xKU0gRUR0LCCRi/be8XZ12/0M41Ka5K/5JjA80PlQKMjfeVVN9ZG0NZbmH8xf5Y8nJxIKmYC7SmLlexeVp2wKb+y++f6KZ3c/03g+qSISPONGDqHRZOk7QGde6XsrjTP+kXTTCpCVGErZteZUDRdhD3Ls65tz64J85ZGyQ0tXDAzckadFlOtv+ZQLoYMgHHaGcrJ7fb56inR3WVJJRVTdVM3kQSh5r1hjlbIGIKVX6ammE1vnmImh4Y4BZHGcvmvx5XQ6BcRIfnPHxV82ZnFUYsh+bWXLzMuwquGwCnvdBUTkqHcPmb+l5cJZcKervlwc8N04sbYwSJC1tsnneemJqh32LksZflr1SUh+pT6q+/ov/krztitDq1s4hP1p7mbfuFfkEKJgSejLh/Wa7Y5GJsdQmEYDoVocDCvnLCvnwPDMzOK/uiVoPS8IxoQi409D2xAU4Hd2xE2DZ3gjvcpVZY+0iqgAbFh7F9grp84xf5D6QFOE/rYo1vto4z6ZVg/COHKAiGJrACaljNHaiaqTp0NeXlr37Ydz/ahSLY9YzLIPMzlxSrxMzM/ochfnO8UHvJJpgTnm+UE5GKMeOu3LrLJPd32+Z1FamfczKli36jzTtHplvPg46o2WgNwEaOqoTk8Jxsu4+vGUruDkCCCJkg171g2ntqMkjrmuYUBwG7LglIq/U7Zr1HEjJrtiay9imIzsqt37gb4/RSZlSsP88iZf5T3kX2xOuBEck2yp13F32NbDuZbHqSjwFrzJbeP5eN6NHOJuoQyXRIZ7Y+3Gh08wohjpW/VOkFMyqagHILnOSAOuflh1bqKggew524Zs1ex+R6cmz1W7Z6clvzzF8T7rLsvnSfBgJVO9cN+ax4/IRwazZLZrqmOSWJjAR0hCdFc/F2AtToTos34POQHAkVw2Sp2m7EKwOEyLVj59w6EtpyjdFYSCCYhaC0n9fcmmr5pb8QBrQl0wqn/hNc82J8Rfc8lWVwVGwLeNDVPTdW30+KZN0Sab5JTBqOBBowIHzeZVJcBjXHdKXfQp93+DgwuIgy9QtqJ8evPhOtRRzZi30iKfBZPxQVNhofDP6sUXh05zA5MH+WKdpAgAJ/lAChqhyQmd5HgFChFoMvar0AaKq8qSGmA6o03lVFCEqx1Q0Ce0075hkgvW93EPNeMZ3Cl93eRl5Q8GVjoBs1tUN1l/rvkn1VOuNXUIAyATv6zz3bXPEo3t7N/L6bBirfV0MimktOclgnDUJHiTWxo9oJOZQT/TDUk0nIYfFODFaMMN4WFqbnEl8BzXtlBX++ATr2KW3eC9kbg/9d2l6/qmdxrq9bdRkBwMtrgd+lpkpxwyWSwAkvRKSfl0phf4l+6acGVeak6QQbCJYH/Gwci+zPi/+oMFEJpLdTDfQ8IpTTl8r/lkQuniX3oR98mjX65sJQZ0wYNu1NU0wZ8RjSUf0Qo22aCU1oAoCazTFe5bdZ1pVIqcv2B12XSm6awxCFNaichCr1I1auDOQFvKxzQHFD4mexGXNfds/PoYB+iMhxzwIC8vcJe7HKVIrBEoLRQkuVL+Ii70lDlMUOR/uHrJdNaAwXo82orksR8gfVUAGFkgy5JfhKdEKncelwhq8SinwMeidX+303VHuvOgCGSRRF2o6vb6FyKmQTGRNTraQt1qJ6EaAPA4V22MYH20wXx+aCyfKFvFAcymiYfCh/YhSQZACFHpBB/l6On2l0s/AgTBWdIHHbpIulzfWDbvAW4r3gPUIwWZ0lW6SoaE0AgDYG6Six0R4OjgWRMwGUAVHuUz+SS2iNQ+XSMAvKqzrLCemdtUo3ifWhpoTi7b/RSfVRH9zBc2y43umXVgtImf3R08c7zCIeYpVoPOtoh+ZjYEhd3kWtV4IHSldEjAV7U/ATHxig89Tx0QUFCtvUJisxnNknuHArSY4+xtNuk4ZQWai4wOBThJRqZJvhYXtptnNTVAHQnQYbT4k7QI6/Vd6w6f/U9h39cUgEg+BCG3rk/AHQ9wlhsz1IUCI3tRPrDVtdlhzO9rxPNke+nuXR0TUIdAMOrDlkJshwEM4QId98C8vKTmUUJHAwww03VNT8ny9hd/cJ9qCaU7QnrpjXvcsKuT6W7VdcvHc+sq95wDCuZILxp9t+TZJWVL/56PPdJzDhjDhG75UyUrsXXtBw9z/PjAObd3729leA++mTOldO07dyl9ghbmnALmYpjybndhO3/VV/dx9IQdlj53YQEAo2din3p1cv1VfDIF8EfvSdJQSZvU3ljGJJOvNuH94kOPs22jwWq3P5edTryG8G/OdtsxOPiZd6O1ppTeK0n43Hb/9yPuYBhPuFFXumEq3231S+ibL/e+yhtP2Zz+iD74hCu83vblr+W1yJ5LgguxmzedRu/8//AUSaqMTR1xAAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: center top 10px; } .footer a { color: #3b5c6b; } /* Main Menu * Displayed in header, contains repository links. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .mainmenu { clear:both; } .mainmenu ul { list-style: none outside; display: block; position: relative; border-top: 1px solid #ccc; padding: 0; } .mainmenu li { outline: 0; display: block; float: left; margin: 0; } .mainmenu li.active { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: center bottom; } .mainmenu li a { color: #3b5c6b; display: block; padding: 10px 15px; } .mainmenu li.active a { font-weight: bold; } .mainmenu li:hover { background-color: #eee; } /* Submenu * Displayed in the middle div. Contains page-specific form controls. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .submenu { padding: 10px 0px; border-bottom: 1px solid #ddd; } .submenu input, .submenu select { margin: 0 0 0 5px; } .submenu a, .submenu label { display: inline; font-weight: normal; color: #3b5c6b; padding: 5px 15px; text-decoration: none; border: 1px solid transparent; border-radius: 5px; } .submenu a:hover, .submenu label:hover { border: 1px solid #ccc; } /* Section * Cap/header to distinguish a section. Displayed within a content div. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .section { font-weight: bold; background-color: #f5f5f5; border: 1px solid #ccc; padding: 9px 10px 10px; margin: 10px 0; } /* Section Menu * Div of buttons/links, displayed with a section div within a content div. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .sectionmenu { border: 1px solid #ccc; border-top: 0; margin-top: -10px; margin-bottom: 10px; padding: 5px; text-align: center; } .sectionmenu a { display: inline-block; margin-top: 5px; margin-right: 1em; } /* File browser * Repository tree navigation. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ ul.browser { list-style: none; } ul.browser li.dir { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: 0px center; padding-left: 22px; padding-top: 2px; } ul.browser li.file { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); background-repeat: no-repeat; background-position: 0px center; padding-left: 22px; padding-top: 2px; } div.filetreeline { display: table; width: 100%; white-space: nowrap; } /* tree-view top-level list */ .filetree > ul { display: inline-block; } /* tree-view lists */ .filetree ul { margin: 0; padding: 0; list-style: none; } /* tree-view collapsed list */ .filetree ul.collapsed { display: none; } /* tree-view lists below the root */ .filetree ul ul { position: relative; margin: 0 0 0 21px; } /* tree-view lists items */ .filetree li { position: relative; margin: 0; padding: 0; } /* tree-view node lines */ .filetree li li:before { content: ''; position: absolute; top: -.8em; left: -14px; width: 16px; height: 1.5em; border-left: 1px solid #ccc; border-bottom: 1px solid #ccc; } /* tree-view directory lines */ .filetree li > ul:before { content: ''; position: absolute; top: -1.5em; bottom: 0; left: -35px; border-left: 1px solid #ccc; } /* hide lines for last-child directories */ .filetree li.last > ul:before { display: none; } .filetree a { position: relative; z-index: 1; display: table-cell; min-height: 16px; padding-left: 22px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExMaPfBcSgAAAFNJREFUOMvtkzEOwDAIA02VL5pHwiOTJZFQmkqFOTex+CwPCCYkAaDjB+4u65ZdYGafQVV9SR4kWQUke0mwS1o2HGcAQKs0R1lpQuQKruD4jVnBAG/cGRqf0U66AAAAAElFTkSuQmCC); background-position: center left; background-repeat: no-repeat; } .filetree .dir > div.filetreeline > a { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAVQBVAFV4xrLkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wMLExABnLjGZQAAAEFJREFUOMtjYKAQMIaGhv4npGj16tWMuORYGBgYGOZW+eDUnNy2Ba/hLMQ4E58rCRpAyHVMlAbiqAGjBhCdmWgKAHp4Dh0ZusP3AAAAAElFTkSuQmCC); } /* Label-Value table * Displayed on the Check-in & Admin pages. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ table.label-value th { vertical-align: middle; } /* Branches table ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .brlist table td { padding: 5px; } /* Timeline * Displays chronologically-ordered check-ins with a branch graph. ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ tr.timelineCurrent { border-left: 2px solid orange; background-color: #ffc; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; } tr.timelineSelected { border-left: 2px solid orange; background-color: #ffffe8; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; } tr.timelineCurrent td.timelineTableCell { } tr.timelineBottom td { border-bottom: 0; } div.timelineDate { font-weight: bold; white-space: nowrap; } td.timelineTime { vertical-align: top; text-align: right; white-space: nowrap; border-bottom: 0; } td.timelineGraph { width: 20px; text-align: left; vertical-align: top; border-bottom: 0; } a.timelineHistLink { text-transform: lowercase; } span.timelineComment { padding: 0px 5px; } /* Login/Loguot ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ table.login_out { } table.login_out .login_out_label { font-weight: 700; text-align: right; } table.login_out td { border: 0; } /* Diff displays ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ pre.udiff, table.sbsdiffcols { width: 100%; overflow: auto; border: 1px solid #ccc; padding: 0px 5px; font-size: 1rem; } pre.udiff:focus, table.sbsdiffcols:focus { outline: none; } /* Ticket Reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ table.report { width: 100%; cursor: auto; border-radius: 4px; border: 1px solid #ccc; margin: 0 0 1em 0; } .report td, .report th { border: 0; font-size: .9em; padding: 5px; } .report th { cursor: pointer; } .report thead+tbody tr:hover { background-color: #f5f9fc !important; } /* Ticket page ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ table.tktDsp { border-top: 1px solid #ccc; border-left: 1px solid #ccc; width: 100%; margin: 15px 0px 10px 0px; } td.tktDspLabel, td.tktDescLabel { width: 70px; text-align: right; overflow: hidden; font-weight: 700; padding: 10px; background-color: #f8f8f8; } td.tktDescLabel { vertical-align: top; } td.tktDspValue, td.tktDescValue { text-align: left; vertical-align: top; border: 1px solid #ccc; padding: 10px; } td.tktDspValue pre, td.tktDescValue pre, td.tktDspValue code, td.tktDescValue code { white-space: pre-wrap; } div.tktComments { width: 100%; margin: 30px 0px 10px 0px; } div.tktComment { } div.tktCommentHeader { border: 1px solid #ccc; background-color: #f8f8f8; padding: 10px 10px; margin-bottom: 10px; } span.tktCommentLogin { display: inline-block; font-weight: 700; color: #002060; } div.tktCommentBody { margin: 10px 40px 30px; } /* User setup table ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ td.usetupEditLabel { font-weight: 700; } /* Utilities ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .full-width { width: 100%; box-sizing: border-box; } .max-full-width { max-width: 100%; box-sizing: border-box; } .pull-right { float: right; } .pull-left { float: left; } /* Clearing ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ .container:after, .mainmenu:after, .row:after, .u-cf { content: ""; display: table; clear: both; } |
Added skins/blitz_no_logo/details.txt.
> > > > | 1 2 3 4 | timeline-arrowheads: 0 timeline-circle-nodes: 1 timeline-color-graph-lines: 1 white-foreground: 0 |
Added skins/blitz_no_logo/footer.txt.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | </div> <!-- end div container --> </div> <!-- end div middle max-full-width --> <div class="footer"> <div class="container"> <div class="pull-right"> <a href="https://www.fossil-scm.org/">Fossil $release_version $manifest_version $manifest_date</a> </div> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s </div> </div> |
Added skins/blitz_no_logo/header.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <div class="header"> <div class="container"> <div class="login pull-right"> <th1> if {[info exists login]} { html "<b>$login</b> — <a class='button' href='$home/login'>Logout</a>\n" } else { html "<a class='button' href='$home/login'>Login</a>\n" } </th1> </div> <div class='title'> <h1>$<project_name> <th1> if {[anycap jor]} { html "<a class='rss' href='$home/timeline.rss'></a>" } </th1> <small> $<title></small></h1> </div> <!-- Main Menu --> <div class="mainmenu"> <ul> <th1> proc menulink {url name} { upvar current_page current upvar home home if {[string range $url 0 [string length $current]] eq "/$current"} { html "<li class='active'>" } else { html "<li>" } html "<a href='$home$url'>$name</a></li>\n" } menulink $index_page Home if {[anycap jor]} { menulink /timeline Timeline } if {[hascap oh]} { menulink /dir?ci=tip Files } if {[hascap o]} { menulink /brlist Branches menulink /taglist Tags } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } if {[hascap r]} { menulink /ticket Tickets } if {[hascap j]} { menulink /wiki Wiki } if {[hascap o]} { menulink /help Help } if {[hascap s]} { menulink /setup Admin } elseif {[hascap a]} { menulink /setup_ulist Users } </th1> </ul> </div> <!-- end div mainmenu --> </div> <!-- end div container --> </div> <!-- end div header --> <div class="middle max-full-width"> <div class="container"> |
Added skins/blitz_no_logo/ticket.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <h4>$<title></h4> <table class="tktDsp"> <tr><td class="tktDspLabel">Ticket UUID</td> <th1> if {[info exists tkt_uuid]} { if {[hascap s]} { html "<td class='tktDspValue' colspan='3'>$tkt_uuid " html "($tkt_id)</td></tr>\n" } else { html "<td class='tktDspValue' colspan='3'>$tkt_uuid</td></tr>\n" } } else { if {[hascap s]} { html "<td class='tktDspValue' colspan='3'>Deleted " html "(0)</td></tr>\n" } else { html "<td class='tktDspValue' colspan='3'>Deleted</td></tr>\n" } } </th1> <tr><td class="tktDspLabel">Status</td><td class="tktDspValue"> $<status> </td> <td class="tktDspLabel">Type</td><td class="tktDspValue"> $<type> </td></tr> <tr><td class="tktDspLabel">Severity</td><td class="tktDspValue"> $<severity> </td> <td class="tktDspLabel">Priority</td><td class="tktDspValue"> $<priority> </td></tr> <tr><td class="tktDspLabel">Subsystem</td><td class="tktDspValue"> $<subsystem> </td> <td class="tktDspLabel">Resolution</td><td class="tktDspValue"> $<resolution> </td></tr> <tr><td class="tktDspLabel">Last Modified</td><td class="tktDspValue"> <th1> if {[info exists tkt_datetime]} { html $tkt_datetime } </th1> </td> <th1>enable_output [hascap e]</th1> <td class="tktDspLabel">Contact</td><td class="tktDspValue"> $<private_contact> </td> <th1>enable_output 1</th1> </tr> <tr><td class="tktDspLabel">Version Found In</td> <td colspan="3" valign="top" class="tktDspValue"> $<foundin> </td></tr> <th1> if {[info exists comment]} { if {[string length $comment]>10} { html { <tr> <td class="tktDescLabel">Description</td> <td class="tktDescValue" colspan="3"> } if {[info exists plaintext]} { set r [randhex] wiki "<verbatim-$r links>\n$comment\n</verbatim-$r>" } else { wiki $comment } html "</td></tr>\n" } } </th1> </table> <div class="tktComments"> <th1> set seenRow 0 set alwaysPlaintext [info exists plaintext] query {SELECT datetime(tkt_mtime) AS xdate, login AS xlogin, mimetype as xmimetype, icomment AS xcomment, username AS xusername FROM ticketchng WHERE tkt_id=$tkt_id AND length(icomment)>0} { if {$seenRow eq "0"} { html "<h5>User Comments</h5>\n" set seenRow 1 } html "<div class='tktComment'>\n" html "<div class='tktCommentHeader'>\n" html "<div class='pull-right'>$xdate</div>\n" html "<span class='tktCommentLogin'>[htmlize $xlogin]</span>" if {$xlogin ne $xusername && [string length $xusername]>0} { html " (claiming to be <span class='tktCommentLogin'>[htmlize $xusername]</span>)" } html " commented</div>\n" html "<div class='tktCommentBody'>\n" if {$alwaysPlaintext || $xmimetype eq "text/plain"} { set r [randhex] if {$xmimetype ne "text/plain"} {html "([htmlize $xmimetype])\n"} wiki "<verbatim-$r>[string trimright $xcomment]</verbatim-$r>\n" } elseif {$xmimetype eq "text/x-fossil-wiki"} { wiki "<p>\n[string trimright $xcomment]\n</p>\n" } elseif {$xmimetype eq "text/html"} { wiki "<p><nowiki>\n[string trimright $xcomment]\n</nowiki></p>\n" } else { set r [randhex] wiki "<verbatim-$r links>[string trimright $xcomment]</verbatim-$r>\n" } html "</div><!-- end comment body -->\n" html "</div><!-- end comment -->\n" } </th1> </div> |
Added skins/bootstrap/css.txt.
cannot compute difference between binary files
Added skins/bootstrap/details.txt.
> > > > | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 1 timeline-color-graph-lines: 1 white-foreground: 0 |
Added skins/bootstrap/footer.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <th1> if {! $is_index && ! $is_home} { html "</div>" } </th1> </div> <div id="push"></div> </div> <footer id="footer"> <p>© Copyright $<project_name>. All right reserved. Fossil $release_version · <a href="$home/timeline.rss">RSS</a></p> </footer> <script> var tables = document.querySelectorAll('table'); for (var i = 0; i < tables.length; i++) { if (tables[i].id !== "timelineTable") tables[i].classList.add('table'); }; var submenus = document.querySelectorAll('.submenu'); for (var i = 0; i < submenus.length; i++) { submenus[i].classList.add('btn-group'); var labels = submenus[i].querySelectorAll('.label'); for (var j = 0; j < labels.length; j++) { labels[j].classList.remove('label'); labels[j].classList.add('btn'); labels[j].classList.add('btn-default'); labels[j].classList.add('btn-sm'); } }; //Handle the collapsible navbar var collapse = document.querySelector('[data-toggle="collapse"]'); collapse.onclick = function(){ var target = document.querySelector( collapse.getAttribute('data-target') ); target.classList.toggle('collapse'); target.classList.toggle('collapsed'); }; </script> |
Added skins/bootstrap/header.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <html lang="en"> <head> <meta charset="utf-8"> <base href="$baseurl/$current_page" /> <title>$<project_name>: $<title></title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="Content-Security-Policy" content="default-src 'self' data:; script-src 'self' 'nonce-$<nonce>'; style-src 'self' 'unsafe-inline'"/> <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="$home/timeline.rss" /> <link rel="stylesheet" href="$home/style.css?default" type="text/css" media="screen" /> <script> function gebi(x){ if(/^#/.test(x)) x = x.substr(1); var e = document.getElementById(x); if(!e) throw new Error("Expecting element with ID "+x); else return e; } </script> </head> <body data-spy="scroll" data-target=".sidebar"> <div id="wrap"> <div class="navbar navbar-inverse navbar-fixed-top" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <th1>html "<a class='navbar-brand' href='$home$index_page'>$project_name</a>"</th1> </div> <div class="collapse navbar-collapse"> <p class="navbar-text pull-right"><th1> if {[info exists login]} { puts "Logged in as $login" html " · <a href='$home/login'>Logout</a>" } else { puts "Not logged in" html " · <a href='$home/login'>Login</a>" } </th1></p> <ul class="nav navbar-nav"> <th1> set is_index [expr [string compare [string range $current_page 0 4] "index"]==0] set is_home [expr [string compare [string range $current_page 0 [expr [string length $index_page]-1] ] $index_page]==0] if {$is_index || $is_home} { html "<li class='active'><a href='$home$index_page'>Home</a></li>\n" } else { html "<li><a href='$home$index_page'>Home</a></li>\n" } if {[hascap j]} { if {[string compare [string range $current_page 0 3] "wiki"] == 0} { html "<li class='active'><a href='$home/wiki'>Wiki</a></li>\n" } else { html "<li><a href='$home/wiki'>Wiki</a></li>\n" } } if {[anycap jor]} { if {[string compare $current_page "timeline"] == 0} { html "<li class='active'><a href='$home/timeline'>Timeline</a></li>\n" } else { html "<li><a href='$home/timeline'>Timeline</a></li>\n" } } if {[hascap oh]} { if {[string compare [string range $current_page 0 2] "dir"] == 0} { html "<li class='active'><a href='$home/dir?ci=tip'>Files</a></li>\n" } else { html "<li><a href='$home/dir?ci=tip'>Files</a></li>\n" } } if {[hascap o]} { if {[string compare $current_page "brlist"] == 0} { html "<li class='active'><a href='$home/brlist'>Branches</a></li>\n" } else { html "<li><a href='$home/brlist'>Branches</a></li>\n" } if {[string compare $current_page "taglist"] == 0} { html "<li class='active'><a href='$home/taglist'>Tags</a></li>\n" } else { html "<li><a href='$home/taglist'>Tags</a></li>\n" } } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { if {[string compare $current_page "forum"] == 0} { html "<li class='active'><a href='$home/forum'>Forum</a></li>\n" } else { html "<li><a href='$home/forum'>Forum</a></li>\n" } } if {[hascap r]} { if {[string compare $current_page "reportlist"] == 0} { html "<li class='active'><a href='$home/reportlist'>Tickets</a></li>\n" } else { html "<li><a href='$home/reportlist'>Tickets</a></li>\n" } } if {[hascap s]} { if {[string compare [string range $current_page 0 4] "setup"] == 0} { html "<li class='active'><a href='$home/setup'>Admin</a></li>\n" } else { html "<li><a href='$home/setup'>Admin</a></li>\n" } } elseif {[hascap a]} { if {[string compare [string range $current_page 0 4] "setup"] == 0} { html "<li class='active'><a href='$home/setup_ulist'>Users</a></li>\n" } else { html "<li><a href='$home/setup_ulist'>Users</a></li>\n" } } </th1> </ul> </div><!--/.nav-collapse --> </div> </div> <div class="content"> <th1> html "<div class='container'>" html "<ul class='breadcrumb'>" html "<li><a href='$home$index_page'>Home</a></li>" html "<li><a href='$home/$current_page'>[htmlize $title]</a></li>" html "</ul>" </th1> |
Deleted skins/darkmode/css.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted skins/darkmode/details.txt.
|
| < < < < |
Deleted skins/darkmode/footer.txt.
|
| < < < < < < < < |
Deleted skins/darkmode/header.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to skins/default/README.md.
|
| | < < < | < < < > | | 1 2 3 4 5 | This skin was contributed by Étienne Deparis. On 2015-03-14 this skin was promoted from an option to the default, which involved moving it from its original home in the skins/etienne1 directory into skins/default. |
Changes to skins/default/css.txt.
|
| < < < | | | > > > > < < < < < < < < < < < | | | | > > | < > > > | | < < < < < < < < < < < < < < < < < | < | | | | | | > | > > | > > | < > | > > > > > > | > > > | > > | > | < > > > > | < > | | | | | | | | > | | | | | > | | | | | | | | | | | | | | | > | | | < < | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > < < < < < < | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | body { margin: 0 auto; background-color: white; font-family: sans-serif; font-size:14pt; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } a { color: #4183C4; text-decoration: none; } a:hover { color: #4183C4; text-decoration: underline; } div.forumPosts a:visited { color: #6A7F94; } hr { color: #eee; } .title { color: #4183C4; float:left; } .title h1 { display:inline; } .title h1:after { content: " / "; color: #777; font-weight: normal; } .content h1 { font-size: 1.25em; } .content h2 { font-size: 1.15em; } .content h3 { font-size: 1.05em; font-weight: bold; } .section { font-size: 1em; font-weight: bold; background-color: #f5f5f5; border: 1px solid #d8d8d8; border-radius: 3px 3px 0 0; padding: 9px 10px 10px; margin: 10px 0; } .sectionmenu { border: 1px solid #d8d8d8; border-radius: 0 0 3px 3px; border-top: 0; margin-top: -10px; margin-bottom: 10px; padding: 10px; } .sectionmenu a { display: inline-block; margin-right: 1em; } .status { float:right; font-size:.7em; } .mainmenu { font-size:.8em; clear:both; background:#eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x; border:1px solid #eaeaea; border-radius:5px; overflow-x: auto; overflow-y: hidden; white-space: nowrap; z-index: 21; /* just above hbdrop */ } .mainmenu a { text-decoration:none; color: #777; border-right:1px solid #eaeaea; } .mainmenu a.active, .mainmenu a:hover { color: #000; border-bottom:2px solid #D26911; } div#hbdrop { background-color: white; border: 1px solid black; border-top: white; border-radius: 0 0 0.5em 0.5em; display: none; font-size: 80%; left: 2em; width: 90%; padding-right: 1em; position: absolute; z-index: 20; /* just below mainmenu, but above timeline bubbles */ } .submenu { font-size: .7em; padding: 10px; border-bottom: 1px solid #ccc; } .submenu a, .submenu label { padding: 10px 11px; text-decoration:none; color: #777; } .submenu a:hover, .submenu label:hover { padding: 6px 10px; border: 1px solid #ccc; border-radius: 5px; color: #000; } .content { padding-top: 10px; font-size:.8em; color: #444; } .udiff, .sbsdiff { font-size: .85em !important; overflow: auto; border: 1px solid #ccc; border-radius: 5px; } .content blockquote { padding: 0 15px; } div.forumHierRoot blockquote, div.forumHier blockquote { background-color: rgba(65, 131, 196, 0.1); border-left: 3px solid #254769; padding: .1em 1em; } table.report { cursor: auto; border-radius: 5px; border: 1px solid #ccc; margin: 1em 0; } .report td, .report th { border: 0; font-size: .8em; padding: 10px; } .report td:first-child { border-top-left-radius: 5px; } .report tbody tr:last-child td:first-child { border-bottom-left-radius: 5px; } .report td:last-child { border-top-right-radius: 5px; } .report tbody tr:last-child { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } .report tbody tr:last-child td:last-child { border-bottom-right-radius: 5px; } .report th { cursor: pointer; } .report thead+tbody tr:hover { background-color: #f5f9fc !important; } td.tktDspLabel { width: 70px; text-align: right; overflow: hidden; } td.tktDspValue { text-align: left; vertical-align: top; background-color: #f8f8f8; border: 1px solid #ccc; } td.tktDspValue pre { white-space: pre-wrap; } span.timelineDetail { font-size: 90%; } .footer { border-top: 1px solid #ccc; padding: 10px; font-size:.7em; margin-top: 10px; color: #ccc; } div.timelineDate { font-weight: bold; white-space: nowrap; } span.submenuctrl, span.submenuctrl input, select.submenuctrl { color: #777; } span.submenuctrl { white-space: nowrap; } div.submenu label { white-space: nowrap; } @media screen and (max-width: 600px) { /* Spacing for mobile */ body { padding-left: 4px; padding-right: 4px; } .title { padding-top: 0px; padding-bottom: 0px; } .status {padding-top: 0px;} .mainmenu a { padding: 10px 10px; } .mainmenu { padding: 10px; } .desktoponly { display: none; } } @media screen and (min-width: 600px) { /* Spacing for desktop */ body { padding-left: 20px; padding-right: 20px; } .title { padding-top: 10px; padding-bottom: 10px; } .status {padding-top: 30px;} .mainmenu a { padding: 10px 20px; } .mainmenu { padding: 10px; } } @media screen and (max-width: 1200px) { /* Special declarations for narrow desktop or wide mobile */ .wideonly { display: none; } } |
Changes to skins/default/details.txt.
|
| < < | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 1 timeline-color-graph-lines: 1 white-foreground: 0 |
Changes to skins/default/footer.txt.
|
| | | > > > | 1 2 3 4 5 6 7 8 | <div class="footer"> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by Fossil $release_version $manifest_version $manifest_date </div> <script nonce="$nonce"> <th1>styleScript</th1> </script> |
Changes to skins/default/header.txt.
|
| | > | < | | < < < < < < < < < < < < | < > | > > > > | > | < < > > | < > | < | < < < < | < < < | < < < | < | < | < > | < > > | < < | > > | < > | < | | < > > | < > > > > | | < | < | 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 | <div class="header"> <div class="title"><h1>$<project_name></h1>$<title></div> <div class="status"><th1> if {[info exists login]} { html "$login — <a href='$home/login'>Logout</a>\n" } else { html "<a href='$home/login'>Login</a>\n" } </th1></div> </div> <div class="mainmenu"> <th1> proc menulink {url name cls} { upvar current_page current upvar home home if {[string range $url 0 [string length $current]] eq "/$current"} { html "<a href='$home$url' class='active $cls'>$name</a>\n" } else { html "<a href='$home$url' class='$cls'>$name</a>\n" } } html "<a id='hbbtn' href='#'>☰</a>" menulink $index_page Home {} if {[anycap jor]} { menulink /timeline Timeline {} } if {[hascap oh]} { menulink /dir?ci=tip Files desktoponly } if {[hascap o]} { menulink /brlist Branches desktoponly menulink /taglist Tags wideonly } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum wideonly } if {[hascap r]} { menulink /ticket Tickets wideonly } if {[hascap j]} { menulink /wiki Wiki wideonly } if {[hascap s]} { menulink /setup Admin {} } elseif {[hascap a]} { menulink /setup_ulist Users {} } </th1></div> <div id='hbdrop'></div> |
Added skins/default/js.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Copyright © 2018 Warren Young ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Contact: wyoung on the Fossil forum, https://fossil-scm.org/forum/ ** ******************************************************************************* ** ** This file contains the JS code specific to the Fossil default skin. ** Currently, the only thing this does is handle clicks on its hamburger ** menu button. */ (function() { var hbButton = document.getElementById("hbbtn"); if (!hbButton) return; // no hamburger button if (!document.addEventListener) { // Turn the button into a link to the sitemap for incompatible browsers. hbButton.href = "$home/sitemap"; return; } var panel = document.getElementById("hbdrop"); if (!panel) return; // site admin might've nuked it if (!panel.style) return; // shouldn't happen, but be sure var panelBorder = panel.style.border; var panelInitialized = false; // reset if browser window is resized var panelResetBorderTimerID = 0; // used to cancel post-animation tasks // Disable animation if this browser doesn't support CSS transitions. // // We need this ugly calling form for old browsers that don't allow // panel.style.hasOwnProperty('transition'); catering to old browsers // is the whole point here. var animate = panel.style.transition !== null && (typeof(panel.style.transition) == "string"); // The duration of the animation can be overridden from the default skin // header.txt by setting the "data-anim-ms" attribute of the panel. var animMS = panel.getAttribute("data-anim-ms"); if (animMS) { // not null or empty string, parse it animMS = parseInt(animMS); if (isNaN(animMS) || animMS == 0) animate = false; // disable animation if non-numeric or zero else if (animMS < 0) animMS = 400; // set default animation duration if negative } else // attribute is null or empty string, use default animMS = 400; // Calculate panel height despite its being hidden at call time. // Based on https://stackoverflow.com/a/29047447/142454 var panelHeight; // computed on first panel display function calculatePanelHeight() { // Clear the max-height CSS property in case the panel size is recalculated // after the browser window was resized. panel.style.maxHeight = ''; // Get initial panel styles so we can restore them below. var es = window.getComputedStyle(panel), edis = es.display, epos = es.position, evis = es.visibility; // Restyle the panel so we can measure its height while invisible. panel.style.visibility = 'hidden'; panel.style.position = 'absolute'; panel.style.display = 'block'; panelHeight = panel.offsetHeight + 'px'; // Revert styles now that job is done. panel.style.display = edis; panel.style.position = epos; panel.style.visibility = evis; } // Show the panel by changing the panel height, which kicks off the // slide-open/closed transition set up in the XHR onload handler. // // Schedule the change for a near-future time in case this is the // first call, where the div was initially invisible. If we were // to change the panel's visibility and height at the same time // instead, that would prevent the browser from seeing the height // change as a state transition, so it'd skip the CSS transition: // // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#JavaScript_examples function showPanel() { // Cancel the timer to remove the panel border after the closing animation, // otherwise double-clicking the hamburger button with the panel opened will // remove the borders from the (closed and immediately reopened) panel. if (panelResetBorderTimerID) { clearTimeout(panelResetBorderTimerID); panelResetBorderTimerID = 0; } if (animate) { if (!panelInitialized) { panelInitialized = true; // Set up a CSS transition to animate the panel open and // closed. Only needs to be done once per page load. // Based on https://stackoverflow.com/a/29047447/142454 calculatePanelHeight(); panel.style.transition = 'max-height ' + animMS + 'ms ease-in-out'; panel.style.overflowY = 'hidden'; panel.style.maxHeight = '0'; } setTimeout(function() { panel.style.maxHeight = panelHeight; panel.style.border = panelBorder; }, 40); // 25ms is insufficient with Firefox 62 } panel.style.display = 'block'; document.addEventListener('keydown',panelKeydown,/* useCapture == */true); document.addEventListener('click',panelClick,false); } var panelKeydown = function(event) { var key = event.which || event.keyCode; if (key == 27) { event.stopPropagation(); // ignore other keydown handlers panelToggle(true); } }; var panelClick = function(event) { if (!panel.contains(event.target)) { // Call event.preventDefault() to have clicks outside the opened panel // just close the panel, and swallow clicks on links or form elements. //event.preventDefault(); panelToggle(true); } }; // Return true if the panel is showing. function panelShowing() { if (animate) { return panel.style.maxHeight == panelHeight; } else { return panel.style.display == 'block'; } } // Check if the specified HTML element has any child elements. Note that plain // text nodes, comments, and any spaces (presentational or not) are ignored. function hasChildren(element) { var childElement = element.firstChild; while (childElement) { if (childElement.nodeType == 1) // Node.ELEMENT_NODE == 1 return true; childElement = childElement.nextSibling; } return false; } // Reset the state of the panel to uninitialized if the browser window is // resized, so the dimensions are recalculated the next time it's opened. window.addEventListener('resize',function(event) { panelInitialized = false; },false); // Click handler for the hamburger button. hbButton.addEventListener('click',function(event) { // Break the event handler chain, or the handler for document → click // (about to be installed) may already be triggered by the current event. event.stopPropagation(); event.preventDefault(); // prevent browser from acting on <a> click panelToggle(false); },false); function panelToggle(suppressAnimation) { if (panelShowing()) { document.removeEventListener('keydown',panelKeydown,/* useCapture == */true); document.removeEventListener('click',panelClick,false); // Transition back to hidden state. if (animate) { if (suppressAnimation) { var transition = panel.style.transition; panel.style.transition = ''; panel.style.maxHeight = '0'; panel.style.border = 'none'; setTimeout(function() { // Make sure CSS transition won't take effect now, so restore it // asynchronously. Outer variable 'transition' still valid here. panel.style.transition = transition; }, 40); // 25ms is insufficient with Firefox 62 } else { panel.style.maxHeight = '0'; panelResetBorderTimerID = setTimeout(function() { // Browsers show a 1px high border line when maxHeight == 0, // our "hidden" state, so hide the borders in that state, too. panel.style.border = 'none'; panelResetBorderTimerID = 0; // clear ID of completed timer }, animMS); } } else { panel.style.display = 'none'; } } else { if (!hasChildren(panel)) { // Only get the sitemap once per page load: it isn't likely to // change on us. var xhr = new XMLHttpRequest(); xhr.onload = function() { var doc = xhr.responseXML; if (doc) { var sm = doc.querySelector("ul#sitemap"); if (sm && xhr.status == 200) { // Got sitemap. Insert it into the drop-down panel. panel.innerHTML = sm.outerHTML; // Display the panel showPanel(); } } // else, can't parse response as HTML or XML } xhr.open("GET", "$home/sitemap?popup"); // note the TH1 substitution! xhr.responseType = "document"; xhr.send(); } else { showPanel(); // just show what we built above } } } })(); |
Changes to skins/eagle/css.txt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* General settings for the entire page */ body { margin: 0ex 1ex; padding: 0px; background-color: #485D7B; font-family: sans-serif; color: white; } /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-cell; text-align: center; vertical-align: bottom; font-weight: bold; color: white; | > > > | < < < < < < < | 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 | /* General settings for the entire page */ body { margin: 0ex 1ex; padding: 0px; background-color: #485D7B; font-family: sans-serif; color: white; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-cell; text-align: center; vertical-align: bottom; font-weight: bold; color: white; padding: 5 0 5 0em; white-space: nowrap; } /* The page title centered at the top of each page */ div.title { display: table-cell; font-size: 2em; font-weight: bold; |
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 | div.status { display: table-cell; text-align: right; vertical-align: bottom; color: white; font-size: 0.8em; font-weight: bold; white-space: nowrap; } /* The header across the top of the page */ | > | | < < < < < < < < < < < < | | | 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 | div.status { display: table-cell; text-align: right; vertical-align: bottom; color: white; font-size: 0.8em; font-weight: bold; min-width: 200px; white-space: nowrap; } /* The header across the top of the page */ div.header { display: table; width: 100%; } /* The main menu bar that appears at the top of the page beneath ** the header */ div.mainmenu { padding: 5px 10px 5px 10px; font-size: 0.9em; font-weight: bold; text-align: center; letter-spacing: 1px; background-color: #76869D; border-top-left-radius: 8px; border-top-right-radius: 8px; color: white; } /* The submenu bar that *sometimes* appears below the main menu */ div.submenu, div.sectionmenu { padding: 3px 10px 3px 0px; font-size: 0.9em; font-weight: bold; text-align: center; background-color: #485D7B; color: white; } div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited, div.submenu label { padding: 3px 10px 3px 10px; color: white; text-decoration: none; } div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover, div.submenu label:hover { text-decoration: underline; } /* All page content from the bottom of the menu or submenu down to ** the footer */ div.content { |
︙ | ︙ | |||
129 130 131 132 133 134 135 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { clear: both; font-size: 0.8em; margin-top: 12px; padding: 5px 10px 5px 10px; text-align: right; background-color: #485D7B; border-bottom-left-radius: 8px; |
︙ | ︙ | |||
181 182 183 184 185 186 187 | border: 0; cellpadding: 0; font-family: "courier new"; border-spacing: 0px 2px; // border-collapse: collapse; } | | < < < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | border: 0; cellpadding: 0; font-family: "courier new"; border-spacing: 0px 2px; // border-collapse: collapse; } tr.timelineSelected { background-color: #7EA2D9; } /* commit node */ .tl-node { width: 10px; height: 10px; border: 1px solid #fff; background: #485D7B; |
︙ | ︙ | |||
208 209 210 211 212 213 214 | top: 3px; left: 3px; width: 4px; height: 4px; background: #fff; } | < < < < < < < < < < | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | top: 3px; left: 3px; width: 4px; height: 4px; background: #fff; } /* up arrow */ .tl-arrow.u { margin-top: -1px; border-width: 0 3px; border-bottom: 7px solid #fff; } |
︙ | ︙ | |||
245 246 247 248 249 250 251 252 | border-right: 3px solid #fff; } /* right merge arrow */ .tl-arrow.merge.r { border-left: 3px solid #fff; } | < < < < < < < < < < < < < < < < < < < < < < < < | > | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | border-right: 3px solid #fff; } /* right merge arrow */ .tl-arrow.merge.r { border-left: 3px solid #fff; } /* Side-by-side diff */ table.sbsdiff { background-color: #485D7B; font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace; font-size: 8pt; border-collapse:collapse; white-space: pre; width: 98%; border: 1px #000 dashed; margin-left: auto; margin-right: auto; } /* format for the layout table, used for the captcha display */ table.captcha { |
︙ | ︙ | |||
311 312 313 314 315 316 317 | /* format for values on ticket display page */ td.tktDspValue { text-align: left; vertical-align: top; background-color: #485D7B; } | < < < < < < < < | | | | | | > > | | < < | > | > > | | > > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | /* format for values on ticket display page */ td.tktDspValue { text-align: left; vertical-align: top; background-color: #485D7B; } /* format for example table cells on the report edit page */ td.rpteditex { border-width: thin; border-color: white; border-style: solid; } /* List of files in a timeline */ ul.filelist { margin-top: 3px; line-height: 100%; } /* side-by-side diff display */ div.sbsdiff { font-family: monospace; font-size: smaller; white-space: pre; } /* context diff display */ div.udiff { font-family: monospace; white-space: pre; } /* changes in a diff */ span.diffchng { background-color: rgb(170, 170, 140); } /* added code in a diff */ span.diffadd { background-color: rgb(100, 200, 100); } /* deleted in a diff */ span.diffrm { background-color: rgb(230, 110, 110); } /* suppressed lines in a diff */ span.diffhr { display: inline-block; margin: .5em 0 1em; color: rgb(150, 150, 140); } /* line numbers in a diff */ span.diffln { color: white; } .fileage tr:hover { background-color: #7EA2D9; } .fileage td { font-family: "courier new"; } div.filetreeline:hover { background-color: #7EA2D9; } div.selectedText { background-color: #7EA2D9; } .statistics-report-graph-line { background-color: #7EA2D9; } .timelineModernCell[id], .timelineColumnarCell[id], .timelineDetailCell[id] { background-color: #455978; } |
Changes to skins/eagle/details.txt.
1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 0 white-foreground: 1 | < | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 0 white-foreground: 1 |
Changes to skins/eagle/footer.txt.
|
| | | 1 2 3 4 5 6 7 8 | <div class="footer"> <th1> proc getTclVersion {} { if {[catch {tclEval info patchlevel} tclVersion] == 0} { return "<a href=\"https://www.tcl.tk/\">Tcl</a> version $tclVersion" } return "" } |
︙ | ︙ | |||
17 18 19 20 21 22 23 | </th1> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by <a href="$fossilUrl/">Fossil</a> version $release_version $tclVersion <a href="$fossilUrl/index.html/info/$version">$manifest_version</a> <a href="$fossilUrl/index.html/timeline?c=$fossilDate&y=ci">$manifest_date</a> | | | 17 18 19 20 21 22 23 24 | </th1> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by <a href="$fossilUrl/">Fossil</a> version $release_version $tclVersion <a href="$fossilUrl/index.html/info/$version">$manifest_version</a> <a href="$fossilUrl/index.html/timeline?c=$fossilDate&y=ci">$manifest_date</a> </div> |
Changes to skins/eagle/header.txt.
|
| | | 1 2 3 4 5 6 7 8 | <div class="header"> <div class="logo"> <th1> ## ## NOTE: The purpose of this procedure is to take the base URL of the ## Fossil project and return the root of the entire web site using ## the same URI scheme as the base URL (e.g. http or https). ## |
︙ | ︙ | |||
54 55 56 57 58 59 60 | set logourl $baseurl } } else { set logourl $baseurl } return $logourl } | < < | < < < < | | | | | | | < < | | | | > > | | | > > | > > | > > > > > > > > | > > > > | > > | < > | > > > > > > > > > > > | < < | 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 | set logourl $baseurl } } else { set logourl $baseurl } return $logourl } set logourl [getLogoUrl $baseurl] </th1> <a href="$logourl"> <img src="$logo_image_url" border="0" alt="$project_name"> </a> </div> <div class="title">$<title></div> <div class="status"><nobr><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></nobr><small><div id="clock"></div></small></div> </div> <th1>html "<script nonce='$nonce'>"</th1> function updateClock(){ var e = document.getElementById("clock"); if(e){ var d = new Date(); function f(n) { return n < 10 ? '0' + n : n; } e.innerHTML = d.getUTCFullYear()+ '-' + f(d.getUTCMonth() + 1) + '-' + f(d.getUTCDate()) + ' ' + f(d.getUTCHours()) + ':' + f(d.getUTCMinutes()); setTimeout(updateClock,(60-d.getUTCSeconds())*1000); } } updateClock(); </script> <div class="mainmenu"> <th1> proc menulink {url name} { upvar home home html "<a href='$home$url'>$name</a>\n" } menulink $index_page Home menulink /help Help if {[anycap jor]} { menulink /timeline Timeline } if {[anoncap oh]} { menulink /dir?ci=tip Files } if {[anoncap o]} { menulink /brlist Branches menulink /taglist Tags } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } if {[anoncap r]} { menulink /ticket Tickets } if {[anoncap j]} { menulink /wiki Wiki } menulink /sitemap More... if {[hascap s]} { menulink /setup Admin } elseif {[hascap a]} { menulink /setup_ulist Users } if {[info exists login]} { menulink /login Logout } else { menulink /login Login } </th1></div> |
Added skins/enhanced1/css.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* General settings for the entire page */ body { margin: 0ex 1ex; padding: 0px; background-color: white; font-family: sans-serif; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-cell; text-align: center; vertical-align: bottom; font-weight: bold; color: #558195; min-width: 200px; white-space: nowrap; } /* The page title centered at the top of each page */ div.title { display: table-cell; font-size: 2em; font-weight: bold; text-align: center; padding: 0 0 0 1em; color: #558195; vertical-align: bottom; width: 100%; } /* The login status message in the top right-hand corner */ div.status { display: table-cell; text-align: right; vertical-align: bottom; color: #558195; font-size: 0.8em; font-weight: bold; min-width: 200px; white-space: nowrap; } /* The header across the top of the page */ div.header { display: table; width: 100%; } /* The main menu bar that appears at the top of the page beneath ** the header */ div.mainmenu { padding: 5px 10px 5px 10px; font-size: 0.9em; font-weight: bold; text-align: center; letter-spacing: 1px; background-color: #558195; border-top-left-radius: 8px; border-top-right-radius: 8px; color: white; } /* The submenu bar that *sometimes* appears below the main menu */ div.submenu, div.sectionmenu { padding: 3px 10px 3px 0px; font-size: 0.9em; text-align: center; background-color: #456878; color: white; } div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited, div.submenu label { padding: 3px 10px 3px 10px; color: white; text-decoration: none; } div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover, div.submenu label:hover { color: #558195; background-color: white; } /* All page content from the bottom of the menu or submenu down to ** the footer */ div.content { padding: 0ex 1ex 1ex 1ex; border: solid #aaa; border-width: 1px; } /* Some pages have section dividers */ div.section { margin-bottom: 0px; margin-top: 1em; padding: 1px 1px 1px 1px; font-size: 1.2em; font-weight: bold; background-color: #558195; color: white; white-space: nowrap; } /* The "Date" that occurs on the left hand side of timelines */ div.divider { background: #a1c4d4; border: 2px #558195 solid; font-size: 1em; font-weight: normal; padding: .25em; margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { clear: both; font-size: 0.8em; padding: 5px 10px 5px 10px; text-align: right; background-color: #558195; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; color: white; } /* Hyperlink colors in the footer */ div.footer a { color: white; } div.footer a:link { color: white; } div.footer a:visited { color: white; } div.footer a:hover { background-color: white; color: #558195; } /* verbatim blocks */ pre.verbatim { background-color: #f5f5f5; padding: 0.5em; white-space: pre-wrap; } /* The label/value pairs on (for example) the ci page */ table.label-value th { vertical-align: top; text-align: right; padding: 0.2ex 2ex; } |
Added skins/enhanced1/details.txt.
> > > > | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 0 white-foreground: 0 |
Added skins/enhanced1/footer.txt.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <div class="footer"> <th1> proc getTclVersion {} { if {[catch {tclEval info patchlevel} tclVersion] == 0} { return "<a href=\"https://www.tcl.tk/\">Tcl</a> version $tclVersion" } return "" } proc getVersion { version } { set length [string length $version] return [string range $version 1 [expr {$length - 2}]] } set version [getVersion $manifest_version] set tclVersion [getTclVersion] set fossilUrl https://www.fossil-scm.org set fossilDate [string range $manifest_date 0 9]T[string range $manifest_date 11 end] </th1> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by <a href="$fossilUrl/">Fossil</a> version $release_version $tclVersion <a href="$fossilUrl/index.html/info/$version">$manifest_version</a> <a href="$fossilUrl/index.html/timeline?c=$fossilDate&y=ci">$manifest_date</a> </div> |
Added skins/enhanced1/header.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <div class="header"> <div class="logo"> <th1> ## ## NOTE: The purpose of this procedure is to take the base URL of the ## Fossil project and return the root of the entire web site using ## the same URI scheme as the base URL (e.g. http or https). ## proc getLogoUrl { baseurl } { set idx(first) [string first // $baseurl] if {$idx(first) != -1} { ## ## NOTE: Skip second slash. ## set idx(first+1) [expr {$idx(first) + 2}] ## ## NOTE: (part 1) The [string first] command does NOT actually ## support the optional startIndex argument as specified ## in the TH1 support manual; therefore, we fake it by ## using the [string range] command and then adding the ## necessary offset to the resulting index manually ## (below). In Tcl, we could use the following instead: ## ## set idx(next) [string first / $baseurl $idx(first+1)] ## set idx(nextRange) [string range $baseurl $idx(first+1) end] set idx(next) [string first / $idx(nextRange)] if {$idx(next) != -1} { ## ## NOTE: (part 2) Add the necessary offset to the result of ## the search for the next slash (i.e. the one after ## the initial search for the two slashes). ## set idx(next) [expr {$idx(next) + $idx(first+1)}] ## ## NOTE: Back up one character from the next slash. ## set idx(next-1) [expr {$idx(next) - 1}] ## ## NOTE: Extract the URI scheme and host from the base URL. ## set scheme [string range $baseurl 0 $idx(first)] set host [string range $baseurl $idx(first+1) $idx(next-1)] ## ## NOTE: Try to stay in SSL mode if we are there now. ## if {[string compare $scheme http:/] == 0} { set scheme http:// } else { set scheme https:// } set logourl $scheme$host/ } else { set logourl $baseurl } } else { set logourl $baseurl } return $logourl } set logourl [getLogoUrl $baseurl] </th1> <a href="$logourl"> <img src="$logo_image_url" border="0" alt="$project_name"> </a> </div> <div class="title">$<title></div> <div class="status"><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></nobr><small><div id="clock"></div></small></div> </div> <th1>html "<script nonce='$nonce'>"</th1> function updateClock(){ var e = document.getElementById("clock"); if(e){ var d = new Date(); function f(n) { return n < 10 ? '0' + n : n; } e.innerHTML = d.getUTCFullYear()+ '-' + f(d.getUTCMonth() + 1) + '-' + f(d.getUTCDate()) + ' ' + f(d.getUTCHours()) + ':' + f(d.getUTCMinutes()); setTimeout(updateClock,(60-d.getUTCSeconds())*1000); } } updateClock(); </script> <div class="mainmenu"> <th1> proc menulink {url name} { upvar home home html "<a href='$home$url'>$name</a>\n" } menulink $index_page Home menulink /help Help if {[anycap jor]} { menulink /timeline Timeline } if {[anoncap oh]} { menulink /dir?ci=tip Files } if {[anoncap o]} { menulink /brlist Branches menulink /taglist Tags } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } if {[anoncap r]} { menulink /ticket Tickets } if {[anoncap j]} { menulink /wiki Wiki } if {[hascap s]} { menulink /setup Admin } elseif {[hascap a]} { menulink /setup_ulist Users } if {[info exists login]} { menulink /login Logout } else { menulink /login Login } </th1></div> |
Deleted skins/etienne/README.md.
|
| < < < < < < < < < < < < < < |
Deleted skins/etienne/css.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted skins/etienne/details.txt.
|
| < < < < |
Deleted skins/etienne/footer.txt.
|
| < < < < < |
Deleted skins/etienne/header.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to skins/khaki/css.txt.
1 2 3 4 5 6 | /* General settings for the entire page */ body { margin: 0ex 0ex; padding: 0px; background-color: #fef3bc; font-family: sans-serif; | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* General settings for the entire page */ body { margin: 0ex 0ex; padding: 0px; background-color: #fef3bc; font-family: sans-serif; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } /* The project logo in the upper left-hand corner of each page */ div.logo { display: inline; text-align: center; vertical-align: bottom; |
︙ | ︙ | |||
39 40 41 42 43 44 45 | padding: 5px 5px 0 0; font-size: 0.8em; font-weight: bold; white-space: nowrap; } /* The header across the top of the page */ | | | < < < < < < < < < < < < < | | | | | | < | < < < < < | 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 | padding: 5px 5px 0 0; font-size: 0.8em; font-weight: bold; white-space: nowrap; } /* The header across the top of the page */ div.header { display: table; width: 100%; } /* The main menu bar that appears at the top of the page beneath ** the header */ div.mainmenu { padding: 5px 10px 5px 10px; font-size: 0.9em; font-weight: bold; text-align: center; letter-spacing: 1px; background-color: #a09048; color: black; } /* The submenu bar that *sometimes* appears below the main menu */ div.submenu, div.sectionmenu { padding: 3px 10px 3px 0px; font-size: 0.9em; text-align: center; background-color: #c0af58; color: white; } div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited, div.submenu label { padding: 3px 10px 3px 10px; color: white; text-decoration: none; } div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover, div.submenu label:hover { color: #a09048; background-color: white; } /* All page content from the bottom of the menu or submenu down to ** the footer */ div.content { padding: 1ex 5px; } div.content a { color: #706532; } div.content a:link { color: #706532; } div.content a:visited { color: #704032; } div.content a:hover { background-color: white; color: #706532; } /* Some pages have section dividers */ div.section { margin-bottom: 0px; margin-top: 1em; padding: 3px 3px 0 3px; font-size: 1.2em; |
︙ | ︙ | |||
131 132 133 134 135 136 137 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ | | | | | | < < < < < < < < < < < < < < < < | 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 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { font-size: 0.8em; margin-top: 12px; padding: 5px 10px 5px 10px; text-align: right; background-color: #a09048; color: white; } /* Hyperlink colors */ div.footer a { color: white; } div.footer a:link { color: white; } div.footer a:visited { color: white; } div.footer a:hover { background-color: white; color: #558195; } /* <verbatim> blocks */ pre.verbatim { background-color: #f5f5f5; padding: 0.5em; white-space: pre-wrap; } /* The label/value pairs on (for example) the ci page */ table.label-value th { vertical-align: top; text-align: right; padding: 0.2ex 2ex; } |
Changes to skins/khaki/details.txt.
1 | timeline-arrowheads: 1 | | | | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 0 white-foreground: 0 |
Changes to skins/khaki/footer.txt.
|
| | | | 1 2 3 | <div class="footer"> Fossil $release_version $manifest_version $manifest_date </div> |
Changes to skins/khaki/header.txt.
|
| | | | | | | | | < | | | > | < > | > > | > > > > > > > > > > | | > > > > > > > > > > | < < | 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 | <div class="header"> <div class="title">$<title></div> <div class="status"> <div class="logo">$<project_name></div><br/> <th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></div> </div> <div class="mainmenu"> <th1> html "<a href='$home$index_page'>Home</a>\n" if {[anycap jor]} { html "<a href='$home/timeline'>Timeline</a>\n" } if {[anoncap oh]} { html "<a href='$home/tree?ci=tip'>Files</a>\n" } if {[anoncap o]} { html "<a href='$home/brlist'>Branches</a>\n" html "<a href='$home/taglist'>Tags</a>\n" } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { html "<a href='$home/forum'>Forum</a>\n" } if {[anoncap r]} { html "<a href='$home/ticket'>Tickets</a>\n" } if {[anoncap j]} { html "<a href='$home/wiki'>Wiki</a>\n" } if {[hascap s]} { html "<a href='$home/setup'>Admin</a>\n" } elseif {[hascap a]} { html "<a href='$home/setup_ulist'>Users</a>\n" } if {[info exists login]} { html "<a href='$home/login'>Logout</a>\n" } else { html "<a href='$home/login'>Login</a>\n" } </th1></div> |
Changes to skins/original/css.txt.
︙ | ︙ | |||
12 13 14 15 16 17 18 | /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-cell; text-align: center; vertical-align: bottom; font-weight: bold; color: #558195; | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-cell; text-align: center; vertical-align: bottom; font-weight: bold; color: #558195; min-width: 200px; white-space: nowrap; } /* The page title centered at the top of each page */ div.title { display: table-cell; font-size: 2em; |
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 | div.status { display: table-cell; text-align: right; vertical-align: bottom; color: #558195; font-size: 0.8em; font-weight: bold; white-space: nowrap; } /* The header across the top of the page */ | > | | | | | | 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 | div.status { display: table-cell; text-align: right; vertical-align: bottom; color: #558195; font-size: 0.8em; font-weight: bold; min-width: 200px; white-space: nowrap; } /* The header across the top of the page */ div.header { display: table; width: 100%; } /* The main menu bar that appears at the top of the page beneath ** the header */ div.mainmenu { padding: 5px 10px 5px 10px; font-size: 0.9em; font-weight: bold; text-align: center; letter-spacing: 1px; background-color: #558195; border-top-left-radius: 8px; border-top-right-radius: 8px; color: white; } /* The submenu bar that *sometimes* appears below the main menu */ div.submenu, div.sectionmenu { padding: 3px 10px 3px 0px; font-size: 0.9em; text-align: center; background-color: #456878; color: white; } div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited, div.submenu label { padding: 3px 10px 3px 10px; color: white; text-decoration: none; } div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover, div.submenu label:hover { color: #558195; background-color: white; } /* All page content from the bottom of the menu or submenu down to ** the footer */ |
︙ | ︙ | |||
113 114 115 116 117 118 119 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ | | | | | | | 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 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { clear: both; font-size: 0.8em; padding: 5px 10px 5px 10px; text-align: right; background-color: #558195; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; color: white; } /* Hyperlink colors in the footer */ div.footer a { color: white; } div.footer a:link { color: white; } div.footer a:visited { color: white; } div.footer a:hover { background-color: white; color: #558195; } /* verbatim blocks */ pre.verbatim { background-color: #f5f5f5; padding: 0.5em; white-space: pre-wrap; } |
︙ | ︙ |
Changes to skins/original/footer.txt.
|
| | < < < < < < < < < < < < < < < < | | < | < < | | 1 2 3 4 5 | <div class="footer"> This page was generated in about <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by Fossil $release_version $manifest_version $manifest_date </div> |
Changes to skins/original/header.txt.
|
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | > | < | | | > | < > | < | | | < < | > > | | | < < > | < > > | < | | > | | | > > | | < | 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 | <div class="header"> <div class="logo"> <img src="$logo_image_url" alt="logo" /> </div> <div class="title"><small>$<project_name></small><br />$<title></div> <div class="status"><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></div> </div> <div class="mainmenu"> <th1> html "<a href='$home$index_page'>Home</a>\n" if {[anycap jor]} { html "<a href='$home/timeline'>Timeline</a>\n" } if {[anoncap oh]} { html "<a href='$home/tree?ci=tip'>Files</a>\n" } if {[anoncap o]} { html "<a href='$home/brlist'>Branches</a>\n" html "<a href='$home/taglist'>Tags</a>\n" } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { html "<a href='$home/forum'>Forum</a>\n" } if {[anoncap r]} { html "<a href='$home/ticket'>Tickets</a>\n" } if {[anoncap j]} { html "<a href='$home/wiki'>Wiki</a>\n" } if {[hascap s]} { html "<a href='$home/setup'>Admin</a>\n" } elseif {[hascap a]} { html "<a href='$home/setup_ulist'>Users</a>\n" } if {[info exists login]} { html "<a href='$home/login'>Logout</a>\n" } else { html "<a href='$home/login'>Login</a>\n" } </th1></div> |
Changes to skins/plain_gray/css.txt.
1 2 3 4 5 6 | /* General settings for the entire page */ body { margin: 0ex 1ex; padding: 0px; background-color: white; font-family: sans-serif; | | > > > > > > > > > > > > > > > > > | | < < < < < < < < < < < < < < < | < < | < < < | < < < | 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 | /* General settings for the entire page */ body { margin: 0ex 1ex; padding: 0px; background-color: white; font-family: sans-serif; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-row; text-align: center; /* vertical-align: bottom;*/ font-size: 2em; font-weight: bold; background-color: #707070; color: #ffffff; min-width: 200px; white-space: nowrap; } /* The page title centered at the top of each page */ div.title { display: table-cell; font-size: 1.5em; font-weight: bold; text-align: center; padding: 0 0 0 10px; color: #404040; vertical-align: bottom; width: 100%; } /* The login status message in the top right-hand corner */ div.status { display: table-cell; text-align: right; vertical-align: bottom; color: #404040; font-size: 0.8em; font-weight: bold; min-width: 200px; white-space: nowrap; } /* The header across the top of the page */ div.header { display: table; width: 100%; } /* The main menu bar that appears at the top of the page beneath ** the header */ div.mainmenu { padding: 5px 10px 5px 10px; font-size: 0.9em; font-weight: bold; text-align: center; letter-spacing: 1px; background-color: #404040; color: white; } /* The submenu bar that *sometimes* appears below the main menu */ div.submenu, div.sectionmenu { padding: 3px 10px 3px 0px; font-size: 0.9em; text-align: center; background-color: #606060; color: white; } div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited, div.submenu label { padding: 3px 10px 3px 10px; color: white; text-decoration: none; } div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover, div.submenu label:hover { color: #404040; background-color: white; } /* All page content from the bottom of the menu or submenu down to ** the footer */ div.content { padding: 0ex 0ex 0ex 0ex; } /* Hyperlink colors */ |
︙ | ︙ | |||
129 130 131 132 133 134 135 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | margin: .2em 0 .2em 0; float: left; clear: left; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { font-size: 0.8em; margin-top: 12px; padding: 5px 10px 5px 10px; text-align: right; background-color: #404040; color: white; } |
︙ | ︙ |
Changes to skins/plain_gray/footer.txt.
|
| | | | 1 2 3 | <div class="footer"> Fossil $release_version $manifest_version $manifest_date </div> |
Changes to skins/plain_gray/header.txt.
|
| | | > > > > > > > | | | > > > > > > > > > | < < > > > > | > > | | | > > > > > > > > > > | < < | 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 | <div class="header"> <div class="title"><small>$<project_name></small><br />$<title></div> <div class="status"><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></div> </div> <div class="mainmenu"> <th1> html "<a href='$home$index_page'>Home</a>\n" if {[anycap jor]} { html "<a href='$home/timeline'>Timeline</a>\n" } if {[anoncap oh]} { html "<a href='$home/tree?ci=tip'>Files</a>\n" } if {[anoncap o]} { html "<a href='$home/brlist'>Branches</a>\n" html "<a href='$home/taglist'>Tags</a>\n" } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { html "<a href='$home/forum'>Forum</a>\n" } if {[anoncap r]} { html "<a href='$home/ticket'>Tickets</a>\n" } if {[anoncap j]} { html "<a href='$home/wiki'>Wiki</a>\n" } if {[hascap s]} { html "<a href='$home/setup'>Admin</a>\n" } elseif {[hascap a]} { html "<a href='$home/setup_ulist'>Users</a>\n" } if {[info exists login]} { html "<a href='$home/login'>Logout</a>\n" } else { html "<a href='$home/login'>Login</a>\n" } </th1></div> |
Added skins/rounded1/css.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* General settings for the entire page */ html { min-height: 100%; } body { margin: 0ex 1ex; padding: 0px; background-color: white; color: #333; font-family: Verdana, sans-serif; font-size: 0.8em; -moz-text-size-adjust: none; -webkit-text-size-adjust: none; -mx-text-size-adjust: none; } /* The project logo in the upper left-hand corner of each page */ div.logo { display: table-cell; text-align: right; vertical-align: bottom; font-weight: normal; white-space: nowrap; } /* Widths */ div.header, div.mainmenu, div.submenu, div.content, div.footer { max-width: 900px; margin: auto; padding: 3px 20px 3px 20px; clear: both; } /* The page title at the top of each page */ div.title { display: table-cell; padding-left: 10px; font-size: 2em; margin: 10px 0 10px -20px; vertical-align: bottom; text-align: left; width: 80%; font-family: Verdana, sans-serif; font-weight: bold; color: #558195; text-shadow: 0px 2px 2px #999999; } /* The login status message in the top right-hand corner */ div.status { display: table-cell; text-align: right; vertical-align: bottom; color: #333; margin-right: -20px; white-space: nowrap; } /* The main menu bar that appears at the top of the page beneath ** the header */ div.mainmenu { text-align: center; color: white; border-top-left-radius: 5px; border-top-right-radius: 5px; vertical-align: middle; padding-top: 8px; padding-bottom: 8px; background-color: #446979; box-shadow: 0px 3px 4px #333333; } /* The submenu bar that *sometimes* appears below the main menu */ div.submenu { padding-top:10px; padding-bottom:0; text-align: right; color: #000; background-color: #fff; height: 1.5em; vertical-align:middle; box-shadow: 0px 3px 4px #999; } div.mainmenu a, div.mainmenu a:visited { padding: 3px 10px 3px 10px; color: white; text-decoration: none; } div.submenu a, div.submenu a:visited, a.button, div.submenu label, div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited { padding: 2px 8px; color: #000; font-family: Arial; text-decoration: none; margin:auto; border-radius: 5px; background-color: #e0e0e0; text-shadow: 0px -1px 0px #eee; border: 1px solid #000; } div.mainmenu a:hover { color: #000; background-color: white; } div.submenu a:hover, div.sectionmenu>a.button:hover, div.submenu label:hover { background-color: #c0c0c0; } /* All page content from the bottom of the menu or submenu down to ** the footer */ div.content { background-color: #fff; box-shadow: 0px 3px 4px #999; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; padding-bottom: 1em; min-height:40%; } /* Some pages have section dividers */ div.section { margin-bottom: 0.5em; margin-top: 1em; margin-right: auto; padding: 1px 1px 1px 1px; font-size: 1.2em; font-weight: bold; text-align: center; color: white; border-radius: 5px; background-color: #446979; box-shadow: 0px 3px 4px #333333; white-space: nowrap; } /* The "Date" that occurs on the left hand side of timelines */ div.divider { font-size: 1.2em; font-family: Georgia, serif; font-weight: bold; margin-top: 1em; white-space: nowrap; } /* The footer at the very bottom of the page */ div.footer { font-size: 0.9em; text-align: right; margin-bottom: 1em; color: #666; } /* Hyperlink colors in the footer */ div.footer a { color: white; } div.footer a:link { color: white; } div.footer a:visited { color: white; } div.footer a:hover { background-color: white; color: #558195; } /* <verbatim> blocks */ pre.verbatim, blockquote pre { font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace; background-color: #f3f3f3; padding: 0.5em; white-space: pre-wrap; } blockquote pre { border: 1px #000 dashed; } /* The label/value pairs on (for example) the ci page */ table.label-value th { vertical-align: top; text-align: right; padding: 0.2ex 2ex; } table.report tr th { padding: 3px 5px; text-transform: capitalize; cursor: pointer; } table.report tr td { padding: 3px 5px; } textarea { font-size: 1em; } .fullsize-text { font-size: 1.25em; } |
Added skins/rounded1/details.txt.
> > > > | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 1 timeline-color-graph-lines: 0 white-foreground: 0 |
Added skins/rounded1/footer.txt.
> > > | 1 2 3 | <div class="footer"> Fossil $release_version $manifest_version $manifest_date </div> |
Added skins/rounded1/header.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <div class="header"> <div class="logo"> <img src="$logo_image_url" alt="logo"> <br />$<project_name> </div> <div class="title">$<title></div> <div class="status"><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></div> </div> <div class="mainmenu"> <th1> html "<a href='$home$index_page'>Home</a>\n" if {[anycap jor]} { html "<a href='$home/timeline'>Timeline</a>\n" } if {[anoncap oh]} { html "<a href='$home/tree?ci=tip'>Files</a>\n" } if {[anoncap o]} { html "<a href='$home/brlist'>Branches</a>\n" html "<a href='$home/taglist'>Tags</a>\n" } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { html "<a href='$home/forum'>Forum</a>\n" } if {[anoncap r]} { html "<a href='$home/ticket'>Tickets</a>\n" } if {[anoncap j]} { html "<a href='$home/wiki'>Wiki</a>\n" } if {[hascap s]} { html "<a href='$home/setup'>Admin</a>\n" } elseif {[hascap a]} { html "<a href='$home/setup_ulist'>Users</a>\n" } if {[info exists login]} { html "<a href='$home/login'>Logout</a>\n" } else { html "<a href='$home/login'>Login</a>\n" } </th1></div> |
Changes to skins/xekri/css.txt.
︙ | ︙ | |||
20 21 22 23 24 25 26 | font-size: 1em; min-height: 100%; } body { margin: 0; padding: 0; | | > > | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | font-size: 1em; min-height: 100%; } body { margin: 0; padding: 0; -moz-text-size-adjust: none; -ms-text-size-adjust: none; -webkit-text-size-adjust: none; } a { color: #07e; } a:hover { font-weight: bold; } blockquote pre { |
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 | h2 { font-size: 1.5rem; } h3 { font-size: 1.25rem; } /************************************** * Main Area */ | > > > > > > > > > | | < < < < < < < < < < > | | | < < | | | | | 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 | h2 { font-size: 1.5rem; } h3 { font-size: 1.25rem; } span[style^=background-color] { color: #000; } td[style^=background-color] { color: #000; } /************************************** * Main Area */ div.header, div.mainmenu, div.submenu, div.content, div.footer { clear: both; margin: 0 auto; max-width: 90%; padding: 0.25rem 1rem; } /************************************** * Main Area: Header */ div.header { margin: 0.5rem auto 0 auto; } div.logo img { float: left; padding: 0; box-shadow: 3px 3px 1px #000; margin: 0 6px 6px 0; } div.logo br { display: none; } div.logo nobr { color: #eee; font-size: 1.2rem; font-weight: bold; padding: 0; text-shadow: 3px 3px 1px #000; vertical-align: top; white-space: nowrap; } div.title { color: #07e; font-family: Verdana, sans-serif; font-weight: bold; font-size: 2.5rem; padding: 0.5rem; text-align: center; text-shadow: 3px 3px 1px #000; } div.status { color: #ee0; font-size: 1rem; padding: 0.25rem; text-align: right; text-shadow: 2px 2px 1px #000; } /************************************** * Main Area: Global Menu */ div.mainmenu, div.submenu { background-color: #080; border-radius: 1rem 1rem 0 0; box-shadow: 3px 4px 1px #000; color: #000; font-weight: bold; font-size: 1.1rem; text-align: center; } div.mainmenu { padding-top: 0.33rem; padding-bottom: 0.25rem; } div.submenu { border-top: 1px solid #0a0; border-radius: 0; display: block; } div.mainmenu a, div.submenu a, div.submenu label { color: #000; padding: 0 0.75rem; text-decoration: none; } div.mainmenu a:hover, div.submenu a:hover, div.submenu label:hover { color: #fff; text-shadow: 0px 0px 6px #0f0; } div.submenu * { margin: 0 0.5rem; vertical-align: middle; |
︙ | ︙ | |||
212 213 214 215 216 217 218 | stroke: white; } /************************************** * Main Area: Footer */ | | | | | | | | < < < < < < < | < | > > | > | < < < < | > | | | | | > > > > > | > | | > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | stroke: white; } /************************************** * Main Area: Footer */ div.footer { color: #ee0; font-size: 0.75rem; padding: 0; text-align: right; width: 75%; } div.footer div { background-color: #222; box-shadow: 3px 3px 1px #000; border-radius: 0 0 1rem 1rem; margin: 0 0 10px 0; padding: 0.5rem 0.75rem; } div.footer div.page-time { float: left; } div.footer div.fossil-info { float: right; } div.footer a, div.footer a:link, div.footer a:visited { color: #ee0; } div.footer a:hover { color: #fff; text-shadow: 0px 0px 6px #ee0; } /************************************** * Check-in */ table.label-value th { vertical-align: top; text-align: right; padding: 0.1rem 1rem; } /************************************** * Diffs */ /* Code Added */ span.diffadd { background-color: #7f7; color: #000; } /* Code Changed */ span.diffchng { background-color: #77f; color: #000; } /* Code Deleted */ span.diffrm { background-color: #f77; color: #000; } /************************************** * Diffs : Side-By-Side */ /* display (column-based) */ table.sbsdiffcols { border-spacing: 0; font-size: 0.85rem; width: 90%; } table.sbsdiffcols pre { border: 0; margin: 0; padding: 0; } table.sbsdiffcols td { padding: 0; vertical-align: top; } /* line number column */ div.difflncol { color: #ee0; padding-right: 0.75em; text-align: right; } /* diff text column */ div.difftxtcol { background-color: #111; overflow-x: auto; width: 45em; } /* suppressed lines */ span.diffhr { display: inline-block; margin-bottom: 0.75em; color: #ff0; } /* diff marker column */ div.diffmkrcol { padding: 0 0.5em; } /************************************** * Diffs : Unified */ pre.udiff { background-color: #111; } /* line numbers */ span.diffln { background-color: #222; color: #ee0; } /************************************** * File List : Flat */ table.browser { |
︙ | ︙ | |||
502 503 504 505 506 507 508 | /************************************** * Statistics Reports */ .statistics-report-graph-line { | < < < < < | 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | /************************************** * Statistics Reports */ .statistics-report-graph-line { background-color: #22e; } .statistics-report-table-events th { padding: 0 1rem; } .statistics-report-table-events td { padding: 0.1rem 1rem; |
︙ | ︙ | |||
562 563 564 565 566 567 568 | margin: 1.2rem auto 0.75rem auto; padding: 0.2rem; text-align: center; } div.sectionmenu { border-radius: 0 0 3rem 3rem; | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | margin: 1.2rem auto 0.75rem auto; padding: 0.2rem; text-align: center; } div.sectionmenu { border-radius: 0 0 3rem 3rem; margin-top: -0.75rem; width: 75%; } div.sectionmenu > a:link, div.sectionmenu > a:visited { color: #000; text-decoration: none; } |
︙ | ︙ | |||
695 696 697 698 699 700 701 | /* format for values on ticket display page */ td.tktDspValue { background-color: #111; text-align: left; vertical-align: top; } | < < < < < | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | /* format for values on ticket display page */ td.tktDspValue { background-color: #111; text-align: left; vertical-align: top; } /* format for ticket error messages */ span.tktError { color: #f00; font-weight: bold; } |
︙ | ︙ | |||
807 808 809 810 811 812 813 | } .timelineTable .timelineSelected { background: #222; border: 0; box-shadow: none; } | < < < < < < < < < | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | } .timelineTable .timelineSelected { background: #222; border: 0; box-shadow: none; } .timelineTable .timelineSelected .timelineTime { background: #333; border-radius: 1rem 0 0 1rem; box-shadow: 2px 2px 1px #000; } .timelineTable .timelineSelected .timelineColumnarCell { background: #333; box-shadow: 2px 2px 1px #000; } .timelineTable .timelineSelected .timelineModernCell , .timelineTable .timelineSelected .timelineCompactCell , .timelineTable .timelineSelected .timelineVerboseCell , .timelineTable .timelineSelected .timelineDetailCell { background: #333; border-radius: 0 1rem 1rem 0; box-shadow: 2px 2px 1px #000; } .timelineTable .timelineModernCell .timelineModernComment , .timelineTable .timelineModernCell .timelineModernDetail , .timelineTable .timelineCompactCell .timelineCompactComment , .timelineTable .timelineCompactCell .timelineCompactDetail , |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | /************************************** * Did not encounter these */ /* selected lines of text within a linenumbered artifact display */ | | | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 | /************************************** * Did not encounter these */ /* selected lines of text within a linenumbered artifact display */ div.selectedText { font-weight: bold; color: #00f; background-color: #d5d5ff; border: 1px #00f solid; } /* format for missing privileges note on user setup page */ p.missingPriv { color: #00f; } |
︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 | /* format for report configuration errors */ blockquote.reportError { color: #f00; font-weight: bold; } /* format for artifact lines, no longer shunned */ p.noMoreShun { | | | | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | /* format for report configuration errors */ blockquote.reportError { color: #f00; font-weight: bold; } /* format for artifact lines, no longer shunned */ p.noMoreShun { color: #00f; } /* format for artifact lines being shunned */ p.shunned { color: #00f; } /* a broken hyperlink */ span.brokenlink { color: #f00; } /* List of files in a timeline */ ul.filelist { |
︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | tr.row0 { /* use default */ } /* odd table row color */ tr.row1 { /* Use default */ } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1102 1103 1104 1105 1106 1107 1108 | tr.row0 { /* use default */ } /* odd table row color */ tr.row1 { /* Use default */ } |
Changes to skins/xekri/details.txt.
1 2 3 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 1 | | | 1 2 3 4 | timeline-arrowheads: 1 timeline-circle-nodes: 0 timeline-color-graph-lines: 1 white-foreground: 0 |
Changes to skins/xekri/footer.txt.
1 | </div> | | | | | | | | | | 1 2 3 4 5 6 7 8 9 | </div> <div class="footer"> <div class="page-time"> Generated in <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s </div> <div class="fossil-info"> Fossil v$release_version $manifest_version </div> </div> |
Changes to skins/xekri/header.txt.
|
| | | 1 2 3 4 5 6 7 8 | <div class="header"> <div class="logo"> <th1> ## ## NOTE: The purpose of this procedure is to take the base URL of the ## Fossil project and return the root of the entire web site using ## the same URI scheme as the base URL (e.g. http or https). ## |
︙ | ︙ | |||
54 55 56 57 58 59 60 | set logourl $baseurl } } else { set logourl $baseurl } return $logourl } | < < | < < < < | < | | | | | < | | | | | | | | | | | | | | | | | | | | > > > > > | > > > | | > > | > > | < > > | > | | < | > | | > > | > > > > | > > > > > | < | 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 | set logourl $baseurl } } else { set logourl $baseurl } return $logourl } set logourl [getLogoUrl $baseurl] </th1> <a href="$logourl"> <img src="$logo_image_url" border="0" alt="$project_name"> </a> </div> <div class="title">$<title></div> <div class="status"><nobr><th1> if {[info exists login]} { puts "Logged in as $login" } else { puts "Not logged in" } </th1></nobr><small><div id="clock"></div></small></div> </div> <th1>html "<script nonce='$nonce'>"</th1> function updateClock(){ var e = document.getElementById("clock"); if(e){ var d = new Date(); function f(n) { return n < 10 ? '0' + n : n; } e.innerHTML = d.getUTCFullYear()+ '-' + f(d.getUTCMonth() + 1) + '-' + f(d.getUTCDate()) + ' ' + f(d.getUTCHours()) + ':' + f(d.getUTCMinutes()); setTimeout(updateClock,(60-d.getUTCSeconds())*1000); } } updateClock(); </script> <div class="mainmenu"> <th1> proc menulink {url name} { upvar current_page current upvar home home if {[string range $url 0 [string length $current]] eq "/$current"} { html "<a href='$home$url' class='active'>$name</a>\n" } else { html "<a href='$home$url'>$name</a>\n" } } menulink $index_page Home if {[anycap jor]} { menulink /timeline Timeline } if {[anoncap oh]} { menulink /dir?ci=tip Files } if {[anoncap o]} { menulink /brlist Branches menulink /taglist Tags } if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } if {[anoncap r]} { menulink /ticket Tickets } if {[anoncap j]} { menulink /wiki Wiki } menulink /sitemap More... if {[hascap s]} { menulink /setup Admin } elseif {[hascap a]} { menulink /setup_ulist Users } if {[info exists login]} { menulink /login Logout } else { menulink /login Login } </th1></div> |
Deleted src/accordion.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/add.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | #include "config.h" #include "add.h" #include <assert.h> #include <dirent.h> #include "cygsup.h" /* | > > > > > > > > > > > > > > > > > > | | | | 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 | #include "config.h" #include "add.h" #include <assert.h> #include <dirent.h> #include "cygsup.h" /* ** WARNING: For Fossil version x.x this value was always zero. For Fossil-NG ** it will probably always be one. When this value is zero, ** files in the checkout will not be moved by the "mv" command and ** files in the checkout will not be removed by the "rm" command. ** ** If the FOSSIL_ENABLE_LEGACY_MV_RM compile-time option is used, ** the "mv-rm-files" setting will be consulted instead of using ** this value. ** ** To retain the Fossil version 2.x behavior when using Fossil-NG ** the FOSSIL_ENABLE_LEGACY_MV_RM compile-time option must be used ** -AND- the "mv-rm-files" setting must be set to zero. */ #ifndef FOSSIL_MV_RM_FILE #define FOSSIL_MV_RM_FILE (0) #endif /* ** This routine returns the names of files in a working checkout that ** are created by Fossil itself, and hence should not be added, deleted, ** or merge, and should be omitted from "clean" and "extras" lists. ** ** Return the N-th name. The first name has N==0. When all names have ** been used, return 0. */ const char *fossil_reserved_name(int N, int omitRepo){ /* Possible names of the local per-checkout database file and ** its associated journals */ static const char *const azName[] = { "_FOSSIL_", "_FOSSIL_-journal", "_FOSSIL_-wal", "_FOSSIL_-shm", ".fslckout", ".fslckout-journal", ".fslckout-wal", ".fslckout-shm", /* The use of ".fos" as the name of the checkout database is ** deprecated. Use ".fslckout" instead. At some point, the following ** entries should be removed. 2012-02-04 */ ".fos", ".fos-journal", ".fos-wal", ".fos-shm", }; |
︙ | ︙ | |||
65 66 67 68 69 70 71 | { "manifest", MFESTFLG_RAW }, { "manifest.uuid", MFESTFLG_UUID }, { "manifest.tags", MFESTFLG_TAGS } }; static const char *azManifests[3]; /* | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | { "manifest", MFESTFLG_RAW }, { "manifest.uuid", MFESTFLG_UUID }, { "manifest.tags", MFESTFLG_TAGS } }; static const char *azManifests[3]; /* ** Names of repository files, if they exist in the checkout. */ static const char *azRepo[4] = { 0, 0, 0, 0 }; /* Cached setting "manifest" */ static int cachedManifest = -1; static int numManifests; |
︙ | ︙ | |||
154 155 156 157 158 159 160 | ** ** Omit any file whose name is pOmit. */ static int add_one_file( const char *zPath, /* Tree-name of file to add. */ int vid /* Add to this VFILE */ ){ | < < < < < < | | | | < | | < < | 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 | ** ** Omit any file whose name is pOmit. */ static int add_one_file( const char *zPath, /* Tree-name of file to add. */ int vid /* Add to this VFILE */ ){ if( !file_is_simple_pathname(zPath, 1) ){ fossil_warning("filename contains illegal characters: %s", zPath); return 0; } if( db_exists("SELECT 1 FROM vfile" " WHERE pathname=%Q %s", zPath, filename_collation()) ){ db_multi_exec("UPDATE vfile SET deleted=0" " WHERE pathname=%Q %s AND deleted", zPath, filename_collation()); }else{ char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); int isExe = file_isexe(zFullname, RepoFILE); db_multi_exec( "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink)" "VALUES(%d,0,0,0,%Q,%d,%d)", vid, zPath, isExe, file_islink(0)); fossil_free(zFullname); } if( db_changes() ){ fossil_print("ADDED %s\n", zPath); return 1; }else{ fossil_print("SKIP %s\n", zPath); return 0; } } /* ** Add all files in the sfile temp table. ** ** Automatically exclude the repository file. */ static int add_files_in_sfile(int vid){ const char *zRepo; /* Name of the repository database file */ int nAdd = 0; /* Number of files added */ int i; /* Loop counter */ const char *zReserved; /* Name of a reserved file */ Blob repoName; /* Treename of the repository */ |
︙ | ︙ | |||
215 216 217 218 219 220 221 | zRepo = blob_str(&repoName); } if( filenames_are_case_sensitive() ){ xCmp = fossil_strcmp; }else{ xCmp = fossil_stricmp; } | | < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | < < < < < | < < < < < < < | | < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | zRepo = blob_str(&repoName); } if( filenames_are_case_sensitive() ){ xCmp = fossil_strcmp; }else{ xCmp = fossil_stricmp; } db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname"); while( db_step(&loop)==SQLITE_ROW ){ const char *zToAdd = db_column_text(&loop, 0); if( fossil_strcmp(zToAdd, zRepo)==0 ) continue; for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){ if( xCmp(zToAdd, zReserved)==0 ) break; } if( zReserved ) continue; nAdd += add_one_file(zToAdd, vid); } db_finalize(&loop); blob_reset(&repoName); return nAdd; } /* ** COMMAND: add ** ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...? ** ** Make arrangements to add one or more files or directories to the ** current checkout at the next commit. ** ** When adding files or directories recursively, filenames that begin ** with "." are excluded by default. To include such files, add ** the "--dotfiles" option to the command-line. ** ** The --ignore and --clean options are comma-separated lists of glob patterns ** for files to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore ** option does not appear on the command line then the "ignore-glob" setting ** is used. If the --clean option does not appear on the command line then ** the "clean-glob" setting is used. ** ** If files are attempted to be added explicitly on the command line which ** match "ignore-glob", a confirmation is asked first. This can be prevented ** using the -f|--force option. ** ** The --case-sensitive option determines whether or not filenames should ** be treated case sensitive or not. If the option is not given, the default ** depends on the global setting, or the operating system default, if not set. ** ** Options: ** ** --case-sensitive <BOOL> Override the case-sensitive setting. ** --dotfiles include files beginning with a dot (".") ** -f|--force Add files without prompting ** --ignore <CSG> Ignore unmanaged files matching patterns from ** the comma separated list of glob patterns. ** --clean <CSG> Also ignore files matching patterns from ** the comma separated list of glob patterns. ** ** See also: addremove, rm */ void add_cmd(void){ int i; /* Loop counter */ int vid; /* Currently checked out version */ int nRoot; /* Full path characters in g.zLocalRoot */ const char *zCleanFlag; /* The --clean option or clean-glob setting */ const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */ unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ int forceFlag; zCleanFlag = find_option("clean",0,1); zIgnoreFlag = find_option("ignore",0,1); forceFlag = find_option("force","f",0)!=0; if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; /* We should be done with options.. */ verify_all_options(); db_must_be_within_tree(); if( zCleanFlag==0 ){ zCleanFlag = db_get("clean-glob", 0); |
︙ | ︙ | |||
431 432 433 434 435 436 437 | pIgnore = glob_create(zIgnoreFlag); nRoot = strlen(g.zLocalRoot); /* Load the names of all files that are to be added into sfile temp table */ for(i=2; i<g.argc; i++){ char *zName; int isDir; | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | pIgnore = glob_create(zIgnoreFlag); nRoot = strlen(g.zLocalRoot); /* Load the names of all files that are to be added into sfile temp table */ for(i=2; i<g.argc; i++){ char *zName; int isDir; Blob fullName; /* file_tree_name() throws a fatal error if g.argv[i] is outside of the ** checkout. */ file_tree_name(g.argv[i], &fullName, 0, 1); blob_reset(&fullName); file_canonical_name(g.argv[i], &fullName, 0); zName = blob_str(&fullName); isDir = file_isdir(zName, RepoFILE); if( isDir==1 ){ vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore); }else if( isDir==0 ){ fossil_warning("not found: %s", zName); }else{ char *zTreeName = &zName[nRoot]; if( !forceFlag && glob_match(pIgnore, zTreeName) ){ Blob ans; char cReply; char *prompt = mprintf("file \"%s\" matches \"ignore-glob\". " "Add it (a=all/y/N)? ", zTreeName); prompt_user(prompt, &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); if( cReply=='a' || cReply=='A' ){ forceFlag = 1; }else if( cReply!='y' && cReply!='Y' ){ blob_reset(&fullName); continue; } } db_multi_exec( "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zTreeName ); } blob_reset(&fullName); } glob_free(pIgnore); glob_free(pClean); add_files_in_sfile(vid); db_end_transaction(0); } /* ** This function adds a file to list of files to delete from disk after ** the other actions required for the parent operation have completed |
︙ | ︙ | |||
528 529 530 531 532 533 534 | } file_tree_name(zOldName, &fullOldName, 1, 1); db_multi_exec("INSERT INTO fremove VALUES('%q');", blob_str(&fullOldName)); blob_reset(&fullOldName); } /* | | | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | } file_tree_name(zOldName, &fullOldName, 1, 1); db_multi_exec("INSERT INTO fremove VALUES('%q');", blob_str(&fullOldName)); blob_reset(&fullOldName); } /* ** This function deletes files from the checkout, using the file names ** contained in the temporary table "fremove". The temporary table is ** created on demand by the add_file_to_remove() function. ** ** If dryRunFlag is non-zero, no files will be removed; however, their ** names will still be output. ** ** The temporary table "fremove" is dropped after being processed. |
︙ | ︙ | |||
579 580 581 582 583 584 585 | ** to do so. ** ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" ** setting is non-zero, files WILL BE removed from disk as well. ** This does NOT apply to the 'forget' command. ** ** Options: | | | | < < < < < < < | | < | < < < < < < > > > > | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | ** to do so. ** ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" ** setting is non-zero, files WILL BE removed from disk as well. ** This does NOT apply to the 'forget' command. ** ** Options: ** --soft Skip removing files from the checkout. ** This supersedes the --hard option. ** --hard Remove files from the checkout. ** --case-sensitive <BOOL> Override the case-sensitive setting. ** -n|--dry-run If given, display instead of run actions. ** ** See also: addremove, add */ void delete_cmd(void){ int i; int removeFiles; int dryRunFlag; int softFlag; int hardFlag; Stmt loop; dryRunFlag = find_option("dry-run","n",0)!=0; softFlag = find_option("soft",0,0)!=0; hardFlag = find_option("hard",0,0)!=0; /* We should be done with options.. */ verify_all_options(); db_must_be_within_tree(); db_begin_transaction(); if( g.argv[1][0]=='f' ){ /* i.e. "forget" */ removeFiles = 0; }else if( softFlag ){ removeFiles = 0; }else if( hardFlag ){ removeFiles = 1; }else{ #if FOSSIL_ENABLE_LEGACY_MV_RM removeFiles = db_get_boolean("mv-rm-files",0); #else removeFiles = FOSSIL_MV_RM_FILE; #endif } db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); for(i=2; i<g.argc; i++){ Blob treeName; char *zTreeName; |
︙ | ︙ | |||
684 685 686 687 688 689 690 | ** ** The case-sensitive setting determines the default value. If ** the case-sensitive setting is undefined, then case sensitivity ** defaults off for Cygwin, Mac and Windows and on for all other unix. ** If case-sensitivity is enabled in the windows kernel, the Cygwin port ** of fossil.exe can detect that, and modifies the default to 'on'. ** | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | ** ** The case-sensitive setting determines the default value. If ** the case-sensitive setting is undefined, then case sensitivity ** defaults off for Cygwin, Mac and Windows and on for all other unix. ** If case-sensitivity is enabled in the windows kernel, the Cygwin port ** of fossil.exe can detect that, and modifies the default to 'on'. ** ** The --case-sensitive <BOOL> command-line option overrides any ** setting. */ int filenames_are_case_sensitive(void){ static int caseSensitive; static int once = 1; if( once ){ |
︙ | ︙ | |||
740 741 742 743 744 745 746 | } /* ** COMMAND: addremove ** ** Usage: %fossil addremove ?OPTIONS? ** | | | | | | | | | | | | | | < < < < < < < < | | | | < < < < < < < < < < < < < | | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | } /* ** COMMAND: addremove ** ** Usage: %fossil addremove ?OPTIONS? ** ** Do all necessary "add" and "rm" commands to synchronize the repository ** with the content of the working checkout: ** ** * All files in the checkout but not in the repository (that is, ** all files displayed using the "extras" command) are added as ** if by the "add" command. ** ** * All files in the repository but missing from the checkout (that is, ** all files that show as MISSING with the "status" command) are ** removed as if by the "rm" command. ** ** The command does not "commit". You must run the "commit" separately ** as a separate step. ** ** Files and directories whose names begin with "." are ignored unless ** the --dotfiles option is used. ** ** The --ignore option overrides the "ignore-glob" setting, as do the ** --case-sensitive option with the "case-sensitive" setting and the ** --clean option with the "clean-glob" setting. See the documentation ** on the "settings" command for further information. ** ** The -n|--dry-run option shows what would happen without actually doing ** anything. ** ** This command can be used to track third party software. ** ** Options: ** --case-sensitive <BOOL> Override the case-sensitive setting. ** --dotfiles Include files beginning with a dot (".") ** --ignore <CSG> Ignore unmanaged files matching patterns from ** the comma separated list of glob patterns. ** --clean <CSG> Also ignore files matching patterns from ** the comma separated list of glob patterns. ** -n|--dry-run If given, display instead of run actions. ** ** See also: add, rm */ void addremove_cmd(void){ Blob path; const char *zCleanFlag = find_option("clean",0,1); const char *zIgnoreFlag = find_option("ignore",0,1); unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; int dryRunFlag = find_option("dry-run","n",0)!=0; int n; Stmt q; int vid; int nAdd = 0; int nDelete = 0; Glob *pIgnore, *pClean; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } /* We should be done with options.. */ verify_all_options(); /* Fail if unprocessed arguments are present, in case user expect the ** addremove command to accept a list of file or directory. */ if( g.argc>2 ){ fossil_fatal( "%s: Can only work on the entire checkout, no arguments supported.", g.argv[1]); } db_must_be_within_tree(); if( zCleanFlag==0 ){ zCleanFlag = db_get("clean-glob", 0); } if( zIgnoreFlag==0 ){ |
︙ | ︙ | |||
851 852 853 854 855 856 857 | db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); n = strlen(g.zLocalRoot); blob_init(&path, g.zLocalRoot, n-1); /* now we read the complete file structure into a temp table */ pClean = glob_create(zCleanFlag); pIgnore = glob_create(zIgnoreFlag); | | | 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); n = strlen(g.zLocalRoot); blob_init(&path, g.zLocalRoot, n-1); /* now we read the complete file structure into a temp table */ pClean = glob_create(zCleanFlag); pIgnore = glob_create(zIgnoreFlag); vfile_scan(&path, blob_size(&path), scanFlags, pClean, pIgnore); glob_free(pIgnore); glob_free(pClean); nAdd = add_files_in_sfile(vid); /* step 2: search for missing files */ db_prepare(&q, "SELECT pathname, %Q || pathname, deleted FROM vfile" |
︙ | ︙ | |||
880 881 882 883 884 885 886 | fossil_print("DELETED %s\n", zFile); nDelete++; } } db_finalize(&q); /* show command summary */ fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); | < < | > | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 | fossil_print("DELETED %s\n", zFile); nDelete++; } } db_finalize(&q); /* show command summary */ fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); db_end_transaction(dryRunFlag); } /* ** Rename a single file. ** ** The original name of the file is zOrig. The new filename is zNew. */ static void mv_one_file( |
︙ | ︙ | |||
953 954 955 956 957 958 959 | db_multi_exec("INSERT INTO fmove VALUES('%q','%q');", zOld, zNew); } blob_reset(&fullNewName); blob_reset(&fullOldName); } /* | | | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | db_multi_exec("INSERT INTO fmove VALUES('%q','%q');", zOld, zNew); } blob_reset(&fullNewName); blob_reset(&fullOldName); } /* ** This function moves files within the checkout, using the file names ** contained in the temporary table "fmove". The temporary table is ** created on demand by the add_file_to_move() function. ** ** If dryRunFlag is non-zero, no files will be moved; however, their ** names will still be output. ** ** The temporary table "fmove" is dropped after being processed. |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | ** or: %fossil mv|rename OLDNAME... DIR ** ** Move or rename one or more files or directories within the repository tree. ** You can either rename a file or directory or move it to another subdirectory. ** ** The 'mv' command does NOT normally rename or move the files on disk. ** This command merely records the fact that file names have changed so | | | | | | | | | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 | ** or: %fossil mv|rename OLDNAME... DIR ** ** Move or rename one or more files or directories within the repository tree. ** You can either rename a file or directory or move it to another subdirectory. ** ** The 'mv' command does NOT normally rename or move the files on disk. ** This command merely records the fact that file names have changed so ** that appropriate notations can be made at the next commit/check-in. ** However, the default behavior of this command may be overridden via ** command line options listed below and/or the 'mv-rm-files' setting. ** ** The 'rename' command never renames or moves files on disk, even when the ** command line options and/or the 'mv-rm-files' setting would otherwise ** require it to do so. ** ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files" ** setting is non-zero, files WILL BE renamed or moved on disk ** as well. This does NOT apply to the 'rename' command. ** ** Options: ** --soft Skip moving files within the checkout. ** This supersedes the --hard option. ** --hard Move files within the checkout. ** --case-sensitive <BOOL> Override the case-sensitive setting. ** -n|--dry-run If given, display instead of run actions. ** ** See also: changes, status */ void mv_cmd(void){ int i; int vid; int moveFiles; int dryRunFlag; int softFlag; |
︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 | hardFlag = find_option("hard",0,0)!=0; /* We should be done with options.. */ verify_all_options(); vid = db_lget_int("checkout", 0); if( vid==0 ){ | | | > > > > | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 | hardFlag = find_option("hard",0,0)!=0; /* We should be done with options.. */ verify_all_options(); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("no checkout in which to rename files"); } if( g.argc<4 ){ usage("OLDNAME NEWNAME"); } zDest = g.argv[g.argc-1]; db_begin_transaction(); if( g.argv[1][0]=='r' ){ /* i.e. "rename" */ moveFiles = 0; }else if( softFlag ){ moveFiles = 0; }else if( hardFlag ){ moveFiles = 1; }else{ #if FOSSIL_ENABLE_LEGACY_MV_RM moveFiles = db_get_boolean("mv-rm-files",0); #else moveFiles = FOSSIL_MV_RM_FILE; #endif } file_tree_name(zDest, &dest, 0, 1); db_multi_exec( "UPDATE vfile SET origname=pathname WHERE origname IS NULL;" ); db_multi_exec( "CREATE TEMP TABLE mv(f TEXT UNIQUE ON CONFLICT IGNORE, t TEXT);" |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 | int nOrig; file_tree_name(g.argv[i], &orig, 0, 1); zOrig = blob_str(&orig); nOrig = blob_size(&orig); db_prepare(&q, "SELECT pathname FROM vfile" " WHERE vid=%d" | | | < < | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 | int nOrig; file_tree_name(g.argv[i], &orig, 0, 1); zOrig = blob_str(&orig); nOrig = blob_size(&orig); db_prepare(&q, "SELECT pathname FROM vfile" " WHERE vid=%d" " AND (pathname='%q' %s OR (pathname>'%q/' %s AND pathname<'%q0' %s))" " ORDER BY 1", vid, zOrig, filename_collation(), zOrig, filename_collation(), zOrig, filename_collation() ); while( db_step(&q)==SQLITE_ROW ){ const char *zPath = db_column_text(&q, 0); int nPath = db_column_bytes(&q, 0); const char *zTail; if( nPath==nOrig ){ zTail = file_tail(zPath); }else if( destType==1 ){ zTail = &zPath[nOrig-strlen(file_tail(zOrig))]; }else{ zTail = &zPath[nOrig+1]; } db_multi_exec( "INSERT INTO mv VALUES('%q','%q%q')", zPath, blob_str(&dest), zTail ); } db_finalize(&q); } } db_prepare(&q, "SELECT f, t FROM mv ORDER BY f"); while( db_step(&q)==SQLITE_ROW ){ const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); mv_one_file(vid, zFrom, zTo, dryRunFlag); if( moveFiles ) add_file_to_move(zFrom, zTo); } db_finalize(&q); db_end_transaction(0); if( moveFiles ) process_files_to_move(dryRunFlag); } /* ** Function for stash_apply to be able to restore a file and indicate ** newly ADDED state. */ int stash_add_files_in_sfile(int vid){ return add_files_in_sfile(vid); } |
Deleted src/ajax.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/alerts.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Logic for email notification, also known as "alerts". ** ** Are you looking for the code that reads and writes the internet ** email protocol? That is not here. See the "smtp.c" file instead. ** Yes, the choice of source code filenames is not the greatest, but ** it is not so bad that changing them seems justified. */ #include "config.h" #include "alerts.h" #include <assert.h> #include <time.h> /* ** Maximum size of the subscriberCode blob, in bytes |
︙ | ︙ | |||
44 45 46 47 48 49 50 | @ -- In the last case the suname column points from the subscriber entry @ -- to the USER entry. @ -- @ -- The ssub field is a string where each character indicates a particular @ -- type of event to subscribe to. Choices: @ -- a - Announcements @ -- c - Check-ins | < < < < < | | < | | < > > > > > > > > > < < < < < < < < < < < < < < < | < < < < < < < | | < < < < | < < | | | | | | < < < < < < < < < < < < < < < < < < | < < < < | < | | | | < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < | < < | | < | | | < < < < < < < < < < < < < < < < < | | | 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 | @ -- In the last case the suname column points from the subscriber entry @ -- to the USER entry. @ -- @ -- The ssub field is a string where each character indicates a particular @ -- type of event to subscribe to. Choices: @ -- a - Announcements @ -- c - Check-ins @ -- t - Ticket changes @ -- w - Wiki changes @ -- Probably different codes will be added in the future. In the future @ -- we might also add a separate table that allows subscribing to email @ -- notifications for specific branches or tags or tickets. @ -- @ CREATE TABLE repository.subscriber( @ subscriberId INTEGER PRIMARY KEY, -- numeric subscriber ID. Internal use @ subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE, -- UUID for subscriber @ semail TEXT UNIQUE COLLATE nocase,-- email address @ suname TEXT, -- corresponding USER entry @ sverified BOOLEAN DEFAULT true, -- email address verified @ sdonotcall BOOLEAN, -- true for Do Not Call @ sdigest BOOLEAN, -- true for daily digests only @ ssub TEXT, -- baseline subscriptions @ sctime INTDATE, -- When this entry was created. unixtime @ mtime INTDATE, -- Last change. unixtime @ smip TEXT -- IP address of last change @ ); @ CREATE INDEX repository.subscriberUname @ ON subscriber(suname) WHERE suname IS NOT NULL; @ @ DROP TABLE IF EXISTS repository.pending_alert; @ -- Email notifications that need to be sent. @ -- @ -- The first character of the eventid determines the event type. @ -- Remaining characters determine the specific event. For example, @ -- 'c4413' means check-in with rid=4413. @ -- @ CREATE TABLE repository.pending_alert( @ eventid TEXT PRIMARY KEY, -- Object that changed @ sentSep BOOLEAN DEFAULT false, -- individual alert sent @ sentDigest BOOLEAN DEFAULT false, -- digest alert sent @ sentMod BOOLEAN DEFAULT false -- pending moderation alert sent @ ) WITHOUT ROWID; @ @ DROP TABLE IF EXISTS repository.alert_bounce; @ -- Record bounced emails. If too many bounces are received within @ -- some defined time range, then cancel the subscription. Older @ -- entries are periodically purged. @ -- @ CREATE TABLE repository.alert_bounce( @ subscriberId INTEGER, -- to whom the email was sent. @ sendTime INTEGER, -- seconds since 1970 when email was sent @ rcvdTime INTEGER -- seconds since 1970 when bounce was received @ ); ; /* ** Return true if the email notification tables exist. */ int alert_tables_exist(void){ return db_table_exists("repository", "subscriber"); } /* ** Make sure the table needed for email notification exist in the repository. ** ** If the bOnlyIfEnabled option is true, then tables are only created ** if the email-send-method is something other than "off". */ void alert_schema(int bOnlyIfEnabled){ if( !alert_tables_exist() ){ if( bOnlyIfEnabled && fossil_strcmp(db_get("email-send-method","off"),"off")==0 ){ return; /* Don't create table for disabled email */ } db_multi_exec(zAlertInit/*works-like:""*/); alert_triggers_enable(); }else if( !db_table_has_column("repository","pending_alert","sentMod") ){ db_multi_exec( "ALTER TABLE repository.pending_alert" " ADD COLUMN sentMod BOOLEAN DEFAULT false;" ); } } /* ** Enable triggers that automatically populate the pending_alert ** table. */ void alert_triggers_enable(void){ if( !db_table_exists("repository","pending_alert") ) return; db_multi_exec( "CREATE TRIGGER IF NOT EXISTS repository.alert_trigger1\n" "AFTER INSERT ON event BEGIN\n" " INSERT INTO pending_alert(eventid)\n" " SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n" " ON CONFLICT(eventId) DO NOTHING;\n" "END;" ); } /* ** Disable triggers the event_pending triggers. ** ** This must be called before rebuilding the EVENT table, for example ** via the "fossil rebuild" command. */ void alert_triggers_disable(void){ db_multi_exec( "DROP TRIGGER IF EXISTS repository.alert_trigger1;\n" "DROP TRIGGER IF EXISTS repository.email_trigger1;\n" // Legacy ); } /* ** Return true if email alerts are active. */ int alert_enabled(void){ if( !alert_tables_exist() ) return 0; if( fossil_strcmp(db_get("email-send-method","off"),"off")==0 ) return 0; return 1; } /* ** If the subscriber table does not exist, then paint an error message ** web page and return true. ** ** If the subscriber table does exist, return 0 without doing anything. */ static int alert_webpages_disabled(void){ if( alert_tables_exist() ) return 0; style_header("Email Alerts Are Disabled"); @ <p>Email alerts are disabled on this server</p> style_footer(); return 1; } /* ** Insert a "Subscriber List" submenu link if the current user ** is an administrator. */ void alert_submenu_common(void){ if( g.perm.Admin ){ if( fossil_strcmp(g.zPath,"subscribers") ){ style_submenu_element("List Subscribers","%R/subscribers"); } if( fossil_strcmp(g.zPath,"subscribe") ){ style_submenu_element("Add New Subscriber","%R/subscribe"); } } } |
︙ | ︙ | |||
306 307 308 309 310 311 312 | login_needed(0); return; } db_begin_transaction(); alert_submenu_common(); style_submenu_element("Send Announcement","%R/announce"); | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > > > > > | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | login_needed(0); return; } db_begin_transaction(); alert_submenu_common(); style_submenu_element("Send Announcement","%R/announce"); style_header("Email Notification Setup"); @ <h1>Status</h1> @ <table class="label-value"> if( alert_enabled() ){ stats_for_email(); }else{ @ <th>Disabled</th> } @ </table> @ <hr> @ <h1> Configuration </h1> @ <form action="%R/setup_notification" method="post"><div> @ <input type="submit" name="submit" value="Apply Changes" /><hr> login_insert_csrf_secret(); entry_attribute("Canonical Server URL", 40, "email-url", "eurl", "", 0); @ <p><b>Required.</b> @ This is URL used as the basename for hyperlinks included in @ email alert text. Omit the trailing "/". @ Suggested value: "%h(g.zBaseURL)" @ (Property: "email-url")</p> @ <hr> entry_attribute("\"Return-Path\" email address", 20, "email-self", "eself", "", 0); @ <p><b>Required.</b> @ This is the email to which email notification bounces should be sent. @ In cases where the email notification does not align with a specific @ Fossil login account (for example, digest messages), this is also @ the "From:" address of the email notification. @ The system administrator should arrange for emails sent to this address @ to be handed off to the "fossil email incoming" command so that Fossil @ can handle bounces. (Property: "email-self")</p> @ <hr> entry_attribute("Repository Nickname", 16, "email-subname", "enn", "", 0); @ <p><b>Required.</b> @ This is short name used to identifies the repository in the @ Subject: line of email alerts. Traditionally this name is @ included in square brackets. Examples: "[fossil-src]", "[sqlite-src]". @ (Property: "email-subname")</p> @ <hr> multiple_choice_attribute("Email Send Method", "email-send-method", "esm", "off", count(azSendMethods)/2, azSendMethods); @ <p>How to send email. Requires auxiliary information from the fields @ that follow. Hint: Use the <a href="%R/announce">/announce</a> page @ to send test message to debug this setting. @ (Property: "email-send-method")</p> alert_schema(1); entry_attribute("Pipe Email Text Into This Command", 60, "email-send-command", "ecmd", "sendmail -ti", 0); @ <p>When the send method is "pipe to a command", this is the command @ that is run. Email messages are piped into the standard input of this @ command. The command is expected to extract the sender address, @ recepient addresses, and subject from the header of the piped email @ text. (Property: "email-send-command")</p> entry_attribute("Store Emails In This Database", 60, "email-send-db", "esdb", "", 0); @ <p>When the send method is "store in a databaes", each email message is @ stored in an SQLite database file with the name given here. @ (Property: "email-send-db")</p> entry_attribute("Store Emails In This Directory", 60, "email-send-dir", "esdir", "", 0); @ <p>When the send method is "store in a directory", each email message is @ stored as a separate file in the directory shown here. @ (Property: "email-send-dir")</p> entry_attribute("SMTP Relay Host", 60, "email-send-relayhost", "esrh", "", 0); @ <p>When the send method is "SMTP relay", each email message is @ transmitted via the SMTP protocol (rfc5321) to a "Mail Submission @ Agent" or "MSA" (rfc4409) at the hostname shown here. Optionally @ append a colon and TCP port number (ex: smtp.example.com:587). @ The default TCP port number is 25. @ (Property: "email-send-relayhost")</p> @ <hr> entry_attribute("Administrator email address", 40, "email-admin", "eadmin", "", 0); @ <p>This is the email for the human administrator for the system. @ Abuse and trouble reports are send here. @ (Property: "email-admin")</p> @ <hr> @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ </div></form> db_end_transaction(0); style_footer(); } #if 0 /* ** Encode pMsg as MIME base64 and append it to pOut */ static void append_base64(Blob *pOut, Blob *pMsg){ |
︙ | ︙ | |||
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | x[1] = "0123456789ABCDEF"[(c>>4)&0xf]; x[2] = "0123456789ABCDEF"[c&0xf]; blob_append(pOut, x, 3); iCol += 3; } } } #if INTERFACE /* ** An instance of the following object is used to send emails. */ struct AlertSender { sqlite3 *db; /* Database emails are sent to */ sqlite3_stmt *pStmt; /* Stmt to insert into the database */ const char *zDest; /* How to send email. */ const char *zDb; /* Name of database file */ const char *zDir; /* Directory in which to store as email files */ const char *zCmd; /* Command to run for each email */ const char *zFrom; /* Emails come from here */ | > > > > > > > < | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | x[1] = "0123456789ABCDEF"[(c>>4)&0xf]; x[2] = "0123456789ABCDEF"[c&0xf]; blob_append(pOut, x, 3); iCol += 3; } } } #if defined(_WIN32) || defined(WIN32) # undef popen # define popen _popen # undef pclose # define pclose _pclose #endif #if INTERFACE /* ** An instance of the following object is used to send emails. */ struct AlertSender { sqlite3 *db; /* Database emails are sent to */ sqlite3_stmt *pStmt; /* Stmt to insert into the database */ const char *zDest; /* How to send email. */ const char *zDb; /* Name of database file */ const char *zDir; /* Directory in which to store as email files */ const char *zCmd; /* Command to run for each email */ const char *zFrom; /* Emails come from here */ SmtpSession *pSmtp; /* SMTP relay connection */ Blob out; /* For zDest=="blob" */ char *zErr; /* Error message */ u32 mFlags; /* Flags */ int bImmediateFail; /* On any error, call fossil_fatal() */ }; |
︙ | ︙ | |||
514 515 516 517 518 519 520 | sqlite3_finalize(p->pStmt); p->pStmt = 0; sqlite3_close(p->db); p->db = 0; p->zDb = 0; p->zDir = 0; p->zCmd = 0; | < | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | sqlite3_finalize(p->pStmt); p->pStmt = 0; sqlite3_close(p->db); p->db = 0; p->zDb = 0; p->zDir = 0; p->zCmd = 0; if( p->pSmtp ){ smtp_client_quit(p->pSmtp); smtp_session_free(p->pSmtp); p->pSmtp = 0; } blob_reset(&p->out); } |
︙ | ︙ | |||
591 592 593 594 595 596 597 | p = fossil_malloc(sizeof(*p)); memset(p, 0, sizeof(*p)); blob_init(&p->out, 0, 0); p->mFlags = mFlags; if( zAltDest ){ p->zDest = zAltDest; }else{ | | < | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | p = fossil_malloc(sizeof(*p)); memset(p, 0, sizeof(*p)); blob_init(&p->out, 0, 0); p->mFlags = mFlags; if( zAltDest ){ p->zDest = zAltDest; }else{ p->zDest = db_get("email-send-method","off"); } if( fossil_strcmp(p->zDest,"off")==0 ) return p; if( emailerGetSetting(p, &p->zFrom, "email-self") ) return p; if( fossil_strcmp(p->zDest,"db")==0 ){ char *zErr; int rc; if( emailerGetSetting(p, &p->zDb, "email-send-db") ) return p; rc = sqlite3_open(p->zDb, &p->db); if( rc ){ emailerError(p, "unable to open output database file \"%s\": %s", |
︙ | ︙ | |||
633 634 635 636 637 638 639 | blob_init(&p->out, 0, 0); }else if( fossil_strcmp(p->zDest, "relay")==0 ){ const char *zRelay = 0; emailerGetSetting(p, &zRelay, "email-send-relayhost"); if( zRelay ){ u32 smtpFlags = SMTP_DIRECT; if( mFlags & ALERT_TRACE ) smtpFlags |= SMTP_TRACE_STDOUT; | | < | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | blob_init(&p->out, 0, 0); }else if( fossil_strcmp(p->zDest, "relay")==0 ){ const char *zRelay = 0; emailerGetSetting(p, &zRelay, "email-send-relayhost"); if( zRelay ){ u32 smtpFlags = SMTP_DIRECT; if( mFlags & ALERT_TRACE ) smtpFlags |= SMTP_TRACE_STDOUT; p->pSmtp = smtp_session_new(p->zFrom, zRelay, smtpFlags); smtp_client_startup(p->pSmtp); } } return p; } /* |
︙ | ︙ | |||
685 686 687 688 689 690 691 | return 1; } } return 0; } /* | < | | | | > > > > > | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | return 1; } } return 0; } /* ** Make a copy of the input string up to but not including the ** first cTerm character. ** ** Verify that the string really that is to be copied really is a ** valid email address. If it is not, then return NULL. ** ** This routine is more restrictive than necessary. It does not ** allow comments, IP address, quoted strings, or certain uncommon ** characters. The only non-alphanumerics allowed in the local ** part are "_", "+", "-" and "+". */ char *email_copy_addr(const char *z, char cTerm ){ int i; int nAt = 0; int nDot = 0; char c; if( z[0]=='.' ) return 0; /* Local part cannot begin with "." */ for(i=0; (c = z[i])!=0 && c!=cTerm; i++){ if( fossil_isalnum(c) ){ |
︙ | ︙ | |||
726 727 728 729 730 731 732 | }else{ return 0; /* Anything else is an error */ } } if( c!=cTerm ) return 0; /* Missing terminator */ if( nAt==0 ) return 0; /* No "@" found anywhere */ if( nDot==0 ) return 0; /* No "." in the domain */ | < | | < < < < < < < < < < < < < < | | < < < | | | | > | > | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | }else{ return 0; /* Anything else is an error */ } } if( c!=cTerm ) return 0; /* Missing terminator */ if( nAt==0 ) return 0; /* No "@" found anywhere */ if( nDot==0 ) return 0; /* No "." in the domain */ /* If we reach this point, the email address is valid */ return mprintf("%.*s", i, z); } /* ** Scan the input string for a valid email address enclosed in <...> ** If the string contains one or more email addresses, extract the first ** one into memory obtained from mprintf() and return a pointer to it. ** If no valid email address can be found, return NULL. */ char *alert_find_emailaddr(const char *zIn){ char *zOut = 0; while( zIn!=0 ){ zIn = (const char*)strchr(zIn, '<'); if( zIn==0 ) break; zIn++; zOut = email_copy_addr(zIn, '>'); if( zOut!=0 ) break; } return zOut; } /* ** SQL function: find_emailaddr(X) ** ** Return the first valid email address of the form <...> in input string |
︙ | ︙ | |||
783 784 785 786 787 788 789 | const char *zIn = (const char*)sqlite3_value_text(argv[0]); char *zOut = alert_find_emailaddr(zIn); if( zOut ){ sqlite3_result_text(context, zOut, -1, fossil_free); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | const char *zIn = (const char*)sqlite3_value_text(argv[0]); char *zOut = alert_find_emailaddr(zIn); if( zOut ){ sqlite3_result_text(context, zOut, -1, fossil_free); } } /* ** Return the hostname portion of an email address - the part following ** the @ */ char *alert_hostname(const char *zAddr){ char *z = strchr(zAddr, '@'); if( z ){ |
︙ | ︙ | |||
874 875 876 877 878 879 880 | */ void email_header_to(Blob *pMsg, int *pnTo, char ***pazTo){ int nTo = 0; char **azTo = 0; Blob v; char *z, *zAddr; int i; | | | | | | | | | | < > < < | | < < < | 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | */ void email_header_to(Blob *pMsg, int *pnTo, char ***pazTo){ int nTo = 0; char **azTo = 0; Blob v; char *z, *zAddr; int i; email_header_value(pMsg, "to", &v); z = blob_str(&v); for(i=0; z[i]; i++){ if( z[i]=='<' && (zAddr = email_copy_addr(&z[i+1],'>'))!=0 ){ azTo = fossil_realloc(azTo, sizeof(azTo[0])*(nTo+1) ); azTo[nTo++] = zAddr; } } *pnTo = nTo; *pazTo = azTo; } /* ** Free a list of To addresses obtained from a prior call to ** email_header_to() */ void email_header_to_free(int nTo, char **azTo){ int i; for(i=0; i<nTo; i++) fossil_free(azTo[i]); fossil_free(azTo); } /* ** Send a single email message. ** ** The recepient(s) must be specified using "To:" or "Cc:" or "Bcc:" fields ** in the header. Likewise, the header must contains a "Subject:" line. ** The header might also include fields like "Message-Id:" or ** "In-Reply-To:". ** ** This routine will add fields to the header as follows: ** ** From: ** Date: ** Message-Id: ** Content-Type: ** Content-Transfer-Encoding: ** MIME-Version: ** X-Fossil-From: ** ** The caller maintains ownership of the input Blobs. This routine will ** read the Blobs and send them onward to the email system, but it will ** not free them. ** ** The Message-Id: field is added if there is not already a Message-Id ** in the pHdr parameter. ** ** If the zFromName argument is not NULL, then it should be a human-readable ** name or handle for the sender. In that case, "From:" becomes a made-up ** email address based on a hash of zFromName and the domain of email-self, ** and an additional "X-Fossil-From:" field is inserted with the email-self ** address. Downstream software might use the X-Fossil-From header to set ** the envelope-from address of the email. If zFromName is a NULL pointer, ** then the "From:" is set to the email-self value and X-Fossil-From is ** omitted. */ void alert_send( AlertSender *p, /* Emailer context */ Blob *pHdr, /* Email header (incomplete) */ Blob *pBody, /* Email body */ const char *zFromName /* Optional human-readable name of sender */ ){ Blob all, *pOut; u64 r1, r2; if( p->mFlags & ALERT_TRACE ){ fossil_print("Sending email\n"); } if( fossil_strcmp(p->zDest, "off")==0 ){ return; } if( fossil_strcmp(p->zDest, "blob")==0 ){ pOut = &p->out; if( blob_size(pOut) ){ blob_appendf(pOut, "%.72c\n", '='); } }else{ blob_init(&all, 0, 0); pOut = &all; } blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr)); if( zFromName ){ blob_appendf(pOut, "From: %s <%s@%s>\r\n", zFromName, alert_mailbox_name(zFromName), alert_hostname(p->zFrom)); blob_appendf(pOut, "X-Fossil-From: <%s>\r\n", p->zFrom); }else{ blob_appendf(pOut, "From: <%s>\r\n", p->zFrom); } blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0))); if( strstr(blob_str(pHdr), "\r\nMessage-Id:")==0 ){ /* Message-id format: "<$(date)x$(random)@$(from-host)>" where $(date) is ** the current unix-time in hex, $(random) is a 64-bit random number, ** and $(from) is the domain part of the email-self setting. */ sqlite3_randomness(sizeof(r1), &r1); r2 = time(0); blob_appendf(pOut, "Message-Id: <%llxx%016llx@%s>\r\n", |
︙ | ︙ | |||
1002 1003 1004 1005 1006 1007 1008 | emailerError(p, "Failed to insert email message into output queue.\n" "%s", sqlite3_errmsg(p->db)); } }else if( p->zCmd ){ FILE *out = popen(p->zCmd, "w"); if( out ){ fwrite(blob_buffer(&all), 1, blob_size(&all), out); | | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 | emailerError(p, "Failed to insert email message into output queue.\n" "%s", sqlite3_errmsg(p->db)); } }else if( p->zCmd ){ FILE *out = popen(p->zCmd, "w"); if( out ){ fwrite(blob_buffer(&all), 1, blob_size(&all), out); fclose(out); }else{ emailerError(p, "Could not open output pipe \"%s\"", p->zCmd); } }else if( p->zDir ){ char *zFile = file_time_tempname(p->zDir, ".email"); blob_write_to_file(&all, zFile); fossil_free(zFile); |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | blob_add_final_newline(&all); fossil_print("%s", blob_str(&all)); } blob_reset(&all); } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < | | < > < < | < | < | | | | | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 | blob_add_final_newline(&all); fossil_print("%s", blob_str(&all)); } blob_reset(&all); } /* ** SETTING: email-send-method width=5 default=off ** Determine the method used to send email. Allowed values are ** "off", "relay", "pipe", "dir", "db", and "stdout". The "off" value ** means no email is ever sent. The "relay" value means emails are sent ** to an Mail Sending Agent using SMTP located at email-send-relayhost. ** The "pipe" value means email messages are piped into a command ** determined by the email-send-command setting. The "dir" value means ** emails are written to individual files in a directory determined ** by the email-send-dir setting. The "db" value means that emails ** are added to an SQLite database named by the* email-send-db setting. ** The "stdout" value writes email text to standard output, for debugging. */ /* ** SETTING: email-send-command width=40 ** This is a command to which outbound email content is piped when the ** email-send-method is set to "pipe". The command must extract ** recipient, sender, subject, and all other relevant information ** from the email header. */ /* ** SETTING: email-send-dir width=40 ** This is a directory into which outbound emails are written as individual ** files if the email-send-method is set to "dir". */ /* ** SETTING: email-send-db width=40 ** This is an SQLite database file into which outbound emails are written ** if the email-send-method is set to "db". */ /* ** SETTING: email-self width=40 ** This is the email address for the repository. Outbound emails add ** this email address as the "From:" field. */ /* ** SETTING: email-send-relayhost width=40 ** This is the hostname and TCP port to which output email messages ** are sent when email-send-method is "relay". There should be an ** SMTP server configured as a Mail Submission Agent listening on the ** designated host and port and all times. */ /* ** COMMAND: alerts* ** ** Usage: %fossil alerts SUBCOMMAND ARGS... ** ** Subcommands: ** ** pending Show all pending alerts. Useful for debugging. ** ** reset Hard reset of all email notification tables ** in the repository. This erases all subscription ** information. ** Use with extreme care ** ** ** send Compose and send pending email alerts. ** Some installations may want to do this via ** a cron-job to make sure alerts are sent ** in a timely manner. ** Options: ** ** --digest Send digests ** --test Write to standard output ** ** settings [NAME VALUE] With no arguments, list all email settings. ** Or change the value of a single email setting. ** ** status Report on the status of the email alert ** subsystem ** ** subscribers [PATTERN] List all subscribers matching PATTERN. ** ** test-message TO [OPTS] Send a single email message using whatever ** email sending mechanism is currently configured. ** Use this for testing the email notification ** configuration. Options: ** ** --body FILENAME ** --smtp-trace ** --stdout ** --subject|-S SUBJECT ** ** unsubscribe EMAIL Remove a single subscriber with the given EMAIL. */ void alert_cmd(void){ const char *zCmd; int nCmd; db_find_and_open_repository(0, 0); |
︙ | ︙ | |||
1215 1216 1217 1218 1219 1220 1221 | "deleting all subscriber information. The information will be\n" "unrecoverable.\n"); prompt_user("Continue? (y/N) ", &yn); c = blob_str(&yn)[0]; blob_reset(&yn); } if( c=='y' ){ | | < | | < < | < < < < < < < < < < < < < < < < < | < | 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | "deleting all subscriber information. The information will be\n" "unrecoverable.\n"); prompt_user("Continue? (y/N) ", &yn); c = blob_str(&yn)[0]; blob_reset(&yn); } if( c=='y' ){ alert_triggers_disable(); db_multi_exec( "DROP TABLE IF EXISTS subscriber;\n" "DROP TABLE IF EXISTS pending_alert;\n" "DROP TABLE IF EXISTS alert_bounce;\n" /* Legacy */ "DROP TABLE IF EXISTS alert_pending;\n" "DROP TABLE IF EXISTS subscription;\n" ); alert_schema(0); } }else if( strncmp(zCmd, "send", nCmd)==0 ){ u32 eFlags = 0; if( find_option("digest",0,0)!=0 ) eFlags |= SENDALERT_DIGEST; if( find_option("test",0,0)!=0 ){ eFlags |= SENDALERT_PRESERVE|SENDALERT_STDOUT; } verify_all_options(); alert_send_alerts(eFlags); }else if( strncmp(zCmd, "settings", nCmd)==0 ){ int isGlobal = find_option("global",0,0)!=0; int nSetting; const Setting *pSetting = setting_info(&nSetting); db_open_config(1, 0); verify_all_options(); if( g.argc!=3 && g.argc!=5 ) usage("setting [NAME VALUE]"); if( g.argc==5 ){ const char *zLabel = g.argv[3]; if( strncmp(zLabel, "email-", 6)!=0 || (pSetting = db_find_setting(zLabel, 1))==0 ){ fossil_fatal("not a valid email setting: \"%s\"", zLabel); } db_set(pSetting->name, g.argv[4], isGlobal); g.argc = 3; } pSetting = setting_info(&nSetting); for(; nSetting>0; nSetting--, pSetting++ ){ if( strncmp(pSetting->name,"email-",6)!=0 ) continue; print_setting(pSetting); } }else if( strncmp(zCmd, "status", nCmd)==0 ){ int nSetting, n; static const char *zFmt = "%-29s %d\n"; const Setting *pSetting = setting_info(&nSetting); db_open_config(1, 0); verify_all_options(); if( g.argc!=3 ) usage("status"); pSetting = setting_info(&nSetting); for(; nSetting>0; nSetting--, pSetting++ ){ if( strncmp(pSetting->name,"email-",6)!=0 ) continue; print_setting(pSetting); } n = db_int(0,"SELECT count(*) FROM pending_alert WHERE NOT sentSep"); fossil_print(zFmt/*works-like:"%s%d"*/, "pending-alerts", n); n = db_int(0,"SELECT count(*) FROM pending_alert WHERE NOT sentDigest"); fossil_print(zFmt/*works-like:"%s%d"*/, "pending-digest-alerts", n); n = db_int(0,"SELECT count(*) FROM subscriber"); fossil_print(zFmt/*works-like:"%s%d"*/, "total-subscribers", n); n = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified" " AND NOT sdonotcall AND length(ssub)>1"); fossil_print(zFmt/*works-like:"%s%d"*/, "active-subscribers", n); }else if( strncmp(zCmd, "subscribers", nCmd)==0 ){ Stmt q; verify_all_options(); if( g.argc!=3 && g.argc!=4 ) usage("subscribers [PATTERN]"); if( g.argc==4 ){ |
︙ | ︙ | |||
1385 1386 1387 1388 1389 1390 1391 | const char *zEAddr; int i, j, n; char c; *peErr = 0; *pzErr = 0; | < < < < < < < < < | < < < < | 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 | const char *zEAddr; int i, j, n; char c; *peErr = 0; *pzErr = 0; /* Check the validity of the email address. ** ** (1) Exactly one '@' character. ** (2) No other characters besides [a-zA-Z0-9._+-] ** ** The local part is currently more restrictive than RFC 5322 allows: ** https://stackoverflow.com/a/2049510/142454 We will expand this as ** necessary. */ zEAddr = P("e"); if( zEAddr==0 ) return 0; for(i=j=n=0; (c = zEAddr[i])!=0; i++){ if( c=='@' ){ n = i; j++; continue; } if( !fossil_isalnum(c) && c!='.' && c!='_' && c!='-' && c!='+' ){ |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | } if( n>i-5 ){ *peErr = 1; *pzErr = mprintf("email domain too short"); return 0; } | | > | | | | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | } if( n>i-5 ){ *peErr = 1; *pzErr = mprintf("email domain too short"); return 0; } /* Verify the captcha */ if( needCaptcha && !captcha_is_correct(1) ){ *peErr = 2; *pzErr = mprintf("incorrect security code"); return 0; } /* Check to make sure the email address is available for reuse */ if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q", zEAddr) ){ *peErr = 1; *pzErr = mprintf("this email address is used by someone else"); return 0; } /* If we reach this point, all is well */ return 1; } /* ** Text of email message sent in order to confirm a subscription. */ static const char zConfirmMsg[] = @ Someone has signed you up for email alerts on the Fossil repository @ at %s. @ @ To confirm your subscription and begin receiving alerts, click on @ the following hyperlink: @ @ %s/alerts/%s |
︙ | ︙ | |||
1503 1504 1505 1506 1507 1508 1509 | ** ** The Alerts permission ("7") is required to access this ** page. To allow anonymous passers-by to sign up for email ** notification, set Email-Alerts on user "nobody" or "anonymous". */ void subscribe_page(void){ int needCaptcha; | | | 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | ** ** The Alerts permission ("7") is required to access this ** page. To allow anonymous passers-by to sign up for email ** notification, set Email-Alerts on user "nobody" or "anonymous". */ void subscribe_page(void){ int needCaptcha; unsigned int uSeed; const char *zDecoded; char *zCaptcha = 0; char *zErr = 0; int eErr = 0; int di; if( alert_webpages_disabled() ) return; |
︙ | ︙ | |||
1536 1537 1538 1539 1540 1541 1542 | }else{ /* Everybody else jumps to the page to administer their own ** account only. */ cgi_redirectf("%R/alerts"); return; } } | < < < < < | > < < < | | | < > > > > < | < < < | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 | }else{ /* Everybody else jumps to the page to administer their own ** account only. */ cgi_redirectf("%R/alerts"); return; } } alert_submenu_common(); needCaptcha = !login_is_individual(); if( P("submit") && cgi_csrf_safe(1) && subscribe_error_check(&eErr,&zErr,needCaptcha) ){ /* A validated request for a new subscription has been received. */ char ssub[20]; const char *zEAddr = P("e"); sqlite3_int64 id; /* New subscriber Id */ const char *zCode; /* New subscriber code (in hex) */ int nsub = 0; const char *suname = PT("suname"); if( suname==0 && needCaptcha==0 && !g.perm.Admin ) suname = g.zLogin; if( suname && suname[0]==0 ) suname = 0; if( PB("sa") ) ssub[nsub++] = 'a'; if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c'; if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f'; if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't'; if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w'; ssub[nsub] = 0; db_multi_exec( "INSERT INTO subscriber(semail,suname," " sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)" "VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)", /* semail */ zEAddr, /* suname */ suname, /* sverified */ needCaptcha==0, /* sdigest */ PB("di"), /* ssub */ ssub, /* smip */ g.zIpAddr ); id = db_last_insert_rowid(); zCode = db_text(0, "SELECT hex(subscriberCode) FROM subscriber WHERE subscriberId=%lld", id); if( !needCaptcha ){ /* The new subscription has been added on behalf of a logged-in user. ** No verification is required. Jump immediately to /alerts page. */ cgi_redirectf("%R/alerts/%s", zCode); return; }else{ /* We need to send a verification email */ Blob hdr, body; AlertSender *pSender = alert_sender_new(0,0); blob_init(&hdr,0,0); blob_init(&body,0,0); |
︙ | ︙ | |||
1606 1607 1608 1609 1610 1611 1612 | @ <p>The following internal error was encountered while trying @ to send the confirmation email: @ <blockquote><pre> @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>An email has been sent to "%h(zEAddr)". That email contains a | | | < < | < < < < < | < | < | 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 | @ <p>The following internal error was encountered while trying @ to send the confirmation email: @ <blockquote><pre> @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>An email has been sent to "%h(zEAddr)". That email contains a @ hyperlink that you must click on in order to activate your @ subscription.</p> } alert_sender_free(pSender); style_footer(); } return; } style_header("Signup For Email Alerts"); if( P("submit")==0 ){ /* If this is the first visit to this page (if this HTTP request did not ** come from a prior Submit of the form) then default all of the ** subscription options to "on" */ cgi_set_parameter_nocopy("sa","1",1); if( g.perm.Read ) cgi_set_parameter_nocopy("sc","1",1); if( g.perm.RdForum ) cgi_set_parameter_nocopy("sf","1",1); if( g.perm.RdTkt ) cgi_set_parameter_nocopy("st","1",1); if( g.perm.RdWiki ) cgi_set_parameter_nocopy("sw","1",1); } @ <p>To receive email notifications for changes to this @ repository, fill out the form below and press "Submit" button.</p> form_begin(0, "%R/subscribe"); @ <table class="subscribe"> @ <tr> @ <td class="form_label">Email Address:</td> @ <td><input type="text" name="e" value="%h(PD("e",""))" size="30"></td> @ <tr> if( eErr==1 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ </tr> if( needCaptcha ){ uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); @ <tr> @ <td class="form_label">Security Code:</td> @ <td><input type="text" name="captcha" value="" size="30"> @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> @ </tr> if( eErr==2 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ </tr> } |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 | @ Announcements</label><br> if( g.perm.Read ){ @ <label><input type="checkbox" name="sc" %s(PCK("sc"))> \ @ Check-ins</label><br> } if( g.perm.RdForum ){ @ <label><input type="checkbox" name="sf" %s(PCK("sf"))> \ | | < < < < < < | 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 | @ Announcements</label><br> if( g.perm.Read ){ @ <label><input type="checkbox" name="sc" %s(PCK("sc"))> \ @ Check-ins</label><br> } if( g.perm.RdForum ){ @ <label><input type="checkbox" name="sf" %s(PCK("sf"))> \ @ Forum Posts</label><br> } if( g.perm.RdTkt ){ @ <label><input type="checkbox" name="st" %s(PCK("st"))> \ @ Ticket changes</label><br> } if( g.perm.RdWiki ){ @ <label><input type="checkbox" name="sw" %s(PCK("sw"))> \ |
︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 | } @ </tr> @ </table> if( needCaptcha ){ @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> | | | | | < < < | | < < < < < < < < < | | < < < | < < | < < | < < < < < < > | < < | | | < < < < | < < < < | < < < < < < | | | < | < | | | | | | | | < < < < < | < < < < < < | < > > | < | < < < < < < < | | < < > | > > | < < < < < | | | < < | | < | > > > > > > > > > > > > > > > > | > > > > > > > | < | < | > | < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < | | < < < | < < < | < < > < > | > | | | < < < < < < < < > < < | | < | < < < < < < < < < < < < < < < | | | | | < < < < < < < < | < < < < < < < < < < | < < < < < < < < < < | < < < < < | < < < < < < < < < < > > > > | | 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 | } @ </tr> @ </table> if( needCaptcha ){ @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter the 8 characters above in the "Security Code" box @ </td></tr></table></div> } @ </form> fossil_free(zErr); style_footer(); } /* ** Either shutdown or completely delete a subscription entry given ** by the hex value zName. Then paint a webpage that explains that ** the entry has been removed. */ static void alert_unsubscribe(const char *zName){ char *zEmail; zEmail = db_text(0, "SELECT semail FROM subscriber" " WHERE subscriberCode=hextoblob(%Q)", zName); if( zEmail==0 ){ style_header("Unsubscribe Fail"); @ <p>Unable to locate a subscriber with the requested key</p> }else{ db_multi_exec( "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)", zName ); style_header("Unsubscribed"); @ <p>The "%h(zEmail)" email address has been delisted. @ All traces of that email address have been removed</p> } style_footer(); return; } /* ** WEBPAGE: alerts ** ** Edit email alert and notification settings. ** ** The subscriber is identified in either of two ways: ** ** (1) The name= query parameter contains the subscriberCode. ** ** (2) The user is logged into an account other than "nobody" or ** "anonymous". In that case the notification settings ** associated with that account can be edited without needing ** to know the subscriber code. */ void alert_page(void){ const char *zName = P("name"); Stmt q; int sa, sc, sf, st, sw; int sdigest, sdonotcall, sverified; const char *ssub; const char *semail; const char *smip; const char *suname; const char *mtime; const char *sctime; int eErr = 0; char *zErr = 0; if( alert_webpages_disabled() ) return; login_check_credentials(); if( !g.perm.EmailAlert ){ login_needed(g.anon.EmailAlert); return; } if( zName==0 && login_is_individual() ){ zName = db_text(0, "SELECT hex(subscriberCode) FROM subscriber" " WHERE suname=%Q", g.zLogin); } if( zName==0 || !validate16(zName, -1) ){ cgi_redirect("subscribe"); return; } alert_submenu_common(); if( P("submit")!=0 && cgi_csrf_safe(1) ){ int sdonotcall = PB("sdonotcall"); int sdigest = PB("sdigest"); char ssub[10]; int nsub = 0; if( PB("sa") ) ssub[nsub++] = 'a'; if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c'; if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f'; if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't'; if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w'; ssub[nsub] = 0; if( g.perm.Admin ){ const char *suname = PT("suname"); int sverified = PB("sverified"); if( suname && suname[0]==0 ) suname = 0; db_multi_exec( "UPDATE subscriber SET" " sdonotcall=%d," " sdigest=%d," " ssub=%Q," " mtime=strftime('%%s','now')," " smip=%Q," " suname=%Q," " sverified=%d" " WHERE subscriberCode=hextoblob(%Q)", sdonotcall, sdigest, ssub, g.zIpAddr, suname, sverified, zName ); }else{ db_multi_exec( "UPDATE subscriber SET" " sdonotcall=%d," " sdigest=%d," " ssub=%Q," " mtime=strftime('%%s','now')," " smip=%Q" " WHERE subscriberCode=hextoblob(%Q)", sdonotcall, sdigest, ssub, g.zIpAddr, zName ); } } if( P("delete")!=0 && cgi_csrf_safe(1) ){ if( !PB("dodelete") ){ eErr = 9; zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to" " unsubscribe"); }else{ alert_unsubscribe(zName); return; } } db_prepare(&q, "SELECT" " semail," /* 0 */ " sverified," /* 1 */ " sdonotcall," /* 2 */ " sdigest," /* 3 */ " ssub," /* 4 */ " smip," /* 5 */ " suname," /* 6 */ " datetime(mtime,'unixepoch')," /* 7 */ " datetime(sctime,'unixepoch')" /* 8 */ " FROM subscriber WHERE subscriberCode=hextoblob(%Q)", zName); if( db_step(&q)!=SQLITE_ROW ){ db_finalize(&q); cgi_redirect("subscribe"); return; } style_header("Update Subscription"); semail = db_column_text(&q, 0); sverified = db_column_int(&q, 1); sdonotcall = db_column_int(&q, 2); sdigest = db_column_int(&q, 3); ssub = db_column_text(&q, 4); sa = strchr(ssub,'a')!=0; sc = strchr(ssub,'c')!=0; sf = strchr(ssub,'f')!=0; st = strchr(ssub,'t')!=0; sw = strchr(ssub,'w')!=0; smip = db_column_text(&q, 5); suname = db_column_text(&q, 6); mtime = db_column_text(&q, 7); sctime = db_column_text(&q, 8); if( !g.perm.Admin && !sverified ){ db_multi_exec( "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)", zName); @ <h1>Your email alert subscription has been verified!</h1> @ <p>Use the form below to update your subscription information.</p> @ <p>Hint: Bookmark this page so that you can more easily update @ your subscription information in the future</p> }else{ @ <p>Make changes to the email subscription shown below and @ press "Submit".</p> } form_begin(0, "%R/alerts"); @ <input type="hidden" name="name" value="%h(zName)"> @ <table class="subscribe"> @ <tr> @ <td class="form_label">Email Address:</td> @ <td>%h(semail)</td> @ </tr> if( g.perm.Admin ){ @ <tr> @ <td class='form_label'>Created:</td> @ <td>%h(sctime)</td> @ </tr> @ <tr> @ <td class='form_label'>Last Modified:</td> @ <td>%h(mtime)</td> @ </tr> @ <tr> @ <td class='form_label'>IP Address:</td> @ <td>%h(smip)</td> @ </tr> @ <tr> @ <td class="form_label">User:</td> @ <td><input type="text" name="suname" value="%h(suname?suname:"")" \ @ size="30"></td> @ </tr> } @ <tr> @ <td class="form_label">Topics:</td> @ <td><label><input type="checkbox" name="sa" %s(sa?"checked":"")>\ @ Announcements</label><br> if( g.perm.Read ){ @ <label><input type="checkbox" name="sc" %s(sc?"checked":"")>\ @ Check-ins</label><br> } if( g.perm.RdForum ){ @ <label><input type="checkbox" name="sf" %s(sf?"checked":"")>\ @ Forum Posts</label><br> } if( g.perm.RdTkt ){ @ <label><input type="checkbox" name="st" %s(st?"checked":"")>\ @ Ticket changes</label><br> } if( g.perm.RdWiki ){ @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\ @ Wiki</label> } @ </td></tr> @ <tr> @ <td class="form_label">Delivery:</td> @ <td><select size="1" name="sdigest"> @ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option> @ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option> @ </select></td> @ </tr> #if 0 @ <label><input type="checkbox" name="sdigest" %s(sdigest?"checked":"")>\ @ Daily digest only</label><br> #endif if( g.perm.Admin ){ @ <tr> @ <td class="form_label">Admin Options:</td><td> @ <label><input type="checkbox" name="sdonotcall" \ @ %s(sdonotcall?"checked":"")> Do not call</label><br> @ <label><input type="checkbox" name="sverified" \ @ %s(sverified?"checked":"")>\ @ Verified</label></td></tr> } if( eErr==9 ){ @ <tr> @ <td class="form_label">Verify:</td><td> |
︙ | ︙ | |||
2135 2136 2137 2138 2139 2140 2141 | @ <td><input type="submit" name="submit" value="Submit"> @ <input type="submit" name="delete" value="Unsubscribe"> @ </tr> @ </table> @ </form> fossil_free(zErr); db_finalize(&q); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < | < | < | > < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 | @ <td><input type="submit" name="submit" value="Submit"> @ <input type="submit" name="delete" value="Unsubscribe"> @ </tr> @ </table> @ </form> fossil_free(zErr); db_finalize(&q); style_footer(); } /* This is the message that gets sent to describe how to change ** or modify a subscription */ static const char zUnsubMsg[] = @ To changes your subscription settings at %s visit this link: @ @ %s/alerts/%s @ @ To completely unsubscribe from %s, visit the following link: @ @ %s/unsubscribe/%s ; /* ** WEBPAGE: unsubscribe ** ** Users visit this page to be delisted from email alerts. ** ** If a valid subscriber code is supplied in the name= query parameter, ** then that subscriber is delisted. ** ** Otherwise, If the users is logged in, then they are redirected ** to the /alerts page where they have an unsubscribe button. ** ** Non-logged-in users with no name= query parameter are invited to enter ** an email address to which will be sent the unsubscribe link that ** contains the correct subscriber code. */ void unsubscribe_page(void){ const char *zName = P("name"); char *zErr = 0; int eErr = 0; unsigned int uSeed; const char *zDecoded; char *zCaptcha = 0; int dx; int bSubmit; const char *zEAddr; char *zCode = 0; /* If a valid subscriber code is supplied, then unsubscribe immediately. */ if( zName && db_exists("SELECT 1 FROM subscriber WHERE subscriberCode=hextoblob(%Q)", zName) ){ alert_unsubscribe(zName); return; } /* Logged in users are redirected to the /alerts page */ login_check_credentials(); if( login_is_individual() ){ cgi_redirectf("%R/alerts"); return; } zEAddr = PD("e",""); dx = atoi(PD("dx","0")); bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(1); if( bSubmit ){ if( !captcha_is_correct(1) ){ eErr = 2; zErr = mprintf("enter the security code shown below"); bSubmit = 0; } } |
︙ | ︙ | |||
2330 2331 2332 2333 2334 2335 2336 | @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>An email has been sent to "%h(zEAddr)" that explains how to @ unsubscribe and/or modify your subscription settings</p> } alert_sender_free(pSender); | | | | 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 | @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>An email has been sent to "%h(zEAddr)" that explains how to @ unsubscribe and/or modify your subscription settings</p> } alert_sender_free(pSender); style_footer(); return; } /* Non-logged-in users have to enter an email address to which is ** sent a message containing the unsubscribe link. */ style_header("Unsubscribe Request"); @ <p>Fill out the form below to request an email message that will @ explain how to unsubscribe and/or change your subscription settings.</p> |
︙ | ︙ | |||
2356 2357 2358 2359 2360 2361 2362 | @ </tr> uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); @ <tr> @ <td class="form_label">Security Code:</td> @ <td><input type="text" name="captcha" value="" size="30"> | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < | < < < < < | < < < | < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 | @ </tr> uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); @ <tr> @ <td class="form_label">Security Code:</td> @ <td><input type="text" name="captcha" value="" size="30"> @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> if( eErr==2 ){ @ <td><span class="loginError">← %h(zErr)</span></td> } @ </tr> @ <tr> @ <td class="form_label">Options:</td> @ <td><label><input type="radio" name="dx" value="0" %s(dx?"":"checked")>\ @ Modify subscription</label><br> @ <label><input type="radio" name="dx" value="1" %s(dx?"checked":"")>\ @ Completely unsubscribe</label><br> @ <tr> @ <td></td> @ <td><input type="submit" name="submit" value="Submit"></td> @ </tr> @ </table> @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter the 8 characters above in the "Security Code" box @ </td></tr></table></div> @ </form> fossil_free(zErr); style_footer(); } /* ** WEBPAGE: subscribers ** ** This page, accessible to administrators only, ** shows a list of email notification email addresses. ** Clicking on an email takes one to the /alerts page ** for that email where the delivery settings can be ** modified. */ void subscriber_list_page(void){ Blob sql; Stmt q; sqlite3_int64 iNow; if( alert_webpages_disabled() ) return; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } alert_submenu_common(); style_header("Subscriber List"); blob_init(&sql, 0, 0); blob_append_sql(&sql, "SELECT hex(subscriberCode)," /* 0 */ " semail," /* 1 */ " ssub," /* 2 */ " suname," /* 3 */ " sverified," /* 4 */ " sdigest," /* 5 */ " mtime," /* 6 */ " date(sctime,'unixepoch')" /* 7 */ " FROM subscriber" ); if( P("only")!=0 ){ blob_append_sql(&sql, " WHERE ssub LIKE '%%%q%%'", P("only")); style_submenu_element("Show All","%R/subscribers"); } blob_append_sql(&sql," ORDER BY mtime DESC"); db_prepare_blob(&q, &sql); iNow = time(0); @ <table border='1' class='sortable' \ @ data-init-sort='6' data-column-types='tttttKt'> @ <thead> @ <tr> @ <th>Email @ <th>Events @ <th>Digest-Only? @ <th>User @ <th>Verified? @ <th>Last change @ <th>Created @ </tr> @ </thead><tbody> while( db_step(&q)==SQLITE_ROW ){ sqlite3_int64 iMtime = db_column_int64(&q, 6); double rAge = (iNow - iMtime)/86400.0; @ <tr> @ <td><a href='%R/alerts/%s(db_column_text(&q,0))'>\ @ %h(db_column_text(&q,1))</a></td> @ <td>%h(db_column_text(&q,2))</td> @ <td>%s(db_column_int(&q,5)?"digest":"")</td> @ <td>%h(db_column_text(&q,3))</td> @ <td>%s(db_column_int(&q,4)?"yes":"pending")</td> @ <td data-sortkey='%010llx(iMtime)'>%z(human_readable_age(rAge))</td> @ <td>%h(db_column_text(&q,7))</td> @ </tr> } @ </tbody></table> db_finalize(&q); style_table_sorter(); style_footer(); } #if LOCAL_INTERFACE /* ** A single event that might appear in an alert is recorded as an ** instance of the following object. */ struct EmailEvent { int type; /* 'c', 'f', 'm', 't', 'w' */ int needMod; /* Pending moderator approval */ Blob hdr; /* Header content, for forum entries */ Blob txt; /* Text description to appear in an alert */ char *zFromName; /* Human name of the sender */ EmailEvent *pNext; /* Next in chronological order */ }; #endif /* ** Free a linked list of EmailEvent objects */ void alert_free_eventlist(EmailEvent *p){ while( p ){ EmailEvent *pNext = p->pNext; blob_reset(&p->txt); blob_reset(&p->hdr); fossil_free(p->zFromName); fossil_free(p); p = pNext; } } /* ** Compute and return a linked list of EmailEvent objects ** corresponding to the current content of the temp.wantalert ** table which should be defined as follows: ** ** CREATE TEMP TABLE wantalert(eventId TEXT, needMod BOOLEAN); */ EmailEvent *alert_compute_event_text(int *pnEvent, int doDigest){ Stmt q; EmailEvent *p; EmailEvent anchor; EmailEvent *pLast; const char *zUrl = db_get("email-url","http://localhost:8080"); const char *zFrom; const char *zSub; /* First do non-forum post events */ db_prepare(&q, "SELECT" " blob.uuid," /* 0 */ " datetime(event.mtime)," /* 1 */ " coalesce(ecomment,comment)" " || ' (user: ' || coalesce(euser,user,'?')" " || (SELECT case when length(x)>0 then ' tags: ' || x else '' end" " FROM (SELECT group_concat(substr(tagname,5), ', ') AS x" " FROM tag, tagxref" " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
︙ | ︙ | |||
2632 2633 2634 2635 2636 2637 2638 | doDigest ); memset(&anchor, 0, sizeof(anchor)); pLast = &anchor; *pnEvent = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zType = ""; | < | | | | < < < < < < < < | | 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 | doDigest ); memset(&anchor, 0, sizeof(anchor)); pLast = &anchor; *pnEvent = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zType = ""; p = fossil_malloc( sizeof(EmailEvent) ); pLast->pNext = p; pLast = p; p->type = db_column_text(&q, 3)[0]; p->needMod = db_column_int(&q, 4); p->zFromName = 0; p->pNext = 0; switch( p->type ){ case 'c': zType = "Check-In"; break; case 'f': zType = "Forum post"; break; case 't': zType = "Wiki Edit"; break; case 'w': zType = "Ticket Change"; break; } blob_init(&p->hdr, 0, 0); blob_init(&p->txt, 0, 0); blob_appendf(&p->txt,"== %s %s ==\n%s\n%s/info/%.20s\n", db_column_text(&q,1), zType, db_column_text(&q,2), zUrl, db_column_text(&q,0) ); if( p->needMod ){ blob_appendf(&p->txt, "** Pending moderator approval (%s/modreq) **\n", zUrl |
︙ | ︙ | |||
2689 2690 2691 2692 2693 2694 2695 | /* If we reach this point, it means that forumposts exist and this ** is a normal email alert. Construct full-text forum post alerts ** using a format that enables them to be sent as separate emails. */ db_prepare(&q, "SELECT" | | | | | < < < < < < < < | < < | | < < | | < | | 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 | /* If we reach this point, it means that forumposts exist and this ** is a normal email alert. Construct full-text forum post alerts ** using a format that enables them to be sent as separate emails. */ db_prepare(&q, "SELECT" " forumpost.fpid," /* 0 */ " (SELECT uuid FROM blob WHERE rid=forumpost.fpid)," /* 1 */ " datetime(event.mtime)," /* 2 */ " substr(comment,instr(comment,':')+2)," /* 3 */ " (SELECT uuid FROM blob WHERE rid=forumpost.firt)," /* 4 */ " wantalert.needMod," /* 5 */ " coalesce(trim(substr(info,1,instr(info,'<')-1)),euser,user)" /* 6 */ " FROM temp.wantalert, event, forumpost" " LEFT JOIN user ON (login=coalesce(euser,user))" " WHERE event.objid=substr(wantalert.eventId,2)+0" " AND eventId GLOB 'f*'" " AND forumpost.fpid=event.objid" " ORDER BY event.mtime" ); zFrom = db_get("email-self",0); zSub = db_get("email-subname",""); while( db_step(&q)==SQLITE_ROW ){ Manifest *pPost = manifest_get(db_column_int(&q,0), CFTYPE_FORUM, 0); const char *zIrt; const char *zUuid; const char *zTitle; const char *z; if( pPost==0 ) continue; p = fossil_malloc( sizeof(EmailEvent) ); pLast->pNext = p; pLast = p; p->type = 'f'; p->needMod = db_column_int(&q, 5); z = db_column_text(&q,6); p->zFromName = z && z[0] ? fossil_strdup(z) : 0; p->pNext = 0; blob_init(&p->hdr, 0, 0); zUuid = db_column_text(&q, 1); zTitle = db_column_text(&q, 3); if( p->needMod ){ blob_appendf(&p->hdr, "Subject: %s Pending Moderation: %s\r\n", zSub, zTitle); }else{ blob_appendf(&p->hdr, "Subject: %s %s\r\n", zSub, zTitle); blob_appendf(&p->hdr, "Message-Id: <%.32s@%s>\r\n", zUuid, alert_hostname(zFrom)); zIrt = db_column_text(&q, 4); if( zIrt && zIrt[0] ){ blob_appendf(&p->hdr, "In-Reply-To: <%.32s@%s>\r\n", zIrt, alert_hostname(zFrom)); } } |
︙ | ︙ | |||
2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 | void email_header(Blob *pOut){ blob_appendf(pOut, "This is an automated email reporting changes " "on Fossil repository %s (%s/timeline)\n", db_get("email-subname","(unknown)"), db_get("email-url","http://localhost:8080")); } /* ** COMMAND: test-alert ** ** Usage: %fossil test-alert EVENTID ... ** ** Generate the text of an email alert for all of the EVENTIDs ** listed on the command-line. Or if no events are listed on the ** command line, generate text for all events named in the | > > > > > > > > > | < | | < < < < < | < | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 | void email_header(Blob *pOut){ blob_appendf(pOut, "This is an automated email reporting changes " "on Fossil repository %s (%s/timeline)\n", db_get("email-subname","(unknown)"), db_get("email-url","http://localhost:8080")); } /* ** Append the "unsubscribe" notification and other footer text to ** the end of an email alert being assemblied in pOut. */ void alert_footer(Blob *pOut){ blob_appendf(pOut, "\n-- \nTo unsubscribe: %s/unsubscribe\n", db_get("email-url","http://localhost:8080")); } /* ** COMMAND: test-alert ** ** Usage: %fossil test-alert EVENTID ... ** ** Generate the text of an email alert for all of the EVENTIDs ** listed on the command-line. Or if no events are listed on the ** command line, generate text for all events named in the ** pending_alert table. ** ** This command is intended for testing and debugging the logic ** that generates email alert text. ** ** Options: ** ** --digest Generate digest alert text ** --needmod Assume all events are pending moderator approval */ void test_alert_cmd(void){ Blob out; int nEvent; int needMod; |
︙ | ︙ | |||
2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 | if( blob_size(&p->hdr) ){ blob_append(&out, blob_buffer(&p->hdr), blob_size(&p->hdr)); blob_append(&out, "\n", 1); } blob_append(&out, blob_buffer(&p->txt), blob_size(&p->txt)); } alert_free_eventlist(pEvent); fossil_print("%s", blob_str(&out)); blob_reset(&out); db_end_transaction(0); } /* ** COMMAND: test-add-alerts ** ** Usage: %fossil test-add-alerts [OPTIONS] EVENTID ... ** ** Add one or more events to the pending_alert queue. Use this ** command during testing to force email notifications for specific ** events. ** ** EVENTIDs are text. The first character is 'c', 'f', 't', or 'w' ** for check-in, forum, ticket, or wiki. The remaining text is a ** integer that references the EVENT.OBJID value for the event. ** Run /timeline?showid to see these OBJID values. ** ** Options: ** --backoffice Run alert_backoffice() after all alerts have ** been added. This will cause the alerts to be ** sent out with the SENDALERT_TRACE option. ** --debug Like --backoffice, but add the SENDALERT_STDOUT ** so that emails are printed to standard output ** rather than being sent. ** --digest Process emails using SENDALERT_DIGEST */ void test_add_alert_cmd(void){ int i; int doAuto = find_option("backoffice",0,0)!=0; unsigned mFlags = 0; if( find_option("debug",0,0)!=0 ){ | > > > > | 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 | if( blob_size(&p->hdr) ){ blob_append(&out, blob_buffer(&p->hdr), blob_size(&p->hdr)); blob_append(&out, "\n", 1); } blob_append(&out, blob_buffer(&p->txt), blob_size(&p->txt)); } alert_free_eventlist(pEvent); alert_footer(&out); fossil_print("%s", blob_str(&out)); blob_reset(&out); db_end_transaction(0); } /* ** COMMAND: test-add-alerts ** ** Usage: %fossil test-add-alerts [OPTIONS] EVENTID ... ** ** Add one or more events to the pending_alert queue. Use this ** command during testing to force email notifications for specific ** events. ** ** EVENTIDs are text. The first character is 'c', 'f', 't', or 'w' ** for check-in, forum, ticket, or wiki. The remaining text is a ** integer that references the EVENT.OBJID value for the event. ** Run /timeline?showid to see these OBJID values. ** ** Options: ** ** --backoffice Run alert_backoffice() after all alerts have ** been added. This will cause the alerts to be ** sent out with the SENDALERT_TRACE option. ** ** --debug Like --backoffice, but add the SENDALERT_STDOUT ** so that emails are printed to standard output ** rather than being sent. ** ** --digest Process emails using SENDALERT_DIGEST */ void test_add_alert_cmd(void){ int i; int doAuto = find_option("backoffice",0,0)!=0; unsigned mFlags = 0; if( find_option("debug",0,0)!=0 ){ |
︙ | ︙ | |||
2894 2895 2896 2897 2898 2899 2900 | } db_end_transaction(0); if( doAuto ){ alert_backoffice(SENDALERT_TRACE|mFlags); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 | } db_end_transaction(0); if( doAuto ){ alert_backoffice(SENDALERT_TRACE|mFlags); } } #if INTERFACE /* ** Flags for alert_send_alerts() */ #define SENDALERT_DIGEST 0x0001 /* Send a digest */ #define SENDALERT_PRESERVE 0x0002 /* Do not mark the task as done */ #define SENDALERT_STDOUT 0x0004 /* Print emails instead of sending */ #define SENDALERT_TRACE 0x0008 /* Trace operation for debugging */ #endif /* INTERFACE */ /* ** Send alert emails to subscribers. ** ** This procedure is run by either the backoffice, or in response to the |
︙ | ︙ | |||
3001 3002 3003 3004 3005 3006 3007 | ** Update 2018-08-09: Do step (3) before step (4). Update the ** pending_alerts table *before* the emails are sent. That way, if ** the process malfunctions or crashes, some notifications may never ** be sent. But that is better than some recurring bug causing ** subscribers to be flooded with repeated notifications every 60 ** seconds! */ | | < < | | 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 | ** Update 2018-08-09: Do step (3) before step (4). Update the ** pending_alerts table *before* the emails are sent. That way, if ** the process malfunctions or crashes, some notifications may never ** be sent. But that is better than some recurring bug causing ** subscribers to be flooded with repeated notifications every 60 ** seconds! */ void alert_send_alerts(u32 flags){ EmailEvent *pEvents, *p; int nEvent = 0; Stmt q; const char *zDigest = "false"; Blob hdr, body; const char *zUrl; const char *zRepoName; const char *zFrom; const char *zDest = (flags & SENDALERT_STDOUT) ? "stdout" : 0; AlertSender *pSender = 0; u32 senderFlags = 0; if( g.fSqlTrace ) fossil_trace("-- BEGIN alert_send_alerts(%u)\n", flags); alert_schema(0); if( !alert_enabled() ) goto send_alert_done; zUrl = db_get("email-url",0); if( zUrl==0 ) goto send_alert_done; zRepoName = db_get("email-subname",0); if( zRepoName==0 ) goto send_alert_done; zFrom = db_get("email-self",0); if( zFrom==0 ) goto send_alert_done; if( flags & SENDALERT_TRACE ){ |
︙ | ︙ | |||
3059 3060 3061 3062 3063 3064 3065 | " EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2))," " sentMod" " FROM pending_alert" " WHERE sentSep IS FALSE;" "DELETE FROM wantalert WHERE needMod AND sentMod;" ); } | < < < < < | | 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 | " EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2))," " sentMod" " FROM pending_alert" " WHERE sentSep IS FALSE;" "DELETE FROM wantalert WHERE needMod AND sentMod;" ); } /* Step 2: compute EmailEvent objects for every notification that ** needs sending. */ pEvents = alert_compute_event_text(&nEvent, (flags & SENDALERT_DIGEST)!=0); if( nEvent==0 ) goto send_alert_done; /* Step 4a: Update the pending_alerts table to designate the ** alerts as having all been sent. This is done *before* step (3) ** so that a crash will not cause alerts to be sent multiple times. ** Better a missed alert than being spammed with hundreds of alerts ** due to a bug. */ |
︙ | ︙ | |||
3102 3103 3104 3105 3106 3107 3108 | blob_init(&hdr, 0, 0); blob_init(&body, 0, 0); db_prepare(&q, "SELECT" " hex(subscriberCode)," /* 0 */ " semail," /* 1 */ " ssub," /* 2 */ | | < | < | < | < < | < < < < < < < < < < < | | | | < | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | < < | | | | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 | blob_init(&hdr, 0, 0); blob_init(&body, 0, 0); db_prepare(&q, "SELECT" " hex(subscriberCode)," /* 0 */ " semail," /* 1 */ " ssub," /* 2 */ " fullcap(user.cap)" /* 3 */ " FROM subscriber LEFT JOIN user ON (login=suname)" " WHERE sverified AND NOT sdonotcall" " AND sdigest IS %s", zDigest/*safe-for-%s*/ ); while( db_step(&q)==SQLITE_ROW ){ const char *zCode = db_column_text(&q, 0); const char *zSub = db_column_text(&q, 2); const char *zEmail = db_column_text(&q, 1); const char *zCap = db_column_text(&q, 3); int nHit = 0; for(p=pEvents; p; p=p->pNext){ if( strchr(zSub,p->type)==0 ) continue; if( p->needMod ){ /* For events that require moderator approval, only send an alert ** if the recipient is a moderator for that type of event. Setup ** and Admin users always get notified. */ char xType = '*'; if( strpbrk(zCap,"as")==0 ){ switch( p->type ){ case 'f': xType = '5'; break; case 't': xType = 'q'; break; case 'w': xType = 'l'; break; } if( strchr(zCap,xType)==0 ) continue; } }else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){ /* Setup and admin users can get any notification that does not ** require moderation */ }else{ /* Other users only see the alert if they have sufficient ** privilege to view the event itself */ char xType = '*'; switch( p->type ){ case 'c': xType = 'o'; break; case 'f': xType = '2'; break; case 't': xType = 'r'; break; case 'w': xType = 'j'; break; } if( strchr(zCap,xType)==0 ) continue; } if( blob_size(&p->hdr)>0 ){ /* This alert should be sent as a separate email */ Blob fhdr, fbody; blob_init(&fhdr, 0, 0); blob_appendf(&fhdr, "To: <%s>\r\n", zEmail); blob_append(&fhdr, blob_buffer(&p->hdr), blob_size(&p->hdr)); blob_init(&fbody, blob_buffer(&p->txt), blob_size(&p->txt)); blob_appendf(&fbody, "\n-- \nSubscription info: %s/alerts/%s\n", zUrl, zCode); alert_send(pSender,&fhdr,&fbody,p->zFromName); blob_reset(&fhdr); blob_reset(&fbody); }else{ /* Events other than forum posts are gathered together into ** a single email message */ if( nHit==0 ){ blob_appendf(&hdr,"To: <%s>\r\n", zEmail); blob_appendf(&hdr,"Subject: %s activity alert\r\n", zRepoName); blob_appendf(&body, "This is an automated email sent by the Fossil repository " "at %s to report changes.\n", zUrl ); } nHit++; blob_append(&body, "\n", 1); blob_append(&body, blob_buffer(&p->txt), blob_size(&p->txt)); } } if( nHit==0 ) continue; blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n", zUrl, zCode); alert_send(pSender,&hdr,&body,0); blob_truncate(&hdr, 0); blob_truncate(&body, 0); } blob_reset(&hdr); blob_reset(&body); db_finalize(&q); alert_free_eventlist(pEvents); /* Step 4b: Update the pending_alerts table to remove all of the ** alerts that have been completely sent. */ db_multi_exec("DELETE FROM pending_alert WHERE sentDigest AND sentSep;"); send_alert_done: alert_sender_free(pSender); if( g.fSqlTrace ) fossil_trace("-- END alert_send_alerts(%u)\n", flags); } /* ** Do backoffice processing for email notifications. In other words, ** check to see if any email notifications need to occur, and then ** do them. ** ** This routine is intended to run in the background, after webpages. ** ** The mFlags option is zero or more of the SENDALERT_* flags. Normally ** this flag is zero, but the test-set-alert command sets it to ** SENDALERT_TRACE. */ void alert_backoffice(u32 mFlags){ int iJulianDay; if( !alert_tables_exist() ) return; alert_send_alerts(mFlags); iJulianDay = db_int(0, "SELECT julianday('now')"); if( iJulianDay>db_get_int("email-last-digest",0) ){ db_set_int("email-last-digest",iJulianDay,0); alert_send_alerts(SENDALERT_DIGEST|mFlags); } } /* ** WEBPAGE: contact_admin ** ** A web-form to send an email message to the repository administrator, ** or (with appropriate permissions) to anybody. */ void contact_admin_page(void){ const char *zAdminEmail = db_get("email-admin",0); unsigned int uSeed = 0; const char *zDecoded; char *zCaptcha = 0; login_check_credentials(); if( zAdminEmail==0 || zAdminEmail[0]==0 ){ style_header("Outbound Email Disabled"); @ <p>Outbound email is disabled on this repository style_footer(); return; } if( P("submit")!=0 && P("subject")!=0 && P("msg")!=0 && P("from")!=0 && cgi_csrf_safe(1) && captcha_is_correct(0) ){ Blob hdr, body; AlertSender *pSender = alert_sender_new(0,0); blob_init(&hdr, 0, 0); blob_appendf(&hdr, "To: <%s>\r\nSubject: %s administrator message\r\n", zAdminEmail, db_get("email-subname","Fossil Repo")); |
︙ | ︙ | |||
3349 3350 3351 3352 3353 3354 3355 | @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>Your message has been sent to the repository administrator. @ Thank you for your input.</p> } alert_sender_free(pSender); | | < < | 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>Your message has been sent to the repository administrator. @ Thank you for your input.</p> } alert_sender_free(pSender); style_footer(); return; } if( captcha_needed() ){ uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); } style_header("Message To Administrator"); form_begin(0, "%R/contact_admin"); @ <p>Enter a message to the repository administrator below:</p> @ <table class="subscribe"> if( zCaptcha ){ @ <tr> @ <td class="form_label">Security Code:</td> @ <td><input type="text" name="captcha" value="" size="10"> @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> @ </tr> } @ <tr> @ <td class="form_label">Your Email Address:</td> @ <td><input type="text" name="from" value="%h(PT("from"))" size="30"></td> @ </tr> |
︙ | ︙ | |||
3393 3394 3395 3396 3397 3398 3399 | @ <td><input type="submit" name="submit" value="Send Message"> @ </tr> @ </table> if( zCaptcha ){ @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> | | | < | < | | < < < | < < < < < < < < | 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 | @ <td><input type="submit" name="submit" value="Send Message"> @ </tr> @ </table> if( zCaptcha ){ @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter the 8 characters above in the "Security Code" box @ </td></tr></table></div> } @ </form> style_footer(); } /* ** Send an annoucement message described by query parameter. ** Permission to do this has already been verified. */ static char *alert_send_announcement(void){ AlertSender *pSender; char *zErr; const char *zTo = PT("to"); char *zSubject = PT("subject"); int bAll = PB("all"); int bAA = PB("aa"); const char *zSub = db_get("email-subname", "[Fossil Repo]"); int bTest2 = fossil_strcmp(P("name"),"test2")==0; Blob hdr, body; blob_init(&body, 0, 0); blob_init(&hdr, 0, 0); blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/); pSender = alert_sender_new(bTest2 ? "blob" : 0, 0); if( zTo[0] ){ blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject); alert_send(pSender, &hdr, &body, 0); } if( bAll || bAA ){ Stmt q; int nUsed = blob_size(&body); const char *zURL = db_get("email-url",0); db_prepare(&q, "SELECT semail, hex(subscriberCode) FROM subscriber " " WHERE sverified AND NOT sdonotcall %s", bAll ? "" : " AND ssub LIKE '%a%'"); while( db_step(&q)==SQLITE_ROW ){ const char *zCode = db_column_text(&q, 1); zTo = db_column_text(&q, 0); blob_truncate(&hdr, 0); blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject); if( zURL ){ blob_truncate(&body, nUsed); |
︙ | ︙ | |||
3482 3483 3484 3485 3486 3487 3488 | ** capability, that allows one to send announcements to whomever ** has subscribed to receive announcements. The administrator can ** also send a message to an arbitrary email address and/or to all ** subscribers regardless of whether or not they have elected to ** receive announcements. */ void announce_page(void){ | < < < < < < < < < | | | < | | < < < | < < < < < < | < | | 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 | ** capability, that allows one to send announcements to whomever ** has subscribed to receive announcements. The administrator can ** also send a message to an arbitrary email address and/or to all ** subscribers regardless of whether or not they have elected to ** receive announcements. */ void announce_page(void){ login_check_credentials(); if( !g.perm.Announce ){ login_needed(0); return; } if( fossil_strcmp(P("name"),"test1")==0 ){ /* Visit the /announce/test1 page to see the CGI variables */ @ <p style='border: 1px solid black; padding: 1ex;'> cgi_print_all(0, 0); @ </p> }else if( P("submit")!=0 && cgi_csrf_safe(1) ){ char *zErr = alert_send_announcement(); style_header("Announcement Sent"); if( zErr ){ @ <h1>Internal Error</h1> @ <p>The following error was reported by the system: @ <blockquote><pre> @ %h(zErr) @ </pre></blockquote> }else{ @ <p>The announcement has been sent.</p> } style_footer(); return; } else if( !alert_enabled() ){ style_header("Cannot Send Announcement"); @ <p>Either you have no subscribers yet, or email alerts are not yet @ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a> @ for this repository.</p> return; } style_header("Send Announcement"); @ <form method="POST"> @ <table class="subscribe"> if( g.perm.Admin ){ int aa = PB("aa"); int all = PB("all"); const char *aack = aa ? "checked" : ""; const char *allck = all ? "checked" : ""; @ <tr> @ <td class="form_label">To:</td> @ <td><input type="text" name="to" value="%h(PT("to"))" size="30"><br> @ <label><input type="checkbox" name="aa" %s(aack)> \ @ All "announcement" subscribers</label> \ @ <a href="%R/subscribers?only=a" target="_blank">(list)</a><br> @ <label><input type="checkbox" name="all" %s(allck)> \ @ All subscribers</label> \ @ <a href="%R/subscribers" target="_blank">(list)</a><br></td> @ </tr> } @ <tr> @ <td class="form_label">Subject:</td> @ <td><input type="text" name="subject" value="%h(PT("subject"))"\ @ size="80"></td> @ </tr> @ <tr> @ <td class="form_label">Message:</td> @ <td><textarea name="msg" cols="80" rows="10" wrap="virtual">\ @ %h(PT("msg"))</textarea> @ </tr> @ <tr> @ <td></td> @ <td><input type="submit" name="submit" value="Send Message"> @ </tr> @ </table> @ </form> style_footer(); } |
Deleted src/alerts/bflat2.wav.
cannot compute difference between binary files
Deleted src/alerts/bflat3.wav.
cannot compute difference between binary files
Deleted src/alerts/bloop.wav.
cannot compute difference between binary files
Deleted src/alerts/mkwav.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/alerts/plunk.wav.
cannot compute difference between binary files
Changes to src/allrepo.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 | ******************************************************************************* ** ** This file contains code to implement the "all" command-line method. */ #include "config.h" #include "allrepo.h" #include <assert.h> /* ** Build a string that contains all of the command-line options | > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | | < < | | | 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 | ******************************************************************************* ** ** This file contains code to implement the "all" command-line method. */ #include "config.h" #include "allrepo.h" #include <assert.h> /* ** The input string is a filename. Return a new copy of this ** filename if the filename requires quoting due to special characters ** such as spaces in the name. ** ** If the filename cannot be safely quoted, return a NULL pointer. ** ** Space to hold the returned string is obtained from malloc. A new ** string is returned even if no quoting is needed. */ static char *quoteFilename(const char *zFilename){ int i, c; int needQuote = 0; for(i=0; (c = zFilename[i])!=0; i++){ if( c=='"' ) return 0; if( fossil_isspace(c) ) needQuote = 1; if( c=='\\' && zFilename[i+1]==0 ) return 0; if( c=='$' ) return 0; } if( needQuote ){ return mprintf("\"%s\"", zFilename); }else{ return mprintf("%s", zFilename); } } /* ** Build a string that contains all of the command-line options ** specified as arguments. If the option name begins with "+" then ** it takes an argument. Without the "+" it does not. */ static void collect_argument(Blob *pExtra, const char *zArg, const char *zShort){ const char *z = find_option(zArg, zShort, 0); if( z!=0 ){ blob_appendf(pExtra, " %s", z); } } static void collect_argument_value(Blob *pExtra, const char *zArg){ const char *zValue = find_option(zArg, 0, 1); if( zValue ){ if( zValue[0] ){ blob_appendf(pExtra, " --%s %s", zArg, zValue); }else{ blob_appendf(pExtra, " --%s \"\"", zArg); } } } static void collect_argv(Blob *pExtra, int iStart){ int i; |
︙ | ︙ | |||
63 64 65 66 67 68 69 | ** that can be useful before or after a period of disconnected operation. ** ** On Win32 systems, the file is named "_fossil" and is located in ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. ** ** Available operations are: ** | < < < | | | | < < < < | | | < < < < | > | | < | < < | | < < < < < < < < | | > > | < < > > > | < < > < | | < < < < < < < < < < | | | | | | | < | | | < < < < < < < < < < < < < | | < | < | | < < < < < < < < < < < < < < < < < < < < < | | | | < < | < < | | | | < < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | ** that can be useful before or after a period of disconnected operation. ** ** On Win32 systems, the file is named "_fossil" and is located in ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. ** ** Available operations are: ** ** cache Manages the cache used for potentially expensive web ** pages. Any additional arguments are passed on verbatim ** to the cache command. ** ** changes Shows all local checkouts that have uncommitted changes. ** This operation has no additional options. ** ** clean Delete all "extra" files in all local checkouts. Extreme ** caution should be exercised with this command because its ** effects cannot be undone. Use of the --dry-run option to ** carefully review the local checkouts to be operated upon ** and the --whatif option to carefully review the files to ** be deleted beforehand is highly recommended. The command ** line options supported by the clean command itself, if any ** are present, are passed along verbatim. ** ** config Only the "config pull AREA" command works. ** ** dbstat Run the "dbstat" command on all repositories. ** ** extras Shows "extra" files from all local checkouts. The command ** line options supported by the extra command itself, if any ** are present, are passed along verbatim. ** ** fts-config Run the "fts-config" command on all repositories. ** ** info Run the "info" command on all repositories. ** ** pull Run a "pull" operation on all repositories. Only the ** --verbose option is supported. ** ** push Run a "push" on all repositories. Only the --verbose ** option is supported. ** ** rebuild Rebuild on all repositories. The command line options ** supported by the rebuild command itself, if any are ** present, are passed along verbatim. The --force and ** --randomize options are not supported. ** ** sync Run a "sync" on all repositories. Only the --verbose ** option is supported. ** ** setting Run the "setting", "set", or "unset" commands on all ** set repositories. These command are particularly useful in ** unset conjunction with the "max-loadavg" setting which cannot ** otherwise be set globally. ** ** server Run the "ui" or "server" commands on all repositories. ** ui The root URI gives a listing of all repos. ** ** ** In addition, the following maintenance operations are supported: ** ** add Add all the repositories named to the set of repositories ** tracked by Fossil. Normally Fossil is able to keep up with ** this list by itself, but sometimes it can benefit from this ** hint if you rename repositories. ** ** ignore Arguments are repositories that should be ignored by ** subsequent clean, extras, list, pull, push, rebuild, and ** sync operations. The -c|--ckout option causes the listed ** local checkouts to be ignored instead. ** ** list | ls Display the location of all repositories. The -c|--ckout ** option causes all local checkouts to be listed instead. ** ** Repositories are automatically added to the set of known repositories ** when one of the following commands are run against the repository: ** clone, info, pull, push, or sync. Even previously ignored repositories ** are added back to the list of repositories by these commands. ** ** Options: ** --showfile Show the repository or checkout being operated upon. ** --dontstop Continue with other repositories even after an error. ** --dry-run If given, display instead of run actions. */ void all_cmd(void){ int n; Stmt q; const char *zCmd; char *zSyscmd; char *zFossil; char *zQFilename; Blob extra; int useCheckouts = 0; int quiet = 0; int dryRunFlag = 0; int showFile = find_option("showfile",0,0)!=0; int stopOnError = find_option("dontstop",0,0)==0; int nToDel = 0; int showLabel = 0; dryRunFlag = find_option("dry-run","n",0)!=0; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } if( g.argc<3 ){ usage("SUBCOMMAND ..."); } n = strlen(g.argv[2]); db_open_config(1, 0); blob_zero(&extra); zCmd = g.argv[2]; if( !login_is_nobody() ) blob_appendf(&extra, " -U %s", g.zLogin); if( strncmp(zCmd, "ui", n)==0 || strncmp(zCmd, "server", n)==0 ){ g.argv[1] = g.argv[2]; g.argv[2] = "/"; cmd_webserver(); return; } if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){ zCmd = "list"; useCheckouts = find_option("ckout","c",0)!=0; }else if( strncmp(zCmd, "clean", n)==0 ){ zCmd = "clean --chdir"; collect_argument(&extra, "allckouts",0); collect_argument_value(&extra, "case-sensitive"); collect_argument_value(&extra, "clean"); collect_argument(&extra, "dirsonly",0); collect_argument(&extra, "disable-undo",0); collect_argument(&extra, "dotfiles",0); collect_argument(&extra, "emptydirs",0); collect_argument(&extra, "force","f"); collect_argument_value(&extra, "ignore"); collect_argument_value(&extra, "keep"); collect_argument(&extra, "no-prompt",0); collect_argument(&extra, "temp",0); collect_argument(&extra, "verbose","v"); collect_argument(&extra, "whatif",0); useCheckouts = 1; }else if( strncmp(zCmd, "config", n)==0 ){ zCmd = "config -R"; collect_argv(&extra, 3); (void)find_option("legacy",0,0); (void)find_option("overwrite",0,0); verify_all_options(); if( g.argc!=5 || fossil_strcmp(g.argv[3],"pull")!=0 ){ usage("configure pull AREA ?OPTIONS?"); } }else if( strncmp(zCmd, "dbstat", n)==0 ){ zCmd = "dbstat --omit-version-info -R"; showLabel = 1; quiet = 1; collect_argument(&extra, "brief", "b"); collect_argument(&extra, "db-check", 0); }else if( strncmp(zCmd, "extras", n)==0 ){ if( showFile ){ zCmd = "extras --chdir"; }else{ zCmd = "extras --header --chdir"; } collect_argument(&extra, "abs-paths",0); collect_argument_value(&extra, "case-sensitive"); collect_argument(&extra, "dotfiles",0); collect_argument_value(&extra, "ignore"); collect_argument(&extra, "rel-paths",0); useCheckouts = 1; stopOnError = 0; quiet = 1; }else if( strncmp(zCmd, "push", n)==0 ){ zCmd = "push -autourl -R"; collect_argument(&extra, "verbose","v"); }else if( strncmp(zCmd, "pull", n)==0 ){ zCmd = "pull -autourl -R"; collect_argument(&extra, "verbose","v"); }else if( strncmp(zCmd, "rebuild", n)==0 ){ zCmd = "rebuild"; collect_argument(&extra, "cluster",0); collect_argument(&extra, "compress",0); collect_argument(&extra, "compress-only",0); collect_argument(&extra, "noverify",0); collect_argument_value(&extra, "pagesize"); collect_argument(&extra, "vacuum",0); collect_argument(&extra, "deanalyze",0); collect_argument(&extra, "analyze",0); collect_argument(&extra, "wal",0); collect_argument(&extra, "stats",0); collect_argument(&extra, "index",0); collect_argument(&extra, "noindex",0); collect_argument(&extra, "ifneeded", 0); }else if( strncmp(zCmd, "setting", n)==0 ){ zCmd = "setting -R"; collect_argv(&extra, 3); }else if( strncmp(zCmd, "unset", n)==0 ){ zCmd = "unset -R"; collect_argv(&extra, 3); }else if( strncmp(zCmd, "fts-config", n)==0 ){ zCmd = "fts-config -R"; collect_argv(&extra, 3); }else if( strncmp(zCmd, "sync", n)==0 ){ zCmd = "sync -autourl -R"; collect_argument(&extra, "verbose","v"); collect_argument(&extra, "unversioned","u"); }else if( strncmp(zCmd, "test-integrity", n)==0 ){ collect_argument(&extra, "parse", 0); zCmd = "test-integrity"; }else if( strncmp(zCmd, "test-orphans", n)==0 ){ zCmd = "test-orphans -R"; }else if( strncmp(zCmd, "test-missing", n)==0 ){ zCmd = "test-missing -q -R"; collect_argument(&extra, "notshunned",0); }else if( strncmp(zCmd, "changes", n)==0 ){ zCmd = "changes --quiet --header --chdir"; useCheckouts = 1; stopOnError = 0; quiet = 1; }else if( strncmp(zCmd, "ignore", n)==0 ){ int j; Blob fn = BLOB_INITIALIZER; Blob sql = BLOB_INITIALIZER; useCheckouts = find_option("ckout","c",0)!=0; verify_all_options(); db_begin_transaction(); for(j=3; j<g.argc; j++, blob_reset(&sql), blob_reset(&fn)){ file_canonical_name(g.argv[j], &fn, useCheckouts?1:0); blob_append_sql(&sql, "DELETE FROM global_config WHERE name GLOB '%s:%q'", useCheckouts?"ckout":"repo", blob_str(&fn) ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ db_multi_exec("%s", blob_sql_text(&sql)); } } db_end_transaction(0); blob_reset(&sql); blob_reset(&fn); blob_reset(&extra); return; }else if( strncmp(zCmd, "add", n)==0 ){ int j; Blob fn = BLOB_INITIALIZER; Blob sql = BLOB_INITIALIZER; verify_all_options(); db_begin_transaction(); for(j=3; j<g.argc; j++, blob_reset(&fn), blob_reset(&sql)){ sqlite3 *db; |
︙ | ︙ | |||
394 395 396 397 398 399 400 | blob_append_sql(&sql, "INSERT OR IGNORE INTO global_config(name,value)" "VALUES('repo:%q',1)", z ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ | < < | | < < < < < < | | < > | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | blob_append_sql(&sql, "INSERT OR IGNORE INTO global_config(name,value)" "VALUES('repo:%q',1)", z ); if( dryRunFlag ){ fossil_print("%s\n", blob_sql_text(&sql)); }else{ db_multi_exec("%s", blob_sql_text(&sql)); } } db_end_transaction(0); blob_reset(&sql); blob_reset(&fn); blob_reset(&extra); return; }else if( strncmp(zCmd, "info", n)==0 ){ zCmd = "info"; showLabel = 1; quiet = 1; }else if( strncmp(zCmd, "cache", n)==0 ){ zCmd = "cache -R"; showLabel = 1; collect_argv(&extra, 3); }else{ fossil_fatal("\"all\" subcommand should be one of: " "add cache changes clean dbstat extras fts-config ignore " "info list ls pull push rebuild server setting sync ui unset"); } verify_all_options(); zFossil = quoteFilename(g.nameOfExe); db_multi_exec("CREATE TEMP TABLE repolist(name,tag);"); if( useCheckouts ){ db_multi_exec( "INSERT INTO repolist " "SELECT DISTINCT substr(name, 7), name COLLATE nocase" " FROM global_config" " WHERE substr(name, 1, 6)=='ckout:'" |
︙ | ︙ | |||
463 464 465 466 467 468 469 | nToDel++; continue; } if( zCmd[0]=='l' ){ fossil_print("%s\n", zFilename); continue; }else if( showFile ){ | | > | | | | | < < < < < | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | nToDel++; continue; } if( zCmd[0]=='l' ){ fossil_print("%s\n", zFilename); continue; }else if( showFile ){ fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository", zFilename); } zQFilename = quoteFilename(zFilename); zSyscmd = mprintf("%s %s %s%s", zFossil, zCmd, zQFilename, blob_str(&extra)); if( showLabel ){ int len = (int)strlen(zFilename); int nStar = 80 - (len + 15); if( nStar<2 ) nStar = 1; fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*'); fflush(stdout); } if( !quiet || dryRunFlag ){ fossil_print("%s\n", zSyscmd); fflush(stdout); } rc = dryRunFlag ? 0 : fossil_system(zSyscmd); free(zSyscmd); free(zQFilename); if( stopOnError && rc ){ break; } } db_finalize(&q); blob_reset(&extra); /* If any repositories whose names appear in the ~/.fossil file could not ** be found, remove those names from the ~/.fossil file. */ if( nToDel>0 ){ const char *zSql = "DELETE FROM global_config WHERE name IN toDel"; if( dryRunFlag ){ fossil_print("%s\n", zSql); }else{ db_multi_exec("%s", zSql /*safe-for-%s*/ ); } } } |
Changes to src/attach.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | #include "attach.h" #include <assert.h> /* ** WEBPAGE: attachlist ** List attachments. ** | | < | < | | < | | | < | 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 | #include "attach.h" #include <assert.h> /* ** WEBPAGE: attachlist ** List attachments. ** ** tkt=TICKETUUID ** page=WIKIPAGE ** ** At most one of technote=, tkt= or page= are supplied. ** If none is given, all attachments are listed. If one is given, ** only attachments for the designated technote, ticket or wiki page ** are shown. TECHNOTEUUID and TICKETUUID may be just a prefix of the ** relevant technical note or ticket, in which case all attachments ** of all technical notes or tickets with the prefix will be listed. */ void attachlist_page(void){ const char *zPage = P("page"); const char *zTkt = P("tkt"); const char *zTechNote = P("technote"); Blob sql; Stmt q; if( zPage && zTkt ) zTkt = 0; login_check_credentials(); blob_zero(&sql); blob_append_sql(&sql, "SELECT datetime(mtime,toLocal()), src, target, filename," " comment, user," " (SELECT uuid FROM blob WHERE rid=attachid), attachid," " (CASE WHEN 'tkt-'||target IN (SELECT tagname FROM tag)" " THEN 1" |
︙ | ︙ | |||
109 110 111 112 113 114 115 | zUrlTail = mprintf("technote=%s&file=%t", zTarget, zFilename); }else{ zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); } @ <li><p> @ Attachment %z(href("%R/ainfo/%!S",zUuid))%S(zUuid)</a> moderation_pending_www(attachid); | | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | zUrlTail = mprintf("technote=%s&file=%t", zTarget, zFilename); }else{ zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); } @ <li><p> @ Attachment %z(href("%R/ainfo/%!S",zUuid))%S(zUuid)</a> moderation_pending_www(attachid); @ <br /><a href="%R/attachview?%s(zUrlTail)">%h(zFilename)</a> @ [<a href="%R/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br> if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; if( zComment && zComment[0] ){ @ %!W(zComment)<br /> } if( zPage==0 && zTkt==0 && zTechNote==0 ){ if( zSrc==0 || zSrc[0]==0 ){ zSrc = "Deleted from"; }else { zSrc = "Added to"; } |
︙ | ︙ | |||
144 145 146 147 148 149 150 | } @ by %h(zDispUser) on hyperlink_to_date(zDate, "."); free(zUrlTail); } db_finalize(&q); @ </ol> | | < | | < | 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 | } @ by %h(zDispUser) on hyperlink_to_date(zDate, "."); free(zUrlTail); } db_finalize(&q); @ </ol> style_footer(); return; } /* ** WEBPAGE: attachdownload ** WEBPAGE: attachimage ** WEBPAGE: attachview ** ** Download or display an attachment. ** Query parameters: ** ** tkt=TICKETUUID ** page=WIKIPAGE ** technote=TECHNOTEUUID ** file=FILENAME ** attachid=ID ** */ void attachview_page(void){ const char *zPage = P("page"); const char *zTkt = P("tkt"); const char *zTechNote = P("technote"); const char *zFile = P("file"); const char *zTarget = 0; int attachid = atoi(PD("attachid","0")); char *zUUID; if( zFile==0 ) fossil_redirect_home(); login_check_credentials(); if( zPage ){ if( g.perm.RdWiki==0 ){ login_needed(g.anon.RdWiki); return; } zTarget = zPage; }else if( zTkt ){ if( g.perm.RdTkt==0 ){ login_needed(g.anon.RdTkt); return; } zTarget = zTkt; }else if( zTechNote ){ |
︙ | ︙ | |||
205 206 207 208 209 210 211 | " ORDER BY mtime DESC LIMIT 1", zTarget, zFile ); } if( zUUID==0 || zUUID[0]==0 ){ style_header("No Such Attachment"); @ No such attachment.... | | | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | " ORDER BY mtime DESC LIMIT 1", zTarget, zFile ); } if( zUUID==0 || zUUID[0]==0 ){ style_header("No Such Attachment"); @ No such attachment.... style_footer(); return; }else if( zUUID[0]=='x' ){ style_header("Missing"); @ Attachment has been deleted style_footer(); return; }else{ g.perm.Read = 1; cgi_replace_parameter("name",zUUID); if( fossil_strcmp(g.zPath,"attachview")==0 ){ artifact_page(); }else{ |
︙ | ︙ | |||
242 243 244 245 246 247 248 | moderation_table_create(); db_multi_exec( "INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);", rid, attachRid ); }else{ rid = content_put(pAttach); | | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | moderation_table_create(); db_multi_exec( "INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);", rid, attachRid ); }else{ rid = content_put(pAttach); db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid); db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid); } manifest_crosslink(rid, pAttach, MC_NONE); } /* ** Commit a new attachment into the repository */ void attach_commit( const char *zName, /* The filename of the attachment */ const char *zTarget, /* The artifact uuid to attach to */ const char *aContent, /* The content of the attachment */ int szContent, /* The length of the attachment */ int needModerator, /* Moderate the attachment? */ const char *zComment /* The comment for the attachment */ ){ Blob content; Blob manifest; |
︙ | ︙ | |||
309 310 311 312 313 314 315 | db_end_transaction(0); } /* ** WEBPAGE: attachadd ** Add a new attachment. ** | | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | db_end_transaction(0); } /* ** WEBPAGE: attachadd ** Add a new attachment. ** ** tkt=TICKETUUID ** page=WIKIPAGE ** technote=TECHNOTEUUID ** from=URL ** */ void attachadd_page(void){ const char *zPage = P("page"); const char *zTkt = P("tkt"); const char *zTechNote = P("technote"); |
︙ | ︙ | |||
375 376 377 378 379 380 381 | " WHERE tagname GLOB 'tkt-%q*'", zTkt); if( zTkt==0 ) fossil_redirect_home(); } zTarget = zTkt; zTargetType = mprintf("Ticket <a href=\"%R/tktview/%s\">%S</a>", zTkt, zTkt); } | | < | | | | | | | | | | | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | " WHERE tagname GLOB 'tkt-%q*'", zTkt); if( zTkt==0 ) fossil_redirect_home(); } zTarget = zTkt; zTargetType = mprintf("Ticket <a href=\"%R/tktview/%s\">%S</a>", zTkt, zTkt); } if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); if( P("cancel") ){ cgi_redirect(zFrom); } if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct(0)) ){ int needModerator = (zTkt!=0 && ticket_need_moderation(0)) || (zPage!=0 && wiki_need_moderation(0)); const char *zComment = PD("comment", ""); attach_commit(zName, zTarget, aContent, szContent, needModerator, zComment); cgi_redirect(zFrom); } style_header("Add Attachment"); if( !goodCaptcha ){ @ <p class="generalError">Error: Incorrect security code.</p> } @ <h2>Add Attachment To %s(zTargetType)</h2> form_begin("enctype='multipart/form-data'", "%R/attachadd"); @ <div> @ File to Attach: @ <input type="file" name="f" size="60" /><br /> @ Description:<br /> @ <textarea name="comment" cols="80" rows="5" wrap="virtual"></textarea><br /> if( zTkt ){ @ <input type="hidden" name="tkt" value="%h(zTkt)" /> }else if( zTechNote ){ @ <input type="hidden" name="technote" value="%h(zTechNote)" /> }else{ @ <input type="hidden" name="page" value="%h(zPage)" /> } @ <input type="hidden" name="from" value="%h(zFrom)" /> @ <input type="submit" name="ok" value="Add Attachment" /> @ <input type="submit" name="cancel" value="Cancel" /> @ </div> captcha_generate(0); @ </form> style_footer(); fossil_free(zTargetType); } /* ** WEBPAGE: ainfo ** URL: /ainfo?name=ARTIFACTID ** ** Show the details of an attachment artifact. */ void ainfo_page(void){ int rid; /* RID for the control artifact */ int ridSrc; /* RID for the attached file */ char *zDate; /* Date attached */ const char *zUuid; /* UUID of the control artifact */ Manifest *pAttach; /* Parse of the control artifact */ const char *zTarget; /* Wiki, ticket or tech note attached to */ const char *zSrc; /* UUID of the attached file */ const char *zName; /* Name of the attached file */ const char *zDesc; /* Description of the attached file */ const char *zWikiName = 0; /* Wiki page name when attached to Wiki */ const char *zTNUuid = 0; /* Tech Note ID when attached to tech note */ const char *zTktUuid = 0; /* Ticket ID when attached to a ticket */ int modPending; /* True if awaiting moderation */ const char *zModAction; /* Moderation action or NULL */ |
︙ | ︙ | |||
450 451 452 453 454 455 456 457 458 459 460 461 462 463 | if( !g.perm.RdTkt && !g.perm.RdWiki ){ login_needed(g.anon.RdTkt || g.anon.RdWiki); return; } rid = name_to_rid_www("name"); if( rid==0 ){ fossil_redirect_home(); } zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); pAttach = manifest_get(rid, CFTYPE_ATTACHMENT, 0); if( pAttach==0 ) fossil_redirect_home(); zTarget = pAttach->zAttachTarget; zSrc = pAttach->zAttachSrc; ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%q'", zSrc); zName = pAttach->zAttachName; zDesc = pAttach->zComment; | > > > > > > > > > > > > > | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | if( !g.perm.RdTkt && !g.perm.RdWiki ){ login_needed(g.anon.RdTkt || g.anon.RdWiki); return; } rid = name_to_rid_www("name"); if( rid==0 ){ fossil_redirect_home(); } zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); #if 0 /* Shunning here needs to get both the attachment control artifact and ** the object that is attached. */ if( g.perm.Admin ){ if( db_exists("SELECT 1 FROM shun WHERE uuid='%q'", zUuid) ){ style_submenu_element("Unshun", "%s/shun?uuid=%s&sub=1", g.zTop, zUuid); }else{ style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } #endif pAttach = manifest_get(rid, CFTYPE_ATTACHMENT, 0); if( pAttach==0 ) fossil_redirect_home(); zTarget = pAttach->zAttachTarget; zSrc = pAttach->zAttachSrc; ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%q'", zSrc); zName = pAttach->zAttachName; zDesc = pAttach->zComment; |
︙ | ︙ | |||
537 538 539 540 541 542 543 | cgi_redirectf("%R/tktview/%!S", zTktUuid); }else{ cgi_redirectf("%R/wiki?name=%t", zWikiName); } return; } if( strcmp(zModAction,"approve")==0 ){ | | < | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | cgi_redirectf("%R/tktview/%!S", zTktUuid); }else{ cgi_redirectf("%R/wiki?name=%t", zWikiName); } return; } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Attachment Details"); style_submenu_element("Raw", "%R/artifact/%s", zUuid); if(fShowContent){ style_submenu_element("Line Numbers", "%R/ainfo/%s%s", zUuid, ((zLn&&*zLn) ? "" : "?ln=0")); } |
︙ | ︙ | |||
589 590 591 592 593 594 595 | @ </table> if( isModerator && modPending ){ @ <div class="section">Moderation</div> @ <blockquote> form_begin(0, "%R/ainfo/%s", zUuid); @ <label><input type="radio" name="modaction" value="delete"> | | | | | | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | @ </table> if( isModerator && modPending ){ @ <div class="section">Moderation</div> @ <blockquote> form_begin(0, "%R/ainfo/%s", zUuid); @ <label><input type="radio" name="modaction" value="delete"> @ Delete this change</label><br /> @ <label><input type="radio" name="modaction" value="approve"> @ Approve this change</label><br /> @ <input type="submit" value="Submit"> @ </form> @ </blockquote> } @ <div class="section">Content Appended</div> @ <blockquote> blob_zero(&attach); if( fShowContent ){ const char *z; content_get(ridSrc, &attach); blob_to_utf8_no_bom(&attach, 0); z = blob_str(&attach); if( zLn ){ output_text_with_line_numbers(z, zLn); }else{ @ <pre> @ %h(z) @ </pre> } }else if( strncmp(zMime, "image/", 6)==0 ){ int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc); @ <i>(file is %d(sz) bytes of image data)</i><br /> @ <img src="%R/raw/%s(zSrc)?m=%s(zMime)"></img> style_submenu_element("Image", "%R/raw/%s?m=%s", zSrc, zMime); }else{ int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc); @ <i>(file is %d(sz) bytes of binary data)</i> } @ </blockquote> manifest_destroy(pAttach); blob_reset(&attach); style_footer(); } /* ** Output HTML to show a list of attachments. */ void attachment_list( const char *zTarget, /* Object that things are attached to */ |
︙ | ︙ | |||
657 658 659 660 661 662 663 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; if( cnt==0 ){ @ %s(zHeader) } cnt++; @ <li> @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a> | < | | | | | | | | | | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; if( cnt==0 ){ @ %s(zHeader) } cnt++; @ <li> @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a> @ added by %h(zDispUser) on hyperlink_to_date(zDate, "."); @ [%z(href("%R/ainfo/%!S",zUuid))details</a>] @ </li> } if( cnt ){ @ </ul> } db_finalize(&q); } /* ** COMMAND: attachment* ** ** Usage: %fossil attachment add ?PAGENAME? FILENAME ?OPTIONS? ** ** Add an attachment to an existing wiki page or tech note. ** ** Options: ** -t|--technote DATETIME Specifies the timestamp of ** the technote to which the attachment ** is to be made. The attachment will be ** to the most recently modified tech note ** with the specified timestamp. ** -t|--technote TECHNOTE-ID Specifies the technote to be ** updated by its technote id. ** ** One of PAGENAME, DATETIME or TECHNOTE-ID must be specified. ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. */ |
︙ | ︙ | |||
748 749 750 751 752 753 754 | if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){ zBody = pWiki->zWiki; } if( zBody==0 ){ fossil_fatal("technote [%s] not found",zETime); } zTarget = db_text(0, | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){ zBody = pWiki->zWiki; } if( zBody==0 ){ fossil_fatal("technote [%s] not found",zETime); } zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag WHERE tagid=(SELECT tagid FROM event WHERE objid='%d')", rid ); zFile = g.argv[3]; } blob_read_from_file(&content, zFile, ExtFILE); user_select(); attach_commit( zFile, /* The filename of the attachment */ zTarget, /* The artifact uuid to attach to */ blob_buffer(&content), /* The content of the attachment */ blob_size(&content), /* The length of the attachment */ 0, /* No need to moderate the attachment */ "" /* Empty attachment comment */ ); if( !zETime ){ fossil_print("Attached %s to wiki page %s.\n", zFile, zPageName); }else{ fossil_print("Attached %s to tech note %s.\n", zFile, zETime); } }else{ goto attachment_cmd_usage; } return; attachment_cmd_usage: usage("add ?PAGENAME? FILENAME [-t|--technote DATETIME ]"); } |
Deleted src/backlink.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/backoffice.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** This file contains code used to manage a background processes that ** occur after user interaction with the repository. Examples of ** backoffice processing includes: ** ** * Sending alerts and notifications ** * Processing the email queue | < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** This file contains code used to manage a background processes that ** occur after user interaction with the repository. Examples of ** backoffice processing includes: ** ** * Sending alerts and notifications ** * Processing the email queue ** * Automatically syncing to peer repositories ** ** Backoffice processing is automatically started whenever there are ** changes to the repository. The backoffice process dies off after ** a period of inactivity. ** ** Steps are taken to ensure that only a single backoffice process is |
︙ | ︙ | |||
76 77 78 79 80 81 82 | # endif # define GETPID (int)GetCurrentProcessId #else # include <unistd.h> # include <sys/types.h> # include <signal.h> # include <errno.h> | < < < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | # endif # define GETPID (int)GetCurrentProcessId #else # include <unistd.h> # include <sys/types.h> # include <signal.h> # include <errno.h> # include <fcntl.h> # define GETPID getpid #endif /* ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice ** processing run is valid. Each backoffice run monopolizes the lease for ** at least this amount of time. Hopefully all backoffice processing is ** finished much faster than this - usually in less than a second. But ** regardless of how long each invocation lasts, successive backoffice runs |
︙ | ︙ | |||
122 123 124 125 126 127 128 | /* This variable is set to the name of a database on which backoffice ** should run if backoffice process is needed. It is set by the ** backoffice_check_if_needed() routine which must be run while the database ** file is open. Later, after the database is closed, the ** backoffice_run_if_needed() will consult this variable to see if it ** should be a no-op. | < < < < < < < < < < < < < < < < < < < < < < < < | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* This variable is set to the name of a database on which backoffice ** should run if backoffice process is needed. It is set by the ** backoffice_check_if_needed() routine which must be run while the database ** file is open. Later, after the database is closed, the ** backoffice_run_if_needed() will consult this variable to see if it ** should be a no-op. */ static char *backofficeDb = 0; /* End of state variables ****************************************************************************/ /* ** This function emits a diagnostic message related to the processing in ** this module. */ |
︙ | ︙ | |||
239 240 241 242 243 244 245 | ** ** No other process should start active backoffice processing until ** process (1) no longer exists and the current time exceeds (2). */ static void backofficeReadLease(Lease *pLease){ Stmt q; memset(pLease, 0, sizeof(*pLease)); | < < | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ** ** No other process should start active backoffice processing until ** process (1) no longer exists and the current time exceeds (2). */ static void backofficeReadLease(Lease *pLease){ Stmt q; memset(pLease, 0, sizeof(*pLease)); db_prepare(&q, "SELECT value FROM repository.config" " WHERE name='backoffice'"); if( db_step(&q)==SQLITE_ROW ){ const char *z = db_column_text(&q,0); z = backofficeParseInt(z, &pLease->idCurrent); z = backofficeParseInt(z, &pLease->tmCurrent); z = backofficeParseInt(z, &pLease->idNext); backofficeParseInt(z, &pLease->tmNext); } db_finalize(&q); } /* ** Return a string that describes how long it has been since the ** last backoffice run. The string is obtained from fossil_malloc(). */ char *backoffice_last_run(void){ |
︙ | ︙ | |||
277 278 279 280 281 282 283 | return mprintf("%z ago", human_readable_age(rAge)); } /* ** Write a lease to the backoffice property */ static void backofficeWriteLease(Lease *pLease){ | < < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | return mprintf("%z ago", human_readable_age(rAge)); } /* ** Write a lease to the backoffice property */ static void backofficeWriteLease(Lease *pLease){ db_multi_exec( "REPLACE INTO repository.config(name,value,mtime)" " VALUES('backoffice','%lld %lld %lld %lld',now())", pLease->idCurrent, pLease->tmCurrent, pLease->idNext, pLease->tmNext); } /* ** Check to see if the specified Win32 process is still alive. It ** should be noted that even if this function returns non-zero, the ** process may die before another operation on it can be completed. */ |
︙ | ︙ | |||
306 307 308 309 310 311 312 | CloseHandle(hProcess); return 1; } #endif /* ** Check to see if the process identified by pid is alive. If | | | | | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | CloseHandle(hProcess); return 1; } #endif /* ** Check to see if the process identified by pid is alive. If ** we cannot prove the the process is dead, return true. */ static int backofficeProcessExists(sqlite3_uint64 pid){ #if defined(_WIN32) return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0; #else return pid>0 && kill((pid_t)pid, 0)==0; #endif } /* ** Check to see if the process identified by pid has finished. If ** we cannot prove the the process is still running, return true. */ static int backofficeProcessDone(sqlite3_uint64 pid){ #if defined(_WIN32) return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0; #else return pid<=0 || kill((pid_t)pid, 0)!=0; #endif } /* ** Return a process id number for the current process */ static sqlite3_uint64 backofficeProcessId(void){ return (sqlite3_uint64)GETPID(); |
︙ | ︙ | |||
362 363 364 365 366 367 368 | backofficeProcessDone(x)); } } /* ** COMMAND: test-backoffice-lease ** | | < < < < < < < < < < < < | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | backofficeProcessDone(x)); } } /* ** COMMAND: test-backoffice-lease ** ** Usage: %fossil test-backoffice-lease ** ** Print out information about the backoffice "lease" entry in the ** config table that controls whether or not backoffice should run. */ void test_backoffice_lease(void){ sqlite3_int64 tmNow = time(0); Lease x; const char *zLease; db_find_and_open_repository(0,0); verify_all_options(); zLease = db_get("backoffice",""); fossil_print("now: %lld\n", tmNow); fossil_print("lease: \"%s\"\n", zLease); backofficeReadLease(&x); fossil_print("idCurrent: %-20lld", x.idCurrent); if( backofficeProcessExists(x.idCurrent) ) fossil_print(" (exists)"); |
︙ | ︙ | |||
424 425 426 427 428 429 430 | Lease x; sqlite3_uint64 tmNow; if( backofficeDb ) return; if( g.zRepositoryName==0 ) return; if( g.db==0 ) return; if( !db_table_exists("repository","config") ) return; | < < < < < < < < | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | Lease x; sqlite3_uint64 tmNow; if( backofficeDb ) return; if( g.zRepositoryName==0 ) return; if( g.db==0 ) return; if( !db_table_exists("repository","config") ) return; tmNow = time(0); backofficeReadLease(&x); if( x.tmNext>=tmNow && backofficeProcessExists(x.idNext) ){ /* Another backoffice process is already queued up to run. This ** process does not need to do any backoffice work. */ return; }else{ /* We need to run backup to be (at a minimum) on-deck */ backofficeDb = fossil_strdup(g.zRepositoryName); } } /* ** Check for errors prior to running backoffice_thread() or backoffice_run(). */ static void backoffice_error_check_one(int *pOnce){ if( *pOnce ){ fossil_panic("multiple calls to backoffice()"); } |
︙ | ︙ | |||
470 471 472 473 474 475 476 | ** If another process is already working as the current backoffice and ** the on-deck backoffice, then this routine returns very quickly ** without doing any work. ** ** If no backoffice processes are running at all, this routine becomes ** the main backoffice. ** | | | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | | < < < < | < < < < < | < < < < < | < < < | < < < < < < < < < < < < | < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | ** If another process is already working as the current backoffice and ** the on-deck backoffice, then this routine returns very quickly ** without doing any work. ** ** If no backoffice processes are running at all, this routine becomes ** the main backoffice. ** ** If a primary backoffice is running, but a on-deck backoffice is ** needed, this routine becomes that on-desk backoffice. */ static void backoffice_thread(void){ Lease x; sqlite3_uint64 tmNow; sqlite3_uint64 idSelf; int lastWarning = 0; int warningDelay = 30; static int once = 0; backoffice_error_check_one(&once); idSelf = backofficeProcessId(); while(1){ tmNow = time(0); db_begin_write(); backofficeReadLease(&x); if( x.tmNext>=tmNow && x.idNext!=idSelf && backofficeProcessExists(x.idNext) ){ /* Another backoffice process is already queued up to run. This ** process does not need to do any backoffice work and can stop ** immediately. */ db_end_transaction(0); break; } if( x.tmCurrent<tmNow && backofficeProcessDone(x.idCurrent) ){ /* This process can start doing backoffice work immediately */ x.idCurrent = idSelf; x.tmCurrent = tmNow + BKOFCE_LEASE_TIME; x.idNext = 0; x.tmNext = 0; backofficeWriteLease(&x); db_end_transaction(0); backofficeTrace("/***** Begin Backoffice Processing %d *****/\n", GETPID()); backoffice_work(); break; } if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",0) ){ /* If the no-delay flag is set, exit immediately rather than queuing ** up. Assume that some future request will come along and handle any ** necessary backoffice work. */ db_end_transaction(0); break; } /* This process needs to queue up and wait for the current lease ** to expire before continuing. */ x.idNext = idSelf; x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME; backofficeWriteLease(&x); db_end_transaction(0); backofficeTrace("/***** Backoffice On-deck %d *****/\n", GETPID()); if( x.tmCurrent >= tmNow ){ if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){ /* The sleep was interrupted by a signal from another thread. */ backofficeTrace("/***** Backoffice Interrupt %d *****/\n", GETPID()); db_end_transaction(0); break; } }else{ if( lastWarning+warningDelay < tmNow ){ fossil_warning( "backoffice process %lld still running after %d seconds", x.idCurrent, (int)(BKOFCE_LEASE_TIME + tmNow - x.tmCurrent)); lastWarning = tmNow; warningDelay *= 2; } if( backofficeSleep(1000) ){ /* The sleep was interrupted by a signal from another thread. */ backofficeTrace("/***** Backoffice Interrupt %d *****/\n", GETPID()); db_end_transaction(0); break; } } } return; } /* ** This routine runs to do the backoffice processing. When adding new ** backoffice processing tasks, add them here. */ void backoffice_work(void){ /* Log the backoffice run for testing purposes. For production deployments ** the "backoffice-logfile" property should be unset and the following code ** should be a no-op. */ char *zLog = db_get("backoffice-logfile",0); if( zLog && zLog[0] ){ FILE *pLog = fossil_fopen(zLog, "a"); if( pLog ){ char *zDate = db_text(0, "SELECT datetime('now');"); fprintf(pLog, "%s (%d) backoffice running\n", zDate, GETPID()); fclose(pLog); } } /* Here is where the actual work of the backoffice happens */ alert_backoffice(0); smtp_cleanup(); } /* ** COMMAND: backoffice* ** ** Usage: backoffice [-R repository] ** ** Run backoffice processing. This might be done by a cron job or ** similar to make sure backoffice processing happens periodically. */ void backoffice_command(void){ if( find_option("trace",0,0)!=0 ) g.fAnyTrace = 1; db_find_and_open_repository(0,0); verify_all_options(); backoffice_thread(); } /* ** This is the main interface to backoffice from the rest of the system. ** This routine launches either backoffice_thread() directly or as a ** subprocess. */ |
︙ | ︙ | |||
853 854 855 856 857 858 859 | int i; setsid(); for(i=0; i<=2; i++){ close(i); open("/dev/null", O_RDWR); } for(i=3; i<100; i++){ close(i); } | < < < | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | int i; setsid(); for(i=0; i<=2; i++){ close(i); open("/dev/null", O_RDWR); } for(i=3; i<100; i++){ close(i); } db_open_repository(backofficeDb); backofficeDb = "x"; backoffice_thread(); db_close(1); backofficeTrace("/***** Backoffice Child %d exits *****/\n", GETPID()); exit(0); } |
︙ | ︙ |
Changes to src/bag.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | */ struct Bag { int cnt; /* Number of integers in the bag */ int sz; /* Number of slots in a[] */ int used; /* Number of used slots in a[] */ int *a; /* Hash table of integers that are in the bag */ }; | < < < < < < | | 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 | */ struct Bag { int cnt; /* Number of integers in the bag */ int sz; /* Number of slots in a[] */ int used; /* Number of used slots in a[] */ int *a; /* Hash table of integers that are in the bag */ }; #endif /* ** Initialize a Bag structure */ void bag_init(Bag *p){ memset(p, 0, sizeof(*p)); } /* ** Destroy a Bag. Delete all of its content. */ void bag_clear(Bag *p){ free(p->a); bag_init(p); } /* ** The hash function */ #define bag_hash(i) (i*101) /* ** Change the size of the hash table on a bag so that ** it contains N slots ** ** Completely reconstruct the hash table from scratch. Deleted ** entries (indicated by a -1) are removed. When finished, it |
︙ | ︙ | |||
99 100 101 102 103 104 105 | memset(p->a, 0, sizeof(p->a[0])*newSize ); for(i=0; i<old.sz; i++){ int e = old.a[i]; if( e>0 ){ unsigned h = bag_hash(e)%newSize; while( p->a[h] ){ h++; | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | memset(p->a, 0, sizeof(p->a[0])*newSize ); for(i=0; i<old.sz; i++){ int e = old.a[i]; if( e>0 ){ unsigned h = bag_hash(e)%newSize; while( p->a[h] ){ h++; if( h==newSize ) h = 0; } p->a[h] = e; nLive++; }else if( e<0 ){ nDel++; } } |
︙ | ︙ | |||
129 130 131 132 133 134 135 | if( p->used+1 >= p->sz/2 ){ int n = p->sz*2; bag_resize(p, n + 20 ); } h = bag_hash(e)%p->sz; while( p->a[h]>0 && p->a[h]!=e ){ h++; | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | if( p->used+1 >= p->sz/2 ){ int n = p->sz*2; bag_resize(p, n + 20 ); } h = bag_hash(e)%p->sz; while( p->a[h]>0 && p->a[h]!=e ){ h++; if( h>=p->sz ) h = 0; } if( p->a[h]<=0 ){ if( p->a[h]==0 ) p->used++; p->a[h] = e; p->cnt++; rc = 1; } |
︙ | ︙ | |||
152 153 154 155 156 157 158 | assert( e>0 ); if( p->sz==0 ){ return 0; } h = bag_hash(e)%p->sz; while( p->a[h] && p->a[h]!=e ){ h++; | | | | 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 | assert( e>0 ); if( p->sz==0 ){ return 0; } h = bag_hash(e)%p->sz; while( p->a[h] && p->a[h]!=e ){ h++; if( h>=p->sz ) h = 0; } return p->a[h]==e; } /* ** Remove element e from the bag if it exists in the bag. ** If e is not in the bag, this is a no-op. */ void bag_remove(Bag *p, int e){ unsigned h; assert( e>0 ); if( p->sz==0 ) return; h = bag_hash(e)%p->sz; while( p->a[h] && p->a[h]!=e ){ h++; if( h>=p->sz ) h = 0; } if( p->a[h] ){ int nx = h+1; if( nx>=p->sz ) nx = 0; if( p->a[nx]==0 ){ p->a[h] = 0; p->used--; |
︙ | ︙ | |||
215 216 217 218 219 220 221 | int bag_next(Bag *p, int e){ unsigned h; assert( p->sz>0 ); assert( e>0 ); h = bag_hash(e)%p->sz; while( p->a[h] && p->a[h]!=e ){ h++; | | | | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | int bag_next(Bag *p, int e){ unsigned h; assert( p->sz>0 ); assert( e>0 ); h = bag_hash(e)%p->sz; while( p->a[h] && p->a[h]!=e ){ h++; if( h>=p->sz ) h = 0; } assert( p->a[h] ); h++; while( h<p->sz && p->a[h]<=0 ){ h++; } return h<p->sz ? p->a[h] : 0; } /* ** Return the number of elements in the bag. */ int bag_count(Bag *p){ return p->cnt; } |
Changes to src/bisect.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | ** Find the shortest path between bad and good. */ void bisect_path(void){ PathNode *p; bisect.bad = db_lget_int("bisect-bad", 0); bisect.good = db_lget_int("bisect-good", 0); if( bisect.good>0 && bisect.bad==0 ){ | | | < < < < < < < < < < < < | < | < < < < < | < < < | 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 | ** Find the shortest path between bad and good. */ void bisect_path(void){ PathNode *p; bisect.bad = db_lget_int("bisect-bad", 0); bisect.good = db_lget_int("bisect-good", 0); if( bisect.good>0 && bisect.bad==0 ){ path_shortest(bisect.good, bisect.good, 0, 0); }else if( bisect.bad>0 && bisect.good==0 ){ path_shortest(bisect.bad, bisect.bad, 0, 0); }else if( bisect.bad==0 && bisect.good==0 ){ fossil_fatal("neither \"good\" nor \"bad\" versions have been identified"); }else{ p = path_shortest(bisect.good, bisect.bad, bisect_option("direct-only"), 0); if( p==0 ){ char *zBad = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.bad); char *zGood = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.good); fossil_fatal("no path from good ([%S]) to bad ([%S]) or back", zGood, zBad); } } } /* ** The set of all bisect options. */ static const struct { const char *zName; const char *zDefault; const char *zDesc; } aBisectOption[] = { { "auto-next", "on", "Automatically run \"bisect next\" after each " "\"bisect good\" or \"bisect bad\"" }, { "direct-only", "on", "Follow only primary parent-child links, not " "merges\n" }, { "display", "chart", "Command to run after \"next\". \"chart\", " "\"log\", \"status\", or \"none\"" }, }; /* ** Return the value of a boolean bisect option. */ int bisect_option(const char *zName){ unsigned int i; int r = -1; for(i=0; i<count(aBisectOption); i++){ if( fossil_strcmp(zName, aBisectOption[i].zName)==0 ){ char *zLabel = mprintf("bisect-%s", zName); char *z = db_lget(zLabel, (char*)aBisectOption[i].zDefault); if( is_truth(z) ) r = 1; if( is_false(z) ) r = 0; if( r<0 ) r = is_truth(aBisectOption[i].zDefault); free(zLabel); break; } } |
︙ | ︙ | |||
187 188 189 190 191 192 193 | } db_multi_exec( "REPLACE INTO vvar(name,value) VALUES('bisect-log'," "COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')" " || '%d')", rid); } | < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | < < < < < < < | < < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | } db_multi_exec( "REPLACE INTO vvar(name,value) VALUES('bisect-log'," "COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')" " || '%d')", rid); } /* ** Create a TEMP table named "bilog" that contains the complete history ** of the current bisect. */ void bisect_create_bilog_table(int iCurrent){ char *zLog = db_lget("bisect-log",""); Blob log, id; Stmt q; int cnt = 0; blob_init(&log, zLog, -1); db_multi_exec( "CREATE TEMP TABLE bilog(" " seq INTEGER PRIMARY KEY," /* Sequence of events */ " stat TEXT," /* Type of occurrence */ " rid INTEGER UNIQUE" /* Check-in number */ ");" ); db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)" " VALUES(:seq,:stat,:rid)"); while( blob_token(&log, &id) ){ int rid = atoi(blob_str(&id)); db_bind_int(&q, ":seq", ++cnt); db_bind_text(&q, ":stat", rid>0 ? "GOOD" : "BAD"); db_bind_int(&q, ":rid", rid>=0 ? rid : -rid); db_step(&q); db_reset(&q); } if( iCurrent>0 ){ db_bind_int(&q, ":seq", ++cnt); db_bind_text(&q, ":stat", "CURRENT"); db_bind_int(&q, ":rid", iCurrent); db_step(&q); } db_finalize(&q); } /* ** Show a chart of bisect "good" and "bad" versions. The chart can be ** sorted either chronologically by bisect time, or by check-in time. */ static void bisect_chart(int sortByCkinTime){ Stmt q; int iCurrent = db_lget_int("checkout",0); bisect_create_bilog_table(iCurrent); db_prepare(&q, "SELECT bilog.seq, bilog.stat," " substr(blob.uuid,1,16), datetime(event.mtime)," " blob.rid==%d" " FROM bilog, blob, event" " WHERE blob.rid=bilog.rid AND event.objid=bilog.rid" " AND event.type='ci'" |
︙ | ︙ | |||
368 369 370 371 372 373 374 | db_column_text(&q, 3), db_column_text(&q, 2), (db_column_int(&q, 4) && zGoodBad[0]!='C') ? " CURRENT" : ""); } db_finalize(&q); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | | | | | | | | | | | | | | | | | < < | < < < < < | | | < < | | | > > | | | > | > | | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | db_column_text(&q, 3), db_column_text(&q, 2), (db_column_int(&q, 4) && zGoodBad[0]!='C') ? " CURRENT" : ""); } db_finalize(&q); } /* ** COMMAND: bisect ** ** Usage: %fossil bisect SUBCOMMAND ... ** ** Run various subcommands useful for searching for bugs. ** ** fossil bisect bad ?VERSION? ** ** Identify version VERSION as non-working. If VERSION is omitted, ** the current checkout is marked as non-working. ** ** fossil bisect good ?VERSION? ** ** Identify version VERSION as working. If VERSION is omitted, ** the current checkout is marked as working. ** ** fossil bisect log ** fossil bisect chart ** ** Show a log of "good" and "bad" versions. "bisect log" shows the ** events in the order that they were tested. "bisect chart" shows ** them in order of check-in. ** ** fossil bisect next ** ** Update to the next version that is halfway between the working and ** non-working versions. ** ** fossil bisect options ?NAME? ?VALUE? ** ** List all bisect options, or the value of a single option, or set the ** value of a bisect option. ** ** fossil bisect reset ** ** Reinitialize a bisect session. This cancels prior bisect history ** and allows a bisect session to start over from the beginning. ** ** fossil bisect vlist|ls|status ?-a|--all? ** ** List the versions in between "bad" and "good". ** ** fossil bisect ui ** ** Like "fossil ui" except start on a timeline that shows only the ** check-ins that are part of the current bisect. ** ** fossil bisect undo ** ** Undo the most recent "good" or "bad" command. ** ** Summary: ** ** fossil bisect bad ?VERSION? ** fossil bisect good ?VERSION? ** fossil bisect log ** fossil bisect chart ** fossil bisect next ** fossil bisect options ** fossil bisect reset ** fossil bisect status ** fossil bisect ui ** fossil bisect undo */ void bisect_cmd(void){ int n; const char *zCmd; int foundCmd = 0; db_must_be_within_tree(); if( g.argc<3 ){ usage("bad|good|log|next|options|reset|status|undo"); } zCmd = g.argv[2]; n = strlen(zCmd); if( n==0 ) zCmd = "-"; if( strncmp(zCmd, "bad", n)==0 ){ int ridBad; foundCmd = 1; |
︙ | ︙ | |||
569 570 571 572 573 574 575 | ridGood = db_lget_int("checkout",0); }else{ ridGood = name_to_typed_rid(g.argv[3], "ci"); } if( ridGood>0 ){ bisect_append_log(ridGood); if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){ | < < < < < < < < < < < < < < < < < < | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | ridGood = db_lget_int("checkout",0); }else{ ridGood = name_to_typed_rid(g.argv[3], "ci"); } if( ridGood>0 ){ bisect_append_log(ridGood); if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){ zCmd = "next"; n = 4; } } }else if( strncmp(zCmd, "undo", n)==0 ){ char *zLog; Blob log, id; |
︙ | ︙ | |||
632 633 634 635 636 637 638 | /* No else here so that the above commands can morph themselves into ** a "next" command */ if( strncmp(zCmd, "next", n)==0 ){ PathNode *pMid; char *zDisplay = db_lget("bisect-display","chart"); int m = (int)strlen(zDisplay); bisect_path(); | < < < < | < < < < < < < | | > > > | < | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | /* No else here so that the above commands can morph themselves into ** a "next" command */ if( strncmp(zCmd, "next", n)==0 ){ PathNode *pMid; char *zDisplay = db_lget("bisect-display","chart"); int m = (int)strlen(zDisplay); bisect_path(); pMid = path_midpoint(); if( pMid==0 ){ fossil_print("bisect complete\n"); }else{ g.argv[1] = "update"; g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid); g.argc = 3; g.fNoSync = 1; update_cmd(); } if( strncmp(zDisplay,"chart",m)==0 ){ bisect_chart(1); }else if( strncmp(zDisplay, "log", m)==0 ){ bisect_chart(0); }else if( strncmp(zDisplay, "status", m)==0 ){ bisect_list(1); } }else if( strncmp(zCmd, "log", n)==0 ){ bisect_chart(0); }else if( strncmp(zCmd, "chart", n)==0 ){ bisect_chart(1); }else if( strncmp(zCmd, "options", n)==0 ){ if( g.argc==3 ){ unsigned int i; for(i=0; i<count(aBisectOption); i++){ char *z = mprintf("bisect-%s", aBisectOption[i].zName); fossil_print(" %-15s %-6s ", aBisectOption[i].zName, db_lget(z, (char*)aBisectOption[i].zDefault)); fossil_free(z); comment_print(aBisectOption[i].zDesc, 0, 27, -1, g.comFmtFlags); } }else if( g.argc==4 || g.argc==5 ){ unsigned int i; n = strlen(g.argv[3]); for(i=0; i<count(aBisectOption); i++){ if( strncmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ char *z = mprintf("bisect-%s", aBisectOption[i].zName); if( g.argc==5 ){ db_lset(z, g.argv[4]); } fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); fossil_free(z); break; } } if( i>=count(aBisectOption) ){ fossil_fatal("no such bisect option: %s", g.argv[3]); } }else{ usage("options ?NAME? ?VALUE?"); } }else if( strncmp(zCmd, "reset", n)==0 ){ db_multi_exec( "DELETE FROM vvar WHERE name IN " " ('bisect-good', 'bisect-bad', 'bisect-log')" ); }else if( strcmp(zCmd, "ui")==0 ){ char *newArgv[8]; newArgv[0] = g.argv[0]; newArgv[1] = "ui"; newArgv[2] = "--page"; newArgv[3] = "timeline?bisect"; newArgv[4] = 0; g.argv = newArgv; g.argc = 4; cmd_webserver(); }else if( strncmp(zCmd, "vlist", n)==0 || strncmp(zCmd, "ls", n)==0 || strncmp(zCmd, "status", n)==0 ){ int fAll = find_option("all", "a", 0)!=0; bisect_list(!fAll); }else if( !foundCmd ){ usage("bad|good|log|next|options|reset|status|ui|undo"); } } |
Changes to src/blob.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** A Blob is a variable-length containers for arbitrary string ** or binary data. */ #include "config.h" | > > > > | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** ******************************************************************************* ** ** A Blob is a variable-length containers for arbitrary string ** or binary data. */ #include "config.h" #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #include "blob.h" #if defined(_WIN32) #include <fcntl.h> #include <io.h> #endif #if INTERFACE |
︙ | ︙ | |||
51 52 53 54 55 56 57 | #define blob_size(X) ((X)->nUsed) /* ** The buffer holding the blob data */ #define blob_buffer(X) ((X)->aData) | < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #define blob_size(X) ((X)->nUsed) /* ** The buffer holding the blob data */ #define blob_buffer(X) ((X)->aData) /* ** Seek whence parameter values */ #define BLOB_SEEK_SET 1 #define BLOB_SEEK_CUR 2 #define BLOB_SEEK_END 3 #endif /* INTERFACE */ /* ** Make sure a blob is initialized */ #define blob_is_init(x) \ |
︙ | ︙ | |||
122 123 124 125 126 127 128 | /* ** Other replacements for ctype.h functions. */ int fossil_islower(char c){ return c>='a' && c<='z'; } int fossil_isupper(char c){ return c>='A' && c<='Z'; } int fossil_isdigit(char c){ return c>='0' && c<='9'; } | < | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | /* ** Other replacements for ctype.h functions. */ int fossil_islower(char c){ return c>='a' && c<='z'; } int fossil_isupper(char c){ return c>='A' && c<='Z'; } int fossil_isdigit(char c){ return c>='0' && c<='9'; } int fossil_tolower(char c){ return fossil_isupper(c) ? c - 'A' + 'a' : c; } int fossil_toupper(char c){ return fossil_islower(c) ? c - 'a' + 'A' : c; } int fossil_isalpha(char c){ |
︙ | ︙ | |||
174 175 176 177 178 179 180 | */ static void blob_panic(void){ static const char zErrMsg[] = "out of memory\n"; fputs(zErrMsg, stderr); fossil_exit(1); } | < < < < < < < < < < < < < < < < < | < < | | 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 | */ static void blob_panic(void){ static const char zErrMsg[] = "out of memory\n"; fputs(zErrMsg, stderr); fossil_exit(1); } /* ** A reallocation function that assumes that aData came from malloc(). ** This function attempts to resize the buffer of the blob to hold ** newSize bytes. ** ** No attempt is made to recover from an out-of-memory error. ** If an OOM error occurs, an error message is printed on stderr ** and the program exits. */ void blobReallocMalloc(Blob *pBlob, unsigned int newSize){ if( newSize==0 ){ free(pBlob->aData); pBlob->aData = 0; pBlob->nAlloc = 0; pBlob->nUsed = 0; pBlob->iCursor = 0; pBlob->blobFlags = 0; }else if( newSize>pBlob->nAlloc || newSize<pBlob->nAlloc-4000 ){ char *pNew = fossil_realloc(pBlob->aData, newSize); pBlob->aData = pNew; pBlob->nAlloc = newSize; if( pBlob->nUsed>pBlob->nAlloc ){ pBlob->nUsed = pBlob->nAlloc; } } } |
︙ | ︙ | |||
236 237 238 239 240 241 242 | ** A reallocation function for when the initial string is in unmanaged ** space. Copy the string to memory obtained from malloc(). */ static void blobReallocStatic(Blob *pBlob, unsigned int newSize){ if( newSize==0 ){ *pBlob = empty_blob; }else{ | < < | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | ** A reallocation function for when the initial string is in unmanaged ** space. Copy the string to memory obtained from malloc(). */ static void blobReallocStatic(Blob *pBlob, unsigned int newSize){ if( newSize==0 ){ *pBlob = empty_blob; }else{ char *pNew = fossil_malloc( newSize ); if( pBlob->nUsed>newSize ) pBlob->nUsed = newSize; memcpy(pNew, pBlob->aData, pBlob->nUsed); pBlob->aData = pNew; pBlob->xRealloc = blobReallocMalloc; pBlob->nAlloc = newSize; } } |
︙ | ︙ | |||
318 319 320 321 322 323 324 | pBlob->aData = (char*)zEmpty; pBlob->iCursor = 0; pBlob->blobFlags = 0; pBlob->xRealloc = blobReallocStatic; } /* | | < < < < < < < < < | < | | < < < < < < < < < < | < < < | < < < < < < | < < < < < < | < | | < | > | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | pBlob->aData = (char*)zEmpty; pBlob->iCursor = 0; pBlob->blobFlags = 0; pBlob->xRealloc = blobReallocStatic; } /* ** Append text or data to the end of a blob. */ void blob_append(Blob *pBlob, const char *aData, int nData){ assert( aData!=0 || nData==0 ); blob_is_init(pBlob); if( nData<0 ) nData = strlen(aData); if( nData==0 ) return; if( pBlob->nUsed + nData >= pBlob->nAlloc ){ pBlob->xRealloc(pBlob, pBlob->nUsed + nData + pBlob->nAlloc + 100); if( pBlob->nUsed + nData >= pBlob->nAlloc ){ blob_panic(); } } memcpy(&pBlob->aData[pBlob->nUsed], aData, nData); pBlob->nUsed += nData; pBlob->aData[pBlob->nUsed] = 0; /* Blobs are always nul-terminated */ } /* ** Append a single character to the blob */ void blob_append_char(Blob *pBlob, char c){ if( pBlob->nUsed+1 >= pBlob->nAlloc ){ pBlob->xRealloc(pBlob, pBlob->nUsed + pBlob->nAlloc + 100); if( pBlob->nUsed + 1 >= pBlob->nAlloc ){ blob_panic(); } } pBlob->aData[pBlob->nUsed++] = c; } /* ** Copy a blob */ void blob_copy(Blob *pTo, Blob *pFrom){ blob_is_init(pFrom); blob_zero(pTo); blob_append(pTo, blob_buffer(pFrom), blob_size(pFrom)); } /* ** Return a pointer to a null-terminated string for a blob. */ char *blob_str(Blob *p){ blob_is_init(p); if( p->nUsed==0 ){ blob_append_char(p, 0); /* NOTE: Changes nUsed. */ p->nUsed = 0; } if( p->aData[p->nUsed]!=0 ){ blob_materialize(p); } return p->aData; } /* ** Return a pointer to a null-terminated string for a blob that has ** been created using blob_append_sql() and not blob_appendf(). If ** text was ever added using blob_appendf() then throw an error. */ char *blob_sql_text(Blob *p){ blob_is_init(p); |
︙ | ︙ | |||
542 543 544 545 546 547 548 | return p->aData; } /* ** Compare two blobs. Return negative, zero, or positive if the first ** blob is less then, equal to, or greater than the second. */ | | | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | return p->aData; } /* ** Compare two blobs. Return negative, zero, or positive if the first ** blob is less then, equal to, or greater than the second. */ int blob_compare(Blob *pA, Blob *pB){ int szA, szB, sz, rc; blob_is_init(pA); blob_is_init(pB); szA = blob_size(pA); szB = blob_size(pB); sz = szA<szB ? szA : szB; rc = memcmp(blob_buffer(pA), blob_buffer(pB), sz); |
︙ | ︙ | |||
588 589 590 591 592 593 594 | /* ** Compare a blob to a string. Return TRUE if they are equal. */ int blob_eq_str(Blob *pBlob, const char *z, int n){ Blob t; blob_is_init(pBlob); | | | < < < < < < < < < < < < < < < < < < < < < < < | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | /* ** Compare a blob to a string. Return TRUE if they are equal. */ int blob_eq_str(Blob *pBlob, const char *z, int n){ Blob t; blob_is_init(pBlob); if( n<=0 ) n = strlen(z); t.aData = (char*)z; t.nUsed = n; t.xRealloc = blobReallocStatic; return blob_compare(pBlob, &t)==0; } /* ** This macro compares a blob against a string constant. We use the sizeof() ** operator on the string constant twice, so it really does need to be a ** string literal or character array - not a character pointer. */ #if INTERFACE # define blob_eq(B,S) \ ((B)->nUsed==sizeof(S)-1 && memcmp((B)->aData,S,sizeof(S)-1)==0) #endif /* ** Attempt to resize a blob so that its internal buffer is ** nByte in size. The blob is truncated if necessary. */ void blob_resize(Blob *pBlob, unsigned int newSize){ pBlob->xRealloc(pBlob, newSize+1); pBlob->nUsed = newSize; pBlob->aData[newSize] = 0; } /* ** Make sure a blob is nul-terminated and is not a pointer to unmanaged ** space. Return a pointer to the data. */ char *blob_materialize(Blob *pBlob){ blob_resize(pBlob, pBlob->nUsed); return pBlob->aData; |
︙ | ︙ | |||
694 695 696 697 698 699 700 | p->iCursor = 0; } /* ** Truncate a blob back to zero length */ void blob_truncate(Blob *p, int sz){ | | > > | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | p->iCursor = 0; } /* ** Truncate a blob back to zero length */ void blob_truncate(Blob *p, int sz){ if( sz>=0 && sz<p->nUsed ) p->nUsed = sz; } /* ** Seek the cursor in a blob to the indicated offset. */ int blob_seek(Blob *p, int offset, int whence){ if( whence==BLOB_SEEK_SET ){ p->iCursor = offset; }else if( whence==BLOB_SEEK_CUR ){ p->iCursor += offset; }else if( whence==BLOB_SEEK_END ){ p->iCursor = p->nUsed + offset - 1; } if( p->iCursor>p->nUsed ){ p->iCursor = p->nUsed; } return p->iCursor; } |
︙ | ︙ | |||
868 869 870 871 872 873 874 | } if( pTo ){ blob_append(pTo, &pFrom->aData[pFrom->iCursor], i - pFrom->iCursor); } pFrom->iCursor = i; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 | } if( pTo ){ blob_append(pTo, &pFrom->aData[pFrom->iCursor], i - pFrom->iCursor); } pFrom->iCursor = i; } /* ** Ensure that the text in pBlob ends with '\n' */ void blob_add_final_newline(Blob *pBlob){ if( pBlob->nUsed<=0 ) return; if( pBlob->aData[pBlob->nUsed-1]!='\n' ){ blob_append_char(pBlob, '\n'); |
︙ | ︙ | |||
1036 1037 1038 1039 1040 1041 1042 | int i; for(i=0; i<n; i++) blob_zero(&aBlob[i]); } void blobarray_reset(Blob *aBlob, int n){ int i; for(i=0; i<n; i++) blob_reset(&aBlob[i]); } | < < < < < < < < < < < < < < < < < < < | < > | | | | | | > > | | | | | > | | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | int i; for(i=0; i<n; i++) blob_zero(&aBlob[i]); } void blobarray_reset(Blob *aBlob, int n){ int i; for(i=0; i<n; i++) blob_reset(&aBlob[i]); } /* ** Parse a blob into space-separated tokens. Store each token in ** an element of the blobarray aToken[]. aToken[] is nToken elements in ** size. Return the number of tokens seen. */ int blob_tokenize(Blob *pIn, Blob *aToken, int nToken){ int i; for(i=0; i<nToken && blob_token(pIn, &aToken[i]); i++){} return i; } /* ** Do printf-style string rendering and append the results to a blob. ** ** The blob_appendf() version sets the BLOBFLAG_NotSQL bit in Blob.blobFlags ** whereas blob_append_sql() does not. */ void blob_appendf(Blob *pBlob, const char *zFormat, ...){ if( pBlob ){ va_list ap; va_start(ap, zFormat); vxprintf(pBlob, zFormat, ap); va_end(ap); pBlob->blobFlags |= BLOBFLAG_NotSQL; } } void blob_append_sql(Blob *pBlob, const char *zFormat, ...){ if( pBlob ){ va_list ap; va_start(ap, zFormat); vxprintf(pBlob, zFormat, ap); va_end(ap); } } void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){ if( pBlob ) vxprintf(pBlob, zFormat, ap); } /* ** Initialize a blob to the data on an input channel. Return ** the number of bytes read into the blob. Any prior content ** of the blob is discarded, not freed. */ |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | } } }else{ blob_resize(pBlob, nToRead); n = fread(blob_buffer(pBlob), 1, nToRead, in); blob_resize(pBlob, n); } | < < < < < < < < < < < < < < < < < < < < < < < < | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 | } } }else{ blob_resize(pBlob, nToRead); n = fread(blob_buffer(pBlob), 1, nToRead, in); blob_resize(pBlob, n); } return blob_size(pBlob); } /* ** Initialize a blob to be the content of a file. If the filename ** is blank or "-" then read from standard input. ** |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | fflush(stdout); _setmode(_fileno(stdout), _O_TEXT); #endif }else{ file_mkfolder(zFilename, ExtFILE, 1, 0); out = fossil_fopen(zFilename, "wb"); if( out==0 ){ | | | | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 | fflush(stdout); _setmode(_fileno(stdout), _O_TEXT); #endif }else{ file_mkfolder(zFilename, ExtFILE, 1, 0); out = fossil_fopen(zFilename, "wb"); if( out==0 ){ #if _WIN32 const char *zReserved = file_is_win_reserved(zFilename); if( zReserved ){ fossil_fatal("cannot open \"%s\" because \"%s\" is " "a reserved name on Windows", zFilename, zReserved); } #endif fossil_fatal_recursive("unable to open file \"%s\" for writing", zFilename); return 0; } blob_is_init(pBlob); nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); fclose(out); if( nWrote!=blob_size(pBlob) ){ fossil_fatal_recursive("short write: %d of %d bytes to %s", nWrote, blob_size(pBlob), zFilename); } } return nWrote; } |
︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | blob_reset(&b1); blob_reset(&b2); blob_reset(&b3); } fossil_print("ok\n"); } /* ** Convert every \n character in the given blob into \r\n. */ void blob_add_cr(Blob *p){ char *z = p->aData; int j = p->nUsed; int i, n; for(i=n=0; i<j; i++){ if( z[i]=='\n' ) n++; } j += n; | > | > | 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 | blob_reset(&b1); blob_reset(&b2); blob_reset(&b3); } fossil_print("ok\n"); } #if defined(_WIN32) || defined(__CYGWIN__) /* ** Convert every \n character in the given blob into \r\n. */ void blob_add_cr(Blob *p){ char *z = p->aData; int j = p->nUsed; int i, n; for(i=n=0; i<j; i++){ if( z[i]=='\n' ) n++; } j += n; if( j>=p->nAlloc ){ blob_resize(p, j); z = p->aData; } p->nUsed = j; z[j] = 0; while( j>i ){ if( (z[--j] = z[--i]) =='\n' ){ z[--j] = '\r'; } } } #endif /* ** Remove every \r character from the given blob, replacing each one with ** a \n character if it was not already part of a \r\n pair. */ void blob_to_lf_only(Blob *p){ int i, j; |
︙ | ︙ | |||
1519 1520 1521 1522 1523 1524 1525 | if( (z[i]<0xa0) && (cp1252[z[i]&0x1f]>=0x800) ){ n++; } n++; } } j += n; | | | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 | if( (z[i]<0xa0) && (cp1252[z[i]&0x1f]>=0x800) ){ n++; } n++; } } j += n; if( j>=p->nAlloc ){ blob_resize(p, j); z = (unsigned char *)p->aData; } p->nUsed = j; z[j] = 0; while( j>i ){ if( z[--i]>=0x80 ){ |
︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 1554 | } }else{ z[--j] = z[i]; } } } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | | | | | > > > > > < < < < | < | < < | | | | < | < < < < < < < < < < | > | | | < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 | } }else{ z[--j] = z[i]; } } } /* ** pBlob is a shell command under construction. This routine safely ** appends argument zIn. ** ** The argument is escaped if it contains white space or other characters ** that need to be escaped for the shell. If zIn contains characters ** that cannot be safely escaped, then throw a fatal error. ** ** The argument is expected to a filename of some kinds. As shell commands ** commonly have command-line options that begin with "-" and since we ** do not want an attacker to be able to invoke these switches using ** filenames that begin with "-", if zIn begins with "-", prepend ** an additional "./". */ void blob_append_escaped_arg(Blob *pBlob, const char *zIn){ int i; char c; int needEscape = 0; int n = blob_size(pBlob); char *z = blob_buffer(pBlob); #if defined(_WIN32) const char cQuote = '"'; /* Use "..." quoting on windows */ #else const char cQuote = '\''; /* Use '...' quoting on unix */ #endif for(i=0; (c = zIn[i])!=0; i++){ if( c==cQuote || c=='\\' || c<' ' || c==';' || c=='*' || c=='?' || c=='[') { Blob bad; blob_token(pBlob, &bad); fossil_fatal("the [%s] argument to the \"%s\" command contains " "a character (ascii 0x%02x) that is a security risk", zIn, blob_str(&bad), c); } if( !needEscape && !fossil_isalnum(c) && c!='/' && c!='.' && c!='_' ){ needEscape = 1; } } if( n>0 && !fossil_isspace(z[n-1]) ){ blob_append_char(pBlob, ' '); } if( needEscape ) blob_append_char(pBlob, cQuote); if( zIn[0]=='-' ) blob_append(pBlob, "./", 2); blob_append(pBlob, zIn, -1); if( needEscape ) blob_append_char(pBlob, cQuote); } /* ** A read(2)-like impl for the Blob class. Reads (copies) up to nLen ** bytes from pIn, starting at position pIn->iCursor, and copies them ** to pDest (which must be valid memory at least nLen bytes long). ** |
︙ | ︙ | |||
1927 1928 1929 1930 1931 1932 1933 | blob_swap(pBlob, &temp); blob_reset(&temp); }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){ zUtf8 = blob_buffer(pBlob); if( bomReverse ){ /* Found BOM, but with reversed bytes */ unsigned int i = blob_size(pBlob); | | | < | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 | blob_swap(pBlob, &temp); blob_reset(&temp); }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){ zUtf8 = blob_buffer(pBlob); if( bomReverse ){ /* Found BOM, but with reversed bytes */ unsigned int i = blob_size(pBlob); while( i>0 ){ /* swap bytes of unicode representation */ char zTemp = zUtf8[--i]; zUtf8[i] = zUtf8[i-1]; zUtf8[--i] = zTemp; } } /* Make sure the blob contains two terminating 0-bytes */ blob_append_char(pBlob, 0); zUtf8 = blob_str(pBlob) + bomSize; zUtf8 = fossil_unicode_to_utf8(zUtf8); blob_set_dynamic(pBlob, zUtf8); }else if( useMbcs && invalid_utf8(pBlob) ){ #if defined(_WIN32) || defined(__CYGWIN__) zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob)); blob_reset(pBlob); blob_append(pBlob, zUtf8, -1); fossil_mbcs_free(zUtf8); #else blob_cp1252_to_utf8(pBlob); #endif /* _WIN32 */ } } |
Changes to src/branch.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** This file contains code used to create new branches within a repository. */ #include "config.h" #include "branch.h" #include <assert.h> /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < > > > > | | | 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 | ** This file contains code used to create new branches within a repository. */ #include "config.h" #include "branch.h" #include <assert.h> /* ** fossil branch new NAME BASIS ?OPTIONS? ** argv0 argv1 argv2 argv3 argv4 */ void branch_new(void){ int rootid; /* RID of the root check-in - what we branch off of */ int brid; /* RID of the branch check-in */ int noSign; /* True if the branch is unsigned */ int i; /* Loop counter */ char *zUuid; /* Artifact ID of origin */ Stmt q; /* Generic query */ const char *zBranch; /* Name of the new branch */ char *zDate; /* Date that branch was created */ char *zComment; /* Check-in comment for the new branch */ const char *zColor; /* Color of the new branch */ Blob branch; /* manifest for the new branch */ Manifest *pParent; /* Parsed parent manifest */ Blob mcksum; /* Self-checksum on the manifest */ const char *zDateOvrd; /* Override date string */ const char *zUserOvrd; /* Override user name */ int isPrivate = 0; /* True if the branch should be private */ noSign = find_option("nosign","",0)!=0; zColor = find_option("bgcolor","c",1); isPrivate = find_option("private",0,0)!=0; zDateOvrd = find_option("date-override",0,1); zUserOvrd = find_option("user-override",0,1); verify_all_options(); if( g.argc<5 ){ usage("new BRANCH-NAME BASIS ?OPTIONS?"); } db_find_and_open_repository(0, 0); noSign = db_get_boolean("omitsign", 0)|noSign; if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; } /* fossil branch new name */ zBranch = g.argv[3]; if( zBranch==0 || zBranch[0]==0 ){ fossil_fatal("branch name cannot be empty"); } if( db_exists( "SELECT 1 FROM tagxref" " WHERE tagtype>0" " AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%q')", zBranch)!=0 ){ fossil_fatal("branch \"%s\" already exists", zBranch); } user_select(); db_begin_transaction(); rootid = name_to_typed_rid(g.argv[4], "ci"); if( rootid==0 ){ fossil_fatal("unable to locate check-in off of which to branch"); |
︙ | ︙ | |||
150 151 152 153 154 155 156 | blob_appendf(&branch, "R %s\n", pParent->zRepoCksum); } manifest_destroy(pParent); /* Add the symbolic branch name and the "branch" tag to identify ** this as a new branch */ if( content_is_private(rootid) ) isPrivate = 1; | | > | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | blob_appendf(&branch, "R %s\n", pParent->zRepoCksum); } manifest_destroy(pParent); /* Add the symbolic branch name and the "branch" tag to identify ** this as a new branch */ if( content_is_private(rootid) ) isPrivate = 1; if( isPrivate && zColor==0 ) zColor = "#fec084"; if( zColor!=0 ){ blob_appendf(&branch, "T *bgcolor * %F\n", zColor); } blob_appendf(&branch, "T *branch * %F\n", zBranch); blob_appendf(&branch, "T *sym-%F *\n", zBranch); if( isPrivate ){ blob_appendf(&branch, "T +private *\n"); noSign = 1; } /* Cancel all other symbolic tags */ db_prepare(&q, "SELECT tagname FROM tagxref, tag" " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid" |
︙ | ︙ | |||
191 192 193 194 195 196 197 | } } brid = content_put_ex(&branch, 0, 0, 0, isPrivate); if( brid==0 ){ fossil_fatal("trouble committing manifest: %s", g.zErrMsg); } | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | < < < < < | | < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > > > > > > | | > > > > | | | > > > > < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } } brid = content_put_ex(&branch, 0, 0, 0, isPrivate); if( brid==0 ){ fossil_fatal("trouble committing manifest: %s", g.zErrMsg); } db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid); if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){ fossil_fatal("%s", g.zErrMsg); } assert( blob_is_reset(&branch) ); content_deltify(rootid, &brid, 1, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); fossil_print("New branch: %s\n", zUuid); if( g.argc==3 ){ fossil_print( "\n" "Note: the local check-out has not been updated to the new\n" " branch. To begin working on the new branch, do this:\n" "\n" " %s update %s\n", g.argv[0], zBranch ); } /* Commit */ db_end_transaction(0); /* Do an autosync push, if requested */ if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries",1),0); } #if INTERFACE /* ** Allows bits in the mBplqFlags parameter to branch_prepare_list_query(). */ #define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */ #define BRL_OPEN_ONLY 0x002 /* Show only open branches */ #define BRL_BOTH 0x003 /* Show both open and closed branches */ #define BRL_OPEN_CLOSED_MASK 0x003 #define BRL_MTIME 0x004 /* Include lastest check-in time */ #define BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/ #endif /* INTERFACE */ /* ** Prepare a query that will list branches. ** ** If (which<0) then the query pulls only closed branches. If ** (which>0) then the query pulls all (closed and opened) ** branches. Else the query pulls currently-opened branches. */ void branch_prepare_list_query(Stmt *pQuery, int brFlags){ switch( brFlags & BRL_OPEN_CLOSED_MASK ){ case BRL_CLOSED_ONLY: { db_prepare(pQuery, "SELECT value FROM tagxref" " WHERE tagid=%d AND value NOT NULL " "EXCEPT " "SELECT value FROM tagxref" " WHERE tagid=%d" " AND rid IN leaf" " AND NOT %z" " ORDER BY value COLLATE nocase /*sort*/", TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") ); break; } case BRL_BOTH: { db_prepare(pQuery, "SELECT DISTINCT value FROM tagxref" " WHERE tagid=%d AND value NOT NULL" " AND rid IN leaf" " ORDER BY value COLLATE nocase /*sort*/", TAG_BRANCH ); break; } case BRL_OPEN_ONLY: { db_prepare(pQuery, "SELECT DISTINCT value FROM tagxref" " WHERE tagid=%d AND value NOT NULL" " AND rid IN leaf" " AND NOT %z" " ORDER BY value COLLATE nocase /*sort*/", TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") ); break; } } } /* ** If the branch named in the argument is open, return a RID for one of ** the open leaves of that branch. If the branch does not exists or is ** closed, return 0. */ |
︙ | ︙ | |||
391 392 393 394 395 396 397 | " WHERE tagid=%d" " AND tagtype=1" " AND ox.rid=ix.rid)", TAG_BRANCH, zBrName, TAG_CLOSED ); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | < | < | | < < < < < < < < < < < < < < < < < < < | < | | | < < | | | | > > > > > > | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | " WHERE tagid=%d" " AND tagtype=1" " AND ox.rid=ix.rid)", TAG_BRANCH, zBrName, TAG_CLOSED ); } /* ** COMMAND: branch ** ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? ** ** Run various subcommands to manage branches of the open repository or ** of the repository identified by the -R or --repository option. ** ** fossil branch current ** ** Print the name of the branch for the current check-out ** ** fossil branch info BRANCH-NAME ** ** Print information about a branch ** ** fossil branch list|ls ?-a|--all|-c|--closed? ** ** List all branches. Use -a or --all to list all branches and ** -c or --closed to list all closed branches. The default is to ** show only open branches. ** ** fossil branch new BRANCH-NAME BASIS ?OPTIONS? ** ** Create a new branch BRANCH-NAME off of check-in BASIS. ** Supported options for this subcommand include: ** --private branch is private (i.e., remains local) ** --bgcolor COLOR use COLOR instead of automatic background ** --nosign do not sign contents on this branch ** --date-override DATE DATE to use instead of 'now' ** --user-override USER USER to use instead of the current default ** ** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be ** replaced by a space, and it may also name a timezone offset ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). ** Either no timezone suffix or "Z" means UTC. ** ** Options: ** -R|--repository FILE Run commands on repository FILE ** ** Summary: ** fossil branch current ** fossil branch info BRANCHNAME ** fossil branch [list|ls] ** fossil branch new */ void branch_cmd(void){ int n; const char *zCmd = "list"; db_find_and_open_repository(0, 0); if( g.argc>=3 ) zCmd = g.argv[2]; n = strlen(zCmd); if( strncmp(zCmd,"current",n)==0 ){ if( !g.localOpen ){ fossil_fatal("not within an open checkout"); }else{ int vid = db_lget_int("checkout", 0); char *zCurrent = db_text(0, "SELECT value FROM tagxref" " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); fossil_print("%s\n", zCurrent); fossil_free(zCurrent); } |
︙ | ︙ | |||
709 710 711 712 713 714 715 | const char *zUuid = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); const char *zDate = db_text(0, "SELECT datetime(mtime,toLocal()) FROM event" " WHERE objid=%d", rid); fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid); } } | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > < < | < < | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | const char *zUuid = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); const char *zDate = db_text(0, "SELECT datetime(mtime,toLocal()) FROM event" " WHERE objid=%d", rid); fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid); } } }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){ Stmt q; int vid; char *zCurrent = 0; int brFlags = BRL_OPEN_ONLY; if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH; if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY; if( g.localOpen ){ vid = db_lget_int("checkout", 0); zCurrent = db_text(0, "SELECT value FROM tagxref" " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); } branch_prepare_list_query(&q, brFlags); while( db_step(&q)==SQLITE_ROW ){ const char *zBr = db_column_text(&q, 0); int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); } db_finalize(&q); }else if( strncmp(zCmd,"new",n)==0 ){ branch_new(); }else{ fossil_fatal("branch subcommand should be one of: " "current info list ls new"); } } static const char brlistQuery[] = @ SELECT @ tagxref.value, @ max(event.mtime), @ EXISTS(SELECT 1 FROM tagxref AS tx @ WHERE tx.rid=tagxref.rid @ AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed') @ AND tx.tagtype>0), @ (SELECT tagxref.value @ FROM plink CROSS JOIN tagxref @ WHERE plink.pid=event.objid @ AND tagxref.rid=plink.cid @ AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch') @ AND tagtype>0), @ count(*), @ (SELECT uuid FROM blob WHERE rid=tagxref.rid), @ event.bgcolor @ FROM tagxref, tag, event @ WHERE tagxref.tagid=tag.tagid @ AND tagxref.tagtype>0 @ AND tag.tagname='branch' @ AND event.objid=tagxref.rid @ GROUP BY 1 @ ORDER BY 2 DESC; ; /* ** This is the new-style branch-list page that shows the branch names ** together with their ages (time of last check-in) and whether or not ** they are closed or merged to another branch. ** ** Control jumps to this routine from brlist_page() (the /brlist handler) ** if there are no query parameters. */ static void new_brlist_page(void){ Stmt q; double rNow; int show_colors = PB("colors"); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("Branches"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_checkbox("colors", "Use Branch Colors", 0, 0); login_anonymous_available(); db_prepare(&q, brlistQuery/*works-like:""*/); rNow = db_double(0.0, "SELECT julianday('now')"); @ <div class="brlist"> @ <table class='sortable' data-column-types='tkNtt' data-init-sort='2'> @ <thead><tr> @ <th>Branch Name</th> @ <th>Age</th> @ <th>Check-ins</th> @ <th>Status</th> @ <th>Resolution</th> @ </tr></thead><tbody> while( db_step(&q)==SQLITE_ROW ){ const char *zBranch = db_column_text(&q, 0); double rMtime = db_column_double(&q, 1); |
︙ | ︙ | |||
885 886 887 888 889 890 891 | } } if( zBgClr && zBgClr[0] && show_colors ){ @ <tr style="background-color:%s(zBgClr)"> }else{ @ <tr> } | | < | < | | < < < < < < | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | } } if( zBgClr && zBgClr[0] && show_colors ){ @ <tr style="background-color:%s(zBgClr)"> }else{ @ <tr> } @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td> @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td> @ <td>%d(nCkin)</td> fossil_free(zAge); @ <td>%s(isClosed?"closed":"")</td> if( zMergeTo ){ @ <td>merged into @ %z(href("%R/timeline?f=%!S",zLastCkin))%h(zMergeTo)</a></td> }else{ @ <td></td> } @ </tr> } @ </tbody></table></div> db_finalize(&q); style_table_sorter(); style_footer(); } /* ** WEBPAGE: brlist ** Show a list of branches. With no query parameters, a sortable table ** is used to show all branches. If query parameters are present a ** fixed bullet list is shown. ** ** Query parameters: ** ** all Show all branches ** closed Show only closed branches ** open Show only open branches (default behavior) ** colortest Show all branches with automatic color */ void brlist_page(void){ Stmt q; int cnt; int showClosed = P("closed")!=0; int showAll = P("all")!=0; int showOpen = P("open")!=0; int colorTest = P("colortest")!=0; int brFlags = BRL_OPEN_ONLY; if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){ new_brlist_page(); return; } login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( colorTest ){ showClosed = 0; showAll = 1; } if( showAll ) brFlags = BRL_BOTH; if( showClosed ) brFlags = BRL_CLOSED_ONLY; style_header("%s", showClosed ? "Closed Branches" : showAll ? "All Branches" : "Open Branches"); style_submenu_element("Timeline", "brtimeline"); if( showClosed ){ style_submenu_element("All", "brlist?all"); style_submenu_element("Open", "brlist?open"); }else if( showAll ){ |
︙ | ︙ | |||
984 985 986 987 988 989 990 | @ closed leaves</a></div>. @ Closed branches are fixed and do not change (unless they are first @ reopened).</li> @ </ol> style_sidebox_end(); #endif | | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | @ closed leaves</a></div>. @ Closed branches are fixed and do not change (unless they are first @ reopened).</li> @ </ol> style_sidebox_end(); #endif branch_prepare_list_query(&q, brFlags); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zBr = db_column_text(&q, 0); if( cnt==0 ){ if( colorTest ){ @ <h2>Default background colors for all branches:</h2> }else if( showClosed ){ |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | cnt++; } if( colorTest ){ const char *zColor = hash_color(zBr); @ <li><span style="background-color: %s(zColor)"> @ %h(zBr) → %s(zColor)</span></li> }else{ | | | | < < < < < < < < < < < < < < < < | | | < < < < < < < | > | < < < < < < | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | cnt++; } if( colorTest ){ const char *zColor = hash_color(zBr); @ <li><span style="background-color: %s(zColor)"> @ %h(zBr) → %s(zColor)</span></li> }else{ @ <li>%z(href("%R/timeline?r=%T&n=200",zBr))%h(zBr)</a></li> } } if( cnt ){ @ </ul> } db_finalize(&q); style_footer(); } /* ** This routine is called while for each check-in that is rendered by ** the timeline of a "brlist" page. Add some additional hyperlinks ** to the end of the line. */ static void brtimeline_extra(int rid){ Stmt q; if( !g.perm.Hyperlink ) return; db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag" " WHERE tagxref.rid=%d" " AND tagxref.tagid=tag.tagid" " AND tagxref.tagtype>0" " AND tag.tagname GLOB 'sym-*'", rid ); while( db_step(&q)==SQLITE_ROW ){ const char *zTagName = db_column_text(&q, 0); @ %z(href("%R/timeline?r=%T&n=200",zTagName))[timeline]</a> } db_finalize(&q); } /* ** WEBPAGE: brtimeline ** ** Show a timeline of all branches */ void brtimeline_page(void){ Stmt q; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("Branches"); style_submenu_element("List", "brlist"); login_anonymous_available(); @ <h2>The initial check-in for each branch:</h2> db_prepare(&q, "%s AND blob.rid IN (SELECT rid FROM tagxref" " WHERE tagtype>0 AND tagid=%d AND srcid!=0)" " ORDER BY event.mtime DESC", timeline_query_for_www(), TAG_BRANCH ); www_print_timeline(&q, 0, 0, 0, 0, brtimeline_extra); db_finalize(&q); style_footer(); } |
Changes to src/browse.c.
︙ | ︙ | |||
57 58 59 60 61 62 63 | sqlite3_result_text(context, (char*)&z[n], len-n, SQLITE_TRANSIENT); }else{ zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]); sqlite3_result_text(context, zOut, i-n+1, sqlite3_free); } } | < < < < < < < < | < | < < < < < < < < < | | | | | | | | | > > > < < < < < < < < < < < < < < < < < < < < < < < < < < | < < > > < < < < < < < > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > | | | > > > > > > > > | > > > > > | | | < > | > > > | | | < < < < | < < | < | | > > | > | > > > > > > > > > | | > > > > | | | | | | | | | | | < < < < < < < < < > < | | < < | > | < < < < < < < < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | sqlite3_result_text(context, (char*)&z[n], len-n, SQLITE_TRANSIENT); }else{ zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]); sqlite3_result_text(context, zOut, i-n+1, sqlite3_free); } } /* ** Given a pathname which is a relative path from the root of ** the repository to a file or directory, compute a string which ** is an HTML rendering of that path with hyperlinks on each ** directory component of the path where the hyperlink redirects ** to the "dir" page for the directory. ** ** There is no hyperlink on the file element of the path. ** ** The computed string is appended to the pOut blob. pOut should ** have already been initialized. */ void hyperlinked_path( const char *zPath, /* Path to render */ Blob *pOut, /* Write into this blob */ const char *zCI, /* check-in name, or NULL */ const char *zURI, /* "dir" or "tree" */ const char *zREx /* Extra query parameters */ ){ int i, j; char *zSep = ""; for(i=0; zPath[i]; i=j){ for(j=i; zPath[j] && zPath[j]!='/'; j++){} if( zPath[j] && g.perm.Hyperlink ){ if( zCI ){ char *zLink = href("%R/%s?name=%#T%s&ci=%!S", zURI, j, zPath, zREx,zCI); blob_appendf(pOut, "%s%z%#h</a>", zSep, zLink, j-i, &zPath[i]); }else{ char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx); blob_appendf(pOut, "%s%z%#h</a>", zSep, zLink, j-i, &zPath[i]); } }else{ blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); } zSep = "/"; while( zPath[j]=='/' ){ j++; } } } /* ** WEBPAGE: dir ** ** Show the files and subdirectories within a single directory of the ** source tree. Only files for a single check-in are shown if the ci= ** query parameter is present. If ci= is missing, the union of files ** across all check-ins is shown. ** ** Query parameters: ** ** name=PATH Directory to display. Optional. Top-level if missing ** ci=LABEL Show only files in this check-in. Optional. ** type=TYPE TYPE=flat: use this display ** TYPE=tree: use the /tree display instead */ void page_dir(void){ char *zD = fossil_strdup(P("name")); int nD = zD ? strlen(zD)+1 : 0; int mxLen; int n; char *zPrefix; Stmt q; const char *zCI = P("ci"); int rid = 0; char *zUuid = 0; Blob dirname; Manifest *pM = 0; const char *zSubdirLink; int linkTrunk = 1; int linkTip = 1; HQuery sURI; if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; } login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } style_header("File List"); style_adunit_config(ADUNIT_RIGHT_OK); sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, pathelementFunc, 0, 0); url_initialize(&sURI, "dir"); cgi_query_parameters_to_url(&sURI); /* If the name= parameter is an empty string, make it a NULL pointer */ if( zD && strlen(zD)==0 ){ zD = 0; } /* If a specific check-in is requested, fetch and parse it. If the ** specific check-in does not exist, clear zCI. zCI==0 will cause all ** files from all check-ins to be displayed. */ if( zCI ){ pM = manifest_get_by_name(zCI, &rid); if( pM ){ int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); linkTrunk = trunkRid && rid != trunkRid; linkTip = rid != symbolic_name_to_rid("tip", "ci"); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); }else{ zCI = 0; } } /* Compute the title of the page */ blob_zero(&dirname); if( zD ){ blob_append(&dirname, "in directory ", -1); hyperlinked_path(zD, &dirname, zCI, "dir", ""); zPrefix = mprintf("%s/", zD); style_submenu_element("Top-Level", "%s", url_render(&sURI, "name", 0, 0, 0)); }else{ blob_append(&dirname, "in the top-level directory", -1); zPrefix = ""; } if( linkTrunk ){ style_submenu_element("Trunk", "%s", url_render(&sURI, "ci", "trunk", 0, 0)); } if( linkTip ){ style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0)); } if( zCI ){ @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] @ %s(blob_str(&dirname)) if( zD ){ @ %z(href("%R/timeline?chng=%T/*", zD))[history]</a> } @ </h2> zSubdirLink = mprintf("%R/dir?ci=%!S&name=%T", zUuid, zPrefix); if( nD==0 ){ style_submenu_element("File Ages", "%R/fileage?name=%!S", zUuid); } }else{ @ <h2>The union of all files from all check-ins @ %s(blob_str(&dirname)) if( zD ){ @ %z(href("%R/timeline?chng=%T/*", zD))[history]</a> } @ </h2> zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); } style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0)); style_submenu_element("Tree-View", "%s", url_render(&sURI, "type", "tree", 0, 0)); /* Compute the temporary table "localfiles" containing the names ** of all files and subdirectories in the zD[] directory. ** ** Subdirectory names begin with "/". This causes them to sort ** first and it also gives us an easy way to distinguish files ** from directories in the loop that follows. */ db_multi_exec( "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u);" ); if( zCI ){ Stmt ins; ManifestFile *pFile; ManifestFile *pPrev = 0; int nPrev = 0; int c; db_prepare(&ins, "INSERT OR IGNORE INTO localfiles VALUES(pathelement(:x,0), :u)" ); manifest_file_rewind(pM); while( (pFile = manifest_file_next(pM,0))!=0 ){ if( nD>0 && (fossil_strncmp(pFile->zName, zD, nD-1)!=0 || pFile->zName[nD-1]!='/') ){ continue; } if( pPrev && fossil_strncmp(&pFile->zName[nD],&pPrev->zName[nD],nPrev)==0 && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/') ){ continue; } db_bind_text(&ins, ":x", &pFile->zName[nD]); db_bind_text(&ins, ":u", pFile->zUuid); db_step(&ins); db_reset(&ins); pPrev = pFile; for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){} if( c=='/' ) nPrev++; } db_finalize(&ins); }else if( zD ){ db_multi_exec( "INSERT OR IGNORE INTO localfiles" " SELECT pathelement(name,%d), NULL FROM filename" " WHERE name GLOB '%q/*'", nD, zD ); }else{ db_multi_exec( "INSERT OR IGNORE INTO localfiles" " SELECT pathelement(name,0), NULL FROM filename" ); } /* Generate a multi-column table listing the contents of zD[] ** directory. */ mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); n = db_int(1,"SELECT count(*) FROM localfiles; /*scan*/"); if( mxLen<12 ) mxLen = 12; mxLen += (mxLen+9)/10; db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/"); @ <div class="columns" style="columns: %d(mxLen)ex %d(n);"> @ <ul class="browser"> while( db_step(&q)==SQLITE_ROW ){ const char *zFN; zFN = db_column_text(&q, 0); if( zFN[0]=='/' ){ zFN++; @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li> }else{ const char *zLink; if( zCI ){ const char *zUuid = db_column_text(&q, 1); zLink = href("%R/artifact/%!S",zUuid); }else{ zLink = href("%R/finfo?name=%T%T",zPrefix,zFN); } @ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li> } } db_finalize(&q); manifest_destroy(pM); @ </ul></div> /* If the directory contains a readme file, then display its content below ** the list of files */ db_prepare(&q, "SELECT x, u FROM localfiles" " WHERE x COLLATE nocase IN" " ('readme','readme.txt','readme.md','readme.wiki','readme.markdown'," " 'readme.html') ORDER BY x LIMIT 1;" ); if( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q,0); const char *zUuid = db_column_text(&q,1); if( zUuid ){ rid = fast_uuid_to_rid(zUuid); }else{ |
︙ | ︙ | |||
440 441 442 443 444 445 446 | @ sandbox="allow-same-origin" @ onload="this.height=this.contentDocument.documentElement.scrollHeight;"> @ </iframe> }else{ Blob content; const char *zMime = mimetype_from_name(zName); content_get(rid, &content); | < < | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | @ sandbox="allow-same-origin" @ onload="this.height=this.contentDocument.documentElement.scrollHeight;"> @ </iframe> }else{ Blob content; const char *zMime = mimetype_from_name(zName); content_get(rid, &content); wiki_render_by_mimetype(&content, zMime); } } } db_finalize(&q); style_footer(); } /* ** Objects used by the "tree" webpage. */ typedef struct FileTreeNode FileTreeNode; typedef struct FileTree FileTree; |
︙ | ︙ | |||
469 470 471 472 473 474 475 | FileTreeNode *pSibling; /* Next element in the same subdirectory */ FileTreeNode *pChild; /* List of child nodes */ FileTreeNode *pLastChild; /* Last child on the pChild list */ char *zName; /* Name of this entry. The "tail" */ char *zFullName; /* Full pathname of this entry */ char *zUuid; /* Artifact hash of this file. May be NULL. */ double mtime; /* Modification time for this entry */ | < < < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | FileTreeNode *pSibling; /* Next element in the same subdirectory */ FileTreeNode *pChild; /* List of child nodes */ FileTreeNode *pLastChild; /* Last child on the pChild list */ char *zName; /* Name of this entry. The "tail" */ char *zFullName; /* Full pathname of this entry */ char *zUuid; /* Artifact hash of this file. May be NULL. */ double mtime; /* Modification time for this entry */ unsigned nFullName; /* Length of zFullName */ unsigned iLevel; /* Levels of parent directories */ }; /* ** A complete file hierarchy */ |
︙ | ︙ | |||
501 502 503 504 505 506 507 | ** a common directory prefix must be added consecutively in order for ** the tree to be constructed properly. */ static void tree_add_node( FileTree *pTree, /* Tree into which nodes are added */ const char *zPath, /* The full pathname of file to add */ const char *zUuid, /* Hash of the file. Might be NULL. */ | | < < | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | ** a common directory prefix must be added consecutively in order for ** the tree to be constructed properly. */ static void tree_add_node( FileTree *pTree, /* Tree into which nodes are added */ const char *zPath, /* The full pathname of file to add */ const char *zUuid, /* Hash of the file. Might be NULL. */ double mtime /* Modification time for this entry */ ){ int i; FileTreeNode *pParent; /* Parent (directory) of the next node to insert */ /* Make pParent point to the most recent ancestor of zPath, or ** NULL if there are no prior entires that are a container for zPath. */ |
︙ | ︙ | |||
557 558 559 560 561 562 563 | pNew->iLevel = pParent->iLevel + 1; pParent->pLastChild = pNew; }else{ if( pTree->pLastTop ) pTree->pLastTop->pSibling = pNew; pTree->pLastTop = pNew; } pNew->mtime = mtime; | < < < < < < | < < < | | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | pNew->iLevel = pParent->iLevel + 1; pParent->pLastChild = pNew; }else{ if( pTree->pLastTop ) pTree->pLastTop->pSibling = pNew; pTree->pLastTop = pNew; } pNew->mtime = mtime; while( zPath[i]=='/' ){ i++; } pParent = pNew; } while( pParent && pParent->pParent ){ if( pParent->pParent->mtime < pParent->mtime ){ pParent->pParent->mtime = pParent->mtime; } pParent = pParent->pParent; } } /* Comparison function for two FileTreeNode objects. Sort first by ** mtime (larger numbers first) and then by zName (smaller names first). ** ** Return negative if pLeft<pRight. ** Return positive if pLeft>pRight. ** Return zero if pLeft==pRight. */ static int compareNodes(FileTreeNode *pLeft, FileTreeNode *pRight){ if( pLeft->mtime>pRight->mtime ) return -1; if( pLeft->mtime<pRight->mtime ) return +1; return fossil_stricmp(pLeft->zName, pRight->zName); } /* Merge together two sorted lists of FileTreeNode objects */ static FileTreeNode *mergeNodes(FileTreeNode *pLeft, FileTreeNode *pRight){ FileTreeNode *pEnd; FileTreeNode base; |
︙ | ︙ | |||
612 613 614 615 616 617 618 | pEnd->pSibling = pLeft; }else{ pEnd->pSibling = pRight; } return base.pSibling; } | | | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | pEnd->pSibling = pLeft; }else{ pEnd->pSibling = pRight; } return base.pSibling; } /* Sort a list of FileTreeNode objects in mtime order. */ static FileTreeNode *sortNodesByMtime(FileTreeNode *p){ FileTreeNode *a[30]; FileTreeNode *pX; int i; memset(a, 0, sizeof(a)); while( p ){ pX = p; |
︙ | ︙ | |||
645 646 647 648 649 650 651 | ** This routine invalidates the following fields: ** ** FileTreeNode.pLastChild ** FileTreeNode.pNext ** ** Use relinkTree to reconnect the pNext pointers. */ | | | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | ** This routine invalidates the following fields: ** ** FileTreeNode.pLastChild ** FileTreeNode.pNext ** ** Use relinkTree to reconnect the pNext pointers. */ static FileTreeNode *sortTreeByMtime(FileTreeNode *p){ FileTreeNode *pX; for(pX=p; pX; pX=pX->pSibling){ if( pX->pChild ) pX->pChild = sortTreeByMtime(pX->pChild); } return sortNodesByMtime(p); } /* Reconstruct the FileTree by reconnecting the FileTreeNode.pNext ** fields in sequential order. */ static void relinkTree(FileTree *pTree, FileTreeNode *pRoot){ while( pRoot ){ |
︙ | ︙ | |||
689 690 691 692 693 694 695 | ** ** type=tree Required to prevent use of /dir format ** name=PATH Directory to display. Optional ** ci=LABEL Show only files in this check-in. Optional. ** re=REGEXP Show only files matching REGEXP. Optional. ** expand Begin with the tree fully expanded. ** nofiles Show directories (folders) only. Omit files. | | | < < < < > > < < < < < < < < < < < < < < < < < < < < < | > | | | < < < < < < < > | | | < | | > | | | < < | | | < | | > < > > > | < < < < < < | | | > | < < > | < < < < < < | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | ** ** type=tree Required to prevent use of /dir format ** name=PATH Directory to display. Optional ** ci=LABEL Show only files in this check-in. Optional. ** re=REGEXP Show only files matching REGEXP. Optional. ** expand Begin with the tree fully expanded. ** nofiles Show directories (folders) only. Omit files. ** mtime Order directory elements by decreasing mtime */ void page_tree(void){ char *zD = fossil_strdup(P("name")); int nD = zD ? strlen(zD)+1 : 0; const char *zCI = P("ci"); int rid = 0; char *zUuid = 0; Blob dirname; Manifest *pM = 0; double rNow = 0; char *zNow = 0; int useMtime = atoi(PD("mtime","0")); int nFile = 0; /* Number of files (or folders with "nofiles") */ int linkTrunk = 1; /* include link to "trunk" */ int linkTip = 1; /* include link to "tip" */ const char *zRE; /* the value for the re=REGEXP query parameter */ const char *zObjType; /* "files" by default or "folders" for "nofiles" */ char *zREx = ""; /* Extra parameters for path hyperlinks */ ReCompiled *pRE = 0; /* Compiled regular expression */ FileTreeNode *p; /* One line of the tree */ FileTree sTree; /* The complete tree of files */ HQuery sURI; /* Hyperlink */ int startExpanded; /* True to start out with the tree expanded */ int showDirOnly; /* Show directories only. Omit files */ int nDir = 0; /* Number of directories. Used for ID attributes */ char *zProjectName = db_get("project-name", 0); if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; } memset(&sTree, 0, sizeof(sTree)); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, pathelementFunc, 0, 0); url_initialize(&sURI, "tree"); cgi_query_parameters_to_url(&sURI); if( PB("nofiles") ){ showDirOnly = 1; style_header("Folder Hierarchy"); }else{ showDirOnly = 0; style_header("File Tree"); } style_adunit_config(ADUNIT_RIGHT_OK); if( PB("expand") ){ startExpanded = 1; }else{ startExpanded = 0; } /* If a regular expression is specified, compile it */ zRE = P("re"); if( zRE ){ re_compile(&pRE, zRE, 0); zREx = mprintf("&re=%T", zRE); } /* If the name= parameter is an empty string, make it a NULL pointer */ if( zD && strlen(zD)==0 ){ zD = 0; } /* If a specific check-in is requested, fetch and parse it. If the ** specific check-in does not exist, clear zCI. zCI==0 will cause all ** files from all check-ins to be displayed. */ if( zCI ){ pM = manifest_get_by_name(zCI, &rid); if( pM ){ int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); linkTrunk = trunkRid && rid != trunkRid; linkTip = rid != symbolic_name_to_rid("tip", "ci"); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); zNow = db_text("", "SELECT datetime(mtime,toLocal())" " FROM event WHERE objid=%d", rid); }else{ zCI = 0; } } if( zCI==0 ){ rNow = db_double(0.0, "SELECT max(mtime) FROM event"); zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event"); } /* Compute the title of the page */ blob_zero(&dirname); if( zD ){ blob_append(&dirname, "within directory ", -1); hyperlinked_path(zD, &dirname, zCI, "tree", zREx); if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); style_submenu_element("Top-Level", "%s", url_render(&sURI, "name", 0, 0, 0)); }else{ if( zRE ){ blob_appendf(&dirname, "matching \"%s\"", zRE); } } style_submenu_binary("mtime","Sort By Time","Sort By Filename", 0); if( zCI ){ style_submenu_element("All", "%s", url_render(&sURI, "ci", 0, 0, 0)); if( nD==0 && !showDirOnly ){ style_submenu_element("File Ages", "%R/fileage?name=%s", zUuid); } } if( linkTrunk ){ style_submenu_element("Trunk", "%s", url_render(&sURI, "ci", "trunk", 0, 0)); } if( linkTip ){ style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0)); } style_submenu_element("Flat-View", "%s", url_render(&sURI, "type", "flat", 0, 0)); /* Compute the file hierarchy. */ if( zCI ){ Stmt q; compute_fileage(rid, 0); db_prepare(&q, "SELECT filename.name, blob.uuid, fileage.mtime\n" " FROM fileage, filename, blob\n" " WHERE filename.fnid=fileage.fnid\n" " AND blob.rid=fileage.fid\n" " ORDER BY filename.name COLLATE nocase;" ); while( db_step(&q)==SQLITE_ROW ){ const char *zFile = db_column_text(&q,0); const char *zUuid = db_column_text(&q,1); double mtime = db_column_double(&q,2); if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){ continue; } if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue; tree_add_node(&sTree, zFile, zUuid, mtime); nFile++; } db_finalize(&q); }else{ Stmt q; db_prepare(&q, "SELECT filename.name, blob.uuid, max(event.mtime)\n" " FROM filename, mlink, blob, event\n" " WHERE mlink.fnid=filename.fnid\n" " AND event.objid=mlink.mid\n" " AND blob.rid=mlink.fid\n" " GROUP BY 1 ORDER BY 1 COLLATE nocase"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zUuid = db_column_text(&q,1); double mtime = db_column_double(&q,2); if( nD>0 && (fossil_strncmp(zName, zD, nD-1)!=0 || zName[nD-1]!='/') ){ continue; } if( pRE && re_match(pRE, (const u8*)zName, -1)==0 ) continue; tree_add_node(&sTree, zName, zUuid, mtime); nFile++; } db_finalize(&q); } if( showDirOnly ){ for(nFile=0, p=sTree.pFirst; p; p=p->pNext){ if( p->pChild!=0 && p->nFullName>nD ) nFile++; } zObjType = "Folders"; }else{ zObjType = "Files"; } style_submenu_checkbox("nofiles", "Folders Only", 0, 0); if( zCI ){ @ <h2>%s(zObjType) from if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){ @ "%h(zCI)" } @ [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname)) }else{ int n = db_int(0, "SELECT count(*) FROM plink"); @ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname)) } if( useMtime ){ @ sorted by modification time</h2> }else{ @ sorted by filename</h2> } /* Generate tree of lists. ** ** Each file and directory is a list element: <li>. Files have class=file ** and if the filename as the suffix "xyz" the file also has class=file-xyz. ** Directories have class=dir. The directory specfied by the name= query ** parameter (or the top-level directory if there is no name= query parameter) |
︙ | ︙ | |||
938 939 940 941 942 943 944 | @ <li class="dir last"> }else{ @ <li class="dir subdir last"> } @ <div class="filetreeline"> @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> if( zNow ){ | | < | | | < | | < | | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | @ <li class="dir last"> }else{ @ <li class="dir subdir last"> } @ <div class="filetreeline"> @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> if( zNow ){ @ <div class="filetreeage">%s(zNow)</div> } @ </div> @ <ul> if( useMtime ){ p = sortTreeByMtime(sTree.pFirst); memset(&sTree, 0, sizeof(sTree)); relinkTree(&sTree, p); } for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ const char *zLastClass = p->pSibling==0 ? " last" : ""; if( p->pChild ){ const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : ""; @ <li class="dir%s(zSubdirClass)%s(zLastClass)"><div class="filetreeline"> @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> if( p->mtime>0.0 ){ char *zAge = human_readable_age(rNow - p->mtime); @ <div class="filetreeage">%s(zAge)</div> } @ </div> if( startExpanded || p->nFullName<=nD ){ @ <ul id="dir%d(nDir)"> }else{ @ <ul id="dir%d(nDir)" class="collapsed"> } nDir++; }else if( !showDirOnly ){ const char *zFileClass = fileext_class(p->zName); char *zLink; if( zCI ){ zLink = href("%R/artifact/%!S",p->zUuid); }else{ zLink = href("%R/finfo?name=%T",p->zFullName); } @ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline"> @ %z(zLink)%h(p->zName)</a> if( p->mtime>0 ){ char *zAge = human_readable_age(rNow - p->mtime); @ <div class="filetreeage">%s(zAge)</div> } @ </div> } if( p->pSibling==0 ){ int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); while( nClose-- > 0 ){ @ </ul> } } } @ </ul> @ </ul></div> style_load_one_js_file("tree.js"); style_footer(); /* We could free memory used by sTree here if we needed to. But ** the process is about to exit, so doing so would not really accomplish ** anything useful. */ } /* |
︙ | ︙ | |||
1036 1037 1038 1039 1040 1041 1042 | @ pathname TEXT @ ); @ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin; ; static const char zComputeFileAgeRun[] = @ WITH RECURSIVE | | | | | > | | 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 | @ pathname TEXT @ ); @ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin; ; static const char zComputeFileAgeRun[] = @ WITH RECURSIVE @ ckin(x,m) AS (SELECT objid, mtime FROM event WHERE objid=:ckin @ UNION @ SELECT plink.pid, event.mtime @ FROM ckin, plink, event @ WHERE plink.cid=ckin.x AND event.objid=plink.pid @ ORDER BY 2 DESC) @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname) @ SELECT filename.fnid, mlink.fid, mlink.mid, event.mtime, filename.name @ FROM foci, filename, blob, mlink, event @ WHERE foci.checkinID=:ckin @ AND foci.filename GLOB :glob @ AND filename.name=foci.filename @ AND blob.uuid=foci.uuid |
︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 | ** temporary table named "fileage" that contains the file-id for each ** files, the pathname, the check-in where the file was added, and the ** mtime on that check-in. If zGlob and *zGlob then only files matching ** the given glob are computed. */ int compute_fileage(int vid, const char* zGlob){ Stmt q; | | | 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 | ** temporary table named "fileage" that contains the file-id for each ** files, the pathname, the check-in where the file was added, and the ** mtime on that check-in. If zGlob and *zGlob then only files matching ** the given glob are computed. */ int compute_fileage(int vid, const char* zGlob){ Stmt q; db_multi_exec(zComputeFileAgeSetup /*works-like:"constant"*/); db_prepare(&q, zComputeFileAgeRun /*works-like:"constant"*/); db_bind_int(&q, ":ckin", vid); db_bind_text(&q, ":glob", zGlob && zGlob[0] ? zGlob : "*"); db_exec(&q); db_finalize(&q); return 0; } |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 | */ void fileage_page(void){ int rid; const char *zName; const char *zGlob; const char *zUuid; const char *zNow; /* Time of check-in */ | < < < < | < | < < < < | > | | > > | < > < | | | | < < < < < < < < < < < < < < < < < | 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 | */ void fileage_page(void){ int rid; const char *zName; const char *zGlob; const char *zUuid; const char *zNow; /* Time of check-in */ int showId = PB("showid"); Stmt q1, q2; double baseTime; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( exclude_spiders() ) return; zName = P("name"); if( zName==0 ) zName = "tip"; rid = symbolic_name_to_rid(zName, "ci"); if( rid==0 ){ fossil_fatal("not a valid check-in: %s", zName); } zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); baseTime = db_double(0.0,"SELECT mtime FROM event WHERE objid=%d", rid); zNow = db_text("", "SELECT datetime(mtime,toLocal()) FROM event" " WHERE objid=%d", rid); style_submenu_element("Tree-View", "%R/tree?ci=%T&mtime=1&type=tree", zName); style_header("File Ages"); zGlob = P("glob"); compute_fileage(rid,zGlob); db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);"); @ <h1>Files in @ %z(href("%R/info/%!S",zUuid))[%S(zUuid)]</a> if( zGlob && zGlob[0] ){ @ that match "%h(zGlob)" } @ ordered by age</h1> @ @ <p>File ages are expressed relative to the @ %z(href("%R/ci/%!S",zUuid))[%S(zUuid)]</a> check-in time of @ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p> @ @ <div class='fileage'><table> @ <tr><th>Age</th><th>Files</th><th>Check-in</th></tr> db_prepare(&q1, "SELECT event.mtime, event.objid, blob.uuid,\n" " coalesce(event.ecomment,event.comment),\n" " coalesce(event.euser,event.user),\n" " coalesce((SELECT value FROM tagxref\n" " WHERE tagtype>0 AND tagid=%d\n" " AND rid=event.objid),'trunk')\n" " FROM event, blob\n" " WHERE event.objid IN (SELECT mid FROM fileage)\n" " AND blob.rid=event.objid\n" " ORDER BY event.mtime DESC;", TAG_BRANCH ); db_prepare(&q2, "SELECT blob.uuid, filename.name, fileage.fid\n" " FROM fileage, blob, filename\n" " WHERE fileage.mid=:mid AND filename.fnid=fileage.fnid" " AND blob.rid=fileage.fid;" ); while( db_step(&q1)==SQLITE_ROW ){ double age = baseTime - db_column_double(&q1, 0); int mid = db_column_int(&q1, 1); const char *zUuid = db_column_text(&q1, 2); const char *zComment = db_column_text(&q1, 3); const char *zUser = db_column_text(&q1, 4); const char *zBranch = db_column_text(&q1, 5); char *zAge = human_readable_age(age); @ <tr><td>%s(zAge)</td> @ <td> db_bind_int(&q2, ":mid", mid); while( db_step(&q2)==SQLITE_ROW ){ const char *zFUuid = db_column_text(&q2,0); const char *zFile = db_column_text(&q2,1); int fid = db_column_int(&q2,2); if( showId ){ @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a> (%d(fid))<br /> }else{ @ %z(href("%R/artifact/%!S",zFUuid))%h(zFile)</a><br /> } } db_reset(&q2); @ </td> @ <td> @ %W(zComment) @ (check-in: %z(href("%R/ci/%!S",zUuid))%S(zUuid)</a>, if( showId ){ @ id: %d(mid) } @ user: %z(href("%R/timeline?u=%t&c=%!S&nd",zUser,zUuid))%h(zUser)</a>, @ branch: \ @ %z(href("%R/timeline?r=%t&c=%!S&nd",zBranch,zUuid))%h(zBranch)</a>) @ </td></tr> @ fossil_free(zAge); } @ </table></div> db_finalize(&q1); db_finalize(&q2); style_footer(); } |
Changes to src/builtin.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** The resources provided by this file are packaged by the "mkbuiltin.c" ** utility program during the built process and stored in the ** builtin_data.h file. Include that information here: */ #include "builtin_data.h" /* | | < < | | < < | | | < < < < < < < < < | | < < < < | < | < < < < < | | < < | | | 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 | ** The resources provided by this file are packaged by the "mkbuiltin.c" ** utility program during the built process and stored in the ** builtin_data.h file. Include that information here: */ #include "builtin_data.h" /* ** Return a pointer to built-in content */ const unsigned char *builtin_file(const char *zFilename, int *piSize){ int lwr, upr, i, c; lwr = 0; upr = count(aBuiltinFiles) - 1; while( upr>=lwr ){ i = (upr+lwr)/2; c = strcmp(aBuiltinFiles[i].zName,zFilename); if( c<0 ){ lwr = i+1; }else if( c>0 ){ upr = i-1; }else{ if( piSize ) *piSize = aBuiltinFiles[i].nByte; return aBuiltinFiles[i].pData; } } if( piSize ) *piSize = 0; return 0; } const char *builtin_text(const char *zFilename){ return (char*)builtin_file(zFilename, 0); } /* ** COMMAND: test-builtin-list ** ** List the names and sizes of all built-in resources. */ void test_builtin_list(void){ int i; for(i=0; i<count(aBuiltinFiles); i++){ fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,aBuiltinFiles[i].nByte); } } /* ** WEBPAGE: test-builtin-files ** ** Show all built-in text files. */ void test_builtin_list_page(void){ int i; style_header("Built-in Text Files"); @ <ul> for(i=0; i<count(aBuiltinFiles); i++){ const char *z = aBuiltinFiles[i].zName; @ <li>%z(href("%R/builtin?name=%T&id=%S",z,MANIFEST_UUID))%h(z)</a> } @ </ul> style_footer(); } /* ** COMMAND: test-builtin-get ** ** Usage: %fossil test-builtin-get NAME ?OUTPUT-FILE? */ |
︙ | ︙ | |||
125 126 127 128 129 130 131 | if( pData==0 ){ fossil_fatal("no such built-in file: [%s]", g.argv[2]); } blob_init(&x, (const char*)pData, nByte); blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-"); blob_reset(&x); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 100 101 102 103 104 105 106 | if( pData==0 ){ fossil_fatal("no such built-in file: [%s]", g.argv[2]); } blob_init(&x, (const char*)pData, nByte); blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-"); blob_reset(&x); } |
Changes to src/bundle.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | /* ** SQL code used to initialize the schema of a bundle. ** ** The bblob.delta field can be an integer, a text string, or NULL. ** If an integer, then the corresponding blobid is the delta basis. ** If a text string, then that string is a SHA1 hash for the delta | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /* ** SQL code used to initialize the schema of a bundle. ** ** The bblob.delta field can be an integer, a text string, or NULL. ** If an integer, then the corresponding blobid is the delta basis. ** If a text string, then that string is a SHA1 hash for the delta ** basis, which is presumably in the master repository. If NULL, then ** data contains content without delta compression. */ static const char zBundleInit[] = @ CREATE TABLE IF NOT EXISTS "%w".bconfig( @ bcname TEXT, @ bcvalue ANY @ ); |
︙ | ︙ | |||
58 59 60 61 62 63 64 | char *zErrMsg = 0; char *zSql; if( !doInit && file_size(zFile, ExtFILE)<0 ){ fossil_fatal("no such file: %s", zFile); } assert( g.db ); zSql = sqlite3_mprintf("ATTACH %Q AS %Q", zFile, zBName); | | | | | 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 | char *zErrMsg = 0; char *zSql; if( !doInit && file_size(zFile, ExtFILE)<0 ){ fossil_fatal("no such file: %s", zFile); } assert( g.db ); zSql = sqlite3_mprintf("ATTACH %Q AS %Q", zFile, zBName); if( zSql==0 ) fossil_panic("out of memory"); rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); sqlite3_free(zSql); if( rc!=SQLITE_OK || zErrMsg ){ if( zErrMsg==0 ) zErrMsg = (char*)sqlite3_errmsg(g.db); fossil_fatal("not a valid bundle: %s", zFile); } if( doInit ){ db_multi_exec(zBundleInit /*works-like:"%w%w"*/, zBName, zBName); }else{ sqlite3_stmt *pStmt; zSql = sqlite3_mprintf("SELECT bcname, bcvalue" " FROM \"%w\".bconfig", zBName); if( zSql==0 ) fossil_panic("out of memory"); rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, 0); if( rc ) fossil_fatal("not a valid bundle: %s", zFile); sqlite3_free(zSql); sqlite3_finalize(pStmt); zSql = sqlite3_mprintf("SELECT blobid, uuid, sz, delta, notes, data" " FROM \"%w\".bblob", zBName); if( zSql==0 ) fossil_panic("out of memory"); rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, 0); if( rc ) fossil_fatal("not a valid bundle: %s", zFile); sqlite3_free(zSql); sqlite3_finalize(pStmt); } } |
︙ | ︙ | |||
112 113 114 115 116 117 118 | fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1)); } db_finalize(&q); fossil_print("%.78c\n",'-'); if( bDetails ){ db_prepare(&q, "SELECT blobid, substr(uuid,1,10), coalesce(substr(delta,1,10),'')," | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1)); } db_finalize(&q); fossil_print("%.78c\n",'-'); if( bDetails ){ db_prepare(&q, "SELECT blobid, substr(uuid,1,10), coalesce(substr(delta,1,10),'')," " sz, length(data), notes" " FROM bblob" ); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%4d %10s %10s %8d %8d %s\n", db_column_int(&q,0), db_column_text(&q,1), db_column_text(&q,2), |
︙ | ︙ | |||
144 145 146 147 148 149 150 | db_finalize(&q); } } /* ** Implement the "fossil bundle append BUNDLE FILE..." command. Add ** the named files into the BUNDLE. Create the BUNDLE if it does not | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | db_finalize(&q); } } /* ** Implement the "fossil bundle append BUNDLE FILE..." command. Add ** the named files into the BUNDLE. Create the BUNDLE if it does not ** alraedy exist. */ static void bundle_append_cmd(void){ Blob content, hash; int i; Stmt q; verify_all_options(); |
︙ | ︙ | |||
528 529 530 531 532 533 534 | fossil_fatal("incorrect hash for artifact %b", &h1); } blob_reset(&h1); bag_remove(&busy, blobid); db_finalize(&q); } | | | | | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | fossil_fatal("incorrect hash for artifact %b", &h1); } blob_reset(&h1); bag_remove(&busy, blobid); db_finalize(&q); } /* fossil bundle cat BUNDLE UUID... ** ** Write elements of a bundle on standard output */ static void bundle_cat_cmd(void){ int i; Blob x; verify_all_options(); if( g.argc<5 ) usage("cat BUNDLE UUID..."); bundle_attach_file(g.argv[3], "b1", 1); blob_zero(&x); for(i=4; i<g.argc; i++){ int blobid = db_int(0,"SELECT blobid FROM bblob WHERE uuid LIKE '%q%%'", g.argv[i]); if( blobid==0 ){ fossil_fatal("no such artifact in bundle: %s", g.argv[i]); } |
︙ | ︙ | |||
567 568 569 570 571 572 573 | */ static void bundle_import_cmd(void){ int forceFlag = find_option("force","f",0)!=0; int isPriv = find_option("publish",0,0)==0; char *zMissingDeltas; verify_all_options(); if ( g.argc!=4 ) usage("import BUNDLE ?OPTIONS?"); | | | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | */ static void bundle_import_cmd(void){ int forceFlag = find_option("force","f",0)!=0; int isPriv = find_option("publish",0,0)==0; char *zMissingDeltas; verify_all_options(); if ( g.argc!=4 ) usage("import BUNDLE ?OPTIONS?"); bundle_attach_file(g.argv[3], "b1", 1); /* Only import a bundle that was generated from a repo with the same ** project code, unless the --force flag is true */ if( !forceFlag ){ if( !db_exists("SELECT 1 FROM config, bconfig" " WHERE config.name='project-code'" " AND bconfig.bcname='project-code'" |
︙ | ︙ | |||
589 590 591 592 593 594 595 | /* If the bundle contains deltas with a basis that is external to the ** bundle and those external basis files are missing from the local ** repo, then the delta encodings cannot be decoded and the bundle cannot ** be extracted. */ zMissingDeltas = db_text(0, "SELECT group_concat(substr(delta,1,10),' ')" " FROM bblob" | | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | /* If the bundle contains deltas with a basis that is external to the ** bundle and those external basis files are missing from the local ** repo, then the delta encodings cannot be decoded and the bundle cannot ** be extracted. */ zMissingDeltas = db_text(0, "SELECT group_concat(substr(delta,1,10),' ')" " FROM bblob" " WHERE typeof(delta)='text' AND length(delta)>=%d" " AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)", HNAME_MIN); if( zMissingDeltas && zMissingDeltas[0] ){ fossil_fatal("delta basis artifacts not found in repository: %s", zMissingDeltas); } |
︙ | ︙ | |||
714 715 716 717 718 719 720 | }else{ purge_artifact_list("ok",0,0); } db_end_transaction(0); } /* | | | | | | | | | | | | > > > > > > > > > > > > > > | | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 | }else{ purge_artifact_list("ok",0,0); } db_end_transaction(0); } /* ** COMMAND: bundle ** ** Usage: %fossil bundle SUBCOMMAND ARGS... ** ** fossil bundle append BUNDLE FILE... ** ** Add files named on the command line to BUNDLE. This subcommand has ** little practical use and is mostly intended for testing. ** ** fossil bundle cat BUNDLE UUID... ** ** Extract one or more artifacts from the bundle and write them ** consecutively on standard output. This subcommand was designed ** for testing and introspection of bundles and is not something ** commonly used. ** ** fossil bundle export BUNDLE ?OPTIONS? ** ** Generate a new bundle, in the file named BUNDLE, that contains a ** subset of the check-ins in the repository (usually a single branch) ** described by the --branch, --from, --to, and/or --checkin options, ** at least one of which is required. If BUNDLE already exists, the ** specified content is added to the bundle. ** ** --branch BRANCH Package all check-ins on BRANCH. ** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2. ** --checkin TAG Package the single check-in TAG ** --standalone Do no use delta-encoding against ** artifacts not in the bundle ** ** fossil bundle extend BUNDLE ** ** The BUNDLE must already exist. This subcommand adds to the bundle ** any check-ins that are descendants of check-ins already in the bundle, ** and any tags that apply to artifacts in the bundle. ** ** fossil bundle import BUNDLE ?--publish? ** ** Import all content from BUNDLE into the repository. By default, the ** imported files are private and will not sync. Use the --publish ** option to make the import public. ** ** fossil bundle ls BUNDLE ** ** List the contents of BUNDLE on standard output ** ** fossil bundle purge BUNDLE ** ** Remove from the repository all files that are used exclusively ** by check-ins in BUNDLE. This has the effect of undoing a ** "fossil bundle import". ** ** SUMMARY: ** fossil bundle append BUNDLE FILE... Add files to BUNDLE ** fossil bundle cat BUNDLE UUID... Extract file from BUNDLE ** fossil bundle export BUNDLE ?OPTIONS? Create a new BUNDLE ** --branch BRANCH --from TAG1 --to TAG2 Check-ins to include ** --checkin TAG Use only check-in TAG ** --standalone Omit dependencies ** fossil bundle extend BUNDLE Update with newer content ** fossil bundle import BUNDLE ?OPTIONS? Import a bundle ** --publish Publish the import ** --force Cross-repo import ** fossil bundle ls BUNDLE List content of a bundle ** fossil bundle purge BUNDLE Undo an import ** ** See also: publish */ void bundle_cmd(void){ const char *zSubcmd; int n; if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?OPTIONS?"); zSubcmd = g.argv[2]; db_find_and_open_repository(0,0); |
︙ | ︙ |
Changes to src/cache.c.
︙ | ︙ | |||
195 196 197 198 199 200 201 | cache_write_end: sqlite3_finalize(pStmt); sqlite3_exec(db, rc ? "COMMIT" : "ROLLBACK", 0, 0, 0); sqlite3_close(db); } | < < < < < < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | cache_write_end: sqlite3_finalize(pStmt); sqlite3_exec(db, rc ? "COMMIT" : "ROLLBACK", 0, 0, 0); sqlite3_close(db); } /* ** Attempt to read content out of the cache with the given zKey. Return ** non-zero on success and zero if unable to locate the content. ** ** Possible reasons for returning zero: ** (1) This server does not implement a cache ** (2) The requested element is not in the cache |
︙ | ︙ | |||
267 268 269 270 271 272 273 | ** clear Remove all entries from the cache. ** ** init Create the cache file if it does not already exist. ** ** list|ls List the keys and content sizes and other stats for ** all entries currently in the cache. ** | < < | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | ** clear Remove all entries from the cache. ** ** init Create the cache file if it does not already exist. ** ** list|ls List the keys and content sizes and other stats for ** all entries currently in the cache. ** ** status Show a summary of the cache status. ** ** The cache is stored in a file that is distinct from the repository ** but that is held in the same directory as the repository. The cache ** file can be deleted in order to completely disable the cache. */ void cache_cmd(void){ |
︙ | ︙ | |||
310 311 312 313 314 315 316 | if( db ){ sqlite3_exec(db, "DELETE FROM cache; DELETE FROM blob; VACUUM;",0,0,0); sqlite3_close(db); fossil_print("cache cleared\n"); }else{ fossil_print("nothing to clear; cache does not exist\n"); } | | | < < < | | | | | < | < < < < < < < | < | < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | | | < < < < < < < | | < < < < < < | < | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | if( db ){ sqlite3_exec(db, "DELETE FROM cache; DELETE FROM blob; VACUUM;",0,0,0); sqlite3_close(db); fossil_print("cache cleared\n"); }else{ fossil_print("nothing to clear; cache does not exist\n"); } }else if(( strncmp(zCmd, "list", nCmd)==0 ) || ( strncmp(zCmd, "ls", nCmd)==0 )){ db = cacheOpen(0); if( db==0 ){ fossil_print("cache does not exist\n"); }else{ int nEntry = 0; char *zDbName = cacheName(); cache_register_sizename(db); pStmt = cacheStmt(db, "SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')" " FROM cache" " ORDER BY tm DESC" ); if( pStmt ){ while( sqlite3_step(pStmt)==SQLITE_ROW ){ fossil_print("%s %4d %8s %s\n", sqlite3_column_text(pStmt, 3), sqlite3_column_int(pStmt, 2), sqlite3_column_text(pStmt, 1), sqlite3_column_text(pStmt, 0)); nEntry++; } sqlite3_finalize(pStmt); } sqlite3_close(db); fossil_print("Entries: %d Cache-file Size: %lld\n", nEntry, file_size(zDbName, ExtFILE)); fossil_free(zDbName); } }else if( strncmp(zCmd, "status", nCmd)==0 ){ fossil_print("TBD...\n"); }else{ fossil_fatal("Unknown subcommand \"%s\"." " Should be one of: clear init list status", zCmd); } } /* ** WEBPAGE: cachestat ** ** Show information about the webpage cache. Requires Admin privilege. */ void cache_page(void){ sqlite3 *db; sqlite3_stmt *pStmt; char zBuf[100]; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Web Cache Status"); db = cacheOpen(0); if( db==0 ){ @ The web-page cache is disabled for this repository }else{ char *zDbName = cacheName(); cache_register_sizename(db); pStmt = cacheStmt(db, "SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')" " FROM cache" " ORDER BY (tm + 3600*min(nRef,48)) DESC" ); if( pStmt ){ @ <ol> while( sqlite3_step(pStmt)==SQLITE_ROW ){ const unsigned char *zName = sqlite3_column_text(pStmt,0); @ <li><p>%z(href("%R/cacheget?key=%T",zName))%h(zName)</a><br /> @ size: %s(sqlite3_column_text(pStmt,1)) @ hit-count: %d(sqlite3_column_int(pStmt,2)) @ last-access: %s(sqlite3_column_text(pStmt,3))</p></li> } sqlite3_finalize(pStmt); @ </ol> } zDbName = cacheName(); bigSizeName(sizeof(zBuf), zBuf, file_size(zDbName, ExtFILE)); @ <p>cache-file name: %h(zDbName)</p> @ <p>cache-file size: %s(zBuf)</p> fossil_free(zDbName); sqlite3_close(db); } style_footer(); } /* ** WEBPAGE: cacheget ** ** Usage: /cacheget?key=KEY ** ** Download a single entry for the cache, identified by KEY. ** This page is normally a hyperlink from the /cachestat page. ** Requires Admin privilege. */ void cache_getpage(void){ const char *zKey; Blob content; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } zKey = PD("key",""); blob_zero(&content); if( cache_read(&content, zKey)==0 ){ style_header("Cache Download Error"); @ The cache does not contain any entry with this key: "%h(zKey)" style_footer(); return; } cgi_set_content(&content); cgi_set_content_type("application/x-compressed"); } |
Changes to src/capabilities.c.
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** Delete a CapabilityString object. */ void capability_free(CapabilityString *p){ fossil_free(p); } /* | | < < < < | 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 | ** Delete a CapabilityString object. */ void capability_free(CapabilityString *p){ fossil_free(p); } /* ** Expand the capability string by including all capabilities for ** special users "nobody" and "anonymous". Also include "reader" ** if "u" is present and "developer" if "v" is present. */ void capability_expand(CapabilityString *pIn){ static char *zNobody = 0; static char *zAnon = 0; static char *zReader = 0; static char *zDev = 0; int doneV = 0; if( pIn==0 ){ fossil_free(zNobody); zNobody = 0; fossil_free(zAnon); zAnon = 0; fossil_free(zReader); zReader = 0; fossil_free(zDev); zDev = 0; return; } if( zNobody==0 ){ zNobody = db_text(0, "SELECT cap FROM user WHERE login='nobody'"); zAnon = db_text(0, "SELECT cap FROM user WHERE login='anonymous'"); zReader = db_text(0, "SELECT cap FROM user WHERE login='reader'"); zDev = db_text(0, "SELECT cap FROM user WHERE login='developer'"); } pIn = capability_add(pIn, zAnon); pIn = capability_add(pIn, zNobody); if( pIn->x['v'] ){ pIn = capability_add(pIn, zDev); doneV = 1; } if( pIn->x['u'] ){ pIn = capability_add(pIn, zReader); if( pIn->x['v'] && !doneV ){ |
︙ | ︙ | |||
237 238 239 240 241 242 243 | unsigned nUser; /* Number of users with this capability */ char *zAbbrev; /* Abbreviated mnemonic name */ char *zOneLiner; /* One-line summary */ } aCap[] = { { 'a', CAPCLASS_SUPER, 0, "Admin", "Create and delete users" }, { 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0, | | < > | < < | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | unsigned nUser; /* Number of users with this capability */ char *zAbbrev; /* Abbreviated mnemonic name */ char *zOneLiner; /* One-line summary */ } aCap[] = { { 'a', CAPCLASS_SUPER, 0, "Admin", "Create and delete users" }, { 'b', CAPCLASS_WIKI|CAPCLASS_TKT, 0, "Attach", "Add attchments to wiki or tickets" }, { 'c', CAPCLASS_TKT, 0, "Append-Tkt", "Append to existing tickets" }, { 'd', CAPCLASS_WIKI|CAPCLASS_TKT, 0, "Delete", "Delete wiki or tickets" }, { 'e', CAPCLASS_DATA, 0, "View-PII", "View sensitive info such as email addresses" }, { 'f', CAPCLASS_WIKI, 0, "New-Wiki", "Create new wiki pages" }, { 'g', CAPCLASS_DATA, 0, "Clone", "Clone the repository" }, { 'h', CAPCLASS_OTHER, 0, |
︙ | ︙ | |||
273 274 275 276 277 278 279 | { 'p', CAPCLASS_OTHER, 0, "Password", "Change your own password" }, { 'q', CAPCLASS_TKT|CAPCLASS_SUPER, 0, "Mod-Tkt", "Moderate tickets" }, { 'r', CAPCLASS_TKT, 0, "Read-Tkt", "View tickets" }, { 's', CAPCLASS_SUPER, 0, | | | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | { 'p', CAPCLASS_OTHER, 0, "Password", "Change your own password" }, { 'q', CAPCLASS_TKT|CAPCLASS_SUPER, 0, "Mod-Tkt", "Moderate tickets" }, { 'r', CAPCLASS_TKT, 0, "Read-Tkt", "View tickets" }, { 's', CAPCLASS_SUPER, 0, "Superuser", "Setup and configure the respository" }, { 't', CAPCLASS_TKT, 0, "Reports", "Create new ticket report formats" }, { 'u', CAPCLASS_OTHER, 0, "Reader", "Inherit all the capabilities of the \"reader\" user" }, { 'v', CAPCLASS_OTHER, 0, "Developer", "Inherit all capabilities of the \"developer\" user" }, { 'w', CAPCLASS_TKT, 0, |
︙ | ︙ | |||
297 298 299 300 301 302 303 | { '3', CAPCLASS_FORUM, 0, "Forum-Write", "Create new forum messages" }, { '4', CAPCLASS_FORUM, 0, "Forum-Trusted", "Create forum messages that bypass moderation" }, { '5', CAPCLASS_FORUM|CAPCLASS_SUPER, 0, "Forum-Mod", "Moderator for forum messages" }, { '6', CAPCLASS_FORUM|CAPCLASS_SUPER, 0, | | < < | | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | { '3', CAPCLASS_FORUM, 0, "Forum-Write", "Create new forum messages" }, { '4', CAPCLASS_FORUM, 0, "Forum-Trusted", "Create forum messages that bypass moderation" }, { '5', CAPCLASS_FORUM|CAPCLASS_SUPER, 0, "Forum-Mod", "Moderator for forum messages" }, { '6', CAPCLASS_FORUM|CAPCLASS_SUPER, 0, "Forum-Admin", "Set or remove capability '4' from other users" }, { '7', CAPCLASS_ALERT, 0, "Alerts", "Sign up for email alerts" }, { 'A', CAPCLASS_ALERT|CAPCLASS_SUPER, 0, "Announce", "Send announcements to all subscribers" }, { 'D', CAPCLASS_OTHER, 0, "Debug", "Enable debugging features" }, }; /* ** Populate the aCap[].nUser values based on the current content ** of the USER table. */ void capabilities_count(void){ int i; static int done = 0; Stmt q; if( done ) return; db_prepare(&q, "SELECT fullcap(cap) FROM user"); while( db_step(&q)==SQLITE_ROW ){ const char *zCap = db_column_text(&q, 0); if( zCap==0 || zCap[0]==0 ) continue; for(i=0; i<sizeof(aCap)/sizeof(aCap[0]); i++){ if( strchr(zCap, aCap[i].cCap) ) aCap[i].nUser++; } } db_finalize(&q); done = 1; } /* ** Generate HTML that lists all of the capability letters together with ** a brief summary of what each letter means. */ void capabilities_table(unsigned mClass){ int i; if( g.perm.Admin ) capabilities_count(); @ <table> @ <tbody> for(i=0; i<sizeof(aCap)/sizeof(aCap[0]); i++){ int n; if( (aCap[i].eClass & mClass)==0 ) continue; @ <tr><th valign="top">%c(aCap[i].cCap)</th> @ <td>%h(aCap[i].zAbbrev)</td><td>%h(aCap[i].zOneLiner)</td>\ n = aCap[i].nUser; if( n && g.perm.Admin ){ @ <td><a href="%R/setup_ulist?with=%c(aCap[i].cCap)">\ |
︙ | ︙ | |||
361 362 363 364 365 366 367 | /* ** Generate a "capability summary table" that shows the major capabilities ** against the various user categories. */ void capability_summary(void){ Stmt q; | < < < < < < < < < < < | < < | | | | < > | | < | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | /* ** Generate a "capability summary table" that shows the major capabilities ** against the various user categories. */ void capability_summary(void){ Stmt q; db_prepare(&q, "WITH t(id,seq) AS (VALUES('nobody',1),('anonymous',2),('reader',3)," "('developer',4))" " SELECT id, fullcap(user.cap),seq,1" " FROM t LEFT JOIN user ON t.id=user.login" " UNION ALL" " SELECT 'New User Default', fullcap(%Q), 10, 1" " UNION ALL" " SELECT 'Regular User', fullcap(capunion(cap)), 20, count(*) FROM user" " WHERE cap NOT GLOB '*[as]*'" " UNION ALL" " SELECT 'Adminstator', fullcap(capunion(cap)), 30, count(*) FROM user" " WHERE cap GLOB '*[as]*'" " ORDER BY 3 ASC", db_get("default-perms","") ); @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1"> @ <tr><th> <th>Code<th>Forum<th>Tickets<th>Wiki\ @ <th>Unversioned Content</th></tr> while( db_step(&q)==SQLITE_ROW ){ const char *zId = db_column_text(&q, 0); const char *zCap = db_column_text(&q, 1); int n = db_column_int(&q, 3); int eType; static const char *azType[] = { "off", "read", "write" }; static const char *azClass[] = { "capsumOff", "capsumRead", "capsumWrite" }; if( n==0 ) continue; /* Code */ if( db_column_int(&q,2)<10 ){ @ <tr><th align="right"><tt>"%h(zId)"</tt></th> }else if( n>1 ){ |
︙ | ︙ | |||
432 433 434 435 436 437 438 | eType = 1; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Ticket */ | | < < < < < < < < | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | eType = 1; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Ticket */ if( sqlite3_strglob("*[ascdnqtw]*",zCap)==0 ){ eType = 2; }else if( sqlite3_strglob("*r*",zCap)==0 ){ eType = 1; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Wiki */ if( sqlite3_strglob("*[asdfklm]*",zCap)==0 ){ eType = 2; }else if( sqlite3_strglob("*j*",zCap)==0 ){ eType = 1; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Unversioned */ if( sqlite3_strglob("*y*",zCap)==0 ){ eType = 2; |
︙ | ︙ |
Changes to src/captcha.c.
︙ | ︙ | |||
456 457 458 459 460 461 462 | const char *zSecret; const char *z; Blob b; static char zRes[20]; zSecret = db_get("captcha-secret", 0); if( zSecret==0 ){ | < < | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | const char *zSecret; const char *z; Blob b; static char zRes[20]; zSecret = db_get("captcha-secret", 0); if( zSecret==0 ){ db_multi_exec( "REPLACE INTO config(name,value)" " VALUES('captcha-secret', lower(hex(randomblob(20))));" ); zSecret = db_get("captcha-secret", 0); assert( zSecret!=0 ); } blob_init(&b, 0, 0); blob_appendf(&b, "%s-%x", zSecret, seed); sha1sum_blob(&b, &b); z = blob_buffer(&b); |
︙ | ︙ | |||
512 513 514 515 516 517 518 519 520 521 522 523 524 525 | } zSeed = P("captchaseed"); if( zSeed==0 ) return 0; zEntered = P("captcha"); if( zEntered==0 || strlen(zEntered)!=8 ) return 0; zDecode = captcha_decode((unsigned int)atoi(zSeed)); assert( strlen(zDecode)==8 ); for(i=0; i<8; i++){ char c = zEntered[i]; if( c>='A' && c<='F' ) c += 'a' - 'A'; if( c=='O' ) c = '0'; z[i] = c; } if( strncmp(zDecode,z,8)!=0 ) return 0; | > | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | } zSeed = P("captchaseed"); if( zSeed==0 ) return 0; zEntered = P("captcha"); if( zEntered==0 || strlen(zEntered)!=8 ) return 0; zDecode = captcha_decode((unsigned int)atoi(zSeed)); assert( strlen(zDecode)==8 ); if( strlen(zEntered)!=8 ) return 0; for(i=0; i<8; i++){ char c = zEntered[i]; if( c>='A' && c<='F' ) c += 'a' - 'A'; if( c=='O' ) c = '0'; z[i] = c; } if( strncmp(zDecode,z,8)!=0 ) return 0; |
︙ | ︙ | |||
542 543 544 545 546 547 548 | uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter security code shown above: | | | < < < < < < < < < < < < < < < < < < < < < | | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter security code shown above: @ <input type="hidden" name="captchaseed" value="%u(uSeed)" /> @ <input type="text" name="captcha" size=8 /> if( showButton ){ @ <input type="submit" value="Submit"> } @ </td></tr></table></div> } /* ** WEBPAGE: test-captcha ** Test the captcha-generator by rendering the value of the name= query ** parameter using ascii-art. If name= is omitted, show a random 16-digit ** hexadecimal number. */ void captcha_test(void){ const char *zPw = P("name"); if( zPw==0 || zPw[0]==0 ){ u64 x; sqlite3_randomness(sizeof(x), &x); zPw = mprintf("%016llx", x); } style_header("Captcha Test"); @ <pre> @ %s(captcha_render(zPw)) @ </pre> style_footer(); } /* ** Check to see if the current request is coming from an agent that might ** be a spider. If the agent is not a spider, then return 0 without doing ** anything. But if the user agent appears to be a spider, offer ** a captcha challenge to allow the user agent to prove that it is human |
︙ | ︙ | |||
619 620 621 622 623 624 625 | if( zCookieValue && atoi(zCookieValue)==1 ) return 0; if( captcha_is_correct(0) ){ cgi_set_cookie(zCookieName, "1", login_cookie_path(), 8*3600); return 0; } /* This appears to be a spider. Offer the captcha */ | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | if( zCookieValue && atoi(zCookieValue)==1 ) return 0; if( captcha_is_correct(0) ){ cgi_set_cookie(zCookieName, "1", login_cookie_path(), 8*3600); return 0; } /* This appears to be a spider. Offer the captcha */ style_header("Verification"); @ <form method='POST' action='%s(g.zPath)'> cgi_query_parameters_to_hidden(); @ <p>Please demonstrate that you are human, not a spider or robot</p> captcha_generate(1); @ </form> style_footer(); return 1; } |
Changes to src/cgi.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < | < < < < < < < < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains C functions and procedures that provide useful ** services to CGI programs. There are procedures for parsing and ** dispensing QUERY_STRING parameters and cookies, the "mprintf()" ** formatting function and its cousins, and routines to encode and ** decode strings in HTML or HTTP. */ #include "config.h" #ifdef _WIN32 # if !defined(_WIN32_WINNT) # define _WIN32_WINNT 0x0501 # endif # include <winsock2.h> |
︙ | ︙ | |||
82 83 84 85 86 87 88 | #ifdef __EMX__ typedef int socklen_t; #endif #include <time.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> | < | | | | | | | < < < < < < < < < < < < < | < < < < < < < < < < < | 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 | #ifdef __EMX__ typedef int socklen_t; #endif #include <time.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "cgi.h" #include "cygsup.h" #if INTERFACE /* ** Shortcuts for cgi_parameter. P("x") returns the value of query parameter ** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y") ** does the same except "y" is returned in place of NULL if there is not match. */ #define P(x) cgi_parameter((x),0) #define PD(x,y) cgi_parameter((x),(y)) #define PT(x) cgi_parameter_trimmed((x),0) #define PDT(x,y) cgi_parameter_trimmed((x),(y)) #define PB(x) cgi_parameter_boolean(x) #define PCK(x) cgi_parameter_checked(x,1) #define PIF(x,y) cgi_parameter_checked(x,y) /* ** Destinations for output text. */ #define CGI_HEADER 0 #define CGI_BODY 1 /* ** Flags for SSH HTTP clients */ #define CGI_SSH_CLIENT 0x0001 /* Client is SSH */ #define CGI_SSH_COMPAT 0x0002 /* Compat for old SSH transport */ #define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */ #endif /* INTERFACE */ /* ** The HTTP reply is generated in two pieces: the header and the body. ** These pieces are generated separately because they are not necessarily ** produced in order. Parts of the header might be built after all or ** part of the body. The header and body are accumulated in separate ** Blob structures then output sequentially once everything has been ** built. ** ** The cgi_destination() interface switches between the buffers. */ static Blob cgiContent[2] = { BLOB_INITIALIZER, BLOB_INITIALIZER }; static Blob *pContent = &cgiContent[0]; /* ** Set the destination buffer into which to accumulate CGI content. |
︙ | ︙ | |||
173 174 175 176 177 178 179 | default: { cgi_panic("bad destination"); } } } /* | | | | | | < < < < < < < | < < | | | < < | < < < < | | < < < | | < < < < < < | < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < | < < < | | < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | | | | < | < < < < < < < < < < < < < | | > > > | > > > > | | | < | > > | | | | | > | | | < < < < < | | < < | < | < < < < < < | < < | | < | | < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | default: { cgi_panic("bad destination"); } } } /* ** Check to see if the header contains the zNeedle string. Return true ** if it does and false if it does not. */ int cgi_header_contains(const char *zNeedle){ return strstr(blob_str(&cgiContent[0]), zNeedle)!=0; } int cgi_body_contains(const char *zNeedle){ return strstr(blob_str(&cgiContent[1]), zNeedle)!=0; } /* ** Append reply content to what already exists. */ void cgi_append_content(const char *zData, int nAmt){ blob_append(pContent, zData, nAmt); } /* ** Reset the HTTP reply text to be an empty string. */ void cgi_reset_content(void){ blob_reset(&cgiContent[0]); blob_reset(&cgiContent[1]); } /* ** Return a pointer to the CGI output blob. */ Blob *cgi_output_blob(void){ return pContent; } /* ** Combine the header and body of the CGI into a single string. */ static void cgi_combine_header_and_body(void){ int size = blob_size(&cgiContent[1]); if( size>0 ){ blob_append(&cgiContent[0], blob_buffer(&cgiContent[1]), size); blob_reset(&cgiContent[1]); } } /* ** Return a pointer to the HTTP reply text. */ char *cgi_extract_content(void){ cgi_combine_header_and_body(); return blob_buffer(&cgiContent[0]); } /* ** Additional information used to form the HTTP reply */ static char *zContentType = "text/html"; /* Content type of the reply */ static char *zReplyStatus = "OK"; /* Reply status description */ static int iReplyStatus = 200; /* Reply status code */ static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ /* ** Set the reply content type */ void cgi_set_content_type(const char *zType){ zContentType = mprintf("%s", zType); } /* ** Set the reply content to the specified BLOB. */ void cgi_set_content(Blob *pNewContent){ cgi_reset_content(); cgi_destination(CGI_HEADER); cgiContent[0] = *pNewContent; blob_zero(pNewContent); } /* ** Set the reply status code */ void cgi_set_status(int iStat, const char *zStat){ zReplyStatus = mprintf("%s", zStat); iReplyStatus = iStat; } /* ** Append text to the header of an HTTP reply */ void cgi_append_header(const char *zLine){ blob_append(&extraHeader, zLine, -1); } /* ** Set a cookie by queuing up the appropriate HTTP header output. If ** !g.isHTTP, this is a no-op. ** ** Zero lifetime implies a session cookie. */ void cgi_set_cookie( const char *zName, /* Name of the cookie */ const char *zValue, /* Value of the cookie. Automatically escaped */ const char *zPath, /* Path cookie applies to. NULL means "/" */ int lifetime /* Expiration of the cookie in seconds from now */ ){ char const *zSecure = ""; if(!g.isHTTP) return /* e.g. JSON CLI mode, where g.zTop is not set */; else if( zPath==0 ){ zPath = g.zTop; if( zPath[0]==0 ) zPath = "/"; } if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){ zSecure = " secure;"; } if( lifetime>0 ){ blob_appendf(&extraHeader, "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly;%s Version=1\r\n", zName, zValue, zPath, lifetime, zSecure); }else{ blob_appendf(&extraHeader, "Set-Cookie: %s=%t; Path=%s; HttpOnly;%s Version=1\r\n", zName, zValue, zPath, zSecure); } } /* ** Return true if the response should be sent with Content-Encoding: gzip. */ static int is_gzippable(void){ if( g.fNoHttpCompress ) return 0; if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; return strncmp(zContentType, "text/", 5)==0 || sqlite3_strglob("application/*xml", zContentType)==0 || sqlite3_strglob("application/*javascript", zContentType)==0; } /* ** Do a normal HTTP reply */ void cgi_reply(void){ int total_size; if( iReplyStatus<=0 ){ iReplyStatus = 200; zReplyStatus = "OK"; } if( g.fullHttpReply ){ fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus); fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0))); fprintf(g.httpOut, "Connection: close\r\n"); fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n"); }else{ fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus); } if( g.isConst ){ /* isConst means that the reply is guaranteed to be invariant, even ** after configuration changes and/or Fossil binary recompiles. */ fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n"); }else if( etag_tag()!=0 ){ fprintf(g.httpOut, "ETag: %s\r\n", etag_tag()); fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage()); }else{ fprintf(g.httpOut, "Cache-control: no-cache\r\n"); } if( etag_mtime()>0 ){ fprintf(g.httpOut, "Last-Modified: %s\r\n", cgi_rfc822_datestamp(etag_mtime())); } if( blob_size(&extraHeader)>0 ){ fprintf(g.httpOut, "%s", blob_buffer(&extraHeader)); } /* Add headers to turn on useful security options in browsers. */ fprintf(g.httpOut, "X-Frame-Options: SAMEORIGIN\r\n"); /* This stops fossil pages appearing in frames or iframes, preventing ** click-jacking attacks on supporting browsers. ** ** Other good headers would be ** Strict-Transport-Security: max-age=62208000 ** if we're using https. However, this would break sites which serve different ** content on http and https protocols. Also, ** X-Content-Security-Policy: allow 'self' ** would help mitigate some XSS and data injection attacks, but will break ** deliberate inclusion of external resources, such as JavaScript syntax ** highlighter scripts. ** ** These headers are probably best added by the web server hosting fossil as ** a CGI script. */ /* Content intended for logged in users should only be cached in ** the browser, not some shared location. */ fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType); if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ cgi_combine_header_and_body(); blob_compress(&cgiContent[0], &cgiContent[0]); } if( iReplyStatus != 304 ) { if( is_gzippable() ){ int i; gzip_begin(0); for( i=0; i<2; i++ ){ int size = blob_size(&cgiContent[i]); if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size); blob_reset(&cgiContent[i]); } gzip_finish(&cgiContent[0]); fprintf(g.httpOut, "Content-Encoding: gzip\r\n"); fprintf(g.httpOut, "Vary: Accept-Encoding\r\n"); } total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]); fprintf(g.httpOut, "Content-Length: %d\r\n", total_size); }else{ total_size = 0; } fprintf(g.httpOut, "\r\n"); if( total_size>0 && iReplyStatus != 304 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0 ){ int i, size; for(i=0; i<2; i++){ size = blob_size(&cgiContent[i]); if( size>0 ){ fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut); } } } fflush(g.httpOut); CGIDEBUG(("DONE\n")); /* After the webpage has been sent, do any useful background ** processing. */ g.cgiOutput = 2; if( g.db!=0 && iReplyStatus==200 ){ backoffice_check_if_needed(); } } /* ** Do a redirect request to the URL given in the argument. ** ** The URL must be relative to the base of the fossil server. */ NORETURN static void cgi_redirect_with_status( const char *zURL, int iStat, const char *zStat ){ char *zLocation; CGIDEBUG(("redirect to %s\n", zURL)); if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 ){ zLocation = mprintf("Location: %s\r\n", zURL); }else if( *zURL=='/' ){ int n1 = (int)strlen(g.zBaseURL); int n2 = (int)strlen(g.zTop); if( g.zBaseURL[n1-1]=='/' ) zURL++; zLocation = mprintf("Location: %.*s%s\r\n", n1-n2, g.zBaseURL, zURL); }else{ |
︙ | ︙ | |||
646 647 648 649 650 651 652 653 | NORETURN void cgi_redirectf(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); cgi_redirect(vmprintf(zFormat, ap)); va_end(ap); } /* | < < < < < < < < < < < < < < < < < < < < < | < | > > > > > | | | > | | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | NORETURN void cgi_redirectf(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); cgi_redirect(vmprintf(zFormat, ap)); va_end(ap); } /* ** Return the URL for the caller. This is obtained from either the ** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter. ** If neither exist, return zDefault. */ const char *cgi_referer(const char *zDefault){ const char *zRef = P("referer"); if( zRef==0 ){ zRef = P("HTTP_REFERER"); if( zRef==0 ) zRef = zDefault; } return zRef; } /* ** Return true if the current request appears to be safe from a ** Cross-Site Request Forgery (CSRF) attack. Conditions that must ** be met: ** ** * The HTTP_REFERER must have the same origin ** * The REQUEST_METHOD must be POST - or requirePost==0 */ int cgi_csrf_safe(int requirePost){ const char *zRef = P("HTTP_REFERER"); int nBase; if( zRef==0 ) return 0; if( requirePost ){ const char *zMethod = P("REQUEST_METHOD"); if( zMethod==0 ) return 0; if( strcmp(zMethod,"POST")!=0 ) return 0; } nBase = (int)strlen(g.zBaseURL); if( strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; return 1; } /* ** Information about all query parameters and cookies are stored ** in these variables. */ static int nAllocQP = 0; /* Space allocated for aParamQP[] */ static int nUsedQP = 0; /* Space actually used in aParamQP[] */ static int sortQP = 0; /* True if aParamQP[] needs sorting */ static int seqQP = 0; /* Sequence numbers */ static struct QParam { /* One entry for each query parameter or cookie */ const char *zName; /* Parameter or cookie name */ const char *zValue; /* Value of the query parameter or cookie */ int seq; /* Order of insertion */ char isQP; /* True for query parameters */ char cTag; /* Tag on query parameters */ } *aParamQP; /* An array of all parameters and cookies */ /* ** Add another query parameter or cookie to the parameter set. ** zName is the name of the query parameter or cookie and zValue ** is its fully decoded value. ** |
︙ | ︙ | |||
797 798 799 800 801 802 803 | aParamQP[nUsedQP].zValue = zValue; if( g.fHttpTrace ){ fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue); } aParamQP[nUsedQP].seq = seqQP++; aParamQP[nUsedQP].isQP = isQP; aParamQP[nUsedQP].cTag = 0; | < < < < < < < < < < < < < < < < < < < < < < | | | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | aParamQP[nUsedQP].zValue = zValue; if( g.fHttpTrace ){ fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue); } aParamQP[nUsedQP].seq = seqQP++; aParamQP[nUsedQP].isQP = isQP; aParamQP[nUsedQP].cTag = 0; nUsedQP++; sortQP = 1; } /* ** Add another query parameter or cookie to the parameter set. ** zName is the name of the query parameter or cookie and zValue ** is its fully decoded value. ** ** Copies are made of both the zName and zValue parameters. */ void cgi_set_parameter(const char *zName, const char *zValue){ cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 0); } void cgi_set_query_parameter(const char *zName, const char *zValue){ cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 1); } /* ** Replace a parameter with a new value. */ void cgi_replace_parameter(const char *zName, const char *zValue){ int i; |
︙ | ︙ | |||
861 862 863 864 865 866 867 | aParamQP[i].zValue = zValue; assert( aParamQP[i].isQP ); return; } } cgi_set_parameter_nocopy(zName, zValue, 1); } | < < < < < | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | aParamQP[i].zValue = zValue; assert( aParamQP[i].isQP ); return; } } cgi_set_parameter_nocopy(zName, zValue, 1); } /* ** Delete a parameter. */ void cgi_delete_parameter(const char *zName){ int i; for(i=0; i<nUsedQP; i++){ |
︙ | ︙ | |||
897 898 899 900 901 902 903 | } return; } } } /* | | | | > | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 | } return; } } } /* ** Add a query parameter. The zName portion is fixed but a copy ** must be made of zValue. */ void cgi_setenv(const char *zName, const char *zValue){ cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0); } /* ** Add a list of query parameters or cookies to the parameter set. ** ** Each parameter is of the form NAME=VALUE. Both the NAME and the ** VALUE may be url-encoded ("+" for space, "%HH" for other special ** characters). But this routine assumes that NAME contains no |
︙ | ︙ | |||
956 957 958 959 960 961 962 | z++; } dehttpize(zValue); }else{ if( *z ){ *z++ = 0; } zValue = ""; } | < | | < < < | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | z++; } dehttpize(zValue); }else{ if( *z ){ *z++ = 0; } zValue = ""; } if( fossil_islower(zName[0]) && fossil_no_strange_characters(zName+1) ){ cgi_set_parameter_nocopy(zName, zValue, isQP); } #ifdef FOSSIL_ENABLE_JSON json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) ); #endif /* FOSSIL_ENABLE_JSON */ } } |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 | *pz = &z[i]; *pLen -= i; return z; } /* ** The input *pz points to content that is terminated by a "\r\n" | | | | | | | < | | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | *pz = &z[i]; *pLen -= i; return z; } /* ** The input *pz points to content that is terminated by a "\r\n" ** followed by the boundry marker zBoundry. An extra "--" may or ** may not be appended to the boundry marker. There are *pLen characters ** in *pz. ** ** This routine adds a "\000" to the end of the content (overwriting ** the "\r\n") and returns a pointer to the content. The *pz input ** is adjusted to point to the first line following the boundry. ** The length of the content is stored in *pnContent. */ static char *get_bounded_content( char **pz, /* Content taken from here */ int *pLen, /* Number of bytes of data in (*pz)[] */ char *zBoundry, /* Boundry text marking the end of content */ int *pnContent /* Write the size of the content here */ ){ char *z = *pz; int len = *pLen; int i; int nBoundry = strlen(zBoundry); *pnContent = len; for(i=0; i<len; i++){ if( z[i]=='\n' && strncmp(zBoundry, &z[i+1], nBoundry)==0 ){ if( i>0 && z[i-1]=='\r' ) i--; z[i] = 0; *pnContent = i; i += nBoundry; break; } } *pz = &z[i]; get_line_from_string(pz, pLen); return z; } |
︙ | ︙ | |||
1093 1094 1095 1096 1097 1098 1099 | ** not copied. The calling function must not deallocate or modify ** "z" after this routine finishes or it could corrupt the parameter ** table. */ static void process_multipart_form_data(char *z, int len){ char *zLine; int nArg, i; | | | | | | < | | | | < < < < < < < | < | < < < < | < | < < < < > > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | | > > | > > > | > > > > | > > | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 | ** not copied. The calling function must not deallocate or modify ** "z" after this routine finishes or it could corrupt the parameter ** table. */ static void process_multipart_form_data(char *z, int len){ char *zLine; int nArg, i; char *zBoundry; char *zValue; char *zName = 0; int showBytes = 0; char *azArg[50]; zBoundry = get_line_from_string(&z, &len); if( zBoundry==0 ) return; while( (zLine = get_line_from_string(&z, &len))!=0 ){ if( zLine[0]==0 ){ int nContent = 0; zValue = get_bounded_content(&z, &len, zBoundry, &nContent); if( zName && zValue && fossil_islower(zName[0]) ){ cgi_set_parameter_nocopy(zName, zValue, 1); if( showBytes ){ cgi_set_parameter_nocopy(mprintf("%s:bytes", zName), mprintf("%d",nContent), 1); } } zName = 0; showBytes = 0; }else{ nArg = tokenize_line(zLine, count(azArg), azArg); for(i=0; i<nArg; i++){ int c = fossil_tolower(azArg[i][0]); int n = strlen(azArg[i]); if( c=='c' && sqlite3_strnicmp(azArg[i],"content-disposition:",n)==0 ){ i++; }else if( c=='n' && sqlite3_strnicmp(azArg[i],"name=",n)==0 ){ zName = azArg[++i]; }else if( c=='f' && sqlite3_strnicmp(azArg[i],"filename=",n)==0 ){ char *z = azArg[++i]; if( zName && z && fossil_islower(zName[0]) ){ cgi_set_parameter_nocopy(mprintf("%s:filename",zName), z, 1); } showBytes = 1; }else if( c=='c' && sqlite3_strnicmp(azArg[i],"content-type:",n)==0 ){ char *z = azArg[++i]; if( zName && z && fossil_islower(zName[0]) ){ cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1); } } } } } } #ifdef FOSSIL_ENABLE_JSON /* ** Internal helper for cson_data_source_FILE_n(). */ typedef struct CgiPostReadState_ { FILE * fh; unsigned int len; unsigned int pos; } CgiPostReadState; /* ** cson_data_source_f() impl which reads only up to ** a specified amount of data from its input FILE. ** state MUST be a full populated (CgiPostReadState*). */ static int cson_data_source_FILE_n( void * state, void * dest, unsigned int * n ){ if( ! state || !dest || !n ) return cson_rc.ArgError; else { CgiPostReadState * st = (CgiPostReadState *)state; if( st->pos >= st->len ){ *n = 0; return 0; }else if( !*n || ((st->pos + *n) > st->len) ){ return cson_rc.RangeError; }else{ unsigned int rsz = (unsigned int)fread( dest, 1, *n, st->fh ); if( ! rsz ){ *n = rsz; return feof(st->fh) ? 0 : cson_rc.IOError; }else{ *n = rsz; st->pos += *n; return 0; } } } } /* ** Reads a JSON object from the first contentLen bytes of zIn. On ** g.json.post is updated to hold the content. On error a ** FSL_JSON_E_INVALID_REQUEST response is output and fossil_exit() is ** called (in HTTP mode exit code 0 is used). ** ** If contentLen is 0 then the whole file is read. */ void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){ cson_value * jv = NULL; int rc; CgiPostReadState state; cson_parse_opt popt = cson_parse_opt_empty; cson_parse_info pinfo = cson_parse_info_empty; assert(g.json.gc.a && "json_main_bootstrap() was not called!"); popt.maxDepth = 15; state.fh = zIn; state.len = contentLen; state.pos = 0; rc = cson_parse( &jv, contentLen ? cson_data_source_FILE_n : cson_data_source_FILE, contentLen ? (void *)&state : (void *)zIn, &popt, &pinfo ); if(rc){ goto invalidRequest; }else{ json_gc_add( "POST.JSON", jv ); g.json.post.v = jv; g.json.post.o = cson_value_get_object( jv ); if( !g.json.post.o ){ /* we don't support non-Object (Array) requests */ goto invalidRequest; } } return; invalidRequest: cgi_set_content_type(json_guess_content_type()); if(0 != pinfo.errorCode){ /* fancy error message */ char * msg = mprintf("JSON parse error at line %u, column %u, " "byte offset %u: %s", pinfo.line, pinfo.col, pinfo.length, cson_rc_string(pinfo.errorCode)); json_err( FSL_JSON_E_INVALID_REQUEST, msg, 1 ); free(msg); }else if(jv && !g.json.post.o){ json_err( FSL_JSON_E_INVALID_REQUEST, "Request envelope must be a JSON Object (not array).", 1 ); }else{ /* generic error message */ json_err( FSL_JSON_E_INVALID_REQUEST, NULL, 1 ); } fossil_exit( g.isHTTP ? 0 : 1); |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | return; } } fputs(z, pLog); } /* Forward declaration */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < | | < < < < < < < < < < < < < < | < < < | | > > > > | < | | < < < < < < < < < < < < < < | < > > > > | < | > | > > | | > > > > > > > > | < | < > | > > | | > > > | | < > > | | < < < < < < < < | < > | < | < | | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 | return; } } fputs(z, pLog); } /* Forward declaration */ static NORETURN void malformed_request(const char *zMsg); /* ** Initialize the query parameter database. Information is pulled from ** the QUERY_STRING environment variable (if it exists), from standard ** input if there is POST data, and from HTTP_COOKIE. ** ** REQUEST_URI, PATH_INFO, and SCRIPT_NAME are related as follows: ** ** REQUEST_URI == SCRIPT_NAME + PATH_INFO ** ** Where "+" means concatenate. Fossil requires SCRIPT_NAME. If ** REQUEST_URI is provided but PATH_INFO is not, then PATH_INFO is ** computed from REQUEST_URI and SCRIPT_NAME. If PATH_INFO is provided ** but REQUEST_URI is not, then compute REQUEST_URI from PATH_INFO and ** SCRIPT_NAME. If neither REQUEST_URI nor PATH_INFO are provided, then ** assume that PATH_INFO is an empty string and set REQUEST_URI equal ** to PATH_INFO. ** ** SCGI typically omits PATH_INFO. CGI sometimes omits REQUEST_URI and ** PATH_INFO when it is empty. */ void cgi_init(void){ char *z; const char *zType; int len; const char *zRequestUri = cgi_parameter("REQUEST_URI",0); const char *zScriptName = cgi_parameter("SCRIPT_NAME",0); const char *zPathInfo = cgi_parameter("PATH_INFO",0); #ifdef FOSSIL_ENABLE_JSON json_main_bootstrap(); #endif g.isHTTP = 1; cgi_destination(CGI_BODY); if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME"); if( zRequestUri==0 ){ const char *z = zPathInfo; if( zPathInfo==0 ){ malformed_request("missing PATH_INFO and/or REQUEST_URI"); } if( z[0]=='/' ) z++; zRequestUri = mprintf("%s/%s", zScriptName, z); cgi_set_parameter("REQUEST_URI", zRequestUri); } if( zPathInfo==0 ){ int i, j; for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){} for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){} cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i)); } z = (char*)P("HTTP_COOKIE"); if( z ){ z = mprintf("%s",z); add_param_list(z, ';'); } z = (char*)P("QUERY_STRING"); if( z ){ z = mprintf("%s",z); add_param_list(z, '&'); } z = (char*)P("REMOTE_ADDR"); if( z ){ g.zIpAddr = mprintf("%s", z); } len = atoi(PD("CONTENT_LENGTH", "0")); g.zContentType = zType = P("CONTENT_TYPE"); blob_zero(&g.cgiIn); if( len>0 && zType ){ if( fossil_strcmp(zType,"application/x-www-form-urlencoded")==0 || strncmp(zType,"multipart/form-data",19)==0 ){ z = fossil_malloc( len+1 ); len = fread(z, 1, len, g.httpIn); z[len] = 0; cgi_trace(z); if( zType[0]=='a' ){ add_param_list(z, '&'); }else{ process_multipart_form_data(z, len); } }else if( fossil_strcmp(zType, "application/x-fossil")==0 ){ blob_read_from_channel(&g.cgiIn, g.httpIn, len); blob_uncompress(&g.cgiIn, &g.cgiIn); }else if( fossil_strcmp(zType, "application/x-fossil-debug")==0 ){ blob_read_from_channel(&g.cgiIn, g.httpIn, len); }else if( fossil_strcmp(zType, "application/x-fossil-uncompressed")==0 ){ blob_read_from_channel(&g.cgiIn, g.httpIn, len); } #ifdef FOSSIL_ENABLE_JSON else if( fossil_strcmp(zType, "application/json") || fossil_strcmp(zType,"text/plain")/*assume this MIGHT be JSON*/ || fossil_strcmp(zType,"application/javascript")){ g.json.isJsonMode = 1; cgi_parse_POST_JSON(g.httpIn, (unsigned int)len); /* FIXMEs: - See if fossil really needs g.cgiIn to be set for this purpose (i don't think it does). If it does then fill g.cgiIn and refactor to parse the JSON from there. - After parsing POST JSON, copy the "first layer" of keys/values to cgi_setenv(), honoring the upper-case distinction used in add_param_list(). However... - If we do that then we might get a disconnect in precedence of GET/POST arguments. i prefer for GET entries to take precedence over like-named POST entries, but in order for that to happen we need to process QUERY_STRING _after_ reading the POST data. */ cgi_set_content_type(json_guess_content_type()); } #endif /* FOSSIL_ENABLE_JSON */ } } /* ** This is the comparison function used to sort the aParamQP[] array of ** query parameters and cookies. */ static int qparam_compare(const void *a, const void *b){ |
︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 | memcpy(&aParamQP[j], &aParamQP[i], sizeof(aParamQP[j])); } j++; } nUsedQP = j; } | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 | memcpy(&aParamQP[j], &aParamQP[i], sizeof(aParamQP[j])); } j++; } nUsedQP = j; } /* Do a binary search for a matching query parameter */ lo = 0; hi = nUsedQP-1; while( lo<=hi ){ mid = (lo+hi)/2; c = fossil_strcmp(aParamQP[mid].zName, zName); if( c==0 ){ CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue)); return aParamQP[mid].zValue; }else if( c>0 ){ hi = mid-1; }else{ lo = mid+1; } } /* If no match is found and the name begins with an upper-case ** letter, then check to see if there is an environment variable ** with the given name. */ if( zName && fossil_isupper(zName[0]) ){ const char *zValue = fossil_getenv(zName); if( zValue ){ cgi_set_parameter_nocopy(zName, zValue, 0); CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue)); return zValue; } } CGIDEBUG(("no-match [%s]\n", zName)); return zDefault; } /* ** Return the value of a CGI parameter with leading and trailing ** spaces removed and with internal \r\n changed to just \n */ char *cgi_parameter_trimmed(const char *zName, const char *zDefault){ const char *zIn; char *zOut, c; |
︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 | if( cgi_parameter(z2,0)==0 ) return 0; } va_end(ap); return 1; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < | | | | < < < < | < < < < | < < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | if( cgi_parameter(z2,0)==0 ) return 0; } va_end(ap); return 1; } /* ** Print all query parameters on standard output. Format the ** parameters as HTML. This is used for testing and debugging. ** ** Omit the values of the cookies unless showAll is true. */ void cgi_print_all(int showAll, int onConsole){ int i; cgi_parameter("",""); /* Force the parameters into sorted order */ for(i=0; i<nUsedQP; i++){ const char *zName = aParamQP[i].zName; if( !showAll ){ if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue; if( fossil_strnicmp("fossil-",zName,7)==0 ) continue; } if( onConsole ){ fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); }else{ cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); } } } /* ** Export all untagged query parameters (but not cookies or environment ** variables) as hidden values of a form. */ |
︙ | ︙ | |||
1919 1920 1921 1922 1923 1924 1925 | vxprintf(pContent,zFormat,ap); } /* ** Send a reply indicating that the HTTP request was malformed */ | | < < < < < | < < < < | < | < | | 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | vxprintf(pContent,zFormat,ap); } /* ** Send a reply indicating that the HTTP request was malformed */ static NORETURN void malformed_request(const char *zMsg){ cgi_set_status(501, "Not Implemented"); cgi_printf( "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg ); cgi_reply(); fossil_exit(0); } /* ** Panic and die while processing a webpage. */ |
︙ | ︙ | |||
2048 2049 2050 2051 2052 2053 2054 | ** environment variables. A call to cgi_init() completes ** the setup. Once all the setup is finished, this procedure returns ** and subsequent code handles the actual generation of the webpage. */ void cgi_handle_http_request(const char *zIpAddr){ char *z, *zToken; int i; | < < | | | < | < | < | | < | | 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 | ** environment variables. A call to cgi_init() completes ** the setup. Once all the setup is finished, this procedure returns ** and subsequent code handles the actual generation of the webpage. */ void cgi_handle_http_request(const char *zIpAddr){ char *z, *zToken; int i; char zLine[2000]; /* A single line of input. */ g.fullHttpReply = 1; if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ malformed_request("missing HTTP header"); } blob_append(&g.httpHeader, zLine, -1); cgi_trace(zLine); zToken = extract_token(zLine, &z); if( zToken==0 ){ malformed_request("malformed HTTP header"); } if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0 && fossil_strcmp(zToken,"HEAD")!=0 ){ malformed_request("unsupported HTTP method"); } cgi_setenv("GATEWAY_INTERFACE","CGI/1.0"); cgi_setenv("REQUEST_METHOD",zToken); zToken = extract_token(z, &z); if( zToken==0 ){ malformed_request("malformed URL in HTTP header"); } cgi_setenv("REQUEST_URI", zToken); cgi_setenv("SCRIPT_NAME", ""); for(i=0; zToken[i] && zToken[i]!='?'; i++){} if( zToken[i] ) zToken[i++] = 0; cgi_setenv("PATH_INFO", zToken); cgi_setenv("QUERY_STRING", &zToken[i]); if( zIpAddr==0 ){ zIpAddr = cgi_remote_ip(fileno(g.httpIn)); } if( zIpAddr ){ cgi_setenv("REMOTE_ADDR", zIpAddr); g.zIpAddr = mprintf("%s", zIpAddr); } /* Get all the optional fields that follow the first line. */ while( fgets(zLine,sizeof(zLine),g.httpIn) ){ char *zFieldName; char *zVal; cgi_trace(zLine); blob_append(&g.httpHeader, zLine, -1); zFieldName = extract_token(zLine,&zVal); if( zFieldName==0 || *zFieldName==0 ) break; |
︙ | ︙ | |||
2116 2117 2118 2119 2120 2121 2122 | cgi_setenv("CONTENT_LENGTH", zVal); }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ cgi_setenv("CONTENT_TYPE", zVal); }else if( fossil_strcmp(zFieldName,"cookie:")==0 ){ cgi_setenv("HTTP_COOKIE", zVal); }else if( fossil_strcmp(zFieldName,"https:")==0 ){ cgi_setenv("HTTPS", zVal); | < < < < < < < | < < < < < < | | < < | 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 | cgi_setenv("CONTENT_LENGTH", zVal); }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ cgi_setenv("CONTENT_TYPE", zVal); }else if( fossil_strcmp(zFieldName,"cookie:")==0 ){ cgi_setenv("HTTP_COOKIE", zVal); }else if( fossil_strcmp(zFieldName,"https:")==0 ){ cgi_setenv("HTTPS", zVal); }else if( fossil_strcmp(zFieldName,"host:")==0 ){ cgi_setenv("HTTP_HOST", zVal); }else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){ cgi_setenv("HTTP_IF_NONE_MATCH", zVal); }else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){ cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ cgi_setenv("HTTP_REFERER", zVal); }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ cgi_setenv("HTTP_USER_AGENT", zVal); }else if( fossil_strcmp(zFieldName,"authorization:")==0 ){ cgi_setenv("HTTP_AUTHORIZATION", zVal); }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ const char *zIpAddr = cgi_accept_forwarded_for(zVal); if( zIpAddr!=0 ){ g.zIpAddr = mprintf("%s", zIpAddr); cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); } } } cgi_init(); cgi_trace(0); } /* ** This routine handles a single HTTP request from an SSH client which is ** coming in on g.httpIn and which replies on g.httpOut |
︙ | ︙ | |||
2172 2173 2174 2175 2176 2177 2178 | static int nCycles = 0; static char *zCmd = 0; char *z, *zToken; const char *zType = 0; int i, content_length = 0; char zLine[2000]; /* A single line of input. */ | < < < < | | < | 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 | static int nCycles = 0; static char *zCmd = 0; char *z, *zToken; const char *zType = 0; int i, content_length = 0; char zLine[2000]; /* A single line of input. */ if( zIpAddr ){ if( nCycles==0 ){ cgi_setenv("REMOTE_ADDR", zIpAddr); g.zIpAddr = mprintf("%s", zIpAddr); } }else{ fossil_panic("missing SSH IP address"); } if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ malformed_request("missing HTTP header"); } cgi_trace(zLine); zToken = extract_token(zLine, &z); if( zToken==0 ){ malformed_request("malformed HTTP header"); |
︙ | ︙ | |||
2242 2243 2244 2245 2246 2247 2248 | } for(i=0; zToken[i] && zToken[i]!='?'; i++){} if( zToken[i] ) zToken[i++] = 0; if( nCycles==0 ){ cgi_setenv("PATH_INFO", zToken); }else{ | | | 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | } for(i=0; zToken[i] && zToken[i]!='?'; i++){} if( zToken[i] ) zToken[i++] = 0; if( nCycles==0 ){ cgi_setenv("PATH_INFO", zToken); }else{ cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken)); } /* Get all the optional fields that follow the first line. */ while( fgets(zLine,sizeof(zLine),g.httpIn) ){ char *zFieldName; char *zVal; |
︙ | ︙ | |||
2264 2265 2266 2267 2268 2269 2270 | zVal[i] = 0; for(i=0; zFieldName[i]; i++){ zFieldName[i] = fossil_tolower(zFieldName[i]); } if( fossil_strcmp(zFieldName,"content-length:")==0 ){ content_length = atoi(zVal); }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ | | | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 | zVal[i] = 0; for(i=0; zFieldName[i]; i++){ zFieldName[i] = fossil_tolower(zFieldName[i]); } if( fossil_strcmp(zFieldName,"content-length:")==0 ){ content_length = atoi(zVal); }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ g.zContentType = zType = mprintf("%s", zVal); }else if( fossil_strcmp(zFieldName,"host:")==0 ){ if( nCycles==0 ){ cgi_setenv("HTTP_HOST", zVal); } }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ if( nCycles==0 ){ cgi_setenv("HTTP_USER_AGENT", zVal); |
︙ | ︙ | |||
2315 2316 2317 2318 2319 2320 2321 | } /* ** This routine handles the old fossil SSH probes */ char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){ /* Start looking for probes */ | < | 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 | } /* ** This routine handles the old fossil SSH probes */ char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){ /* Start looking for probes */ while( fossil_strcmp(zToken, "echo")==0 ){ zToken = extract_token(z, &z); if( zToken==0 ){ malformed_request("malformed probe"); } if( fossil_strncmp(zToken, "test", 4)==0 || fossil_strncmp(zToken, "probe-", 6)==0 ){ |
︙ | ︙ | |||
2342 2343 2344 2345 2346 2347 2348 | } } /* Got all probes now first transport_open is completed ** so return the command that was requested */ g.fSshClient |= CGI_SSH_COMPAT; | | < | 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 | } } /* Got all probes now first transport_open is completed ** so return the command that was requested */ g.fSshClient |= CGI_SSH_COMPAT; return mprintf("%s", zToken); } /* ** This routine handles the old fossil SSH transport_flip ** and transport_open communications if detected. */ void cgi_handle_ssh_transport(const char *zCmd){ char *z, *zToken; char zLine[2000]; /* A single line of input. */ /* look for second newline of transport_flip */ if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ malformed_request("incorrect transport_flip"); } cgi_trace(zLine); zToken = extract_token(zLine, &z); if( zToken && strlen(zToken)==0 ){ |
︙ | ︙ | |||
2403 2404 2405 2406 2407 2408 2409 | void cgi_handle_scgi_request(void){ char *zHdr; char *zToFree; int nHdr = 0; int nRead; int c, n, m; | < | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 | void cgi_handle_scgi_request(void){ char *zHdr; char *zToFree; int nHdr = 0; int nRead; int c, n, m; while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit((char)c) ){ nHdr = nHdr*10 + (char)c - '0'; } if( nHdr<16 ) malformed_request("SCGI header too short"); zToFree = zHdr = fossil_malloc(nHdr); nRead = (int)fread(zHdr, 1, nHdr, g.httpIn); if( nRead<nHdr ) malformed_request("cannot read entire SCGI header"); |
︙ | ︙ | |||
2435 2436 2437 2438 2439 2440 2441 | ** Bitmap values for the flags parameter to cgi_http_server(). */ #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */ #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */ #define HTTP_SERVER_HAD_REPOSITORY 0x0004 /* Was the repository open? */ #define HTTP_SERVER_HAD_CHECKOUT 0x0008 /* Was a checkout open? */ #define HTTP_SERVER_REPOLIST 0x0010 /* Allow repo listing */ | < | 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 | ** Bitmap values for the flags parameter to cgi_http_server(). */ #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */ #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */ #define HTTP_SERVER_HAD_REPOSITORY 0x0004 /* Was the repository open? */ #define HTTP_SERVER_HAD_CHECKOUT 0x0008 /* Was a checkout open? */ #define HTTP_SERVER_REPOLIST 0x0010 /* Allow repo listing */ #endif /* INTERFACE */ /* ** Maximum number of child processes that we can have running ** at one time. Set this to 0 for "no limit". */ |
︙ | ︙ | |||
2484 2485 2486 2487 2488 2489 2490 | int iPort = mnPort; while( iPort<=mxPort ){ memset(&inaddr, 0, sizeof(inaddr)); inaddr.sin_family = AF_INET; if( zIpAddr ){ inaddr.sin_addr.s_addr = inet_addr(zIpAddr); | | | 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 | int iPort = mnPort; while( iPort<=mxPort ){ memset(&inaddr, 0, sizeof(inaddr)); inaddr.sin_family = AF_INET; if( zIpAddr ){ inaddr.sin_addr.s_addr = inet_addr(zIpAddr); if( inaddr.sin_addr.s_addr == (-1) ){ fossil_fatal("not a valid IP address: %s", zIpAddr); } }else if( flags & HTTP_SERVER_LOCALHOST ){ inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); }else{ inaddr.sin_addr.s_addr = htonl(INADDR_ANY); } |
︙ | ︙ | |||
2511 2512 2513 2514 2515 2516 2517 | iPort++; continue; } break; } if( iPort>mxPort ){ if( mnPort==mxPort ){ | | | < | | < < < | < | 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 | iPort++; continue; } break; } if( iPort>mxPort ){ if( mnPort==mxPort ){ fossil_fatal("unable to open listening socket on ports %d", mnPort); }else{ fossil_fatal("unable to open listening socket on any" " port in the range %d..%d", mnPort, mxPort); } } if( iPort>mxPort ) return 1; listen(listener,10); fossil_print("Listening for %s requests on TCP port %d\n", (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort); fflush(stdout); if( zBrowser ){ assert( strstr(zBrowser,"%d")!=0 ); zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort); #if defined(__CYGWIN__) /* On Cygwin, we can do better than "echo" */ if( strncmp(zBrowser, "echo ", 5)==0 ){ wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5); wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */ if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){ fossil_warning("cannot start browser\n"); } }else #endif if( system(zBrowser)<0 ){ fossil_warning("cannot start browser: %s\n", zBrowser); } } while( 1 ){ #if FOSSIL_MAX_CONNECTIONS>0 while( nchildren>=FOSSIL_MAX_CONNECTIONS ){ if( wait(0)>=0 ) nchildren--; } #endif delay.tv_sec = 0; delay.tv_usec = 100000; FD_ZERO(&readfds); assert( listener>=0 ); FD_SET( listener, &readfds); select( listener+1, &readfds, 0, 0, &delay); if( FD_ISSET(listener, &readfds) ){ lenaddr = sizeof(inaddr); connection = accept(listener, (struct sockaddr*)&inaddr, &lenaddr); if( connection>=0 ){ child = fork(); if( child!=0 ){ if( child>0 ){ nchildren++; nRequest++; } close(connection); }else{ |
︙ | ︙ | |||
2599 2600 2601 2602 2603 2604 2605 | if( x<=0 ) break; if( WIFSIGNALED(iStatus) && g.fAnyTrace ){ fprintf(stderr, "/***** Child %d exited on signal %d (%s) *****/\n", x, WTERMSIG(iStatus), strsignal(WTERMSIG(iStatus))); } nchildren--; } | | | 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | if( x<=0 ) break; if( WIFSIGNALED(iStatus) && g.fAnyTrace ){ fprintf(stderr, "/***** Child %d exited on signal %d (%s) *****/\n", x, WTERMSIG(iStatus), strsignal(WTERMSIG(iStatus))); } nchildren--; } } } /* NOT REACHED */ fossil_exit(1); #endif /* NOT REACHED */ return 0; } |
︙ | ︙ | |||
2640 2641 2642 2643 2644 2645 2646 | }else{ return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000", azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon], pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 | }else{ return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000", azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon], pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec); } } /* ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return ** a Unix epoch time. <= zero is returned on failure. ** ** Note that this won't handle all the _allowed_ HTTP formats, just the ** most popular one (the one generated by cgi_rfc822_datestamp(), actually). */ time_t cgi_rfc822_parsedate(const char *zDate){ int mday, mon, year, yday, hour, min, sec; char zIgnore[4]; char zMonth[4]; static const char *const azMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; if( 7==sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore, &mday, zMonth, &year, &hour, &min, &sec)){ if( year > 1900 ) year -= 1900; for(mon=0; azMonths[mon]; mon++){ if( !strncmp( azMonths[mon], zMonth, 3 )){ int nDay; int isLeapYr; static int priorDays[] = { 0, 31, 59, 90,120,151,181,212,243,273,304,334 }; if( mon<0 ){ int nYear = (11 - mon)/12; year -= nYear; |
︙ | ︙ | |||
2736 2737 2738 2739 2740 2741 2742 | ** its IP or return default */ const char *cgi_ssh_remote_addr(const char *zDefault){ char *zIndex; const char *zSshConn = fossil_getenv("SSH_CONNECTION"); if( zSshConn && zSshConn[0] ){ | | | 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 | ** its IP or return default */ const char *cgi_ssh_remote_addr(const char *zDefault){ char *zIndex; const char *zSshConn = fossil_getenv("SSH_CONNECTION"); if( zSshConn && zSshConn[0] ){ char *zSshClient = mprintf("%s",zSshConn); if( (zIndex = strchr(zSshClient,' '))!=0 ){ zSshClient[zIndex-zSshClient] = '\0'; return zSshClient; } } return zDefault; } |
︙ | ︙ | |||
2766 2767 2768 2769 2770 2771 2772 | */ int cgi_from_mobile(void){ const char *zAgent = P("HTTP_USER_AGENT"); if( zAgent==0 ) return 0; if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0; return sqlite3_strlike("%mobile%", zAgent, 0)==0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2078 2079 2080 2081 2082 2083 2084 | */ int cgi_from_mobile(void){ const char *zAgent = P("HTTP_USER_AGENT"); if( zAgent==0 ) return 0; if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0; return sqlite3_strlike("%mobile%", zAgent, 0)==0; } |
Deleted src/chat.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/checkin.c.
︙ | ︙ | |||
59 60 61 62 63 64 65 | }; /* ** Create a TEMP table named SFILE and add all unmanaged files named on ** the command-line to that table. If directories are named, then add ** all unmanaged files contained underneath those directories. If there ** are no files or directories named on the command-line, then add all | | < < < | | | < | < < | | | 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 | }; /* ** Create a TEMP table named SFILE and add all unmanaged files named on ** the command-line to that table. If directories are named, then add ** all unmanaged files contained underneath those directories. If there ** are no files or directories named on the command-line, then add all ** unmanaged files anywhere in the checkout. */ static void locate_unmanaged_files( int argc, /* Number of command-line arguments to examine */ char **argv, /* values of command-line arguments */ unsigned scanFlags, /* Zero or more SCAN_xxx flags */ Glob *pIgnore /* Do not add files that match this GLOB */ ){ Blob name; /* Name of a candidate file or directory */ char *zName; /* Name of a candidate file or directory */ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */ int i; /* Loop counter */ int nRoot; /* length of g.zLocalRoot */ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s," " mtime INTEGER, size INTEGER)", filename_collation()); nRoot = (int)strlen(g.zLocalRoot); if( argc==0 ){ blob_init(&name, g.zLocalRoot, nRoot - 1); vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0); blob_reset(&name); }else{ for(i=0; i<argc; i++){ file_canonical_name(argv[i], &name, 0); zName = blob_str(&name); isDir = file_isdir(zName, RepoFILE); if( isDir==1 ){ vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0); }else if( isDir==0 ){ fossil_warning("not found: %s", &zName[nRoot]); }else if( file_access(zName, R_OK) ){ fossil_fatal("cannot open %s", &zName[nRoot]); }else{ db_multi_exec( "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", &zName[nRoot] ); } blob_reset(&name); } } } /* ** Generate text describing all changes. ** ** We assume that vfile_check_signature has been run. */ static void status_report( Blob *report, /* Append the status report here */ unsigned flags /* Filter and other configuration flags */ ){ Stmt q; int nErr = 0; Blob rewrittenPathname; Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER; const char *zName; int i; /* Skip the file report if no files are requested at all. */ if( !(flags & (C_ALL | C_EXTRA)) ){ goto skipFiles; |
︙ | ︙ | |||
154 155 156 157 158 159 160 | /* Obtain the list of managed files if appropriate. */ blob_zero(&sql); if( flags & C_ALL ){ /* Start with a list of all managed files. */ blob_append_sql(&sql, "SELECT pathname, %s as mtime, %s as size, deleted, chnged, rid," | | < | | < < | 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 | /* Obtain the list of managed files if appropriate. */ blob_zero(&sql); if( flags & C_ALL ){ /* Start with a list of all managed files. */ blob_append_sql(&sql, "SELECT pathname, %s as mtime, %s as size, deleted, chnged, rid," " coalesce(origname!=pathname,0) AS renamed, 1 AS managed" " FROM vfile LEFT JOIN blob USING (rid)" " WHERE is_selected(id)%s", flags & C_MTIME ? "datetime(checkin_mtime(:vid, rid), " "'unixepoch', toLocal())" : "''" /*safe-for-%s*/, flags & C_SIZE ? "coalesce(blob.size, 0)" : "0" /*safe-for-%s*/, blob_sql_text(&where)); /* Exclude unchanged files unless requested. */ if( !(flags & C_UNCHANGED) ){ blob_append_sql(&sql, " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"); } } /* If C_EXTRA, add unmanaged files to the query result too. */ if( flags & C_EXTRA ){ if( blob_size(&sql) ){ blob_append_sql(&sql, " UNION ALL"); } blob_append_sql(&sql, " SELECT pathname, %s, %s, 0, 0, 0, 0, 0" " FROM sfile WHERE pathname NOT IN (%s)%s", flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''", flags & C_SIZE ? "size" : "0", fossil_all_reserved_names(0), blob_sql_text(&where)); } blob_reset(&where); /* Pre-create the "ok" temporary table so the checkin_mtime() SQL function * does not lead to SQLITE_ABORT_ROLLBACK during execution of the OP_OpenRead * SQLite opcode. checkin_mtime() calls mtime_of_manifest_file() which * creates a temporary table if it doesn't already exist, thus invalidating * the prepared statement in the middle of its execution. */ db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"); /* Append an ORDER BY clause then compile the query. */ blob_append_sql(&sql, " ORDER BY pathname"); db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); /* Bind the checkout version ID to the query if needed. */ if( (flags & C_ALL) && (flags & C_MTIME) ){ db_bind_int(&q, ":vid", db_lget_int("checkout", 0)); } /* Execute the query and assemble the report. */ blob_zero(&rewrittenPathname); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q, 0); const char *zClass = 0; int isManaged = db_column_int(&q, 7); const char *zMtime = db_column_text(&q, 1); int size = db_column_int(&q, 2); int isDeleted = db_column_int(&q, 3); int isChnged = db_column_int(&q, 4); int isNew = isManaged && !db_column_int(&q, 5); int isRenamed = db_column_int(&q, 6); char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); int isMissing = !file_isfile_or_link(zFullName); /* Determine the file change classification, if any. */ if( isDeleted ){ if( flags & C_DELETED ){ zClass = "DELETED"; |
︙ | ︙ | |||
267 268 269 270 271 272 273 274 275 276 277 278 279 | zClass = "UNLINK"; }else if( (flags & C_CONFLICT) && isChnged && !file_islink(zFullName) && file_contains_merge_marker(zFullName) ){ zClass = "CONFLICT"; }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged && (isChnged<2 || isChnged>9) ){ zClass = "EDITED"; }else if( (flags & C_UNCHANGED) && isManaged && !isNew && !isChnged && !isRenamed ){ zClass = "UNCHANGED"; }else if( (flags & C_EXTRA) && !isManaged ){ zClass = "EXTRA"; } | > > < < < < < < > | | | < < | < < < < | < < < > | | < | > | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | zClass = "UNLINK"; }else if( (flags & C_CONFLICT) && isChnged && !file_islink(zFullName) && file_contains_merge_marker(zFullName) ){ zClass = "CONFLICT"; }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged && (isChnged<2 || isChnged>9) ){ zClass = "EDITED"; }else if( (flags & C_RENAMED) && isRenamed ){ zClass = "RENAMED"; }else if( (flags & C_UNCHANGED) && isManaged && !isNew && !isChnged && !isRenamed ){ zClass = "UNCHANGED"; }else if( (flags & C_EXTRA) && !isManaged ){ zClass = "EXTRA"; } /* Only report files for which a change classification was determined. */ if( zClass ){ if( flags & C_COMMENT ){ blob_append(report, "# ", 2); } if( flags & C_CLASSIFY ){ blob_appendf(report, "%-10s ", zClass); } if( flags & C_MTIME ){ blob_append(report, zMtime, -1); blob_append(report, " ", 2); } if( flags & C_SIZE ){ blob_appendf(report, "%7d ", size); } if( flags & C_RELPATH ){ /* If C_RELPATH, display paths relative to current directory. */ const char *zDisplayName; file_relative_name(zFullName, &rewrittenPathname, 0); zDisplayName = blob_str(&rewrittenPathname); if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){ zDisplayName += 2; /* no unnecessary ./ prefix */ } blob_append(report, zDisplayName, -1); }else{ /* If not C_RELPATH, display paths relative to project root. */ blob_append(report, zPathname, -1); } blob_append(report, "\n", 1); } free(zFullName); } blob_reset(&rewrittenPathname); db_finalize(&q); /* If C_MERGE, put merge contributors at the end of the report. */ skipFiles: if( flags & C_MERGE ){ db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid" " WHERE id<=0"); while( db_step(&q)==SQLITE_ROW ){ if( flags & C_COMMENT ){ blob_append(report, "# ", 2); } if( flags & C_CLASSIFY ){ const char *zClass; switch( db_column_int(&q, 1) ){ |
︙ | ︙ | |||
373 374 375 376 377 378 379 | /* ** COMMAND: changes ** COMMAND: status ** ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...? ** | | | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | /* ** COMMAND: changes ** COMMAND: status ** ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...? ** ** Report the change status of files in the current checkout. If one or ** more PATHS are specified, only changes among the named files and ** directories are reported. Directories are searched recursively. ** ** The status command is similar to the changes command, except it lacks ** several of the options supported by changes and it has its own header ** and footer information. The header information is a subset of that ** shown by the info command, and the footer shows if there are any forks. ** Change type classification is always enabled for the status command. ** ** Each line of output is the name of a changed file, with paths shown ** according to the "relative-paths" setting, unless overridden by the ** --abs-paths or --rel-paths options. ** ** By default, all changed files are selected for display. This behavior ** can be overridden by using one or more filter options (listed below), ** in which case only files with the specified change type(s) are shown. ** As a special case, the --no-merge option does not inhibit this default. ** This default shows exactly the set of changes that would be checked ** in by the commit command. ** ** If no filter options are used, or if the --merge option is used, the ** artifact hash of each merge contributor check-in version is displayed at ** the end of the report. The --no-merge option is useful to display the ** default set of changed files without the merge contributors. ** |
︙ | ︙ | |||
415 416 417 418 419 420 421 | ** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE. ** If the file had to be merged with any other changes, it is considered ** to be merged or conflicted and therefore will be shown by --edited, not ** --updated, with types EDITED or CONFLICT. The --changed option can be ** used to display the union of --edited and --updated. ** ** --differ is so named because it lists all the differences between the | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | ** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE. ** If the file had to be merged with any other changes, it is considered ** to be merged or conflicted and therefore will be shown by --edited, not ** --updated, with types EDITED or CONFLICT. The --changed option can be ** used to display the union of --edited and --updated. ** ** --differ is so named because it lists all the differences between the ** checked-out version and the checkout directory. In addition to the ** default changes (excluding --merge), it lists extra files which (if ** ignore-glob is set correctly) may be worth adding. Prior to doing a ** commit, it is good practice to check --differ to see not only which ** changes would be committed but also if any files should be added. ** ** If both --merge and --no-merge are used, --no-merge has priority. The ** same is true of --classify and --no-classify. ** ** The "fossil changes --extra" command is equivalent to "fossil extras". ** ** General options: ** --abs-paths Display absolute pathnames. ** --rel-paths Display pathnames relative to the current working ** directory. ** --hash Verify file status using hashing rather than ** relying on file mtimes. ** --case-sensitive <BOOL> Override case-sensitive setting. ** --dotfiles Include unmanaged files beginning with a dot. ** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns. ** ** Options specific to the changes command: ** --header Identify the repository if report is non-empty. ** -v|--verbose Say "(none)" if the change report is empty. ** --classify Start each line with the file's change type. ** --no-classify Do not print file change types. ** ** Filter options: ** --edited Display edited, merged, and conflicted files. ** --updated Display files updated by merge/integrate. ** --changed Combination of the above two options. ** --missing Display missing files. ** --added Display added files. ** --deleted Display deleted files. ** --renamed Display renamed files. ** --conflict Display files having merge conflicts. ** --meta Display files with metadata changes. ** --unchanged Display unchanged files. ** --all Display all managed files, i.e. all of the above. ** --extra Display unmanaged files. ** --differ Display modified and extra files. ** --merge Display merge contributors. ** --no-merge Do not display merge contributors. ** ** See also: extras, ls */ void status_cmd(void){ /* Affirmative and negative flag option tables. */ static const struct { const char *option; /* Flag name. */ unsigned mask; /* Flag bits. */ } flagDefs[] = { |
︙ | ︙ | |||
523 524 525 526 527 528 529 | for( i=0; i<count(noFlagDefs); ++i ){ if( (command==CHANGES || !(noFlagDefs[i].mask & C_CLASSIFY)) && find_option(noFlagDefs[i].option, 0, 0) ){ flags &= ~noFlagDefs[i].mask; } } | | | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | for( i=0; i<count(noFlagDefs); ++i ){ if( (command==CHANGES || !(noFlagDefs[i].mask & C_CLASSIFY)) && find_option(noFlagDefs[i].option, 0, 0) ){ flags &= ~noFlagDefs[i].mask; } } /* Confirm current working directory is within checkout. */ db_must_be_within_tree(); /* Get checkout version. l*/ vid = db_lget_int("checkout", 0); /* Relative path flag determination is done by a shared function. */ if( determine_cwd_relative_option() ){ flags |= C_RELPATH; } |
︙ | ︙ | |||
591 592 593 594 595 596 597 | /* The status command ends with warnings about ambiguous leaves (forks). */ if( command==STATUS ){ leaf_ambiguity_warning(vid, vid); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 | /* The status command ends with warnings about ambiguous leaves (forks). */ if( command==STATUS ){ leaf_ambiguity_warning(vid, vid); } } /* ** Take care of -r version of ls command */ static void ls_cmd_rev( const char *zRev, /* Revision string given */ int verboseFlag, /* Verbose flag given */ int showAge, /* Age flag given */ int timeOrder /* Order by time flag given */ ){ Stmt q; char *zOrderBy = "pathname COLLATE nocase"; char *zName; Blob where; int rid; int i; /* Handle given file names */ blob_zero(&where); for(i=2; i<g.argc; i++){ Blob fname; file_tree_name(g.argv[i], &fname, 0, 1); zName = blob_str(&fname); |
︙ | ︙ | |||
728 729 730 731 732 733 734 | "SELECT datetime(fileage.mtime, toLocal()), fileage.pathname,\n" " blob.size\n" " FROM fileage, blob\n" " WHERE blob.rid=fileage.fid %s\n" " ORDER BY %s;", blob_sql_text(&where), zOrderBy /*safe-for-%s*/ ); blob_reset(&where); | < < < | < < < < | | | | | | < < < | < < < < < < < < < | | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 | "SELECT datetime(fileage.mtime, toLocal()), fileage.pathname,\n" " blob.size\n" " FROM fileage, blob\n" " WHERE blob.rid=fileage.fid %s\n" " ORDER BY %s;", blob_sql_text(&where), zOrderBy /*safe-for-%s*/ ); blob_reset(&where); while( db_step(&q)==SQLITE_ROW ){ const char *zTime = db_column_text(&q,0); const char *zFile = db_column_text(&q,1); int size = db_column_int(&q,2); if( verboseFlag ){ fossil_print("%s %7d %s\n", zTime, size, zFile); }else if( showAge ){ fossil_print("%s %s\n", zTime, zFile); }else{ fossil_print("%s\n", zFile); } } db_finalize(&q); } /* ** COMMAND: ls ** ** Usage: %fossil ls ?OPTIONS? ?PATHS ...? ** ** List all files in the current checkout. If PATHS is included, only the ** named files (or their children if directories) are shown. ** ** The ls command is essentially two related commands in one, depending on ** whether or not the -r option is given. -r selects a specific check-in ** version to list, in which case -R can be used to select the repository. ** The fine behavior of the --age, -v, and -t options is altered by the -r ** option as well, as explained below. ** ** The --age option displays file commit times. Like -r, --age has the ** side effect of making -t sort by commit time, not modification time. ** ** The -v option provides extra information about each file. Without -r, ** -v displays the change status, in the manner of the changes command. ** With -r, -v shows the commit time and size of the checked-in files. ** ** The -t option changes the sort order. Without -t, files are sorted by ** path and name (case insensitive sort if -r). If neither --age nor -r ** are used, -t sorts by modification time, otherwise by commit time. ** ** Options: ** --age Show when each file was committed. ** -v|--verbose Provide extra information about each file. ** -t Sort output in time order. ** -r VERSION The specific check-in to list. ** -R|--repository FILE Extract info from repository FILE. ** ** See also: changes, extras, status */ void ls_cmd(void){ int vid; Stmt q; int verboseFlag; int showAge; int timeOrder; char *zOrderBy = "pathname"; Blob where; int i; const char *zName; const char *zRev; verboseFlag = find_option("verbose","v", 0)!=0; if( !verboseFlag ){ verboseFlag = find_option("l","l", 0)!=0; /* deprecated */ } showAge = find_option("age",0,0)!=0; zRev = find_option("r","r",1); timeOrder = find_option("t","t",0)!=0; if( zRev!=0 ){ db_find_and_open_repository(0, 0); verify_all_options(); ls_cmd_rev(zRev,verboseFlag,showAge,timeOrder); return; }else if( find_option("R",0,1)!=0 ){ fossil_fatal("the -r is required in addition to -R"); } db_must_be_within_tree(); vid = db_lget_int("checkout", 0); |
︙ | ︙ | |||
853 854 855 856 857 858 859 | " %s (pathname=%Q %s) " "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", (blob_size(&where)>0) ? "OR" : "WHERE", zName, filename_collation(), zName, filename_collation(), zName, filename_collation() ); } | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | " %s (pathname=%Q %s) " "OR (pathname>'%q/' %s AND pathname<'%q0' %s)", (blob_size(&where)>0) ? "OR" : "WHERE", zName, filename_collation(), zName, filename_collation(), zName, filename_collation() ); } vfile_check_signature(vid, 0); if( showAge ){ db_prepare(&q, "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," " datetime(checkin_mtime(%d,rid),'unixepoch',toLocal())" " FROM vfile %s" " ORDER BY %s", vid, blob_sql_text(&where), zOrderBy /*safe-for-%s*/ |
︙ | ︙ | |||
921 922 923 924 925 926 927 | fossil_print("%s%s\n", type, zPathname); } free(zFullName); } db_finalize(&q); } | < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | < | < < < < < > > < < < | < | | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 | fossil_print("%s%s\n", type, zPathname); } free(zFullName); } db_finalize(&q); } /* ** COMMAND: extras ** ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...? ** ** Print a list of all files in the source tree that are not part of the ** current checkout. See also the "clean" command. If paths are specified, ** only files in the given directories will be listed. ** ** Files and subdirectories whose names begin with "." are normally ** ignored but can be included by adding the --dotfiles option. ** ** Files whose names match any of the glob patterns in the "ignore-glob" ** setting are ignored. This setting can be overridden by the --ignore ** option, whose CSG argument is a comma-separated list of glob patterns. ** ** Pathnames are displayed according to the "relative-paths" setting, ** unless overridden by the --abs-paths or --rel-paths options. ** ** Options: ** --abs-paths Display absolute pathnames. ** --case-sensitive <BOOL> override case-sensitive setting ** --dotfiles include files beginning with a dot (".") ** --header Identify the repository if there are extras ** --ignore <CSG> ignore files matching patterns from the argument ** --rel-paths Display pathnames relative to the current working ** directory. ** ** See also: changes, clean, status */ void extras_cmd(void){ Blob report = BLOB_INITIALIZER; const char *zIgnoreFlag = find_option("ignore",0,1); unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; unsigned flags = C_EXTRA; int showHdr = find_option("header",0,0)!=0; Glob *pIgnore; if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; db_must_be_within_tree(); if( determine_cwd_relative_option() ){ flags |= C_RELPATH; } if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; /* We should be done with options.. */ verify_all_options(); if( zIgnoreFlag==0 ){ zIgnoreFlag = db_get("ignore-glob", 0); } pIgnore = glob_create(zIgnoreFlag); /* Always consider symlinks. */ g.allowSymlinks = db_allow_symlinks_by_default(); locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore); glob_free(pIgnore); blob_zero(&report); status_report(&report, flags); if( blob_size(&report) ){ if( showHdr ){ fossil_print("Extras for %s at %s:\n", db_get("project-name","<unnamed>"), g.zLocalRoot); } blob_write_to_file(&report, "-"); } blob_reset(&report); } /* ** COMMAND: clean ** ** Usage: %fossil clean ?OPTIONS? ?PATH ...? ** ** Delete all "extra" files in the source tree. "Extra" files are files ** that are not officially part of the checkout. If one or more PATH ** arguments appear, then only the files named, or files contained with ** directories named, will be removed. ** ** If the --prompt option is used, prompts are issued to confirm the ** permanent removal of each file. Otherwise, files are backed up to the ** undo buffer prior to removal, and prompts are issued only for files ** whose removal cannot be undone due to their large size or due to |
︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 | ** ** The --verily option ignores the keep-glob and ignore-glob settings and ** turns on --force, --emptydirs, --dotfiles, and --disable-undo. Use the ** --verily option when you really want to clean up everything. Extreme ** care should be exercised when using the --verily option. ** ** Options: | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | ** ** The --verily option ignores the keep-glob and ignore-glob settings and ** turns on --force, --emptydirs, --dotfiles, and --disable-undo. Use the ** --verily option when you really want to clean up everything. Extreme ** care should be exercised when using the --verily option. ** ** Options: ** --allckouts Check for empty directories within any checkouts ** that may be nested within the current one. This ** option should be used with great care because the ** empty-dirs setting (and other applicable settings) ** belonging to the other repositories, if any, will ** not be checked. ** --case-sensitive <BOOL> override case-sensitive setting ** --dirsonly Only remove empty directories. No files will ** be removed. Using this option will automatically ** enable the --emptydirs option as well. ** --disable-undo WARNING: This option disables use of the undo ** mechanism for this clean operation and should be ** used with extreme caution. ** --dotfiles Include files beginning with a dot ("."). ** --emptydirs Remove any empty directories that are not ** explicitly exempted via the empty-dirs setting ** or another applicable setting or command line ** argument. Matching files, if any, are removed ** prior to checking for any empty directories; ** therefore, directories that contain only files ** that were removed will be removed as well. ** -f|--force Remove files without prompting. ** -i|--prompt Prompt before removing each file. This option ** implies the --disable-undo option. ** -x|--verily WARNING: Removes everything that is not a managed ** file or the repository itself. This option ** implies the --force, --emptydirs, --dotfiles, and ** --disable-undo options. ** Furthermore, it completely disregards the keep-glob ** and ignore-glob settings. However, it does honor ** the --ignore and --keep options. ** --clean <CSG> WARNING: Never prompt to delete any files matching ** this comma separated list of glob patterns. Also, ** deletions of any files matching this pattern list ** cannot be undone. ** --ignore <CSG> Ignore files matching patterns from the ** comma separated list of glob patterns. ** --keep <CSG> Keep files matching this comma separated ** list of glob patterns. ** -n|--dry-run Delete nothing, but display what would have been ** deleted. ** --no-prompt This option disables prompting the user for input ** and assumes an answer of 'No' for every question. ** --temp Remove only Fossil-generated temporary files. ** -v|--verbose Show all files as they are removed. ** ** See also: addremove, extras, status */ void clean_cmd(void){ int allFileFlag, allDirFlag, dryRunFlag, verboseFlag; int emptyDirsFlag, dirsOnlyFlag; int disableUndo, noPrompt; int alwaysPrompt = 0; unsigned scanFlags = 0; |
︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | } if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; verify_all_options(); pIgnore = glob_create(zIgnoreFlag); pKeep = glob_create(zKeepFlag); pClean = glob_create(zCleanFlag); nRoot = (int)strlen(g.zLocalRoot); if( !dirsOnlyFlag ){ Stmt q; Blob repo; if( !dryRunFlag && !disableUndo ) undo_begin(); locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore); db_prepare(&q, "SELECT %Q || pathname FROM sfile" | > > | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | } if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; verify_all_options(); pIgnore = glob_create(zIgnoreFlag); pKeep = glob_create(zKeepFlag); pClean = glob_create(zCleanFlag); nRoot = (int)strlen(g.zLocalRoot); /* Always consider symlinks. */ g.allowSymlinks = db_allow_symlinks_by_default(); if( !dirsOnlyFlag ){ Stmt q; Blob repo; if( !dryRunFlag && !disableUndo ) undo_begin(); locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore); db_prepare(&q, "SELECT %Q || pathname FROM sfile" |
︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 | } if( emptyDirsFlag ){ Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0)); Stmt q; Blob root; blob_init(&root, g.zLocalRoot, nRoot - 1); vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, | | | 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 | } if( emptyDirsFlag ){ Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0)); Stmt q; Blob root; blob_init(&root, g.zLocalRoot, nRoot - 1); vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pEmptyDirs); blob_reset(&root); db_prepare(&q, "SELECT %Q || x FROM dscan_temp" " WHERE x NOT IN (%s) AND y = 0" " ORDER BY 1 DESC", g.zLocalRoot, fossil_all_reserved_names(0) ); |
︙ | ︙ | |||
1324 1325 1326 1327 1328 1329 1330 | const char *zEditor; char *zCmd; char *zFile; Blob reply, line; char *zComment; int i; | > > | > > > > > > > > > > > > > | < | < < < < < < < | > | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | const char *zEditor; char *zCmd; char *zFile; Blob reply, line; char *zComment; int i; zEditor = db_get("editor", 0); if( zEditor==0 ){ zEditor = fossil_getenv("VISUAL"); } if( zEditor==0 ){ zEditor = fossil_getenv("EDITOR"); } #if defined(_WIN32) || defined(__CYGWIN__) if( zEditor==0 ){ zEditor = mprintf("%s\\notepad.exe", fossil_getenv("SYSTEMROOT")); #if defined(__CYGWIN__) zEditor = fossil_utf8_to_path(zEditor, 0); blob_add_cr(pPrompt); #endif } #endif if( zEditor==0 ){ if( blob_size(pPrompt)>0 ){ blob_append(pPrompt, "#\n" "# Since no default text editor is set using EDITOR or VISUAL\n" "# environment variables or the \"fossil set editor\" command,\n" "# and because no comment was specified using the \"-m\" or \"-M\"\n" "# command-line options, you will need to enter the comment below.\n" "# Type \".\" on a line by itself when you are done:\n", -1); } zFile = mprintf("-"); }else{ Blob fname; blob_zero(&fname); if( g.zLocalRoot!=0 ){ file_relative_name(g.zLocalRoot, &fname, 1); zFile = db_text(0, "SELECT '%qci-comment-'||hex(randomblob(6))||'.txt'", blob_str(&fname)); }else{ file_tempname(&fname, "ci-comment"); zFile = mprintf("%s", blob_str(&fname)); } blob_reset(&fname); } #if defined(_WIN32) blob_add_cr(pPrompt); #endif if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile); if( zEditor ){ zCmd = mprintf("%s \"%s\"", zEditor, zFile); fossil_print("%s\n", zCmd); if( fossil_system(zCmd) ){ fossil_fatal("editor aborted: \"%s\"", zCmd); } blob_read_from_file(&reply, zFile, ExtFILE); }else{ char zIn[300]; blob_zero(&reply); while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ){ break; } |
︙ | ︙ | |||
1422 1423 1424 1425 1426 1427 1428 | ** ** parent_rid is the recordid of the parent check-in. */ static void prepare_commit_comment( Blob *pComment, char *zInit, CheckinInfo *p, | | < < < < < | 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 | ** ** parent_rid is the recordid of the parent check-in. */ static void prepare_commit_comment( Blob *pComment, char *zInit, CheckinInfo *p, int parent_rid ){ Blob prompt; #if defined(_WIN32) || defined(__CYGWIN__) int bomSize; const unsigned char *bom = get_utf8_bom(&bomSize); blob_init(&prompt, (const char *) bom, bomSize); if( zInit && zInit[0]){ blob_append(&prompt, zInit, -1); } #else blob_init(&prompt, zInit, -1); #endif blob_append(&prompt, "\n" "# Enter a commit message for this check-in." " Lines beginning with # are ignored.\n" "#\n", -1 ); blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name()); if( p->zBranch && p->zBranch[0] ){ blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch); }else{ char *zTags = info_tags_of_checkin(parent_rid, 1); if( zTags || p->azTag ){ |
︙ | ︙ | |||
1482 1483 1484 1485 1486 1487 1488 | if( p->integrateFlag ){ blob_append(&prompt, "#\n" "# All merged-in branches will be closed due to the --integrate flag\n" "#\n", -1 ); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 | if( p->integrateFlag ){ blob_append(&prompt, "#\n" "# All merged-in branches will be closed due to the --integrate flag\n" "#\n", -1 ); } prompt_for_user_comment(pComment, &prompt); blob_reset(&prompt); } /* ** Populate the Global.aCommitFile[] based on the command line arguments ** to a [commit] command. Global.aCommitFile is an array of integers ** sized at (N+1), where N is the number of arguments passed to [commit]. ** The contents are the [id] values from the vfile table corresponding ** to the filenames passed as arguments. |
︙ | ︙ | |||
1663 1664 1665 1666 1667 1668 1669 | } g.aCommitFile[jj] = 0; bag_clear(&toCommit); } return result; } | < < < < < < < < < < < < < < < < < < | > > > > > | > > < < | 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 | } g.aCommitFile[jj] = 0; bag_clear(&toCommit); } return result; } /* ** Make sure the current check-in with timestamp zDate is younger than its ** ancestor identified rid and zUuid. Throw a fatal error if not. */ static void checkin_verify_younger( int rid, /* The record ID of the ancestor */ const char *zUuid, /* The artifact ID of the ancestor */ const char *zDate /* Date & time of the current check-in */ ){ #ifndef FOSSIL_ALLOW_OUT_OF_ORDER_DATES int b; b = db_exists( "SELECT 1 FROM event" " WHERE datetime(mtime)>=%Q" " AND type='ci' AND objid=%d", zDate, rid ); if( b ){ fossil_fatal("ancestor check-in [%S] (%s) is not older (clock skew?)" " Use --allow-older to override.", zUuid, zDate); } #endif } /* ** zDate should be a valid date string. Convert this string into the ** format YYYY-MM-DDTHH:MM:SS. If the string is not a valid date, ** print a fatal error and quit. */ char *date_in_standard_format(const char *zInputDate){ |
︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 | */ struct CheckinInfo { Blob *pComment; /* Check-in comment text */ const char *zMimetype; /* Mimetype of check-in command. May be NULL */ int verifyDate; /* Verify that child is younger */ int closeFlag; /* Close the branch being committed */ int integrateFlag; /* Close merged-in branches */ | < | | | | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 | */ struct CheckinInfo { Blob *pComment; /* Check-in comment text */ const char *zMimetype; /* Mimetype of check-in command. May be NULL */ int verifyDate; /* Verify that child is younger */ int closeFlag; /* Close the branch being committed */ int integrateFlag; /* Close merged-in branches */ Blob *pCksum; /* Repository checksum. May be 0 */ const char *zDateOvrd; /* Date override. If 0 then use 'now' */ const char *zUserOvrd; /* User override. If 0 then use login_name() */ const char *zBranch; /* Branch name. May be 0 */ const char *zColor; /* One-time background color. May be 0 */ const char *zBrClr; /* Persistent branch color. May be 0 */ const char **azTag; /* Tags to apply to this check-in */ }; #endif /* INTERFACE */ /* ** Create a manifest. */ static void create_manifest( Blob *pOut, /* Write the manifest here */ const char *zBaselineUuid, /* UUID of baseline, or zero */ Manifest *pBaseline, /* Make it a delta manifest if not zero */ int vid, /* BLOB.id for the parent check-in */ CheckinInfo *p, /* Information about the check-in */ int *pnFBcard /* OUT: Number of generated B- and F-cards */ ){ char *zDate; /* Date of the check-in */ char *zParentUuid = 0; /* UUID of parent check-in */ Blob filename; /* A single filename */ int nBasename; /* Size of base filename */ Stmt q; /* Various queries */ Blob mcksum; /* Manifest checksum */ ManifestFile *pFile; /* File from the baseline */ int nFBcard = 0; /* Number of B-cards and F-cards */ int i; /* Loop counter */ const char *zColor; /* Modified value of p->zColor */ assert( pBaseline==0 || pBaseline->zBaseline==0 ); assert( pBaseline==0 || zBaselineUuid!=0 ); blob_zero(pOut); if( vid ){ zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND " "EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)", vid, vid); if( !zParentUuid ){ fossil_fatal("Could not find a valid check-in for RID %d. " "Possible checkout/repo mismatch.", vid); } } if( pBaseline ){ blob_appendf(pOut, "B %s\n", zBaselineUuid); manifest_file_rewind(pBaseline); pFile = manifest_file_next(pBaseline, 0); nFBcard++; |
︙ | ︙ | |||
1898 1899 1900 1901 1902 1903 1904 | db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2"); while( db_step(&q)==SQLITE_ROW ){ char *zMergeUuid; int mid = db_column_int(&q, 0); if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ){ continue; } | | | | > | | > | 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 | db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2"); while( db_step(&q)==SQLITE_ROW ){ char *zMergeUuid; int mid = db_column_int(&q, 0); if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ){ continue; } zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid); if( zMergeUuid ){ blob_appendf(pOut, " %s", zMergeUuid); if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate); free(zMergeUuid); } } db_finalize(&q); blob_appendf(pOut, "\n"); } free(zDate); db_prepare(&q, "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge" " FROM vmerge, blob" " WHERE (vmerge.id=-1 OR vmerge.id=-2)" " AND blob.rid=vmerge.merge" " ORDER BY 1"); while( db_step(&q)==SQLITE_ROW ){ const char *zCherrypickUuid = db_column_text(&q, 0); int mid = db_column_int(&q, 1); if( mid != vid ){ blob_appendf(pOut, "Q %s\n", zCherrypickUuid); } } db_finalize(&q); if( p->pCksum ) blob_appendf(pOut, "R %b\n", p->pCksum); zColor = p->zColor; if( p->zBranch && p->zBranch[0] ){ /* Set tags for the new branch */ |
︙ | ︙ | |||
1941 1942 1943 1944 1945 1946 1947 | if( zColor && zColor[0] ){ /* One-time background color */ blob_appendf(pOut, "T +bgcolor * %F\n", zColor); } if( p->closeFlag ){ blob_appendf(pOut, "T +closed *\n"); } | | < < < < < < < < | 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 | if( zColor && zColor[0] ){ /* One-time background color */ blob_appendf(pOut, "T +bgcolor * %F\n", zColor); } if( p->closeFlag ){ blob_appendf(pOut, "T +closed *\n"); } db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" " WHERE id %s ORDER BY 1", p->integrateFlag ? "IN(0,-4)" : "=(-4)"); while( db_step(&q)==SQLITE_ROW ){ const char *zIntegrateUuid = db_column_text(&q, 0); int rid = db_column_int(&q, 1); if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref " " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){ blob_appendf(pOut, "T +closed %s\n", zIntegrateUuid); } } db_finalize(&q); if( p->azTag ){ for(i=0; p->azTag[i]; i++){ |
︙ | ︙ | |||
2005 2006 2007 2008 2009 2010 2011 | ** and the original file will have been renamed to "<filename>-original". */ static int commit_warning( Blob *pContent, /* The content of the file being committed. */ int crlfOk, /* Non-zero if CR/LF warnings should be disabled. */ int binOk, /* Non-zero if binary warnings should be disabled. */ int encodingOk, /* Non-zero if encoding warnings should be disabled. */ | < < < < | | | | | | | | | | | | | < < < < < < | | | < > > | 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 | ** and the original file will have been renamed to "<filename>-original". */ static int commit_warning( Blob *pContent, /* The content of the file being committed. */ int crlfOk, /* Non-zero if CR/LF warnings should be disabled. */ int binOk, /* Non-zero if binary warnings should be disabled. */ int encodingOk, /* Non-zero if encoding warnings should be disabled. */ int noPrompt, /* 0 to always prompt, 1 for 'N', 2 for 'Y'. */ const char *zFilename, /* The full name of the file being committed. */ Blob *pReason /* Reason for warning, if any (non-fatal only). */ ){ int bReverse; /* UTF-16 byte order is reversed? */ int fUnicode; /* return value of could_be_utf16() */ int fBinary; /* does the blob content appear to be binary? */ int lookFlags; /* output flags from looks_like_utf8/utf16() */ int fHasAnyCr; /* the blob contains one or more CR chars */ int fHasLoneCrOnly; /* all detected line endings are CR only */ int fHasCrLfOnly; /* all detected line endings are CR/LF pairs */ int fHasInvalidUtf8 = 0;/* contains invalid UTF-8 */ char *zMsg; /* Warning message */ Blob fname; /* Relative pathname of the file */ static int allOk = 0; /* Set to true to disable this routine */ if( allOk ) return 0; fUnicode = could_be_utf16(pContent, &bReverse); if( fUnicode ){ lookFlags = looks_like_utf16(pContent, bReverse, LOOK_NUL); }else{ lookFlags = looks_like_utf8(pContent, LOOK_NUL); if( !(lookFlags & LOOK_BINARY) && invalid_utf8(pContent) ){ fHasInvalidUtf8 = 1; } } fHasAnyCr = (lookFlags & LOOK_CR); fBinary = (lookFlags & LOOK_BINARY); fHasLoneCrOnly = ((lookFlags & LOOK_EOL) == LOOK_LONE_CR); fHasCrLfOnly = ((lookFlags & LOOK_EOL) == LOOK_CRLF); if( fUnicode || fHasAnyCr || fBinary || fHasInvalidUtf8 ){ const char *zWarning; const char *zDisable; const char *zConvert = "c=convert/"; Blob ans; char cReply; if( fBinary ){ int fHasNul = (lookFlags & LOOK_NUL); /* contains NUL chars? */ int fHasLong = (lookFlags & LOOK_LONG); /* overly long line? */ if( binOk ){ return 0; /* We don't want binary warnings for this file. */ } if( !fHasNul && fHasLong ){ zWarning = "long lines"; zConvert = ""; /* We cannot convert overlong lines. */ }else{ |
︙ | ︙ | |||
2095 2096 2097 2098 2099 2100 2101 | zWarning = "CR line endings"; }else if( fHasCrLfOnly ){ zWarning = "CR/LF line endings"; }else{ zWarning = "mixed line endings"; } zDisable = "\"crlf-glob\" setting"; | < < < < | < < < < < | | | | < | 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 | zWarning = "CR line endings"; }else if( fHasCrLfOnly ){ zWarning = "CR/LF line endings"; }else{ zWarning = "mixed line endings"; } zDisable = "\"crlf-glob\" setting"; }else{ if( encodingOk ){ return 0; /* We don't want encoding warnings for this file. */ } zWarning = "Unicode"; zDisable = "\"encoding-glob\" setting"; } file_relative_name(zFilename, &fname, 0); zMsg = mprintf( "%s contains %s. Use --no-warnings or the %s to" " disable this warning.\n" "Commit anyhow (a=all/%sy/N)? ", blob_str(&fname), zWarning, zDisable, zConvert); if( noPrompt==0 ){ prompt_user(zMsg, &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); }else if( noPrompt==2 ){ cReply = 'Y'; }else{ |
︙ | ︙ | |||
2155 2156 2157 2158 2159 2160 2161 | blob_to_lf_only(pContent); } fwrite(blob_buffer(pContent), 1, blob_size(pContent), f); fclose(f); } return 1; }else if( cReply!='y' && cReply!='Y' ){ | | | | < < | < | | 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | blob_to_lf_only(pContent); } fwrite(blob_buffer(pContent), 1, blob_size(pContent), f); fclose(f); } return 1; }else if( cReply!='y' && cReply!='Y' ){ fossil_fatal("Abandoning commit due to %s in %s", zWarning, blob_str(&fname)); }else if( noPrompt==2 ){ if( pReason ){ blob_append(pReason, zWarning, -1); } return 1; } blob_reset(&fname); } return 0; } /* ** COMMAND: test-commit-warning ** ** Usage: %fossil test-commit-warning ?OPTIONS? ** ** Check each file in the checkout, including unmodified ones, using all ** the pre-commit checks. ** ** Options: ** --no-settings Do not consider any glob settings. ** -v|--verbose Show per-file results for all pre-commit checks. ** ** See also: commit, extras */ void test_commit_warning(void){ int rc = 0; int noSettings; int verboseFlag; Stmt q; noSettings = find_option("no-settings",0,0)!=0; verboseFlag = find_option("verbose","v",0)!=0; verify_all_options(); db_must_be_within_tree(); db_prepare(&q, "SELECT %Q || pathname, pathname, %s, %s, %s FROM vfile" " WHERE NOT deleted", g.zLocalRoot, glob_expr("pathname", noSettings ? 0 : db_get("crlf-glob", db_get("crnl-glob",""))), glob_expr("pathname", noSettings ? 0 : db_get("binary-glob","")), glob_expr("pathname", noSettings ? 0 : db_get("encoding-glob","")) ); while( db_step(&q)==SQLITE_ROW ){ const char *zFullname; const char *zName; Blob content; Blob reason; int crlfOk, binOk, encodingOk; int fileRc; zFullname = db_column_text(&q, 0); zName = db_column_text(&q, 1); crlfOk = db_column_int(&q, 2); binOk = db_column_int(&q, 3); encodingOk = db_column_int(&q, 4); blob_zero(&content); blob_read_from_file(&content, zFullname, RepoFILE); blob_zero(&reason); fileRc = commit_warning(&content, crlfOk, binOk, encodingOk, 2, zFullname, &reason); if( fileRc || verboseFlag ){ fossil_print("%d\t%s\t%s\n", fileRc, zName, blob_str(&reason)); } blob_reset(&reason); rc |= fileRc; } |
︙ | ︙ | |||
2241 2242 2243 2244 2245 2246 2247 | static int tagCmp(const void *a, const void *b){ char **pA = (char**)a; char **pB = (char**)b; return fossil_strcmp(pA[0], pB[0]); } /* | | < | | 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | static int tagCmp(const void *a, const void *b){ char **pA = (char**)a; char **pB = (char**)b; return fossil_strcmp(pA[0], pB[0]); } /* ** COMMAND: ci* ** COMMAND: commit ** ** Usage: %fossil commit ?OPTIONS? ?FILE...? ** ** Create a new version containing all of the changes in the current ** checkout. You will be prompted to enter a check-in comment unless ** the comment has been specified on the command-line using "-m" or a ** file containing the comment using -M. The editor defined in the ** "editor" fossil option (see %fossil help set) will be used, or from ** the "VISUAL" or "EDITOR" environment variables (in that order) if ** no editor is set. ** ** All files that have changed will be committed unless some subset of |
︙ | ︙ | |||
2299 2300 2301 2302 2303 2304 2305 | ** ** The --tag option applies the symbolic tag name to the check-in. ** ** The --hash option detects edited files by computing each file's ** artifact hash rather than just checking for changes to its size or mtime. ** ** Options: | | | | | | | | | < < | < | < < < < < < < | | | | < | < | < | > > | | | | < < < < | 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 | ** ** The --tag option applies the symbolic tag name to the check-in. ** ** The --hash option detects edited files by computing each file's ** artifact hash rather than just checking for changes to its size or mtime. ** ** Options: ** --allow-conflict allow unresolved merge conflicts ** --allow-empty allow a commit with no changes ** --allow-fork allow the commit to fork ** --allow-older allow a commit older than its ancestor ** --baseline use a baseline manifest in the commit process ** --bgcolor COLOR apply COLOR to this one check-in only ** --branch NEW-BRANCH-NAME check in to this new branch ** --branchcolor COLOR apply given COLOR to the branch ** --close close the branch being committed ** --delta use a delta manifest in the commit process ** --integrate close all merged-in branches ** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment ** -M|--message-file FILE read the commit comment from given file ** --mimetype MIMETYPE mimetype of check-in comment ** -n|--dry-run If given, display instead of run actions ** --no-prompt This option disables prompting the user for ** input and assumes an answer of 'No' for every ** question. ** --no-warnings omit all warnings about file contents ** --nosign do not attempt to sign this commit with gpg ** --private do not sync changes and their descendants ** --hash verify file status using hashing rather ** than relying on file mtimes ** --tag TAG-NAME assign given tag TAG-NAME to the check-in ** --date-override DATETIME DATE to use instead of 'now' ** --user-override USER USER to use instead of the current default ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. ** ** See also: branch, changes, checkout, extras, sync */ void commit_cmd(void){ int hasChanges; /* True if unsaved changes exist */ int vid; /* blob-id of parent version */ int nrid; /* blob-id of a modified file */ int nvid; /* Blob-id of the new check-in */ Blob comment; /* Check-in comment */ const char *zComment; /* Check-in comment */ Stmt q; /* Various queries */ char *zUuid; /* UUID of the new check-in */ int useHash = 0; /* True to verify file status using hashing */ int noSign = 0; /* True to omit signing the manifest using GPG */ int isAMerge = 0; /* True if checking in a merge */ int noWarningFlag = 0; /* True if skipping all warnings */ int noPrompt = 0; /* True if skipping all prompts */ int forceFlag = 0; /* Undocumented: Disables all checks */ int forceDelta = 0; /* Force a delta-manifest */ int forceBaseline = 0; /* Force a baseline-manifest */ int allowConflict = 0; /* Allow unresolve merge conflicts */ int allowEmpty = 0; /* Allow a commit with no changes */ int allowFork = 0; /* Allow the commit to fork */ |
︙ | ︙ | |||
2387 2388 2389 2390 2391 2392 2393 | Blob manifest; /* Manifest in baseline form */ Blob muuid; /* Manifest uuid */ Blob cksum1, cksum2; /* Before and after commit checksums */ Blob cksum1b; /* Checksum recorded in the manifest */ int szD; /* Size of the delta manifest */ int szB; /* Size of the baseline manifest */ int nConflict = 0; /* Number of unresolved merge conflicts */ | | | | < < < < < < < < < | < | < < < < < < < < < < < < > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > | | > > > > > > | < < > | | | < | < | | < < < | | | 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 | Blob manifest; /* Manifest in baseline form */ Blob muuid; /* Manifest uuid */ Blob cksum1, cksum2; /* Before and after commit checksums */ Blob cksum1b; /* Checksum recorded in the manifest */ int szD; /* Size of the delta manifest */ int szB; /* Size of the baseline manifest */ int nConflict = 0; /* Number of unresolved merge conflicts */ int abortCommit = 0; Blob ans; char cReply; memset(&sCiInfo, 0, sizeof(sCiInfo)); url_proxy_options(); /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */ useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0; noSign = find_option("nosign",0,0)!=0; forceDelta = find_option("delta",0,0)!=0; forceBaseline = find_option("baseline",0,0)!=0; if( forceDelta && forceBaseline ){ fossil_fatal("cannot use --delta and --baseline together"); } dryRunFlag = find_option("dry-run","n",0)!=0; if( !dryRunFlag ){ dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ } zComment = find_option("comment","m",1); forceFlag = find_option("force", "f", 0)!=0; allowConflict = find_option("allow-conflict",0,0)!=0; allowEmpty = find_option("allow-empty",0,0)!=0; allowFork = find_option("allow-fork",0,0)!=0; allowOlder = find_option("allow-older",0,0)!=0; noPrompt = find_option("no-prompt", 0, 0)!=0; noWarningFlag = find_option("no-warnings", 0, 0)!=0; sCiInfo.zBranch = find_option("branch","b",1); sCiInfo.zColor = find_option("bgcolor",0,1); sCiInfo.zBrClr = find_option("branchcolor",0,1); sCiInfo.closeFlag = find_option("close",0,0)!=0; sCiInfo.integrateFlag = find_option("integrate",0,0)!=0; sCiInfo.zMimetype = find_option("mimetype",0,1); while( (zTag = find_option("tag",0,1))!=0 ){ if( zTag[0]==0 ) continue; sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2)); sCiInfo.azTag[nTag++] = zTag; sCiInfo.azTag[nTag] = 0; } zComFile = find_option("message-file", "M", 1); if( find_option("private",0,0) ){ g.markPrivate = 1; if( sCiInfo.zBranch==0 ) sCiInfo.zBranch = "private"; if( sCiInfo.zBrClr==0 && sCiInfo.zColor==0 ){ sCiInfo.zBrClr = "#fec084"; /* Orange */ } } sCiInfo.zDateOvrd = find_option("date-override",0,1); sCiInfo.zUserOvrd = find_option("user-override",0,1); db_must_be_within_tree(); noSign = db_get_boolean("omitsign", 0)|noSign; if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; } useCksum = db_get_boolean("repo-cksum", 1); outputManifest = db_get_manifest_setting(); verify_all_options(); /* Do not allow the creation of a new branch using an existing open ** branch name unless the --force flag is used */ if( sCiInfo.zBranch!=0 && !forceFlag && fossil_strcmp(sCiInfo.zBranch,"private")!=0 && branch_is_open(sCiInfo.zBranch) ){ fossil_fatal("an open branch named \"%s\" already exists - use --force" " to override", sCiInfo.zBranch); } /* Escape special characters in tags and put all tags in sorted order */ if( nTag ){ int i; for(i=0; i<nTag; i++) sCiInfo.azTag[i] = mprintf("%F", sCiInfo.azTag[i]); qsort((void*)sCiInfo.azTag, nTag, sizeof(sCiInfo.azTag[0]), tagCmp); } /* So that older versions of Fossil (that do not understand delta- ** manifest) can continue to use this repository, do not create a new ** delta-manifest unless this repository already contains one or more ** delta-manifests, or unless the delta-manifest is explicitly requested ** by the --delta option. */ if( !forceDelta && !db_get_boolean("seen-delta-manifest",0) ){ forceBaseline = 1; } /* Get the ID of the parent manifest artifact */ vid = db_lget_int("checkout", 0); if( vid==0 ){ useCksum = 1; }else if( content_is_private(vid) ){ g.markPrivate = 1; } /* ** Autosync if autosync is enabled and this is not a private check-in. */ if( !g.markPrivate ){ if( autosync_loop(SYNC_PULL, db_get_int("autosync-tries", 1), 1) ){ fossil_exit(1); } } /* Require confirmation to continue with the check-in if there is ** clock skew */ if( g.clockSkewSeen ){ if( !noPrompt ){ prompt_user("continue in spite of time skew (y/N)? ", &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); }else{ fossil_print("Abandoning commit due to time skew\n"); cReply = 'N'; } if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } } /* There are two ways this command may be executed. If there are ** no arguments following the word "commit", then all modified files ** in the checked out directory are committed. If one or more arguments ** follows "commit", then only those files are committed. ** ** After the following function call has returned, the Global.aCommitFile[] ** array is allocated to contain the "id" field from the vfile table ** for each file to be committed. Or, if aCommitFile is NULL, all files ** should be committed. */ |
︙ | ︙ | |||
2636 2637 2638 2639 2640 2641 2642 | " WHERE is_selected(id)" " AND (chnged OR deleted OR rid=0 OR pathname!=origname)") ){ fossil_fatal("none of the selected files have changed; use " "--allow-empty to override."); } | < < < < < | | | | | > | | > | > > > > | < | < < < < < < | < | | < | | | | | | > > | | | | | | | | | | < < < < < < < < | | | | | | | > > | | | | | | | | | | | | < < < < < < < < < < | < < < < < < < > | | | < | < | < < < < < < < < < | | < | < | | | | < | < | 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 | " WHERE is_selected(id)" " AND (chnged OR deleted OR rid=0 OR pathname!=origname)") ){ fossil_fatal("none of the selected files have changed; use " "--allow-empty to override."); } /* ** Do not allow a commit that will cause a fork unless the --allow-fork ** or --force flags is used, or unless this is a private check-in. ** The initial commit MUST have tags "trunk" and "sym-trunk". */ if( !vid ){ if( sCiInfo.zBranch==0 ){ if( allowFork==0 && forceFlag==0 && g.markPrivate==0 && db_exists("SELECT 1 from event where type='ci'") ){ fossil_fatal("would fork. \"update\" first or use --allow-fork."); } sCiInfo.zBranch = db_get("main-branch", "trunk"); } }else if( sCiInfo.zBranch==0 && allowFork==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){ fossil_fatal("would fork. \"update\" first or use --allow-fork."); } /* ** Do not allow a commit against a closed leaf unless the commit ** ends up on a different branch. */ if( /* parent check-in has the "closed" tag... */ db_exists("SELECT 1 FROM tagxref" " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, vid) /* ... and the new check-in has no --branch option or the --branch ** option does not actually change the branch */ && (sCiInfo.zBranch==0 || db_exists("SELECT 1 FROM tagxref" " WHERE tagid=%d AND rid=%d AND tagtype>0" " AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch)) ){ fossil_fatal("cannot commit against a closed leaf"); } if( zComment ){ blob_zero(&comment); blob_append(&comment, zComment, -1); }else if( zComFile ){ blob_zero(&comment); blob_read_from_file(&comment, zComFile, ExtFILE); blob_to_utf8_no_bom(&comment, 1); }else if( dryRunFlag ){ blob_zero(&comment); }else if( !noPrompt ){ char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'"); prepare_commit_comment(&comment, zInit, &sCiInfo, vid); if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){ prompt_user("unchanged check-in comment. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } } free(zInit); } if( blob_size(&comment)==0 ){ if( !dryRunFlag ){ if( !noPrompt ){ prompt_user("empty check-in comment. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); }else{ fossil_print("Abandoning commit due to empty check-in comment\n"); cReply = 'N'; } if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } } }else{ db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment); db_end_transaction(0); db_begin_transaction(); } /* ** Step 1: Compute an aggregate MD5 checksum over the disk image ** of every file in vid. The file names are part of the checksum. ** The resulting checksum is the same as is expected on the R-card ** of a manifest. */ if( useCksum ) vfile_aggregate_checksum_disk(vid, &cksum1); /* Step 2: Insert records for all modified files into the blob ** table. If there were arguments passed to this command, only ** the identified files are inserted (if they have been modified). */ db_prepare(&q, "SELECT id, %Q || pathname, mrid, %s, %s, %s FROM vfile " "WHERE chnged==1 AND NOT deleted AND is_selected(id)", g.zLocalRoot, glob_expr("pathname", db_get("crlf-glob",db_get("crnl-glob",""))), glob_expr("pathname", db_get("binary-glob","")), glob_expr("pathname", db_get("encoding-glob","")) ); while( db_step(&q)==SQLITE_ROW ){ int id, rid; const char *zFullname; Blob content; int crlfOk, binOk, encodingOk; id = db_column_int(&q, 0); zFullname = db_column_text(&q, 1); rid = db_column_int(&q, 2); crlfOk = db_column_int(&q, 3); binOk = db_column_int(&q, 4); encodingOk = db_column_int(&q, 5); blob_zero(&content); blob_read_from_file(&content, zFullname, RepoFILE); /* Do not emit any warnings when they are disabled. */ if( !noWarningFlag ){ abortCommit |= commit_warning(&content, crlfOk, binOk, encodingOk, noPrompt, zFullname, 0); } if( contains_merge_marker(&content) ){ Blob fname; /* Relative pathname of the file */ nConflict++; file_relative_name(zFullname, &fname, 0); fossil_print("possible unresolved merge conflict in %s\n", blob_str(&fname)); blob_reset(&fname); } nrid = content_put(&content); blob_reset(&content); if( rid>0 ){ content_deltify(rid, &nrid, 1, 0); } db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id); db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); } db_finalize(&q); if( nConflict && !allowConflict ){ fossil_fatal("abort due to unresolved merge conflicts; " "use --allow-conflict to override"); }else if( abortCommit ){ fossil_fatal("one or more files were converted on your request; " |
︙ | ︙ | |||
2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 | } if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){ if( !noPrompt ){ prompt_user("unable to sign manifest. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); }else{ cReply = 'N'; } if( cReply!='y' && cReply!='Y' ){ | > | | 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 | } if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){ if( !noPrompt ){ prompt_user("unable to sign manifest. continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; blob_reset(&ans); }else{ fossil_print("Abandoning commit due to manifest signing failure\n"); cReply = 'N'; } if( cReply!='y' && cReply!='Y' ){ fossil_exit(1); } } /* If the -n|--dry-run option is specified, output the manifest file ** and rollback the transaction. */ if( dryRunFlag ){ |
︙ | ︙ | |||
2912 2913 2914 2915 2916 2917 2918 | free(zManifestFile); } nvid = content_put(&manifest); if( nvid==0 ){ fossil_fatal("trouble committing manifest: %s", g.zErrMsg); } | | > | | 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 | free(zManifestFile); } nvid = content_put(&manifest); if( nvid==0 ){ fossil_fatal("trouble committing manifest: %s", g.zErrMsg); } db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); if( manifest_crosslink(nvid, &manifest, dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){ fossil_fatal("%s", g.zErrMsg); } assert( blob_is_reset(&manifest) ); content_deltify(vid, &nvid, 1, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" " WHERE id=-4"); while( db_step(&q)==SQLITE_ROW ){ const char *zIntegrateUuid = db_column_text(&q, 0); if( is_a_leaf(db_column_int(&q, 1)) ){ fossil_print("Closed: %s\n", zIntegrateUuid); }else{ fossil_print("Not_Closed: %s (not a leaf any more)\n", zIntegrateUuid); } |
︙ | ︙ | |||
2947 2948 2949 2950 2951 2952 2953 | } /* Update the vfile and vmerge tables */ db_multi_exec( "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);" "DELETE FROM vmerge;" "UPDATE vfile SET vid=%d;" | | | | 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 | } /* Update the vfile and vmerge tables */ db_multi_exec( "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);" "DELETE FROM vmerge;" "UPDATE vfile SET vid=%d;" "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL" " WHERE is_selected(id);" , vid, nvid ); db_lset_int("checkout", nvid); /* Update the isexe and islink columns of the vfile table */ db_prepare(&q, "UPDATE vfile SET isexe=:exec, islink=:link" " WHERE vid=:vid AND pathname=:path AND (isexe!=:exec OR islink!=:link)" ); db_bind_int(&q, ":vid", nvid); |
︙ | ︙ | |||
2979 2980 2981 2982 2983 2984 2985 | /* Verify that the repository checksum matches the expected checksum ** calculated before the check-in started (and stored as the R record ** of the manifest file). */ vfile_aggregate_checksum_repository(nvid, &cksum2); if( blob_compare(&cksum1, &cksum2) ){ vfile_compare_repository_to_disk(nvid); | | | | | < | < < | 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 | /* Verify that the repository checksum matches the expected checksum ** calculated before the check-in started (and stored as the R record ** of the manifest file). */ vfile_aggregate_checksum_repository(nvid, &cksum2); if( blob_compare(&cksum1, &cksum2) ){ vfile_compare_repository_to_disk(nvid); fossil_fatal("working checkout does not match what would have ended " "up in the repository: %b versus %b", &cksum1, &cksum2); } /* Verify that the manifest checksum matches the expected checksum */ vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b); if( blob_compare(&cksum1, &cksum1b) ){ fossil_fatal("manifest checksum self-test failed: " "%b versus %b", &cksum1, &cksum1b); } if( blob_compare(&cksum1, &cksum2) ){ fossil_fatal( "working checkout does not match manifest after commit: " "%b versus %b", &cksum1, &cksum2); } /* Verify that the commit did not modify any disk images. */ vfile_aggregate_checksum_disk(nvid, &cksum2); if( blob_compare(&cksum1, &cksum2) ){ fossil_fatal("working checkout before and after commit does not match"); } } /* Clear the undo/redo stack */ undo_reset(); /* Commit */ db_multi_exec("DELETE FROM vvar WHERE name='ci-comment'"); db_multi_exec("PRAGMA repository.application_id=252006673;"); db_multi_exec("PRAGMA localdb.application_id=252006674;"); if( dryRunFlag ){ db_end_transaction(1); exit(1); } db_end_transaction(0); if( outputManifest & MFESTFLG_TAGS ){ Blob tagslist; zManifestFile = mprintf("%smanifest.tags", g.zLocalRoot); blob_zero(&tagslist); get_checkin_taglist(nvid, &tagslist); blob_write_to_file(&tagslist, zManifestFile); blob_reset(&tagslist); free(zManifestFile); } if( !g.markPrivate ){ autosync_loop(SYNC_PUSH|SYNC_PULL, db_get_int("autosync-tries", 1), 0); } if( count_nonbranch_children(vid)>1 ){ fossil_print("**** warning: a fork has occurred *****\n"); } } |
Changes to src/checkout.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** from the local repository. */ #include "config.h" #include "checkout.h" #include <assert.h> /* | | | | < < < < < | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < > | | | 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 | ** from the local repository. */ #include "config.h" #include "checkout.h" #include <assert.h> /* ** Check to see if there is an existing checkout that has been ** modified. Return values: ** ** 0: There is an existing checkout but it is unmodified ** 1: There is a modified checkout - there are unsaved changes */ int unsaved_changes(unsigned int cksigFlags){ int vid; db_must_be_within_tree(); vid = db_lget_int("checkout",0); vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE); return db_exists("SELECT 1 FROM vfile WHERE chnged" " OR coalesce(origname!=pathname,0)"); } /* ** Undo the current check-out. Unlink all files from the disk. ** Clear the VFILE table. */ void uncheckout(int vid){ if( vid>0 ){ vfile_unlink(vid); } db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid); } /* ** Given the abbreviated UUID name of a version, load the content of that ** version in the VFILE table. Return the VID for the version. ** ** If anything goes wrong, panic. */ int load_vfile(const char *zName, int forceMissingFlag){ Blob uuid; int vid; blob_init(&uuid, zName, -1); if( name_to_uuid(&uuid, 1, "ci") ){ fossil_fatal("%s", g.zErrMsg); } vid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid); if( vid==0 ){ fossil_fatal("no such check-in: %s", g.argv[2]); } if( !is_a_version(vid) ){ fossil_fatal("object [%S] is not a check-in", blob_str(&uuid)); } if( load_vfile_from_rid(vid) && !forceMissingFlag ){ fossil_fatal("missing content, unable to checkout"); }; return vid; } /* ** Set or clear the vfile.isexe flag for a file. */ |
︙ | ︙ | |||
178 179 180 181 182 183 184 | int flg; flg = db_get_manifest_setting(); if( flg & MFESTFLG_RAW ){ blob_zero(&manifest); content_get(vid, &manifest); | | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | int flg; flg = db_get_manifest_setting(); if( flg & MFESTFLG_RAW ){ blob_zero(&manifest); content_get(vid, &manifest); sterilize_manifest(&manifest); zManFile = mprintf("%smanifest", g.zLocalRoot); blob_write_to_file(&manifest, zManFile); free(zManFile); }else{ if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ zManFile = mprintf("%smanifest", g.zLocalRoot); file_delete(zManFile); |
︙ | ︙ | |||
255 256 257 258 259 260 261 | db_reset(&stmt); db_finalize(&stmt); } /* ** COMMAND: checkout* | | < < < < < | | | | | | | < < < | | | | | < < | < < | | < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | db_reset(&stmt); db_finalize(&stmt); } /* ** COMMAND: checkout* ** COMMAND: co* ** ** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS? ** or: %fossil co ?VERSION | --latest? ?OPTIONS? ** ** Check out a version specified on the command-line. This command ** will abort if there are edited files in the current checkout unless ** the --force option appears on the command-line. The --keep option ** leaves files on disk unchanged, except the manifest and manifest.uuid ** files. ** ** The --latest flag can be used in place of VERSION to checkout the ** latest version in the repository. ** ** Options: ** --force Ignore edited files in the current checkout ** --keep Only update the manifest and manifest.uuid files ** --force-missing Force checkout even if content is missing ** ** See also: update */ void checkout_cmd(void){ int forceFlag; /* Force checkout even if edits exist */ int forceMissingFlag; /* Force checkout even if missing content */ int keepFlag; /* Do not change any files on disk */ int latestFlag; /* Checkout the latest version */ char *zVers; /* Version to checkout */ int promptFlag; /* True to prompt before overwriting */ int vid, prior; Blob cksum1, cksum1b, cksum2; db_must_be_within_tree(); db_begin_transaction(); forceFlag = find_option("force","f",0)!=0; forceMissingFlag = find_option("force-missing",0,0)!=0; keepFlag = find_option("keep",0,0)!=0; latestFlag = find_option("latest",0,0)!=0; promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; /* We should be done with options.. */ verify_all_options(); if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ usage("VERSION|--latest ?--force? ?--keep?"); } if( !forceFlag && unsaved_changes(0) ){ fossil_fatal("there are unsaved changes in the current checkout"); } if( forceFlag ){ db_multi_exec("DELETE FROM vfile"); prior = 0; }else{ prior = db_lget_int("checkout",0); } if( latestFlag ){ compute_leaves(db_lget_int("checkout",0), 1); zVers = db_text(0, "SELECT uuid FROM leaves, event, blob" " WHERE event.objid=leaves.rid AND blob.rid=leaves.rid" " ORDER BY event.mtime DESC"); if( zVers==0 ){ zVers = db_text(0, "SELECT uuid FROM event, blob" " WHERE event.objid=blob.rid AND event.type='ci'" " ORDER BY event.mtime DESC"); } if( zVers==0 ){ return; } }else{ zVers = g.argv[2]; } vid = load_vfile(zVers, forceMissingFlag); if( prior==vid ){ db_end_transaction(0); return; } if( !keepFlag ){ uncheckout(prior); } db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); if( !keepFlag ){ vfile_to_disk(vid, 0, !g.fQuiet, promptFlag); } checkout_set_all_exe(vid); manifest_to_disk(vid); ensure_empty_dirs_created(); db_lset_int("checkout", vid); undo_reset(); db_multi_exec("DELETE FROM vmerge"); if( !keepFlag && db_get_boolean("repo-cksum",1) ){ vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); vfile_aggregate_checksum_disk(vid, &cksum2); if( blob_compare(&cksum1, &cksum2) ){ fossil_print("WARNING: manifest checksum does not agree with disk\n"); } if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ fossil_print("WARNING: manifest checksum does not agree with manifest\n"); } } db_end_transaction(0); } /* ** Unlink the local database file */ static void unlink_local_database(int manifestOnly){ |
︙ | ︙ | |||
390 391 392 393 394 395 396 | } /* ** COMMAND: close* ** ** Usage: %fossil close ?OPTIONS? ** | | | | | | | > > | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | } /* ** COMMAND: close* ** ** Usage: %fossil close ?OPTIONS? ** ** The opposite of "open". Close the current database connection. ** Require a -f or --force flag if there are unsaved changes in the ** current check-out or if there is non-empty stash. ** ** Options: ** --force|-f necessary to close a check out with uncommitted changes ** ** See also: open */ void close_cmd(void){ int forceFlag = find_option("force","f",0)!=0; db_must_be_within_tree(); /* We should be done with options.. */ verify_all_options(); if( !forceFlag && unsaved_changes(0) ){ fossil_fatal("there are unsaved changes in the current checkout"); } if( !forceFlag && db_table_exists("localdb","stash") && db_exists("SELECT 1 FROM localdb.stash") ){ fossil_fatal("closing the checkout will delete your stash"); } if( db_is_writeable("repository") ){ char *zUnset = mprintf("ckout:%q", g.zLocalRoot); db_unset(zUnset, 1); fossil_free(zUnset); } unlink_local_database(1); db_close(1); unlink_local_database(0); } |
Changes to src/clone.c.
︙ | ︙ | |||
78 79 80 81 82 83 84 | ); } /* ** COMMAND: clone ** | | | < | < | < | | < | > | < | | | | | | < < < < < < < < < | | | | < < < < < < | > < < | < < < < < < < < < < | < < < < < < < | | < < < < < < < < < < < < < < < < | | < < < < | < | | < | | | | | < < < < | | < < < < < < < | < < | < | < < < < | < < | < < < < < | < < < < < < < < < < < < < < < < < < < < > | > | > > < < < | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | ); } /* ** COMMAND: clone ** ** Usage: %fossil clone ?OPTIONS? URI FILENAME ** ** Make a clone of a repository specified by URI in the local ** file named FILENAME. ** ** URI may be one of the following form: ([...] mean optional) ** HTTP/HTTPS protocol: ** http[s]://[userid[:password]@]host[:port][/path] ** ** SSH protocol: ** ssh://[userid@]host[:port]/path/to/repo.fossil\\ ** [?fossil=path/to/fossil.exe] ** ** Filesystem: ** [file://]path/to/repo.fossil ** ** Note 1: For ssh and filesystem, path must have an extra leading ** '/' to use an absolute path. ** ** Note 2: Use %HH escapes for special characters in the userid and ** password. For example "%40" in place of "@", "%2f" in place ** of "/", and "%3a" in place of ":". ** ** By default, your current login name is used to create the default ** admin user. This can be overridden using the -A|--admin-user ** parameter. ** ** Options: ** --admin-user|-A USERNAME Make USERNAME the administrator ** --nocompress Omit extra delta compression ** --once Don't remember the URI. ** --private Also clone private branches ** --ssl-identity FILENAME Use the SSL identity if requested by the server ** --ssh-command|-c SSH Use SSH as the "ssh" command ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests ** -u|--unversioned Also sync unversioned content ** -v|--verbose Show more statistics in output ** ** See also: init */ void clone_cmd(void){ char *zPassword; const char *zDefaultUser; /* Optional name of the default user */ const char *zHttpAuth; /* HTTP Authorization user:pass information */ int nErr = 0; int urlFlags = URL_PROMPT_PW | URL_REMEMBER; int syncFlags = SYNC_CLONE; int noCompress = find_option("nocompress",0,0)!=0; /* Also clone private branches */ if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE; if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER; if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE; if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED; zHttpAuth = find_option("httpauth","B",1); zDefaultUser = find_option("admin-user","A",1); clone_ssh_find_options(); url_proxy_options(); /* We should be done with options.. */ verify_all_options(); if( g.argc < 4 ){ usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY"); } db_open_config(0, 0); if( -1 != file_size(g.argv[3], ExtFILE) ){ fossil_fatal("file already exists: %s", g.argv[3]); } url_parse(g.argv[2], urlFlags); if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user; if( g.url.isFile ){ file_copy(g.url.name, g.argv[3]); db_close(1); db_open_repository(g.argv[3]); db_record_repository_filename(g.argv[3]); url_remember(); if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content(); shun_artifacts(); db_create_default_users(1, zDefaultUser); if( zDefaultUser ){ g.zLogin = zDefaultUser; }else{ g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); } fossil_print("Repository cloned into %s\n", g.argv[3]); }else{ db_close_config(); db_create_repository(g.argv[3]); db_open_repository(g.argv[3]); db_open_config(0,0); db_begin_transaction(); db_record_repository_filename(g.argv[3]); db_initial_setup(0, 0, zDefaultUser); user_select(); db_set("content-schema", CONTENT_SCHEMA, 0); db_set("aux-schema", AUX_SCHEMA_MAX, 0); db_set("rebuilt", get_version(), 0); db_unset("hash-policy", 0); remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]); url_remember(); if( g.zSSLIdentity!=0 ){ /* If the --ssl-identity option was specified, store it as a setting */ Blob fn; blob_zero(&fn); file_canonical_name(g.zSSLIdentity, &fn, 0); db_set("ssl-identity", blob_str(&fn), 0); blob_reset(&fn); } db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('server-code', lower(hex(randomblob(20))), now());" "DELETE FROM config WHERE name='project-code';" ); url_enable_proxy(0); clone_ssh_db_set_options(); url_get_password_if_needed(); g.xlinkClusterOnly = 1; nErr = client_sync(syncFlags,CONFIGSET_ALL,0); g.xlinkClusterOnly = 0; verify_cancel(); db_end_transaction(0); db_close(1); if( nErr ){ file_delete(g.argv[3]); fossil_fatal("server returned an error - clone aborted"); } db_open_repository(g.argv[3]); } db_begin_transaction(); fossil_print("Rebuilding repository meta-data...\n"); rebuild_db(0, 1, 0); if( !noCompress ){ fossil_print("Extra delta compression... "); fflush(stdout); extra_deltification(); fossil_print("\n"); } db_end_transaction(0); fossil_print("Vacuuming the database... "); fflush(stdout); if( db_int(0, "PRAGMA page_count")>1000 && db_int(0, "PRAGMA page_size")<8192 ){ db_multi_exec("PRAGMA page_size=8192;"); } db_multi_exec("VACUUM"); fossil_print("\nproject-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); } /* ** If user chooses to use HTTP Authentication over unencrypted HTTP, ** remember decision. Otherwise, if the URL is being changed and no ** preference has been indicated, err on the safe side and revert the ** decision. Set the global preference if the URL is not being changed. */ void remember_or_get_http_auth( const char *zHttpAuth, /* Credentials in the form "user:password" */ int fRemember, /* True to remember credentials for later reuse */ const char *zUrl /* URL for which these credentials apply */ ){ char *zKey = mprintf("http-auth:%s", g.url.canonical); if( zHttpAuth && zHttpAuth[0] ){ g.zHttpAuth = mprintf("%s", zHttpAuth); } if( fRemember ){ if( g.zHttpAuth && g.zHttpAuth[0] ){ set_httpauth(g.zHttpAuth); }else if( zUrl && zUrl[0] ){ db_unset(zKey, 0); }else{ g.zHttpAuth = get_httpauth(); } }else if( g.zHttpAuth==0 && zUrl==0 ){ g.zHttpAuth = get_httpauth(); } free(zKey); } /* ** Get the HTTP Authorization preference from db. */ char *get_httpauth(void){ char *zKey = mprintf("http-auth:%s", g.url.canonical); char * rc = unobscure(db_get(zKey, 0)); free(zKey); return rc; } /* ** Set the HTTP Authorization preference in db. */ void set_httpauth(const char *zHttpAuth){ char *zKey = mprintf("http-auth:%s", g.url.canonical); db_set(zKey, obscure(zHttpAuth), 0); free(zKey); } /* ** Look for SSH clone command line options and setup in globals. */ void clone_ssh_find_options(void){ const char *zSshCmd; /* SSH command string */ zSshCmd = find_option("ssh-command","c",1); if( zSshCmd && zSshCmd[0] ){ g.zSshCmd = mprintf("%s", zSshCmd); } } /* ** Set SSH options discovered in global variables (set from command line ** options). */ void clone_ssh_db_set_options(void){ if( g.zSshCmd && g.zSshCmd[0] ){ db_set("ssh-command", g.zSshCmd, 0); } } /* ** WEBPAGE: download ** ** Provide a simple page that enables newbies to download the latest tarball or ** ZIP archive, and provides instructions on how to clone. */ void download_page(void){ login_check_credentials(); style_header("Download Page"); if( !g.perm.Zip ){ @ <p>Bummer. You do not have permission to download. if( g.zLogin==0 || g.zLogin[0]==0 ){ @ Maybe it would work better if you @ <a href="../login">logged in</a>. }else{ @ Contact the site administrator and ask them to give @ you "Download Zip" privileges. } }else{ const char *zDLTag = db_get("download-tag","trunk"); const char *zNm = db_get("short-project-name","download"); char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm); @ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a> zUrl = href("%R/tarball/%t/%t.tar.gz", zDLTag, zNm); @ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a> zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm); @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a> } if( !g.perm.Clone ){ @ <p>You are not authorized to clone this repository. if( g.zLogin==0 || g.zLogin[0]==0 ){ @ Maybe you would be able to clone if you @ <a href="../login">logged in</a>. }else{ @ Contact the site administrator and ask them to give @ you "Clone" privileges in order to clone. } }else{ const char *zNm = db_get("short-project-name","clone"); @ <p>Clone the repository using this command: @ <blockquote><pre> @ fossil clone %s(g.zBaseURL) %h(zNm).fossil @ </pre></blockquote> } style_footer(); } |
Added src/codecheck1.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | /* ** Copyright (c) 2014 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This program reads Fossil source code files and tries to verify that ** printf-style format strings are correct. ** ** This program implements a compile-time validation step on the Fossil ** source code. Running this program is entirely optional. Its role is ** similar to the -Wall compiler switch on gcc, or the scan-build utility ** of clang, or other static analyzers. The purpose is to try to identify ** problems in the source code at compile-time. The difference is that this ** static checker is specifically designed for the particular printf formatter ** implementation used by Fossil. ** ** Checks include: ** ** * Verify that vararg formatting routines like blob_printf() or ** db_multi_exec() have the correct number of arguments for their ** format string. ** ** * For routines designed to generate SQL, warn about the use of %s ** which might allow SQL injection. */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <assert.h> /* ** Debugging switch */ static int eVerbose = 0; /* ** Malloc, aborting if it fails. */ void *safe_malloc(int nByte){ void *x = malloc(nByte); if( x==0 ){ fprintf(stderr, "failed to allocate %d bytes\n", nByte); exit(1); } return x; } void *safe_realloc(void *pOld, int nByte){ void *x = realloc(pOld, nByte); if( x==0 ){ fprintf(stderr, "failed to allocate %d bytes\n", nByte); exit(1); } return x; } /* ** Read the entire content of the file named zFilename into memory obtained ** from malloc(). Add a zero-terminator to the end. ** Return a pointer to that memory. */ static char *read_file(const char *zFilename){ FILE *in; char *z; int nByte; int got; in = fopen(zFilename, "rb"); if( in==0 ){ return 0; } fseek(in, 0, SEEK_END); nByte = ftell(in); fseek(in, 0, SEEK_SET); z = safe_malloc( nByte+1 ); got = fread(z, 1, nByte, in); z[got] = 0; fclose(in); return z; } /* ** When parsing the input file, the following token types are recognized. */ #define TK_SPACE 1 /* Whitespace or comments */ #define TK_ID 2 /* An identifier */ #define TK_STR 3 /* A string literal in double-quotes */ #define TK_OTHER 4 /* Any other token */ #define TK_EOF 99 /* End of file */ /* ** Determine the length and type of the token beginning at z[0] */ static int token_length(const char *z, int *pType, int *pLN){ int i; if( z[0]==0 ){ *pType = TK_EOF; return 0; } if( z[0]=='"' || z[0]=='\'' ){ for(i=1; z[i] && z[i]!=z[0]; i++){ if( z[i]=='\\' && z[i+1]!=0 ){ if( z[i+1]=='\n' ) (*pLN)++; i++; } } if( z[i]!=0 ) i++; *pType = z[0]=='"' ? TK_STR : TK_OTHER; return i; } if( isalnum(z[0]) || z[0]=='_' ){ for(i=1; isalnum(z[i]) || z[i]=='_'; i++){} *pType = isalpha(z[0]) || z[0]=='_' ? TK_ID : TK_OTHER; return i; } if( isspace(z[0]) ){ if( z[0]=='\n' ) (*pLN)++; for(i=1; isspace(z[i]); i++){ if( z[i]=='\n' ) (*pLN)++; } *pType = TK_SPACE; return i; } if( z[0]=='/' && z[1]=='*' ){ for(i=2; z[i] && (z[i]!='*' || z[i+1]!='/'); i++){ if( z[i]=='\n' ) (*pLN)++; } if( z[i] ) i += 2; *pType = TK_SPACE; return i; } if( z[0]=='/' && z[1]=='/' ){ for(i=2; z[i] && z[i]!='\n'; i++){} if( z[i] ){ (*pLN)++; i++; } *pType = TK_SPACE; return i; } if( z[0]=='\\' && (z[1]=='\n' || (z[1]=='\r' && z[2]=='\n')) ){ *pType = TK_SPACE; return 1; } *pType = TK_OTHER; return 1; } /* ** Return the next non-whitespace token */ const char *next_non_whitespace(const char *z, int *pLen, int *pType){ int len; int eType; int ln = 0; while( (len = token_length(z, &eType, &ln))>0 && eType==TK_SPACE ){ z += len; } *pLen = len; *pType = eType; return z; } /* ** Return index into z[] for the first balanced TK_OTHER token with ** value cValue. */ static int distance_to(const char *z, char cVal){ int len; int dist = 0; int eType; int nNest = 0; int ln = 0; while( z[0] && (len = token_length(z, &eType, &ln))>0 ){ if( eType==TK_OTHER ){ if( z[0]==cVal && nNest==0 ){ break; }else if( z[0]=='(' ){ nNest++; }else if( z[0]==')' ){ nNest--; } } dist += len; z += len; } return dist; } /* ** Return the first non-whitespace characters in z[] */ static const char *skip_space(const char *z){ while( isspace(z[0]) ){ z++; } return z; } /* ** Remove excess whitespace and nested "()" from string z. */ static char *simplify_expr(char *z){ int n = (int)strlen(z); while( n>0 ){ if( isspace(z[0]) ){ z++; n--; continue; } if( z[0]=='(' && z[n-1]==')' ){ z++; n -= 2; continue; } break; } z[n] = 0; return z; } /* ** Return true if the input is a string literal. */ static int is_string_lit(const char *z){ int nu1, nu2; z = next_non_whitespace(z, &nu1, &nu2); if( strcmp(z, "NULL")==0 ) return 1; return z[0]=='"'; } /* ** Return true if the input is an expression of string literals: ** ** EXPR ? "..." : "..." */ static int is_string_expr(const char *z){ int len = 0, eType; const char *zOrig = z; len = distance_to(z, '?'); if( z[len]==0 && skip_space(z)[0]=='(' ){ z = skip_space(z) + 1; len = distance_to(z, '?'); } z += len; if( z[0]=='?' ){ z++; z = next_non_whitespace(z, &len, &eType); if( eType==TK_STR ){ z += len; z = next_non_whitespace(z, &len, &eType); if( eType==TK_OTHER && z[0]==':' ){ z += len; z = next_non_whitespace(z, &len, &eType); if( eType==TK_STR ){ z += len; z = next_non_whitespace(z, &len, &eType); if( eType==TK_EOF ) return 1; if( eType==TK_OTHER && z[0]==')' && skip_space(zOrig)[0]=='(' ){ z += len; z = next_non_whitespace(z, &len, &eType); if( eType==TK_EOF ) return 1; } } } } } return 0; } /* ** A list of functions that return strings that are safe to insert into ** SQL using %s. */ static const char *azSafeFunc[] = { "filename_collation", "leaf_is_closed_sql", "timeline_query_for_www", "timeline_query_for_tty", "blob_sql_text", "glob_expr", "fossil_all_reserved_names", "configure_inop_rhs", "db_setting_inop_rhs", }; /* ** Return true if the input is an argument that is safe to use with %s ** while building an SQL statement. */ static int is_sql_safe(const char *z){ int len, eType; int i; /* A string literal is safe for use with %s */ if( is_string_lit(z) ) return 1; /* Certain functions are guaranteed to return a string that is safe ** for use with %s */ z = next_non_whitespace(z, &len, &eType); for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){ if( eType==TK_ID && strncmp(z, azSafeFunc[i], len)==0 && strlen(azSafeFunc[i])==len ){ return 1; } } /* Expressions of the form: EXPR ? "..." : "...." can count as ** a string literal. */ if( is_string_expr(z) ) return 1; /* If the "safe-for-%s" comment appears in the argument, then ** let it through */ if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1; return 0; } /* ** Return true if the input is an argument that is never safe for use ** with %s. */ static int never_safe(const char *z){ if( strstr(z,"/*safe-for-%s*/")!=0 ) return 0; if( z[0]=='P' ){ if( strncmp(z,"PIF(",4)==0 ) return 0; if( strncmp(z,"PCK(",4)==0 ) return 0; return 1; } if( strncmp(z,"cgi_param",9)==0 ) return 1; return 0; } /* ** Processing flags */ #define FMT_SQL 0x00001 /* Generates SQL text */ #define FMT_HTML 0x00002 /* Generates HTML text */ #define FMT_URL 0x00004 /* Generates URLs */ #define FMT_SAFE 0x00008 /* Always safe for %s */ /* ** A list of internal Fossil interfaces that take a printf-style format ** string. */ struct { const char *zFName; /* Name of the function */ int iFmtArg; /* Index of format argument. Leftmost is 1. */ unsigned fmtFlags; /* Processing flags */ } aFmtFunc[] = { { "admin_log", 1, 0 }, { "blob_append_sql", 2, FMT_SQL }, { "blob_appendf", 2, 0 }, { "cgi_debug", 1, FMT_SAFE }, { "cgi_panic", 1, FMT_SAFE }, { "cgi_printf", 1, FMT_HTML }, { "cgi_redirectf", 1, FMT_URL }, { "chref", 2, FMT_URL }, { "db_blob", 2, FMT_SQL }, { "db_debug", 1, FMT_SQL }, { "db_double", 2, FMT_SQL }, { "db_err", 1, 0 }, { "db_exists", 1, FMT_SQL }, { "db_get_mprintf", 2, 0 }, { "db_int", 2, FMT_SQL }, { "db_int64", 2, FMT_SQL }, { "db_multi_exec", 1, FMT_SQL }, { "db_optional_sql", 2, FMT_SQL }, { "db_prepare", 2, FMT_SQL }, { "db_prepare_ignore_error", 2, FMT_SQL }, { "db_set_mprintf", 3, 0 }, { "db_static_prepare", 2, FMT_SQL }, { "db_text", 2, FMT_SQL }, { "db_unset_mprintf", 2, 0 }, { "form_begin", 2, FMT_URL }, { "fossil_error", 2, FMT_SAFE }, { "fossil_errorlog", 1, FMT_SAFE }, { "fossil_fatal", 1, FMT_SAFE }, { "fossil_fatal_recursive", 1, FMT_SAFE }, { "fossil_panic", 1, FMT_SAFE }, { "fossil_print", 1, FMT_SAFE }, { "fossil_trace", 1, FMT_SAFE }, { "fossil_warning", 1, FMT_SAFE }, { "href", 1, FMT_URL }, { "json_new_string_f", 1, 0 }, { "json_set_err", 2, 0 }, { "json_warn", 2, 0 }, { "mprintf", 1, 0 }, { "socket_set_errmsg", 1, 0 }, { "ssl_set_errmsg", 1, 0 }, { "style_header", 1, FMT_HTML }, { "style_js_onload", 1, FMT_HTML }, { "style_set_current_page", 1, FMT_URL }, { "style_submenu_element", 2, FMT_URL }, { "style_submenu_sql", 3, FMT_SQL }, { "webpage_error", 1, FMT_SAFE }, { "xhref", 2, FMT_URL }, }; /* ** Determine if the indentifier zIdent of length nIndent is a Fossil ** internal interface that uses a printf-style argument. Return zero if not. ** Return the index of the format string if true with the left-most ** argument having an index of 1. */ static int isFormatFunc(const char *zIdent, int nIdent, unsigned *pFlags){ int upr, lwr; lwr = 0; upr = sizeof(aFmtFunc)/sizeof(aFmtFunc[0]) - 1; while( lwr<=upr ){ unsigned x = (lwr + upr)/2; int c = strncmp(zIdent, aFmtFunc[x].zFName, nIdent); if( c==0 ){ if( aFmtFunc[x].zFName[nIdent]==0 ){ *pFlags = aFmtFunc[x].fmtFlags; return aFmtFunc[x].iFmtArg; } c = -1; } if( c<0 ){ upr = x - 1; }else{ lwr = x + 1; } } *pFlags = 0; return 0; } /* ** Return the expected number of arguments for the format string. ** Return -1 if the value cannot be computed. ** ** For each argument less than nType, store the conversion character ** for that argument in cType[i]. */ static int formatArgCount(const char *z, int nType, char *cType){ int nArg = 0; int i, k; int len; int eType; int ln = 0; while( z[0] ){ len = token_length(z, &eType, &ln); if( eType==TK_STR ){ for(i=1; i<len-1; i++){ if( z[i]!='%' ) continue; if( z[i+1]=='%' ){ i++; continue; } for(k=i+1; k<len && !isalpha(z[k]); k++){ if( z[k]=='*' || z[k]=='#' ){ if( nArg<nType ) cType[nArg] = z[k]; nArg++; } } if( z[k]!='R' ){ if( nArg<nType ) cType[nArg] = z[k]; nArg++; } } } z += len; } return nArg; } /* ** The function call that begins at zFCall[0] (which is on line lnFCall of the ** original file) is a function that uses a printf-style format string ** on argument number fmtArg. It has processings flags fmtFlags. Do ** compile-time checking on this function, output any errors, and return ** the number of errors. */ static int checkFormatFunc( const char *zFilename, /* Name of the file being processed */ const char *zFCall, /* Pointer to start of function call */ int lnFCall, /* Line number that holds z[0] */ int fmtArg, /* Format string should be this argument */ int fmtFlags /* Extra processing flags */ ){ int szFName; int eToken; int ln = lnFCall; int len; const char *zStart; char *z; char *zCopy; int nArg = 0; const char **azArg = 0; int i, k; int nErr = 0; char *acType; szFName = token_length(zFCall, &eToken, &ln); zStart = next_non_whitespace(zFCall+szFName, &len, &eToken); assert( zStart[0]=='(' && len==1 ); len = distance_to(zStart+1, ')'); zCopy = safe_malloc( len + 1 ); memcpy(zCopy, zStart+1, len); zCopy[len] = 0; azArg = 0; nArg = 0; z = zCopy; while( z[0] ){ char cEnd; len = distance_to(z, ','); cEnd = z[len]; z[len] = 0; azArg = safe_realloc((char*)azArg, (sizeof(azArg[0])+1)*(nArg+1)); azArg[nArg++] = simplify_expr(z); if( cEnd==0 ) break; z += len + 1; } acType = (char*)&azArg[nArg]; if( fmtArg>nArg ){ printf("%s:%d: too few arguments to %.*s()\n", zFilename, lnFCall, szFName, zFCall); nErr++; }else{ const char *zFmt = azArg[fmtArg-1]; const char *zOverride = strstr(zFmt, "/*works-like:"); if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1; if( !is_string_lit(zFmt) ){ printf("%s:%d: %.*s() has non-constant format on arg[%d]\n", zFilename, lnFCall, szFName, zFCall, fmtArg-1); nErr++; }else if( (k = formatArgCount(zFmt, nArg, acType))>=0 && nArg!=fmtArg+k ){ printf("%s:%d: too %s arguments to %.*s() " "- got %d and expected %d\n", zFilename, lnFCall, (nArg<fmtArg+k ? "few" : "many"), szFName, zFCall, nArg, fmtArg+k); nErr++; }else if( (fmtFlags & FMT_SAFE)==0 ){ for(i=0; i<nArg && i<k; i++){ if( (acType[i]=='s' || acType[i]=='z' || acType[i]=='b') ){ const char *zExpr = azArg[fmtArg+i]; if( never_safe(zExpr) ){ printf("%s:%d: Argument %d to %.*s() is not safe for" " a query parameter\n", zFilename, lnFCall, i+fmtArg, szFName, zFCall); nErr++; }else if( (fmtFlags & FMT_SQL)!=0 && !is_sql_safe(zExpr) ){ printf("%s:%d: Argument %d to %.*s() not safe for SQL\n", zFilename, lnFCall, i+fmtArg, szFName, zFCall); nErr++; } } } } } if( nErr ){ for(i=0; i<nArg; i++){ printf(" arg[%d]: %s\n", i, azArg[i]); } }else if( eVerbose>1 ){ printf("%s:%d: %.*s() ok for %d arguments\n", zFilename, lnFCall, szFName, zFCall, nArg); } free((char*)azArg); free(zCopy); return nErr; } /* ** Do a design-rule check of format strings for the file named zName ** with content zContent. Write errors on standard output. Return ** the number of errors. */ static int scan_file(const char *zName, const char *zContent){ const char *z; int ln = 0; int szToken; int eToken; const char *zPrev = 0; int ePrev = 0; int szPrev = 0; int lnPrev = 0; int nCurly = 0; int x; unsigned fmtFlags = 0; int nErr = 0; if( zContent==0 ){ printf("cannot read file: %s\n", zName); return 1; } for(z=zContent; z[0]; z += szToken){ szToken = token_length(z, &eToken, &ln); if( eToken==TK_SPACE ) continue; if( eToken==TK_OTHER ){ if( z[0]=='{' ){ nCurly++; }else if( z[0]=='}' ){ nCurly--; }else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID && (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){ nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags); } } zPrev = z; ePrev = eToken; szPrev = szToken; lnPrev = ln; } return nErr; } /* ** Check for format-string design rule violations on all files listed ** on the command-line. ** ** The eVerbose global variable is incremented with each "-v" argument. */ int main(int argc, char **argv){ int i; int nErr = 0; for(i=1; i<argc; i++){ char *zFile; if( strcmp(argv[i],"-v")==0 ){ eVerbose++; continue; } if( eVerbose>0 ) printf("Processing %s...\n", argv[i]); zFile = read_file(argv[i]); nErr += scan_file(argv[i], zFile); free(zFile); } return nErr; } |
Deleted src/color.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/comformat.c.
1 2 3 4 5 6 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) | | > > > > > > | < | 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 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to format and print comments or other ** text on a TTY. */ #include "config.h" #include "comformat.h" #include <assert.h> #ifdef _WIN32 # include <windows.h> #else # include <termios.h> # include <sys/ioctl.h> #endif #if INTERFACE #define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */ #define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */ #define COMMENT_PRINT_TRIM_CRLF ((u32)0x00000002) /* Trim leading CR/LF. */ #define COMMENT_PRINT_TRIM_SPACE ((u32)0x00000004) /* Trim leading/trailing. */ #define COMMENT_PRINT_WORD_BREAK ((u32)0x00000008) /* Break lines on words. */ #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */ #define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */ #endif /* ** This is the previous value used by most external callers when they ** needed to specify a default maximum line length to be used with the ** comment_print() function. */ |
︙ | ︙ | |||
59 60 61 62 63 64 65 | ** returned to indicate the terminal line width is using the hard-coded ** legacy default value. */ static int comment_set_maxchars( int indent, int *pMaxChars ){ | | | > > > | | > > > | | > > | | | | | | | | < > | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > > > | 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 | ** returned to indicate the terminal line width is using the hard-coded ** legacy default value. */ static int comment_set_maxchars( int indent, int *pMaxChars ){ #if defined(_WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; memset(&csbi, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) ){ *pMaxChars = csbi.srWindow.Right - csbi.srWindow.Left - indent; return 1; } return 0; #elif defined(TIOCGWINSZ) struct winsize w; memset(&w, 0, sizeof(struct winsize)); if( ioctl(0, TIOCGWINSZ, &w)!=-1 ){ *pMaxChars = w.ws_col - indent; return 1; } return 0; #else /* ** Fallback to using more-or-less the "legacy semantics" of hard-coding ** the maximum line length to a value reasonable for the vast majority ** of supported systems. */ *pMaxChars = COMMENT_LEGACY_LINE_LENGTH - indent; return -1; #endif } /* ** This function checks the current line being printed against the original ** comment text. Upon matching, it emits a new line and updates the provided ** character and line counts, if applicable. */ static int comment_check_orig( const char *zOrigText, /* [in] Original comment text ONLY, may be NULL. */ const char *zLine, /* [in] The comment line to print. */ int *pCharCnt, /* [in/out] Pointer to the line character count. */ int *pLineCnt /* [in/out] Pointer to the total line count. */ ){ if( zOrigText && fossil_strcmp(zLine, zOrigText)==0 ){ fossil_print("\n"); if( pCharCnt ) *pCharCnt = 0; if( pLineCnt ) (*pLineCnt)++; return 1; } return 0; } /* ** This function scans the specified comment line starting just after the ** initial index and returns the index of the next spacing character -OR- ** zero if such a character cannot be found. For the purposes of this ** algorithm, the NUL character is treated the same as a spacing character. */ static int comment_next_space( const char *zLine, /* [in] The comment line being printed. */ int index /* [in] The current character index being handled. */ ){ int nextIndex = index + 1; for(;;){ char c = zLine[nextIndex]; if( c==0 || fossil_isspace(c) ){ return nextIndex; } nextIndex++; } return 0; /* NOT REACHED */ } /* ** This function is called when printing a logical comment line to perform ** the necessary indenting. */ static void comment_print_indent( const char *zLine, /* [in] The comment line being printed. */ int indent, /* [in] Number of spaces to indent, zero for none. */ int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ int *piIndex /* [in/out] Pointer to first non-space character. */ ){ if( indent>0 ){ fossil_print("%*s", indent, ""); } if( zLine && piIndex ){ int index = *piIndex; if( trimCrLf ){ while( zLine[index]=='\r' || zLine[index]=='\n' ){ index++; } } if( trimSpace ){ while( fossil_isspace(zLine[index]) ){ index++; } |
︙ | ︙ | |||
202 203 204 205 206 207 208 | int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ int wordBreak, /* [in] Non-zero to try breaking on word boundaries. */ int origBreak, /* [in] Non-zero to break before original comment. */ int *pLineCnt, /* [in/out] Pointer to the total line count. */ const char **pzLine /* [out] Pointer to the end of the logical line. */ ){ | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | | < < < | | | < | | | < < < < < < < < < < < | | < < < < < < | 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 | int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ int wordBreak, /* [in] Non-zero to try breaking on word boundaries. */ int origBreak, /* [in] Non-zero to break before original comment. */ int *pLineCnt, /* [in/out] Pointer to the total line count. */ const char **pzLine /* [out] Pointer to the end of the logical line. */ ){ int index = 0, charCnt = 0, lineCnt = 0, maxChars; if( !zLine ) return; if( lineChars<=0 ) return; comment_print_indent(zLine, indent, trimCrLf, trimSpace, &index); maxChars = lineChars; for(;;){ int useChars = 1; char c = zLine[index]; if( c==0 ){ break; }else{ if( origBreak && index>0 ){ const char *zCurrent = &zLine[index]; if( comment_check_orig(zOrigText, zCurrent, &charCnt, &lineCnt) ){ comment_print_indent(zCurrent, origIndent, trimCrLf, trimSpace, &index); maxChars = lineChars; } } index++; } if( c=='\n' ){ lineCnt++; charCnt = 0; useChars = 0; }else if( c=='\t' ){ int nextIndex = comment_next_space(zLine, index); if( nextIndex<=0 || (nextIndex-index)>maxChars ){ break; } charCnt++; useChars = COMMENT_TAB_WIDTH; if( maxChars<useChars ){ fossil_print(" "); break; } }else if( wordBreak && fossil_isspace(c) ){ int nextIndex = comment_next_space(zLine, index); if( nextIndex<=0 || (nextIndex-index)>maxChars ){ break; } charCnt++; }else{ charCnt++; } assert( c!='\n' || charCnt==0 ); fossil_print("%c", c); if( (c&0x80)==0 || (zLine[index+1]&0xc0)!=0xc0 ) maxChars -= useChars; if( maxChars<=0 ) break; if( c=='\n' ) break; } if( charCnt>0 ){ fossil_print("\n"); lineCnt++; } if( pLineCnt ){ *pLineCnt += lineCnt; } if( pzLine ){ *pzLine = zLine + index; } } |
︙ | ︙ | |||
331 332 333 334 335 336 337 | */ static int comment_print_legacy( const char *zText, /* The comment text to be printed. */ int indent, /* Number of spaces to indent each non-initial line. */ int width /* Maximum number of characters per line. */ ){ int maxChars = width - indent; | | < < | | | < < < < < < < < < < < < < < < | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | */ static int comment_print_legacy( const char *zText, /* The comment text to be printed. */ int indent, /* Number of spaces to indent each non-initial line. */ int width /* Maximum number of characters per line. */ ){ int maxChars = width - indent; int si, sk, i, k; int doIndent = 0; char *zBuf; char zBuffer[400]; int lineCnt = 0; if( width<0 ){ comment_set_maxchars(indent, &maxChars); } if( zText==0 ) zText = "(NULL)"; if( maxChars<=0 ){ maxChars = strlen(zText); } if( maxChars >= (sizeof(zBuffer)) ){ zBuf = fossil_malloc(maxChars+1); }else{ zBuf = zBuffer; } for(;;){ while( fossil_isspace(zText[0]) ){ zText++; } if( zText[0]==0 ){ if( doIndent==0 ){ fossil_print("\n"); lineCnt = 1; } if( zBuf!=zBuffer) fossil_free(zBuf); return lineCnt; } for(sk=si=i=k=0; zText[i] && k<maxChars; i++){ char c = zText[i]; if( fossil_isspace(c) ){ si = i; sk = k; if( k==0 || zBuf[k-1]!=' ' ){ zBuf[k++] = ' '; } }else{ zBuf[k] = c; |
︙ | ︙ | |||
500 501 502 503 504 505 506 | maxChars, trimCrLf, trimSpace, wordBreak, origBreak, &lineCnt, &zLine); if( !zLine || !zLine[0] ) break; } return lineCnt; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | maxChars, trimCrLf, trimSpace, wordBreak, origBreak, &lineCnt, &zLine); if( !zLine || !zLine[0] ) break; } return lineCnt; } /* ** ** COMMAND: test-comment-format ** ** Usage: %fossil test-comment-format ?OPTIONS? PREFIX TEXT ?ORIGTEXT? ** ** Test comment formatting and printing. Use for testing only. ** ** Options: ** --file The comment text is really just a file name to ** read it from. ** --decode Decode the text using the same method used when ** handling the value of a C-card from a manifest. ** --legacy Use the legacy comment printing algorithm. ** --trimcrlf Enable trimming of leading/trailing CR/LF. ** --trimspace Enable trimming of leading/trailing spaces. ** --wordbreak Attempt to break lines on word boundaries. ** --origbreak Attempt to break when the original comment text ** is detected. ** --indent Number of spaces to indent (default (-1) is to ** auto-detect). Zero means no indent. ** -W|--width <num> Width of lines (default (-1) is to auto-detect). ** Zero means no limit. */ void test_comment_format(void){ const char *zWidth; const char *zIndent; const char *zPrefix; char *zText; |
︙ | ︙ |
Changes to src/config.h.
︙ | ︙ | |||
64 65 66 67 68 69 70 | #if defined( __MINGW32__) || defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__) # if defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__) typedef int socklen_t; # endif # ifndef _WIN32 # define _WIN32 # endif | < < < < < < | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #if defined( __MINGW32__) || defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__) # if defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__) typedef int socklen_t; # endif # ifndef _WIN32 # define _WIN32 # endif #else # include <sys/types.h> # include <signal.h> # include <pwd.h> #endif /* |
︙ | ︙ | |||
181 182 183 184 185 186 187 | #if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION) /* ** MSVC does not include the "stdint.h" header file until 2010. */ #if defined(_MSC_VER) && _MSC_VER<1600 | < < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | #if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION) /* ** MSVC does not include the "stdint.h" header file until 2010. */ #if defined(_MSC_VER) && _MSC_VER<1600 typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else # include <stdint.h> #endif |
︙ | ︙ | |||
249 250 251 252 253 254 255 | #endif /* ** A marker for functions that never return. */ #if defined(__GNUC__) || defined(__clang__) # define NORETURN __attribute__((__noreturn__)) | < < < | < | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | #endif /* ** A marker for functions that never return. */ #if defined(__GNUC__) || defined(__clang__) # define NORETURN __attribute__((__noreturn__)) #elif defined(_MSC_VER) && (_MSC_VER >= 1310) # define NORETURN __declspec(noreturn) #else # define NORETURN #endif /* ** Number of elements in an array */ #define count(X) (sizeof(X)/sizeof(X[0])) /* ** The pledge() interface is currently only available on OpenBSD 5.9 ** and later. Make calls to fossil_pledge() no-ops on all platforms ** that omit the HAVE_PLEDGE configuration parameter. */ #if !defined(HAVE_PLEDGE) # define fossil_pledge(A) #endif #endif /* _RC_COMPILE_ */ |
Changes to src/configure.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | #define CONFIGSET_PROJ 0x000008 /* Project name */ #define CONFIGSET_SHUN 0x000010 /* Shun settings */ #define CONFIGSET_USER 0x000020 /* The USER table */ #define CONFIGSET_ADDR 0x000040 /* The CONCEALED table */ #define CONFIGSET_XFER 0x000080 /* Transfer configuration */ #define CONFIGSET_ALIAS 0x000100 /* URL Aliases */ #define CONFIGSET_SCRIBER 0x000200 /* Email subscribers */ | < | | | | | | | | | | | < | < < < < < < < < < < < < | | | > | 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 | #define CONFIGSET_PROJ 0x000008 /* Project name */ #define CONFIGSET_SHUN 0x000010 /* Shun settings */ #define CONFIGSET_USER 0x000020 /* The USER table */ #define CONFIGSET_ADDR 0x000040 /* The CONCEALED table */ #define CONFIGSET_XFER 0x000080 /* Transfer configuration */ #define CONFIGSET_ALIAS 0x000100 /* URL Aliases */ #define CONFIGSET_SCRIBER 0x000200 /* Email subscribers */ #define CONFIGSET_ALL 0x0003ff /* Everything */ #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ /* ** This mask is used for the common TH1 configuration settings (i.e. those ** that are not specific to one particular subsystem, such as the transfer ** subsystem). */ #define CONFIGSET_TH1 (CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER) #endif /* INTERFACE */ /* ** Names of the configuration sets */ static struct { const char *zName; /* Name of the configuration set */ int groupMask; /* Mask for that configuration set */ const char *zHelp; /* What it does */ } aGroupName[] = { { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, { "/project", CONFIGSET_PROJ, "Project name and description" }, { "/skin", CONFIGSET_SKIN | CONFIGSET_CSS, "Web interface appearance settings" }, { "/css", CONFIGSET_CSS, "Style sheet" }, { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" }, { "/ticket", CONFIGSET_TKT, "Ticket setup", }, { "/user", CONFIGSET_USER, "Users and privilege settings" }, { "/xfer", CONFIGSET_XFER, "Transfer setup", }, { "/alias", CONFIGSET_ALIAS, "URL Aliases", }, { "/subscriber", CONFIGSET_SCRIBER,"Email notification subscriber list" }, { "/all", CONFIGSET_ALL, "All of the above" }, }; /* ** The following is a list of settings that we are willing to ** transfer. ** ** Setting names that begin with an alphabetic characters refer to ** single entries in the CONFIG table. Setting names that begin with ** "@" are for special processing. */ static struct { const char *zName; /* Name of the configuration parameter */ int groupMask; /* Which config groups is it part of */ } aConfig[] = { { "css", CONFIGSET_CSS }, { "header", CONFIGSET_SKIN }, { "footer", CONFIGSET_SKIN }, { "details", CONFIGSET_SKIN }, { "logo-mimetype", CONFIGSET_SKIN }, { "logo-image", CONFIGSET_SKIN }, { "background-mimetype", CONFIGSET_SKIN }, { "background-image", CONFIGSET_SKIN }, { "timeline-block-markup", CONFIGSET_SKIN }, { "timeline-max-comment", CONFIGSET_SKIN }, { "timeline-plaintext", CONFIGSET_SKIN }, { "adunit", CONFIGSET_SKIN }, { "adunit-omit-if-admin", CONFIGSET_SKIN }, { "adunit-omit-if-user", CONFIGSET_SKIN }, { "sitemap-docidx", CONFIGSET_SKIN }, { "sitemap-download", CONFIGSET_SKIN }, { "sitemap-license", CONFIGSET_SKIN }, { "sitemap-contact", CONFIGSET_SKIN }, #ifdef FOSSIL_ENABLE_TH1_DOCS { "th1-docs", CONFIGSET_TH1 }, #endif #ifdef FOSSIL_ENABLE_TH1_HOOKS { "th1-hooks", CONFIGSET_TH1 }, #endif |
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 | { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, { "parent-project-code", CONFIGSET_PROJ }, { "parent-project-name", CONFIGSET_PROJ }, { "hash-policy", CONFIGSET_PROJ }, | > | | < > > < < < | 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 | { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "allow-symlinks", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, { "parent-project-code", CONFIGSET_PROJ }, { "parent-project-name", CONFIGSET_PROJ }, { "hash-policy", CONFIGSET_PROJ }, #ifdef FOSSIL_ENABLE_LEGACY_MV_RM { "mv-rm-files", CONFIGSET_PROJ }, #endif { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, { "ticket-change", CONFIGSET_TKT }, { "ticket-newpage", CONFIGSET_TKT }, { "ticket-viewpage", CONFIGSET_TKT }, { "ticket-editpage", CONFIGSET_TKT }, { "ticket-reportlist", CONFIGSET_TKT }, { "ticket-report-template", CONFIGSET_TKT }, { "ticket-key-template", CONFIGSET_TKT }, { "ticket-title-expr", CONFIGSET_TKT }, { "ticket-closed-expr", CONFIGSET_TKT }, { "@reportfmt", CONFIGSET_TKT }, { "@user", CONFIGSET_USER }, { "@concealed", CONFIGSET_ADDR }, { "@shun", CONFIGSET_SHUN }, { "@alias", CONFIGSET_ALIAS }, { "@subscriber", CONFIGSET_SCRIBER }, { "xfer-common-script", CONFIGSET_XFER }, { "xfer-push-script", CONFIGSET_XFER }, { "xfer-commit-script", CONFIGSET_XFER }, { "xfer-ticket-script", CONFIGSET_XFER }, }; static int iConfig = 0; |
︙ | ︙ | |||
259 260 261 262 263 264 265 | } return m; } } if( strncmp(zName, "walias:/", 8)==0 ){ return CONFIGSET_ALIAS; } | < < < | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | } return m; } } if( strncmp(zName, "walias:/", 8)==0 ){ return CONFIGSET_ALIAS; } return 0; } /* ** A mask of all configuration tables that have been reset already. */ static int configHasBeenReset = 0; |
︙ | ︙ | |||
356 357 358 359 360 361 362 | ** In overview, we have: ** ** NAME CONTENT ** ------- ----------------------------------------------------------- ** /config $MTIME $NAME value $VALUE ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE ** /shun $MTIME $UUID scom $VALUE | | | | | | | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | ** In overview, we have: ** ** NAME CONTENT ** ------- ----------------------------------------------------------- ** /config $MTIME $NAME value $VALUE ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE ** /shun $MTIME $UUID scom $VALUE ** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE ** /concealed $MTIME $HASH content $VALUE ** /subscriber $SMTIME $SEMAIL suname $V ... */ void configure_receive(const char *zName, Blob *pContent, int groupMask){ int checkMask; /* Masks for which we must first check existance of tables */ checkMask = CONFIGSET_SCRIBER; if( zName[0]=='/' ){ /* The new format */ char *azToken[24]; int nToken = 0; int ii, jj; int thisMask; Blob name, value, sql; static const struct receiveType { const char *zName; /* Configuration key for this table */ const char *zPrimKey; /* Primary key column */ int nField; /* Number of data fields */ const char *azField[6]; /* Names of the data fields */ } aType[] = { { "/config", "name", 1, { "value", 0,0,0,0,0 } }, { "@user", "login", 4, { "pw","cap","info","photo",0,0} }, { "@shun", "uuid", 1, { "scom", 0,0,0,0,0} }, { "@reportfmt", "title", 3, { "owner","cols","sqlcode",0,0,0}}, { "@concealed", "hash", 1, { "content", 0,0,0,0,0 } }, { "@subscriber","semail",6, { "suname","sdigest","sdonotcall","ssub","sctime","smip"} }, }; /* Locate the receiveType in aType[ii] */ for(ii=0; ii<count(aType); ii++){ if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break; } if( ii>=count(aType) ) return; |
︙ | ︙ | |||
434 435 436 437 438 439 440 | } blob_append_sql(&sql, "REPLACE INTO "); }else{ blob_append_sql(&sql, "INSERT OR IGNORE INTO "); } blob_append_sql(&sql, "\"%w\"(\"%w\",mtime", &zName[1], aType[ii].zPrimKey); | | < < < < < < < < < < < | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | } blob_append_sql(&sql, "REPLACE INTO "); }else{ blob_append_sql(&sql, "INSERT OR IGNORE INTO "); } blob_append_sql(&sql, "\"%w\"(\"%w\",mtime", &zName[1], aType[ii].zPrimKey); if( fossil_stricmp(zName,"/subscriber") ) alert_schema(0); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ",\"%w\"", azToken[jj]); } blob_append_sql(&sql,") VALUES(%s,%s", azToken[1] /*safe-for-%s*/, azToken[0]/*safe-for-%s*/); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/); } db_multi_exec("%s)", blob_sql_text(&sql)); if( db_changes()==0 ){ blob_reset(&sql); blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s", &zName[1], azToken[0]/*safe-for-%s*/); for(jj=2; jj<nToken; jj+=2){ blob_append_sql(&sql, ", \"%w\"=%s", azToken[jj], azToken[jj+1]/*safe-for-%s*/); } blob_append_sql(&sql, " WHERE \"%w\"=%s AND mtime<%s", aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/, azToken[0]/*safe-for-%s*/); db_multi_exec("%s", blob_sql_text(&sql)); } blob_reset(&sql); rebuildMask |= thisMask; } } /* ** Process a file full of "config" cards. |
︙ | ︙ | |||
540 541 542 543 544 545 546 | blob_size(&rec), blob_str(&rec)); nCard++; blob_reset(&rec); } db_finalize(&q); } if( groupMask & CONFIGSET_USER ){ | < | | | < < < < < < > | | < | < | < | < | < > < | < < < < | | < < > | | < | < | < | < > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | blob_size(&rec), blob_str(&rec)); nCard++; blob_reset(&rec); } db_finalize(&q); } if( groupMask & CONFIGSET_USER ){ db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap)," " quote(info), quote(photo) FROM user" " WHERE mtime>=%lld", iStart); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&rec,"%s %s pw %s cap %s info %s photo %s", db_column_text(&q, 0), db_column_text(&q, 1), db_column_text(&q, 2), db_column_text(&q, 3), db_column_text(&q, 4), db_column_text(&q, 5) ); blob_appendf(pOut, "config /user %d\n%s\n", blob_size(&rec), blob_str(&rec)); nCard++; blob_reset(&rec); } db_finalize(&q); } if( groupMask & CONFIGSET_TKT ){ db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols)," " quote(sqlcode) FROM reportfmt" " WHERE mtime>=%lld", iStart); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&rec,"%s %s owner %s cols %s sqlcode %s", db_column_text(&q, 0), db_column_text(&q, 1), db_column_text(&q, 2), db_column_text(&q, 3), db_column_text(&q, 4) ); blob_appendf(pOut, "config /reportfmt %d\n%s\n", blob_size(&rec), blob_str(&rec)); nCard++; blob_reset(&rec); } db_finalize(&q); } |
︙ | ︙ | |||
617 618 619 620 621 622 623 | } db_finalize(&q); } if( groupMask & CONFIGSET_ALIAS ){ db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config" " WHERE name GLOB 'walias:/*' AND mtime>=%lld", iStart); while( db_step(&q)==SQLITE_ROW ){ | < < < < < < < < < < < < < < < < | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | } db_finalize(&q); } if( groupMask & CONFIGSET_ALIAS ){ db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config" " WHERE name GLOB 'walias:/*' AND mtime>=%lld", iStart); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&rec,"%s %s value %s", db_column_text(&q, 0), db_column_text(&q, 1), db_column_text(&q, 2) ); blob_appendf(pOut, "config /config %d\n%s\n", blob_size(&rec), blob_str(&rec)); |
︙ | ︙ | |||
750 751 752 753 754 755 756 | /* ** COMMAND: configuration* ** ** Usage: %fossil configuration METHOD ... ?OPTIONS? ** | | > | | < | | | | | | | | | 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | /* ** COMMAND: configuration* ** ** Usage: %fossil configuration METHOD ... ?OPTIONS? ** ** Where METHOD is one of: export import merge pull push reset. All methods ** accept the -R or --repository option to specify a repository. ** ** %fossil configuration export AREA FILENAME ** ** Write to FILENAME exported configuration information for AREA. ** AREA can be one of: ** ** all email project shun skin ticket user alias subscriber ** ** %fossil configuration import FILENAME ** ** Read a configuration from FILENAME, overwriting the current ** configuration. ** ** %fossil configuration merge FILENAME ** ** Read a configuration from FILENAME and merge its values into ** the current configuration. Existing values take priority over ** values read from FILENAME. ** ** %fossil configuration pull AREA ?URL? ** ** Pull and install the configuration from a different server ** identified by URL. If no URL is specified, then the default ** server is used. Use the --overwrite flag to completely ** replace local settings with content received from URL. ** ** %fossil configuration push AREA ?URL? ** ** Push the local configuration into the remote server identified ** by URL. Admin privilege is required on the remote server for ** this to work. When the same record exists both locally and on ** the remote end, the one that was most recently changed wins. ** ** %fossil configuration reset AREA ** ** Restore the configuration to the default. AREA as above. ** ** %fossil configuration sync AREA ?URL? ** ** Synchronize configuration changes in the local repository with ** the remote repository at URL. ** ** Options: ** -R|--repository FILE Extract info from repository FILE ** ** See also: settings, unset */ void configuration_cmd(void){ int n; const char *zMethod; db_find_and_open_repository(0, 0); db_open_config(0, 0); if( g.argc<3 ){ |
︙ | ︙ | |||
839 840 841 842 843 844 845 | blob_read_from_file(&in, g.argv[3], ExtFILE); db_begin_transaction(); if( zMethod[0]=='i' ){ groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE; }else{ groupMask = CONFIGSET_ALL; } | < < | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | blob_read_from_file(&in, g.argv[3], ExtFILE); db_begin_transaction(); if( zMethod[0]=='i' ){ groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE; }else{ groupMask = CONFIGSET_ALL; } configure_receive_all(&in, groupMask); db_end_transaction(0); }else if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 || strncmp(zMethod, "sync", n)==0 ){ int mask; |
︙ | ︙ | |||
863 864 865 866 867 868 869 | if( g.argc!=4 && g.argc!=5 ){ usage(mprintf("%s AREA ?URL?", zMethod)); } mask = configure_name_to_mask(g.argv[3], 1); if( g.argc==5 ){ zServer = g.argv[4]; } | | | < | < | < < < < | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | if( g.argc!=4 && g.argc!=5 ){ usage(mprintf("%s AREA ?URL?", zMethod)); } mask = configure_name_to_mask(g.argv[3], 1); if( g.argc==5 ){ zServer = g.argv[4]; } url_parse(zServer, URL_PROMPT_PW); if( g.url.protocol==0 ) fossil_fatal("no server URL specified"); user_select(); url_enable_proxy("via proxy: "); if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; if( strncmp(zMethod, "push", n)==0 ){ client_sync(0,0,(unsigned)mask); }else if( strncmp(zMethod, "pull", n)==0 ){ client_sync(0,(unsigned)mask,0); }else{ client_sync(0,(unsigned)mask,(unsigned)mask); } }else if( strncmp(zMethod, "reset", n)==0 ){ int mask, i; char *zBackup; if( g.argc!=4 ) usage("reset AREA"); mask = configure_name_to_mask(g.argv[3], 1); zBackup = db_text(0, "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); db_begin_transaction(); export_config(mask, g.argv[3], 0, zBackup); for(i=0; i<count(aConfig); i++){ const char *zName = aConfig[i].zName; if( (aConfig[i].groupMask & mask)==0 ) continue; if( zName[0]!='@' ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); }else if( fossil_strcmp(zName,"@user")==0 ){ db_multi_exec("DELETE FROM user"); db_create_default_users(0, 0); }else if( fossil_strcmp(zName,"@concealed")==0 ){ db_multi_exec("DELETE FROM concealed"); }else if( fossil_strcmp(zName,"@shun")==0 ){ db_multi_exec("DELETE FROM shun"); }else if( fossil_strcmp(zName,"@subscriber")==0 ){ if( db_table_exists("repository","subscriber") ){ |
︙ | ︙ | |||
1109 1110 1111 1112 1113 1114 1115 | if( zBlob ) fossil_fatal("cannot do both --file or --blob"); blob_read_from_file(&x, zFile, ExtFILE); }else if( zBlob ){ blob_read_from_file(&x, zBlob, ExtFILE); }else{ blob_init(&x,g.argv[3],-1); } | < < | 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | if( zBlob ) fossil_fatal("cannot do both --file or --blob"); blob_read_from_file(&x, zFile, ExtFILE); }else if( zBlob ){ blob_read_from_file(&x, zBlob, ExtFILE); }else{ blob_init(&x,g.argv[3],-1); } db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" "VALUES(%Q,:val,now())", zVar); if( zBlob ){ db_bind_blob(&ins, ":val", &x); }else{ db_bind_text(&ins, ":val", blob_str(&x)); } db_step(&ins); db_finalize(&ins); blob_reset(&x); } |
Changes to src/content.c.
︙ | ︙ | |||
97 98 99 100 101 102 103 | contentCache.szTotal += blob_size(pBlob); p->content = *pBlob; blob_zero(pBlob); bag_insert(&contentCache.inCache, rid); } /* | | < < | < < < < < | 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 | contentCache.szTotal += blob_size(pBlob); p->content = *pBlob; blob_zero(pBlob); bag_insert(&contentCache.inCache, rid); } /* ** Clear the content cache. */ void content_clear_cache(void){ int i; for(i=0; i<contentCache.n; i++){ blob_reset(&contentCache.a[i].content); } bag_clear(&contentCache.missing); bag_clear(&contentCache.available); bag_clear(&contentCache.inCache); contentCache.n = 0; contentCache.szTotal = 0; } /* ** Return the srcid associated with rid. Or return 0 if rid is ** original content and not a delta. */ int delta_source_rid(int rid){ |
︙ | ︙ | |||
318 319 320 321 322 323 324 | /* ** COMMAND: artifact* ** ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS? ** ** Extract an artifact by its artifact hash and write the results on | | | | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | /* ** COMMAND: artifact* ** ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS? ** ** Extract an artifact by its artifact hash and write the results on ** standard output, or if the optional 4th argument is given, in ** the named output file. ** ** Options: ** -R|--repository FILE Extract artifacts from repository FILE ** ** See also: finfo */ void artifact_cmd(void){ int rid; Blob content; const char *zFile; db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); if( g.argc!=4 && g.argc!=3 ) usage("ARTIFACT-ID ?FILENAME? ?OPTIONS?"); |
︙ | ︙ | |||
553 554 555 556 557 558 559 | /* Check to see if the entry already exists and if it does whether ** or not the entry is a phantom */ db_prepare(&s1, "SELECT rid, size FROM blob WHERE uuid=%B", &hash); if( db_step(&s1)==SQLITE_ROW ){ rid = db_column_int(&s1, 0); | | | > | | | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | /* Check to see if the entry already exists and if it does whether ** or not the entry is a phantom */ db_prepare(&s1, "SELECT rid, size FROM blob WHERE uuid=%B", &hash); if( db_step(&s1)==SQLITE_ROW ){ rid = db_column_int(&s1, 0); if( db_column_int(&s1, 1)>=0 || pBlob==0 ){ /* Either the entry is not a phantom or it is a phantom but we ** have no data with which to dephantomize it. In either case, ** there is nothing for us to do other than return the RID. */ db_finalize(&s1); db_end_transaction(0); return rid; } }else{ rid = 0; /* No entry with the same UUID currently exists */ markAsUnclustered = 1; } db_finalize(&s1); /* Construct a received-from ID if we do not already have one */ content_rcvid_init(0); |
︙ | ︙ | |||
602 603 604 605 606 607 608 | db_exec(&s1); rid = db_last_insert_rowid(); if( !pBlob ){ db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); } } if( g.markPrivate || isPrivate ){ | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | db_exec(&s1); rid = db_last_insert_rowid(); if( !pBlob ){ db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); } } if( g.markPrivate || isPrivate ){ db_multi_exec("INSERT INTO private VALUES(%d)", rid); markAsUnclustered = 0; } if( nBlob==0 ) blob_reset(&cmpr); /* If the srcId is specified, then the data we just added is ** really a delta. Record this fact in the delta table. */ |
︙ | ︙ | |||
656 657 658 659 660 661 662 | */ int content_put(Blob *pBlob){ return content_put_ex(pBlob, 0, 0, 0, 0); } /* | | | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 | */ int content_put(Blob *pBlob){ return content_put_ex(pBlob, 0, 0, 0, 0); } /* ** Create a new phantom with the given UUID and return its artifact ID. */ int content_new(const char *zUuid, int isPrivate){ int rid; static Stmt s1, s2, s3; assert( g.repositoryOpen ); db_begin_transaction(); |
︙ | ︙ | |||
775 776 777 778 779 780 781 | db_static_prepare(&s1, "DELETE FROM private WHERE rid=:rid" ); db_bind_int(&s1, ":rid", rid); db_exec(&s1); } | < < < < < < < < < < < < < < | | < < < < < < < < < < < < < | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | db_static_prepare(&s1, "DELETE FROM private WHERE rid=:rid" ); db_bind_int(&s1, ":rid", rid); db_exec(&s1); } /* ** Try to change the storage of rid so that it is a delta from one ** of the artifacts given in aSrc[0]..aSrc[nSrc-1]. The aSrc[*] that ** gives the smallest delta is choosen. ** ** If rid is already a delta from some other place then no ** conversion occurs and this is a no-op unless force==1. If force==1, ** then nSrc must also be 1. ** ** Never generate a delta that carries a private artifact into a public ** artifact. Otherwise, when we go to send the public artifact on a ** sync operation, the other end of the sync will never be able to receive ** the source of the delta. It is OK to delta private->private and ** public->private and public->public. Just no private->public delta. ** ** If aSrc[bestSrc] is already a dleta that depends on rid, then it is ** converted to undeltaed text before the aSrc[bestSrc]->rid delta is ** created, in order to prevent a delta loop. ** ** If either rid or aSrc[i] contain less than 50 bytes, or if the ** resulting delta does not achieve a compression of at least 25% ** the rid is left untouched. ** ** Return 1 if a delta is made and 0 if no delta occurs. */ int content_deltify(int rid, int *aSrc, int nSrc, int force){ int s; Blob data; /* Content of rid */ Blob src; /* Content of aSrc[i] */ Blob delta; /* Delta from aSrc[i] to rid */ Blob bestDelta; /* Best delta seen so far */ int bestSrc = 0; /* Which aSrc is the source of the best delta */ int rc = 0; /* Value to return */ int i; /* Loop variable for aSrc[] */ /* If rid is already a child (a delta) of some other artifact, return ** immediately if the force flags is false */ if( !force && delta_source_rid(rid)>0 ) return 0; /* Get the complete content of the object to be delta-ed. If the size ** is less than 50 bytes, then there really is no point in trying to do ** a delta, so return immediately */ content_get(rid, &data); if( blob_size(&data)<50 ){ /* Do not try to create a delta for objects smaller than 50 bytes */ |
︙ | ︙ | |||
902 903 904 905 906 907 908 | if( bestSrc>0 ){ Stmt s1, s2; /* Statements used to create the delta */ blob_compress(&bestDelta, &bestDelta); db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid); db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, bestSrc); db_bind_blob(&s1, ":data", &bestDelta); db_begin_transaction(); | < | | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | if( bestSrc>0 ){ Stmt s1, s2; /* Statements used to create the delta */ blob_compress(&bestDelta, &bestDelta); db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid); db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, bestSrc); db_bind_blob(&s1, ":data", &bestDelta); db_begin_transaction(); db_exec(&s1); db_exec(&s2); db_end_transaction(0); db_finalize(&s1); db_finalize(&s2); verify_before_commit(rid); rc = 1; } blob_reset(&data); blob_reset(&bestDelta); return rc; } /* |
︙ | ︙ | |||
957 958 959 960 961 962 963 | ** COMMAND: test-integrity ** ** Verify that all content can be extracted from the BLOB table correctly. ** If the BLOB table is correct, then the repository can always be ** successfully reconstructed using "fossil rebuild". ** ** Options: | | < < < < < < < < < < < < < < < < < | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 | ** COMMAND: test-integrity ** ** Verify that all content can be extracted from the BLOB table correctly. ** If the BLOB table is correct, then the repository can always be ** successfully reconstructed using "fossil rebuild". ** ** Options: ** ** --parse Parse all manifests, wikis, tickets, events, and ** so forth, reporting any errors found. */ void test_integrity(void){ Stmt q; Blob content; int n1 = 0; int n2 = 0; int nErr = 0; int total; int nCA = 0; int anCA[10]; int bParse = find_option("parse",0,0)!=0; db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); memset(anCA, 0, sizeof(anCA)); /* Make sure no public artifact is a delta from a private artifact */ db_prepare(&q, "SELECT " " rid, (SELECT uuid FROM blob WHERE rid=delta.rid)," " srcid, (SELECT uuid FROM blob WHERE rid=delta.srcid)" |
︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 | fossil_print(" %d/%d\r", n1, total); fflush(stdout); if( size<0 ){ fossil_print("skip phantom %d %s\n", rid, zUuid); continue; /* Ignore phantoms */ } content_get(rid, &content); | | | | 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 | fossil_print(" %d/%d\r", n1, total); fflush(stdout); if( size<0 ){ fossil_print("skip phantom %d %s\n", rid, zUuid); continue; /* Ignore phantoms */ } content_get(rid, &content); if( blob_size(&content)!=size ){ fossil_print("size mismatch on artifact %d: wanted %d but got %d\n", rid, size, blob_size(&content)); nErr++; } if( !hname_verify_hash(&content, zUuid, nUuid) ){ fossil_print("wrong hash on artifact %d\n",rid); nErr++; } if( bParse && looks_like_control_artifact(&content) ){ Blob err; int i, n; char *z; Manifest *p; char zFirstLine[400]; blob_zero(&err); z = blob_buffer(&content); n = blob_size(&content); for(i=0; i<n && z[i] && z[i]!='\n' && i<sizeof(zFirstLine)-1; i++){} memcpy(zFirstLine, z, i); zFirstLine[i] = 0; p = manifest_parse(&content, 0, &err); if( p==0 ){ fossil_print("manifest_parse failed for %s:\n%s\n", zUuid, blob_str(&err)); if( strncmp(blob_str(&err), "line 1:", 7)==0 ){ |
︙ | ︙ | |||
1120 1121 1122 1123 1124 1125 1126 | } /* Allowed flags for check_exists */ #define MISSING_SHUNNED 0x0001 /* Do not report shunned artifacts */ /* This is a helper routine for test-artifacts. ** | | | < | | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | } /* Allowed flags for check_exists */ #define MISSING_SHUNNED 0x0001 /* Do not report shunned artifacts */ /* This is a helper routine for test-artifacts. ** ** Check to see that artifact zUuid exists in the repository. If it does, ** return 0. If it does not, generate an error message and return 1. */ static int check_exists( const char *zUuid, /* The artifact we are checking for */ unsigned flags, /* Flags */ Manifest *p, /* The control artifact that references zUuid */ const char *zRole, /* Role of zUuid in p */ const char *zDetail /* Additional information, such as a filename */ ){ static Stmt q; int rc = 0; |
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 | ** Usage: %fossil test-missing ** ** Look at every artifact in the repository and verify that ** all references are satisfied. Report any referenced artifacts ** that are missing or shunned. ** ** Options: ** --notshunned Do not report shunned artifacts ** --quiet Only show output if there are errors */ void test_missing(void){ Stmt q; Blob content; int nErr = 0; | > | 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 | ** Usage: %fossil test-missing ** ** Look at every artifact in the repository and verify that ** all references are satisfied. Report any referenced artifacts ** that are missing or shunned. ** ** Options: ** ** --notshunned Do not report shunned artifacts ** --quiet Only show output if there are errors */ void test_missing(void){ Stmt q; Blob content; int nErr = 0; |
︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 | ** WARNING: This command destroys data and can cause you to lose work. ** Make sure you have a backup copy before using this command! ** ** WARNING: You must run "fossil rebuild" after this command to rebuild ** the metadata. ** ** Note that the arguments are the integer raw RID values from the BLOB table, | | | 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 | ** WARNING: This command destroys data and can cause you to lose work. ** Make sure you have a backup copy before using this command! ** ** WARNING: You must run "fossil rebuild" after this command to rebuild ** the metadata. ** ** Note that the arguments are the integer raw RID values from the BLOB table, ** not artifact hashs or labels. */ void test_content_erase(void){ int i; Blob x; char c; Stmt q; prompt_user("This command erases information from the repository and\n" |
︙ | ︙ |
Changes to src/cookies.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | ** be called once. ** ** char *cookie_value(zPName, zDefault); ** ** Look up the value of a cookie parameter zPName. Return zDefault if ** there is no display preferences cookie or if zPName does not exist. */ | < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | ** be called once. ** ** char *cookie_value(zPName, zDefault); ** ** Look up the value of a cookie parameter zPName. Return zDefault if ** there is no display preferences cookie or if zPName does not exist. */ #include "cookies.h" #include <assert.h> #include <string.h> #if INTERFACE /* the standard name of the display settings cookie for fossil */ # define DISPLAY_SETTINGS_COOKIE "fossil_display_settings" |
︙ | ︙ | |||
125 126 127 128 129 130 131 | int i; cookie_parse(); for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){} if( zQVal==0 && (flags & COOKIE_READ)!=0 && i<cookies.nParam ){ cgi_set_parameter_nocopy(zQP, cookies.aParam[i].zPValue, 1); return; } | | < < < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | int i; cookie_parse(); for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){} if( zQVal==0 && (flags & COOKIE_READ)!=0 && i<cookies.nParam ){ cgi_set_parameter_nocopy(zQP, cookies.aParam[i].zPValue, 1); return; } if( zQVal==0 ) zQVal = zDflt; if( (flags & COOKIE_WRITE)!=0 && i<COOKIE_NPARAM && (i==cookies.nParam || strcmp(zQVal, cookies.aParam[i].zPValue)) ){ if( i==cookies.nParam ){ cookies.aParam[i].zPName = zPName; cookies.nParam++; |
︙ | ︙ | |||
171 172 173 174 175 176 177 | const char *zQP, /* The query parameter */ const char *zPName, /* The name of the cookie value */ const char *zDflt /* Default value for the parameter */ ){ cookie_readwrite(zQP, zPName, zDflt, COOKIE_READ|COOKIE_WRITE); } | | < < < | < < < < < < < < | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | const char *zQP, /* The query parameter */ const char *zPName, /* The name of the cookie value */ const char *zDflt /* Default value for the parameter */ ){ cookie_readwrite(zQP, zPName, zDflt, COOKIE_READ|COOKIE_WRITE); } /* Update the user preferences cookie, if necessary, and shut down this ** module */ void cookie_render(void){ if( cookies.bChanged && P("udc")!=0 ){ Blob new; int i; blob_init(&new, 0, 0); for(i=0;i<cookies.nParam;i++){ |
︙ | ︙ | |||
211 212 213 214 215 216 217 | assert( zPName!=0 ); cookie_parse(); for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){} return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault; } /* | < < < < < < | > | < | < < > < | < | > < < < < < < > | < < < < < < < < < < | > | | | | < < < < < < < < < < < < < | | 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 | assert( zPName!=0 ); cookie_parse(); for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){} return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault; } /* ** WEBPAGE: cookies ** ** Show the current display settings contained in the ** "fossil_display_settings" cookie. */ void cookie_page(void){ int i; if( PB("clear") ){ cgi_set_cookie(DISPLAY_SETTINGS_COOKIE, "", 0, 1); cgi_replace_parameter(DISPLAY_SETTINGS_COOKIE, ""); } cookie_parse(); style_header("User Preference Cookie Values"); if( cookies.nParam ){ style_submenu_element("Clear", "%R/cookies?clear"); } @ <p>The following are user preference settings held in the @ "fossil_display_settings" cookie. @ <ul> @ <li>Raw cookie value: "%h(PD("fossil_display_settings",""))" for(i=0; i<cookies.nParam; i++){ @ <li>%h(cookies.aParam[i].zPName): "%h(cookies.aParam[i].zPValue)" } @ </ul> style_footer(); } |
Deleted src/copybtn.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/cson_amalgamation.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 | #ifdef FOSSIL_ENABLE_JSON /* auto-generated! Do not edit! */ #include "cson_amalgamation.h" /* begin file parser/JSON_parser.h */ /* See JSON_parser.c for copyright information and licensing. */ #ifndef JSON_PARSER_H #define JSON_PARSER_H /* JSON_parser.h */ #include <stddef.h> /* Windows DLL stuff */ #ifdef JSON_PARSER_DLL # ifdef _MSC_VER # ifdef JSON_PARSER_DLL_EXPORTS # define JSON_PARSER_DLL_API __declspec(dllexport) # else # define JSON_PARSER_DLL_API __declspec(dllimport) # endif # else # define JSON_PARSER_DLL_API # endif #else # define JSON_PARSER_DLL_API #endif /* Determine the integer type use to parse non-floating point numbers */ #ifdef _WIN32 typedef __int64 JSON_int_t; #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%I64d" #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%I64d" #elif (__STDC_VERSION__ >= 199901L) || (HAVE_LONG_LONG == 1) typedef long long JSON_int_t; #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%lld" #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%lld" #else typedef long JSON_int_t; #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%ld" #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%ld" #endif #ifdef __cplusplus extern "C" { #endif typedef enum { JSON_E_NONE = 0, JSON_E_INVALID_CHAR, JSON_E_INVALID_KEYWORD, JSON_E_INVALID_ESCAPE_SEQUENCE, JSON_E_INVALID_UNICODE_SEQUENCE, JSON_E_INVALID_NUMBER, JSON_E_NESTING_DEPTH_REACHED, JSON_E_UNBALANCED_COLLECTION, JSON_E_EXPECTED_KEY, JSON_E_EXPECTED_COLON, JSON_E_OUT_OF_MEMORY } JSON_error; typedef enum { JSON_T_NONE = 0, JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END, JSON_T_INTEGER, JSON_T_FLOAT, JSON_T_NULL, JSON_T_TRUE, JSON_T_FALSE, JSON_T_STRING, JSON_T_KEY, JSON_T_MAX } JSON_type; typedef struct JSON_value_struct { union { JSON_int_t integer_value; double float_value; struct { const char* value; size_t length; } str; } vu; } JSON_value; typedef struct JSON_parser_struct* JSON_parser; /*! \brief JSON parser callback \param ctx The pointer passed to new_JSON_parser. \param type An element of JSON_type but not JSON_T_NONE. \param value A representation of the parsed value. This parameter is NULL for JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END, JSON_T_NULL, JSON_T_TRUE, and JSON_T_FALSE. String values are always returned as zero-terminated C strings. \return Non-zero if parsing should continue, else zero. */ typedef int (*JSON_parser_callback)(void* ctx, int type, const JSON_value* value); /** A typedef for allocator functions semantically compatible with malloc(). */ typedef void* (*JSON_malloc_t)(size_t n); /** A typedef for deallocator functions semantically compatible with free(). */ typedef void (*JSON_free_t)(void* mem); /*! \brief The structure used to configure a JSON parser object */ typedef struct { /** Pointer to a callback, called when the parser has something to tell the user. This parameter may be NULL. In this case the input is merely checked for validity. */ JSON_parser_callback callback; /** Callback context - client-specified data to pass to the callback function. This parameter may be NULL. */ void* callback_ctx; /** Specifies the levels of nested JSON to allow. Negative numbers yield unlimited nesting. If negative, the parser can parse arbitrary levels of JSON, otherwise the depth is the limit. */ int depth; /** To allow C style comments in JSON, set to non-zero. */ int allow_comments; /** To decode floating point numbers manually set this parameter to non-zero. */ int handle_floats_manually; /** The memory allocation routine, which must be semantically compatible with malloc(3). If set to NULL, malloc(3) is used. If this is set to a non-NULL value then the 'free' member MUST be set to the proper deallocation counterpart for this function. Failure to do so results in undefined behaviour at deallocation time. */ JSON_malloc_t malloc; /** The memory deallocation routine, which must be semantically compatible with free(3). If set to NULL, free(3) is used. If this is set to a non-NULL value then the 'alloc' member MUST be set to the proper allocation counterpart for this function. Failure to do so results in undefined behaviour at deallocation time. */ JSON_free_t free; } JSON_config; /*! \brief Initializes the JSON parser configuration structure to default values. The default configuration is - 127 levels of nested JSON (depends on JSON_PARSER_STACK_SIZE, see json_parser.c) - no parsing, just checking for JSON syntax - no comments - Uses realloc() for memory de/allocation. \param config. Used to configure the parser. */ JSON_PARSER_DLL_API void init_JSON_config(JSON_config * config); /*! \brief Create a JSON parser object \param config. Used to configure the parser. Set to NULL to use the default configuration. See init_JSON_config. Its contents are copied by this function, so it need not outlive the returned object. \return The parser object, which is owned by the caller and must eventually be freed by calling delete_JSON_parser(). */ JSON_PARSER_DLL_API JSON_parser new_JSON_parser(JSON_config const* config); /*! \brief Destroy a previously created JSON parser object. */ JSON_PARSER_DLL_API void delete_JSON_parser(JSON_parser jc); /*! \brief Parse a character. \return Non-zero, if all characters passed to this function are part of are valid JSON. */ JSON_PARSER_DLL_API int JSON_parser_char(JSON_parser jc, int next_char); /*! \brief Finalize parsing. Call this method once after all input characters have been consumed. \return Non-zero, if all parsed characters are valid JSON, zero otherwise. */ JSON_PARSER_DLL_API int JSON_parser_done(JSON_parser jc); /*! \brief Determine if a given string is valid JSON white space \return Non-zero if the string is valid, zero otherwise. */ JSON_PARSER_DLL_API int JSON_parser_is_legal_white_space_string(const char* s); /*! \brief Gets the last error that occurred during the use of JSON_parser. \return A value from the JSON_error enum. */ JSON_PARSER_DLL_API int JSON_parser_get_last_error(JSON_parser jc); /*! \brief Re-sets the parser to prepare it for another parse run. \return True (non-zero) on success, 0 on error (e.g. !jc). */ JSON_PARSER_DLL_API int JSON_parser_reset(JSON_parser jc); #ifdef __cplusplus } #endif #endif /* JSON_PARSER_H */ /* end file parser/JSON_parser.h */ /* begin file parser/JSON_parser.c */ /* Copyright (c) 2007-2013 Jean Gressmann (jean@0x42.de) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Changelog: 2013-09-08 Updated license to to be compatible with Debian license requirements. 2012-06-06 Fix for invalid UTF16 characters and some comment fixex (thomas.h.moog@intel.com). 2010-11-25 Support for custom memory allocation (sgbeal@googlemail.com). 2010-05-07 Added error handling for memory allocation failure (sgbeal@googlemail.com). Added diagnosis errors for invalid JSON. 2010-03-25 Fixed buffer overrun in grow_parse_buffer & cleaned up code. 2009-10-19 Replaced long double in JSON_value_struct with double after reports of strtold being broken on some platforms (charles@transmissionbt.com). 2009-05-17 Incorporated benrudiak@googlemail.com fix for UTF16 decoding. 2009-05-14 Fixed float parsing bug related to a locale being set that didn't use '.' as decimal point character (charles@transmissionbt.com). 2008-10-14 Renamed states.IN to states.IT to avoid name clash which IN macro defined in windef.h (alexey.pelykh@gmail.com) 2008-07-19 Removed some duplicate code & debugging variable (charles@transmissionbt.com) 2008-05-28 Made JSON_value structure ansi C compliant. This bug was report by trisk@acm.jhu.edu 2008-05-20 Fixed bug reported by charles@transmissionbt.com where the switching from static to dynamic parse buffer did not copy the static parse buffer's content. */ #include <assert.h> #include <ctype.h> #include <float.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <locale.h> #ifdef _MSC_VER # if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ # pragma warning(disable:4996) /* unsecure sscanf */ # pragma warning(disable:4127) /* conditional expression is constant */ # endif #endif #define true 1 #define false 0 #define XX -1 /* the universal error code */ /* values chosen so that the object size is approx equal to one page (4K) */ #ifndef JSON_PARSER_STACK_SIZE # define JSON_PARSER_STACK_SIZE 128 #endif #ifndef JSON_PARSER_PARSE_BUFFER_SIZE # define JSON_PARSER_PARSE_BUFFER_SIZE 3500 #endif typedef void* (*JSON_debug_malloc_t)(size_t bytes, const char* reason); #ifdef JSON_PARSER_DEBUG_MALLOC # define JSON_parser_malloc(func, bytes, reason) ((JSON_debug_malloc_t)func)(bytes, reason) #else # define JSON_parser_malloc(func, bytes, reason) func(bytes) #endif typedef unsigned short UTF16; struct JSON_parser_struct { JSON_parser_callback callback; void* ctx; signed char state, before_comment_state, type, escaped, comment, allow_comments, handle_floats_manually, error; char decimal_point; UTF16 utf16_high_surrogate; int current_char; int depth; int top; int stack_capacity; signed char* stack; char* parse_buffer; size_t parse_buffer_capacity; size_t parse_buffer_count; signed char static_stack[JSON_PARSER_STACK_SIZE]; char static_parse_buffer[JSON_PARSER_PARSE_BUFFER_SIZE]; JSON_malloc_t malloc; JSON_free_t free; }; #define COUNTOF(x) (sizeof(x)/sizeof(x[0])) /* Characters are mapped into these character classes. This allows for a significant reduction in the size of the state transition table. */ enum classes { C_SPACE, /* space */ C_WHITE, /* other whitespace */ C_LCURB, /* { */ C_RCURB, /* } */ C_LSQRB, /* [ */ C_RSQRB, /* ] */ C_COLON, /* : */ C_COMMA, /* , */ C_QUOTE, /* " */ C_BACKS, /* \ */ C_SLASH, /* / */ C_PLUS, /* + */ C_MINUS, /* - */ C_POINT, /* . */ C_ZERO , /* 0 */ C_DIGIT, /* 123456789 */ C_LOW_A, /* a */ C_LOW_B, /* b */ C_LOW_C, /* c */ C_LOW_D, /* d */ C_LOW_E, /* e */ C_LOW_F, /* f */ C_LOW_L, /* l */ C_LOW_N, /* n */ C_LOW_R, /* r */ C_LOW_S, /* s */ C_LOW_T, /* t */ C_LOW_U, /* u */ C_ABCDF, /* ABCDF */ C_E, /* E */ C_ETC, /* everything else */ C_STAR, /* * */ NR_CLASSES }; static const signed char ascii_class[128] = { /* This array maps the 128 ASCII characters into character classes. The remaining Unicode characters should be mapped to C_ETC. Non-whitespace control characters are errors. */ XX, XX, XX, XX, XX, XX, XX, XX, XX, C_WHITE, C_WHITE, XX, XX, C_WHITE, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_STAR, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH, C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC, C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC, C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC }; /* The state codes. */ enum states { GO, /* start */ OK, /* ok */ OB, /* object */ KE, /* key */ CO, /* colon */ VA, /* value */ AR, /* array */ ST, /* string */ ESC, /* escape */ U1, /* u1 */ U2, /* u2 */ U3, /* u3 */ U4, /* u4 */ MI, /* minus */ ZE, /* zero */ IT, /* integer */ FR, /* fraction */ E1, /* e */ E2, /* ex */ E3, /* exp */ T1, /* tr */ T2, /* tru */ T3, /* true */ F1, /* fa */ F2, /* fal */ F3, /* fals */ F4, /* false */ N1, /* nu */ N2, /* nul */ N3, /* null */ C1, /* / */ C2, /* / * */ C3, /* * */ FX, /* *.* *eE* */ D1, /* second UTF-16 character decoding started by \ */ D2, /* second UTF-16 character proceeded by u */ NR_STATES }; enum actions { CB = -10, /* comment begin */ CE = -11, /* comment end */ FA = -12, /* false */ TR = -13, /* false */ NU = -14, /* null */ DE = -15, /* double detected by exponent e E */ DF = -16, /* double detected by fraction . */ SB = -17, /* string begin */ MX = -18, /* integer detected by minus */ ZX = -19, /* integer detected by zero */ IX = -20, /* integer detected by 1-9 */ EX = -21, /* next char is escaped */ UC = -22 /* Unicode character read */ }; static const signed char state_transition_table[NR_STATES][NR_CLASSES] = { /* The state transition table takes the current state and the current symbol, and returns either a new state or an action. An action is represented as a negative number. A JSON text is accepted if at the end of the text the state is OK and if the mode is MODE_DONE. white 1-9 ABCDF etc space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E | * */ /*start GO*/ {GO,GO,-6,XX,-5,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*ok OK*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*object OB*/ {OB,OB,XX,-9,XX,XX,XX,XX,SB,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*key KE*/ {KE,KE,XX,XX,XX,XX,XX,XX,SB,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*colon CO*/ {CO,CO,XX,XX,XX,XX,-2,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*value VA*/ {VA,VA,-6,XX,-5,XX,XX,XX,SB,XX,CB,XX,MX,XX,ZX,IX,XX,XX,XX,XX,XX,FA,XX,NU,XX,XX,TR,XX,XX,XX,XX,XX}, /*array AR*/ {AR,AR,-6,XX,-5,-7,XX,XX,SB,XX,CB,XX,MX,XX,ZX,IX,XX,XX,XX,XX,XX,FA,XX,NU,XX,XX,TR,XX,XX,XX,XX,XX}, /*string ST*/ {ST,XX,ST,ST,ST,ST,ST,ST,-4,EX,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST}, /*escape ES*/ {XX,XX,XX,XX,XX,XX,XX,XX,ST,ST,ST,XX,XX,XX,XX,XX,XX,ST,XX,XX,XX,ST,XX,ST,ST,XX,ST,U1,XX,XX,XX,XX}, /*u1 U1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U2,U2,U2,U2,U2,U2,U2,U2,XX,XX,XX,XX,XX,XX,U2,U2,XX,XX}, /*u2 U2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U3,U3,U3,U3,U3,U3,U3,U3,XX,XX,XX,XX,XX,XX,U3,U3,XX,XX}, /*u3 U3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U4,U4,U4,U4,U4,U4,U4,U4,XX,XX,XX,XX,XX,XX,U4,U4,XX,XX}, /*u4 U4*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,UC,UC,UC,UC,UC,UC,UC,UC,XX,XX,XX,XX,XX,XX,UC,UC,XX,XX}, /*minus MI*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,ZE,IT,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*zero ZE*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,DF,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*int IT*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,DF,IT,IT,XX,XX,XX,XX,DE,XX,XX,XX,XX,XX,XX,XX,XX,DE,XX,XX}, /*frac FR*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,CB,XX,XX,XX,FR,FR,XX,XX,XX,XX,E1,XX,XX,XX,XX,XX,XX,XX,XX,E1,XX,XX}, /*e E1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,E2,E2,XX,E3,E3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*ex E2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,E3,E3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*exp E3*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,XX,XX,XX,XX,E3,E3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*tr T1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,T2,XX,XX,XX,XX,XX,XX,XX}, /*tru T2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,T3,XX,XX,XX,XX}, /*true T3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,OK,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*fa F1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,F2,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*fal F2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,F3,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*fals F3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,F4,XX,XX,XX,XX,XX,XX}, /*false F4*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,OK,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*nu N1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,N2,XX,XX,XX,XX}, /*nul N2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,N3,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*null N3*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CB,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,OK,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*/ C1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C2}, /*/star C2*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3}, /** C3*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,CE,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3}, /*_. FX*/ {OK,OK,XX,-8,XX,-7,XX,-3,XX,XX,XX,XX,XX,XX,FR,FR,XX,XX,XX,XX,E1,XX,XX,XX,XX,XX,XX,XX,XX,E1,XX,XX}, /*\ D1*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,D2,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX}, /*\ D2*/ {XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,U1,XX,XX,XX,XX}, }; /* These modes can be pushed on the stack. */ enum modes { MODE_ARRAY = 1, MODE_DONE = 2, MODE_KEY = 3, MODE_OBJECT = 4 }; static void set_error(JSON_parser jc) { switch (jc->state) { case GO: switch (jc->current_char) { case '{': case '}': case '[': case ']': jc->error = JSON_E_UNBALANCED_COLLECTION; break; default: jc->error = JSON_E_INVALID_CHAR; break; } break; case OB: jc->error = JSON_E_EXPECTED_KEY; break; case AR: jc->error = JSON_E_UNBALANCED_COLLECTION; break; case CO: jc->error = JSON_E_EXPECTED_COLON; break; case KE: jc->error = JSON_E_EXPECTED_KEY; break; /* \uXXXX\uYYYY */ case U1: case U2: case U3: case U4: case D1: case D2: jc->error = JSON_E_INVALID_UNICODE_SEQUENCE; break; /* true, false, null */ case T1: case T2: case T3: case F1: case F2: case F3: case F4: case N1: case N2: case N3: jc->error = JSON_E_INVALID_KEYWORD; break; /* minus, integer, fraction, exponent */ case MI: case ZE: case IT: case FR: case E1: case E2: case E3: jc->error = JSON_E_INVALID_NUMBER; break; default: jc->error = JSON_E_INVALID_CHAR; break; } } static int push(JSON_parser jc, int mode) { /* Push a mode onto the stack. Return false if there is overflow. */ assert(jc->top <= jc->stack_capacity); if (jc->depth < 0) { if (jc->top == jc->stack_capacity) { const size_t bytes_to_copy = jc->stack_capacity * sizeof(jc->stack[0]); const size_t new_capacity = jc->stack_capacity * 2; const size_t bytes_to_allocate = new_capacity * sizeof(jc->stack[0]); void* mem = JSON_parser_malloc(jc->malloc, bytes_to_allocate, "stack"); if (!mem) { jc->error = JSON_E_OUT_OF_MEMORY; return false; } jc->stack_capacity = (int)new_capacity; memcpy(mem, jc->stack, bytes_to_copy); if (jc->stack != &jc->static_stack[0]) { jc->free(jc->stack); } jc->stack = (signed char*)mem; } } else { if (jc->top == jc->depth) { jc->error = JSON_E_NESTING_DEPTH_REACHED; return false; } } jc->stack[++jc->top] = (signed char)mode; return true; } static int pop(JSON_parser jc, int mode) { /* Pop the stack, assuring that the current mode matches the expectation. Return false if there is underflow or if the modes mismatch. */ if (jc->top < 0 || jc->stack[jc->top] != mode) { return false; } jc->top -= 1; return true; } #define parse_buffer_clear(jc) \ do {\ jc->parse_buffer_count = 0;\ jc->parse_buffer[0] = 0;\ } while (0) #define parse_buffer_pop_back_char(jc)\ do {\ assert(jc->parse_buffer_count >= 1);\ --jc->parse_buffer_count;\ jc->parse_buffer[jc->parse_buffer_count] = 0;\ } while (0) void delete_JSON_parser(JSON_parser jc) { if (jc) { if (jc->stack != &jc->static_stack[0]) { jc->free((void*)jc->stack); } if (jc->parse_buffer != &jc->static_parse_buffer[0]) { jc->free((void*)jc->parse_buffer); } jc->free((void*)jc); } } int JSON_parser_reset(JSON_parser jc) { if (NULL == jc) { return false; } jc->state = GO; jc->top = -1; /* parser has been used previously? */ if (NULL == jc->parse_buffer) { /* Do we want non-bound stack? */ if (jc->depth > 0) { jc->stack_capacity = jc->depth; if (jc->depth <= (int)COUNTOF(jc->static_stack)) { jc->stack = &jc->static_stack[0]; } else { const size_t bytes_to_alloc = jc->stack_capacity * sizeof(jc->stack[0]); jc->stack = (signed char*)JSON_parser_malloc(jc->malloc, bytes_to_alloc, "stack"); if (jc->stack == NULL) { return false; } } } else { jc->stack_capacity = (int)COUNTOF(jc->static_stack); jc->depth = -1; jc->stack = &jc->static_stack[0]; } /* set up the parse buffer */ jc->parse_buffer = &jc->static_parse_buffer[0]; jc->parse_buffer_capacity = COUNTOF(jc->static_parse_buffer); } /* set parser to start */ push(jc, MODE_DONE); parse_buffer_clear(jc); return true; } JSON_parser new_JSON_parser(JSON_config const * config) { /* new_JSON_parser starts the checking process by constructing a JSON_parser object. It takes a depth parameter that restricts the level of maximum nesting. To continue the process, call JSON_parser_char for each character in the JSON text, and then call JSON_parser_done to obtain the final result. These functions are fully reentrant. */ int use_std_malloc = false; JSON_config default_config; JSON_parser jc; JSON_malloc_t alloc; /* set to default configuration if none was provided */ if (NULL == config) { /* initialize configuration */ init_JSON_config(&default_config); config = &default_config; } /* use std malloc if either the allocator or deallocator function isn't set */ use_std_malloc = NULL == config->malloc || NULL == config->free; alloc = use_std_malloc ? malloc : config->malloc; jc = (JSON_parser)JSON_parser_malloc(alloc, sizeof(*jc), "parser"); if (NULL == jc) { return NULL; } /* configure the parser */ memset(jc, 0, sizeof(*jc)); jc->malloc = alloc; jc->free = use_std_malloc ? free : config->free; jc->callback = config->callback; jc->ctx = config->callback_ctx; jc->allow_comments = (signed char)(config->allow_comments != 0); jc->handle_floats_manually = (signed char)(config->handle_floats_manually != 0); jc->decimal_point = *localeconv()->decimal_point; /* We need to be able to push at least one object */ jc->depth = config->depth == 0 ? 1 : config->depth; /* reset the parser */ if (!JSON_parser_reset(jc)) { jc->free(jc); return NULL; } return jc; } static int parse_buffer_grow(JSON_parser jc) { const size_t bytes_to_copy = jc->parse_buffer_count * sizeof(jc->parse_buffer[0]); const size_t new_capacity = jc->parse_buffer_capacity * 2; const size_t bytes_to_allocate = new_capacity * sizeof(jc->parse_buffer[0]); void* mem = JSON_parser_malloc(jc->malloc, bytes_to_allocate, "parse buffer"); if (mem == NULL) { jc->error = JSON_E_OUT_OF_MEMORY; return false; } assert(new_capacity > 0); memcpy(mem, jc->parse_buffer, bytes_to_copy); if (jc->parse_buffer != &jc->static_parse_buffer[0]) { jc->free(jc->parse_buffer); } jc->parse_buffer = (char*)mem; jc->parse_buffer_capacity = new_capacity; return true; } static int parse_buffer_reserve_for(JSON_parser jc, unsigned chars) { while (jc->parse_buffer_count + chars + 1 > jc->parse_buffer_capacity) { if (!parse_buffer_grow(jc)) { assert(jc->error == JSON_E_OUT_OF_MEMORY); return false; } } return true; } #define parse_buffer_has_space_for(jc, count) \ (jc->parse_buffer_count + (count) + 1 <= jc->parse_buffer_capacity) #define parse_buffer_push_back_char(jc, c)\ do {\ assert(parse_buffer_has_space_for(jc, 1)); \ jc->parse_buffer[jc->parse_buffer_count++] = c;\ jc->parse_buffer[jc->parse_buffer_count] = 0;\ } while (0) #define assert_is_non_container_type(jc) \ assert( \ jc->type == JSON_T_NULL || \ jc->type == JSON_T_FALSE || \ jc->type == JSON_T_TRUE || \ jc->type == JSON_T_FLOAT || \ jc->type == JSON_T_INTEGER || \ jc->type == JSON_T_STRING) static int parse_parse_buffer(JSON_parser jc) { if (jc->callback) { JSON_value value, *arg = NULL; if (jc->type != JSON_T_NONE) { assert_is_non_container_type(jc); switch(jc->type) { case JSON_T_FLOAT: arg = &value; if (jc->handle_floats_manually) { value.vu.str.value = jc->parse_buffer; value.vu.str.length = jc->parse_buffer_count; } else { /* not checking with end pointer b/c there may be trailing ws */ value.vu.float_value = strtod(jc->parse_buffer, NULL); } break; case JSON_T_INTEGER: arg = &value; sscanf(jc->parse_buffer, JSON_PARSER_INTEGER_SSCANF_TOKEN, &value.vu.integer_value); break; case JSON_T_STRING: arg = &value; value.vu.str.value = jc->parse_buffer; value.vu.str.length = jc->parse_buffer_count; break; } if (!(*jc->callback)(jc->ctx, jc->type, arg)) { return false; } } } parse_buffer_clear(jc); return true; } #define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800) #define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00) #define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000) static const unsigned char utf8_lead_bits[4] = { 0x00, 0xC0, 0xE0, 0xF0 }; static int decode_unicode_char(JSON_parser jc) { int i; unsigned uc = 0; char* p; int trail_bytes; assert(jc->parse_buffer_count >= 6); p = &jc->parse_buffer[jc->parse_buffer_count - 4]; for (i = 12; i >= 0; i -= 4, ++p) { unsigned x = *p; if (x >= 'a') { x -= ('a' - 10); } else if (x >= 'A') { x -= ('A' - 10); } else { x &= ~0x30u; } assert(x < 16); uc |= x << i; } /* clear UTF-16 char from buffer */ jc->parse_buffer_count -= 6; jc->parse_buffer[jc->parse_buffer_count] = 0; if (uc == 0xffff || uc == 0xfffe) { return false; } /* attempt decoding ... */ if (jc->utf16_high_surrogate) { if (IS_LOW_SURROGATE(uc)) { uc = DECODE_SURROGATE_PAIR(jc->utf16_high_surrogate, uc); trail_bytes = 3; jc->utf16_high_surrogate = 0; } else { /* high surrogate without a following low surrogate */ return false; } } else { if (uc < 0x80) { trail_bytes = 0; } else if (uc < 0x800) { trail_bytes = 1; } else if (IS_HIGH_SURROGATE(uc)) { /* save the high surrogate and wait for the low surrogate */ jc->utf16_high_surrogate = (UTF16)uc; return true; } else if (IS_LOW_SURROGATE(uc)) { /* low surrogate without a preceding high surrogate */ return false; } else { trail_bytes = 2; } } jc->parse_buffer[jc->parse_buffer_count++] = (char) ((uc >> (trail_bytes * 6)) | utf8_lead_bits[trail_bytes]); for (i = trail_bytes * 6 - 6; i >= 0; i -= 6) { jc->parse_buffer[jc->parse_buffer_count++] = (char) (((uc >> i) & 0x3F) | 0x80); } jc->parse_buffer[jc->parse_buffer_count] = 0; return true; } static int add_escaped_char_to_parse_buffer(JSON_parser jc, int next_char) { assert(parse_buffer_has_space_for(jc, 1)); jc->escaped = 0; /* remove the backslash */ parse_buffer_pop_back_char(jc); switch(next_char) { case 'b': parse_buffer_push_back_char(jc, '\b'); break; case 'f': parse_buffer_push_back_char(jc, '\f'); break; case 'n': parse_buffer_push_back_char(jc, '\n'); break; case 'r': parse_buffer_push_back_char(jc, '\r'); break; case 't': parse_buffer_push_back_char(jc, '\t'); break; case '"': parse_buffer_push_back_char(jc, '"'); break; case '\\': parse_buffer_push_back_char(jc, '\\'); break; case '/': parse_buffer_push_back_char(jc, '/'); break; case 'u': parse_buffer_push_back_char(jc, '\\'); parse_buffer_push_back_char(jc, 'u'); break; default: return false; } return true; } static int add_char_to_parse_buffer(JSON_parser jc, int next_char, int next_class) { if (!parse_buffer_reserve_for(jc, 1)) { assert(JSON_E_OUT_OF_MEMORY == jc->error); return false; } if (jc->escaped) { if (!add_escaped_char_to_parse_buffer(jc, next_char)) { jc->error = JSON_E_INVALID_ESCAPE_SEQUENCE; return false; } } else if (!jc->comment) { if ((jc->type != JSON_T_NONE) | !((next_class == C_SPACE) | (next_class == C_WHITE)) /* non-white-space */) { parse_buffer_push_back_char(jc, (char)next_char); } } return true; } #define assert_type_isnt_string_null_or_bool(jc) \ assert(jc->type != JSON_T_FALSE); \ assert(jc->type != JSON_T_TRUE); \ assert(jc->type != JSON_T_NULL); \ assert(jc->type != JSON_T_STRING) int JSON_parser_char(JSON_parser jc, int next_char) { /* After calling new_JSON_parser, call this function for each character (or partial character) in your JSON text. It can accept UTF-8, UTF-16, or UTF-32. It returns true if things are looking ok so far. If it rejects the text, it returns false. */ int next_class, next_state; /* Store the current char for error handling */ jc->current_char = next_char; /* Determine the character's class. */ if (next_char < 0) { jc->error = JSON_E_INVALID_CHAR; return false; } if (next_char >= 128) { next_class = C_ETC; } else { next_class = ascii_class[next_char]; if (next_class <= XX) { set_error(jc); return false; } } if (!add_char_to_parse_buffer(jc, next_char, next_class)) { return false; } /* Get the next state from the state transition table. */ next_state = state_transition_table[jc->state][next_class]; if (next_state >= 0) { /* Change the state. */ jc->state = (signed char)next_state; } else { /* Or perform one of the actions. */ switch (next_state) { /* Unicode character */ case UC: if(!decode_unicode_char(jc)) { jc->error = JSON_E_INVALID_UNICODE_SEQUENCE; return false; } /* check if we need to read a second UTF-16 char */ if (jc->utf16_high_surrogate) { jc->state = D1; } else { jc->state = ST; } break; /* escaped char */ case EX: jc->escaped = 1; jc->state = ESC; break; /* integer detected by minus */ case MX: jc->type = JSON_T_INTEGER; jc->state = MI; break; /* integer detected by zero */ case ZX: jc->type = JSON_T_INTEGER; jc->state = ZE; break; /* integer detected by 1-9 */ case IX: jc->type = JSON_T_INTEGER; jc->state = IT; break; /* floating point number detected by exponent*/ case DE: assert_type_isnt_string_null_or_bool(jc); jc->type = JSON_T_FLOAT; jc->state = E1; break; /* floating point number detected by fraction */ case DF: assert_type_isnt_string_null_or_bool(jc); if (!jc->handle_floats_manually) { /* Some versions of strtod (which underlies sscanf) don't support converting C-locale formated floating point values. */ assert(jc->parse_buffer[jc->parse_buffer_count-1] == '.'); jc->parse_buffer[jc->parse_buffer_count-1] = jc->decimal_point; } jc->type = JSON_T_FLOAT; jc->state = FX; break; /* string begin " */ case SB: parse_buffer_clear(jc); assert(jc->type == JSON_T_NONE); jc->type = JSON_T_STRING; jc->state = ST; break; /* n */ case NU: assert(jc->type == JSON_T_NONE); jc->type = JSON_T_NULL; jc->state = N1; break; /* f */ case FA: assert(jc->type == JSON_T_NONE); jc->type = JSON_T_FALSE; jc->state = F1; break; /* t */ case TR: assert(jc->type == JSON_T_NONE); jc->type = JSON_T_TRUE; jc->state = T1; break; /* closing comment */ case CE: jc->comment = 0; assert(jc->parse_buffer_count == 0); assert(jc->type == JSON_T_NONE); jc->state = jc->before_comment_state; break; /* opening comment */ case CB: if (!jc->allow_comments) { return false; } parse_buffer_pop_back_char(jc); if (!parse_parse_buffer(jc)) { return false; } assert(jc->parse_buffer_count == 0); assert(jc->type != JSON_T_STRING); switch (jc->stack[jc->top]) { case MODE_ARRAY: case MODE_OBJECT: switch(jc->state) { case VA: case AR: jc->before_comment_state = jc->state; break; default: jc->before_comment_state = OK; break; } break; default: jc->before_comment_state = jc->state; break; } jc->type = JSON_T_NONE; jc->state = C1; jc->comment = 1; break; /* empty } */ case -9: parse_buffer_clear(jc); if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) { return false; } if (!pop(jc, MODE_KEY)) { return false; } jc->state = OK; break; /* } */ case -8: parse_buffer_pop_back_char(jc); if (!parse_parse_buffer(jc)) { return false; } if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) { return false; } if (!pop(jc, MODE_OBJECT)) { jc->error = JSON_E_UNBALANCED_COLLECTION; return false; } jc->type = JSON_T_NONE; jc->state = OK; break; /* ] */ case -7: parse_buffer_pop_back_char(jc); if (!parse_parse_buffer(jc)) { return false; } if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_END, NULL)) { return false; } if (!pop(jc, MODE_ARRAY)) { jc->error = JSON_E_UNBALANCED_COLLECTION; return false; } jc->type = JSON_T_NONE; jc->state = OK; break; /* { */ case -6: parse_buffer_pop_back_char(jc); if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_BEGIN, NULL)) { return false; } if (!push(jc, MODE_KEY)) { return false; } assert(jc->type == JSON_T_NONE); jc->state = OB; break; /* [ */ case -5: parse_buffer_pop_back_char(jc); if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_BEGIN, NULL)) { return false; } if (!push(jc, MODE_ARRAY)) { return false; } assert(jc->type == JSON_T_NONE); jc->state = AR; break; /* string end " */ case -4: parse_buffer_pop_back_char(jc); switch (jc->stack[jc->top]) { case MODE_KEY: assert(jc->type == JSON_T_STRING); jc->type = JSON_T_NONE; jc->state = CO; if (jc->callback) { JSON_value value; value.vu.str.value = jc->parse_buffer; value.vu.str.length = jc->parse_buffer_count; if (!(*jc->callback)(jc->ctx, JSON_T_KEY, &value)) { return false; } } parse_buffer_clear(jc); break; case MODE_ARRAY: case MODE_OBJECT: assert(jc->type == JSON_T_STRING); if (!parse_parse_buffer(jc)) { return false; } jc->type = JSON_T_NONE; jc->state = OK; break; default: return false; } break; /* , */ case -3: parse_buffer_pop_back_char(jc); if (!parse_parse_buffer(jc)) { return false; } switch (jc->stack[jc->top]) { case MODE_OBJECT: /* A comma causes a flip from object mode to key mode. */ if (!pop(jc, MODE_OBJECT) || !push(jc, MODE_KEY)) { return false; } assert(jc->type != JSON_T_STRING); jc->type = JSON_T_NONE; jc->state = KE; break; case MODE_ARRAY: assert(jc->type != JSON_T_STRING); jc->type = JSON_T_NONE; jc->state = VA; break; default: return false; } break; /* : */ case -2: /* A colon causes a flip from key mode to object mode. */ parse_buffer_pop_back_char(jc); if (!pop(jc, MODE_KEY) || !push(jc, MODE_OBJECT)) { return false; } assert(jc->type == JSON_T_NONE); jc->state = VA; break; /* Bad action. */ default: set_error(jc); return false; } } return true; } int JSON_parser_done(JSON_parser jc) { if ((jc->state == OK || jc->state == GO) && pop(jc, MODE_DONE)) { return true; } jc->error = JSON_E_UNBALANCED_COLLECTION; return false; } int JSON_parser_is_legal_white_space_string(const char* s) { int c, char_class; if (s == NULL) { return false; } for (; *s; ++s) { c = *s; if (c < 0 || c >= 128) { return false; } char_class = ascii_class[c]; if (char_class != C_SPACE && char_class != C_WHITE) { return false; } } return true; } int JSON_parser_get_last_error(JSON_parser jc) { return jc->error; } void init_JSON_config(JSON_config* config) { if (config) { memset(config, 0, sizeof(*config)); config->depth = JSON_PARSER_STACK_SIZE - 1; config->malloc = malloc; config->free = free; } } #undef XX #undef COUNTOF #undef parse_buffer_clear #undef parse_buffer_pop_back_char /* end file parser/JSON_parser.c */ /* begin file ./cson.c */ #include <assert.h> #include <stdlib.h> /* malloc()/free() */ #include <string.h> #include <errno.h> #ifdef _MSC_VER # if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ # pragma warning( push ) # pragma warning(disable:4996) /* unsecure sscanf (but snscanf() isn't in c89) */ # pragma warning(disable:4244) /* complaining about data loss due to integer precision in the sqlite3 utf decoding routines */ # endif #endif #if 1 #include <stdio.h> #define MARKER if(1) printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); if(1) printf #else static void noop_printf(char const * fmt, ...) {} #define MARKER if(0) printf #endif #if defined(__cplusplus) extern "C" { #endif /** This type holds the "vtbl" for type-specific operations when working with cson_value objects. All cson_values of a given logical type share a pointer to a single library-internal instance of this class. */ struct cson_value_api { /** The logical JavaScript/JSON type associated with this object. */ const cson_type_id typeID; /** Must free any memory associated with self, but not free self. If self is NULL then this function must do nothing. */ void (*cleanup)( cson_value * self ); /** POSSIBLE TODOs: // Deep copy. int (*clone)( cson_value const * self, cson_value ** tgt ); // Using JS semantics for true/value char (*bool_value)( cson_value const * self ); // memcmp() return value semantics int (*compare)( cson_value const * self, cson_value const * other ); */ }; typedef struct cson_value_api cson_value_api; /** Empty-initialized cson_value_api object. */ #define cson_value_api_empty_m { \ CSON_TYPE_UNDEF/*typeID*/, \ NULL/*cleanup*/\ } /** Empty-initialized cson_value_api object. */ /*static const cson_value_api cson_value_api_empty = cson_value_api_empty_m;*/ typedef unsigned int cson_counter_t; struct cson_value { /** The "vtbl" of type-specific operations. All instances of a given logical value type share a single api instance. Results are undefined if this value is NULL. */ cson_value_api const * api; /** The raw value. Its interpretation depends on the value of the api member. Some value types require dynamically-allocated memory, so one must always call cson_value_free() to destroy a value when it is no longer needed. For stack-allocated values (which client could SHOULD NOT USE unless they are intimately familiar with the memory management rules and don't mind an occasional leak or crash), use cson_value_clean() instead of cson_value_free(). */ void * value; /** We use this to allow us to store cson_value instances in multiple containers or multiple times within a single container (provided no cycles are introduced). Notes about the rc implementation: - The refcount is for the cson_value instance itself, not its value pointer. - Instances start out with a refcount of 0 (not 1). Adding them to a container will increase the refcount. Cleaning up the container will decrement the count. - cson_value_free() decrements the refcount (if it is not already 0) and cleans/frees the value only when the refcount is 0. - Some places in the internals add an "extra" reference to objects to avoid a premature deletion. Don't try this at home. */ cson_counter_t refcount; }; /** Empty-initialized cson_value object. */ const cson_parse_opt cson_parse_opt_empty = cson_parse_opt_empty_m; const cson_output_opt cson_output_opt_empty = cson_output_opt_empty_m; const cson_object_iterator cson_object_iterator_empty = cson_object_iterator_empty_m; const cson_buffer cson_buffer_empty = cson_buffer_empty_m; const cson_parse_info cson_parse_info_empty = cson_parse_info_empty_m; static void cson_value_destroy_zero_it( cson_value * self ); static void cson_value_destroy_object( cson_value * self ); /** If self is-a array then this function destroys its contents, else this function does nothing. */ static void cson_value_destroy_array( cson_value * self ); static const cson_value_api cson_value_api_null = { CSON_TYPE_NULL, cson_value_destroy_zero_it }; static const cson_value_api cson_value_api_undef = { CSON_TYPE_UNDEF, cson_value_destroy_zero_it }; static const cson_value_api cson_value_api_bool = { CSON_TYPE_BOOL, cson_value_destroy_zero_it }; static const cson_value_api cson_value_api_integer = { CSON_TYPE_INTEGER, cson_value_destroy_zero_it }; static const cson_value_api cson_value_api_double = { CSON_TYPE_DOUBLE, cson_value_destroy_zero_it }; static const cson_value_api cson_value_api_string = { CSON_TYPE_STRING, cson_value_destroy_zero_it }; static const cson_value_api cson_value_api_array = { CSON_TYPE_ARRAY, cson_value_destroy_array }; static const cson_value_api cson_value_api_object = { CSON_TYPE_OBJECT, cson_value_destroy_object }; static const cson_value cson_value_undef = { &cson_value_api_undef, NULL, 0 }; static const cson_value cson_value_integer_empty = { &cson_value_api_integer, NULL, 0 }; static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 }; static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 }; static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 }; static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 }; /** Strings are allocated as an instances of this class with N+1 trailing bytes, where N is the length of the string being allocated. To convert a cson_string to c-string we simply increment the cson_string pointer. To do the opposite we use (cstr - sizeof(cson_string)). Zero-length strings are a special case handled by a couple of the cson_string functions. */ struct cson_string { unsigned int length; }; #define cson_string_empty_m {0/*length*/} static const cson_string cson_string_empty = cson_string_empty_m; /** Assumes V is a (cson_value*) ans V->value is a (T*). Returns V->value cast to a (T*). */ #define CSON_CAST(T,V) ((T*)((V)->value)) /** Assumes V is a pointer to memory which is allocated as part of a cson_value instance (the bytes immediately after that part). Returns a pointer a a cson_value by subtracting sizeof(cson_value) from that address and casting it to a (cson_value*) */ #define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value))) /** CSON_INT(V) assumes that V is a (cson_value*) of type CSON_TYPE_INTEGER. This macro returns a (cson_int_t*) representing its value (how that is stored depends on whether we are running in 32- or 64-bit mode). */ #if CSON_VOID_PTR_IS_BIG # define CSON_INT(V) ((cson_int_t*)(&((V)->value))) #else # define CSON_INT(V) ((cson_int_t*)(V)->value) #endif #define CSON_DBL(V) CSON_CAST(cson_double_t,(V)) #define CSON_STR(V) CSON_CAST(cson_string,(V)) #define CSON_OBJ(V) CSON_CAST(cson_object,(V)) #define CSON_ARRAY(V) CSON_CAST(cson_array,(V)) /** Holds special shared "constant" (though they are non-const) values. */ static struct CSON_EMPTY_HOLDER_ { char trueValue; cson_string stringValue; } CSON_EMPTY_HOLDER = { 1/*trueValue*/, cson_string_empty_m }; /** Indexes into the CSON_SPECIAL_VALUES array. If this enum changes in any way, makes damned sure that CSON_SPECIAL_VALUES is updated to match!!! */ enum CSON_INTERNAL_VALUES { CSON_VAL_UNDEF = 0, CSON_VAL_NULL = 1, CSON_VAL_TRUE = 2, CSON_VAL_FALSE = 3, CSON_VAL_INT_0 = 4, CSON_VAL_DBL_0 = 5, CSON_VAL_STR_EMPTY = 6, CSON_INTERNAL_VALUES_LENGTH }; /** Some "special" shared cson_value instances. These values MUST be initialized in the order specified by the CSON_INTERNAL_VALUES enum. Note that they are not const because they are used as shared-allocation objects in non-const contexts. However, the public API provides no way to modifying them, and clients who modify values directly are subject to The Wrath of Undefined Behaviour. */ static cson_value CSON_SPECIAL_VALUES[] = { { &cson_value_api_undef, NULL, 0 }, /* UNDEF */ { &cson_value_api_null, NULL, 0 }, /* NULL */ { &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */ { &cson_value_api_bool, NULL, 0 }, /* FALSE */ { &cson_value_api_integer, NULL, 0 }, /* INT_0 */ { &cson_value_api_double, NULL, 0 }, /* DBL_0 */ { &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */ { NULL, NULL, 0 } }; /** Returns non-0 (true) if m is one of our special "built-in" values, e.g. from CSON_SPECIAL_VALUES and some "empty" values. If this returns true, m MUST NOT be free()d! */ static char cson_value_is_builtin( void const * m ) { if((m >= (void const *)&CSON_EMPTY_HOLDER) && ( m < (void const *)(&CSON_EMPTY_HOLDER+1))) return 1; else return ((m >= (void const *)&CSON_SPECIAL_VALUES[0]) && ( m < (void const *)&CSON_SPECIAL_VALUES[CSON_INTERNAL_VALUES_LENGTH]) ) ? 1 : 0; } char const * cson_rc_string(int rc) { if(0 == rc) return "OK"; #define CHECK(N) else if(cson_rc.N == rc ) return #N CHECK(OK); CHECK(ArgError); CHECK(RangeError); CHECK(TypeError); CHECK(IOError); CHECK(AllocError); CHECK(NYIError); CHECK(InternalError); CHECK(UnsupportedError); CHECK(NotFoundError); CHECK(UnknownError); CHECK(Parse_INVALID_CHAR); CHECK(Parse_INVALID_KEYWORD); CHECK(Parse_INVALID_ESCAPE_SEQUENCE); CHECK(Parse_INVALID_UNICODE_SEQUENCE); CHECK(Parse_INVALID_NUMBER); CHECK(Parse_NESTING_DEPTH_REACHED); CHECK(Parse_UNBALANCED_COLLECTION); CHECK(Parse_EXPECTED_KEY); CHECK(Parse_EXPECTED_COLON); else return "UnknownError"; #undef CHECK } /** If CSON_LOG_ALLOC is true then the cson_malloc/realloc/free() routines will log a message to stderr. */ #define CSON_LOG_ALLOC 0 /** CSON_FOSSIL_MODE is only for use in the Fossil source tree, so that we can plug in to its allocators. We can't do this by, e.g., defining macros for the malloc/free funcs because fossil's lack of header files means we would have to #include "main.c" here to get the declarations. */ #if defined(CSON_FOSSIL_MODE) extern void *fossil_malloc(size_t n); extern void fossil_free(void *p); extern void *fossil_realloc(void *p, size_t n); # define CSON_MALLOC_IMPL fossil_malloc # define CSON_FREE_IMPL fossil_free # define CSON_REALLOC_IMPL fossil_realloc #endif #if !defined CSON_MALLOC_IMPL # define CSON_MALLOC_IMPL malloc #endif #if !defined CSON_FREE_IMPL # define CSON_FREE_IMPL free #endif #if !defined CSON_REALLOC_IMPL # define CSON_REALLOC_IMPL realloc #endif /** A test/debug macro for simulating an OOM after the given number of bytes have been allocated. */ #define CSON_SIMULATE_OOM 0 #if CSON_SIMULATE_OOM static unsigned int cson_totalAlloced = 0; #endif /** Simple proxy for malloc(). descr is a description of the allocation. */ static void * cson_malloc( size_t n, char const * descr ) { #if CSON_LOG_ALLOC fprintf(stderr, "Allocating %u bytes [%s].\n", (unsigned int)n, descr); #endif #if CSON_SIMULATE_OOM cson_totalAlloced += n; if( cson_totalAlloced > CSON_SIMULATE_OOM ) { return NULL; } #endif return CSON_MALLOC_IMPL(n); } /** Simple proxy for free(). descr is a description of the memory being freed. */ static void cson_free( void * p, char const * descr ) { #if CSON_LOG_ALLOC fprintf(stderr, "Freeing @%p [%s].\n", p, descr); #endif if( !cson_value_is_builtin(p) ) { CSON_FREE_IMPL( p ); } } /** Simple proxy for realloc(). descr is a description of the (re)allocation. */ static void * cson_realloc( void * hint, size_t n, char const * descr ) { #if CSON_LOG_ALLOC fprintf(stderr, "%sllocating %u bytes [%s].\n", hint ? "Rea" : "A", (unsigned int)n, descr); #endif #if CSON_SIMULATE_OOM cson_totalAlloced += n; if( cson_totalAlloced > CSON_SIMULATE_OOM ) { return NULL; } #endif if( 0==n ) { cson_free(hint, descr); return NULL; } else { return CSON_REALLOC_IMPL( hint, n ); } } #undef CSON_LOG_ALLOC #undef CSON_SIMULATE_OOM /** CLIENTS CODE SHOULD NEVER USE THIS because it opens up doors to memory leaks if it is not used in very controlled circumstances. Users must be very aware of how the underlying memory management works. Frees any resources owned by val, but does not free val itself (which may be stack-allocated). If !val or val->api or val->api->cleanup are NULL then this is a no-op. If v is a container type (object or array) its children are also cleaned up, recursively. After calling this, val will have the special "undefined" type. */ static void cson_value_clean( cson_value * val ); /** Increments cv's reference count by 1. As a special case, values for which cson_value_is_builtin() returns true are not modified. assert()s if (NULL==cv). */ static void cson_refcount_incr( cson_value * cv ) { assert( NULL != cv ); if( cson_value_is_builtin( cv ) ) { /* do nothing: we do not want to modify the shared instances. */ return; } else { ++cv->refcount; } } #if 0 int cson_value_refcount_set( cson_value * cv, unsigned short rc ) { if( NULL == cv ) return cson_rc.ArgError; else { cv->refcount = rc; return 0; } } #endif int cson_value_add_reference( cson_value * cv ) { if( NULL == cv ) return cson_rc.ArgError; else if( (cv->refcount+1) < cv->refcount ) { return cson_rc.RangeError; } else { cson_refcount_incr( cv ); return 0; } } /** If cv is NULL or cson_value_is_builtin(cv) returns true then this function does nothing and returns 0, otherwise... If cv->refcount is 0 or 1 then cson_value_clean(cv) is called, cv is freed, and 0 is returned. If cv->refcount is any other value then it is decremented and the new value is returned. */ static cson_counter_t cson_refcount_decr( cson_value * cv ) { if( (NULL == cv) || cson_value_is_builtin(cv) ) return 0; else if( (0 == cv->refcount) || (0 == --cv->refcount) ) { cson_value_clean(cv); cson_free(cv,"cson_value::refcount=0"); return 0; } else return cv->refcount; } unsigned int cson_string_length_bytes( cson_string const * str ) { return str ? str->length : 0; } /** Fetches v's string value as a non-const string. cson_strings are intended to be immutable, but this form provides access to the immutable bits, which are v->length bytes long. A length-0 string is returned as NULL from here, as opposed to "". (This is a side-effect of the string allocation mechanism.) Returns NULL if !v or if v is the internal empty-string singleton. */ static char * cson_string_str(cson_string *v) { /* See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a */ #if 1 if( !v || (&CSON_EMPTY_HOLDER.stringValue == v) ) return NULL; else return (char *)((unsigned char *)( v+1 )); #else static char empty[2] = {0,0}; return ( NULL == v ) ? NULL : (v->length ? (char *) (((unsigned char *)v) + sizeof(cson_string)) : empty) ; #endif } /** Fetches v's string value as a const string. */ char const * cson_string_cstr(cson_string const *v) { /* See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a */ #if 1 if( ! v ) return NULL; else if( v == &CSON_EMPTY_HOLDER.stringValue ) return ""; else { assert((0 < v->length) && "How do we have a non-singleton empty string?"); return (char const *)((unsigned char const *)(v+1)); } #else return (NULL == v) ? NULL : (v->length ? (char const *) ((unsigned char const *)(v+1)) : ""); #endif } #if 0 /** Just like strndup(3), in that neither are C89/C99-standard and both are documented in detail in strndup(3). */ static char * cson_strdup( char const * src, size_t n ) { char * rc = (char *)cson_malloc(n+1, "cson_strdup"); if( ! rc ) return NULL; memset( rc, 0, n+1 ); rc[n] = 0; return strncpy( rc, src, n ); } #endif int cson_string_cmp_cstr_n( cson_string const * str, char const * other, unsigned int otherLen ) { if( ! other && !str ) return 0; else if( other && !str ) return 1; else if( str && !other ) return -1; else if( !otherLen ) return str->length ? 1 : 0; else if( !str->length ) return otherLen ? -1 : 0; else { unsigned const int max = (otherLen > str->length) ? otherLen : str->length; int const rc = strncmp( cson_string_cstr(str), other, max ); return ( (0 == rc) && (otherLen != str->length) ) ? (str->length < otherLen) ? -1 : 1 : rc; } } int cson_string_cmp_cstr( cson_string const * lhs, char const * rhs ) { return cson_string_cmp_cstr_n( lhs, rhs, (rhs&&*rhs) ? strlen(rhs) : 0 ); } int cson_string_cmp( cson_string const * lhs, cson_string const * rhs ) { return cson_string_cmp_cstr_n( lhs, cson_string_cstr(rhs), rhs ? rhs->length : 0 ); } /** If self is not NULL, *self is overwritten to have the undefined type. self is not cleaned up or freed. */ void cson_value_destroy_zero_it( cson_value * self ) { if( self ) { *self = cson_value_undef; } } /** A key/value pair collection. Each of these objects owns its key/value pointers, and they are cleaned up by cson_kvp_clean(). */ struct cson_kvp { cson_value * key; cson_value * value; }; #define cson_kvp_empty_m {NULL,NULL} static const cson_kvp cson_kvp_empty = cson_kvp_empty_m; /** @def CSON_OBJECT_PROPS_SORT Don't use this - it has not been updated to account for internal changes in cson_object. If CSON_OBJECT_PROPS_SORT is set to a true value then qsort() and bsearch() are used to sort (upon insertion) and search cson_object::kvp property lists. This costs us a re-sort on each insertion but searching is O(log n) average/worst case (and O(1) best-case). i'm not yet convinced that the overhead of the qsort() justifies the potentially decreased search times - it has not been measured. Object property lists tend to be relatively short in JSON, and a linear search which uses the cson_string::length property as a quick check is quite fast when one compares it with the sort overhead required by the bsearch() approach. */ #define CSON_OBJECT_PROPS_SORT 0 /** @def CSON_OBJECT_PROPS_SORT_USE_LENGTH Don't use this - i'm not sure that it works how i'd like. If CSON_OBJECT_PROPS_SORT_USE_LENGTH is true then we use string lengths as quick checks when sorting property keys. This leads to a non-intuitive sorting order but "should" be faster. This is ignored if CSON_OBJECT_PROPS_SORT is false. */ #define CSON_OBJECT_PROPS_SORT_USE_LENGTH 0 #if CSON_OBJECT_PROPS_SORT /** cson_kvp comparator for use with qsort(). ALMOST compares with strcmp() semantics, but it uses the strings' lengths as a quicker approach. This might give non-intuitive results, but it's faster. */ static int cson_kvp_cmp( void const * lhs, void const * rhs ) { cson_kvp const * lk = *((cson_kvp const * const*)lhs); cson_kvp const * rk = *((cson_kvp const * const*)rhs); cson_string const * l = cson_string_value(lk->key); cson_string const * r = cson_string_value(rk->key); #if CSON_OBJECT_PROPS_SORT_USE_LENGTH if( l->length < r->length ) return -1; else if( l->length > r->length ) return 1; else return strcmp( cson_string_cstr( l ), cson_string_cstr( r ) ); #else return strcmp( cson_string_cstr( l ), cson_string_cstr( r ) ); #endif /*CSON_OBJECT_PROPS_SORT_USE_LENGTH*/ } #endif /*CSON_OBJECT_PROPS_SORT*/ #if CSON_OBJECT_PROPS_SORT #error "Need to rework this for cson_string-to-cson_value refactoring" /** A bsearch() comparison function which requires that lhs be a (char const *) and rhs be-a (cson_kvp const * const *). It compares lhs to rhs->key's value, using strcmp() semantics. */ static int cson_kvp_cmp_vs_cstr( void const * lhs, void const * rhs ) { char const * lk = (char const *)lhs; cson_kvp const * rk = *((cson_kvp const * const*)rhs) ; #if CSON_OBJECT_PROPS_SORT_USE_LENGTH unsigned int llen = strlen(lk); if( llen < rk->key->length ) return -1; else if( llen > rk->key->length ) return 1; else return strcmp( lk, cson_string_cstr( rk->key ) ); #else return strcmp( lk, cson_string_cstr( rk->key ) ); #endif /*CSON_OBJECT_PROPS_SORT_USE_LENGTH*/ } #endif /*CSON_OBJECT_PROPS_SORT*/ struct cson_kvp_list { cson_kvp ** list; unsigned int count; unsigned int alloced; }; typedef struct cson_kvp_list cson_kvp_list; #define cson_kvp_list_empty_m {NULL/*list*/,0/*count*/,0/*alloced*/} /*static const cson_kvp_list cson_kvp_list_empty = cson_kvp_list_empty_m;*/ struct cson_object { cson_kvp_list kvp; }; /*typedef struct cson_object cson_object;*/ #define cson_object_empty_m { cson_kvp_list_empty_m/*kvp*/ } static const cson_object cson_object_empty = cson_object_empty_m; struct cson_value_list { cson_value ** list; unsigned int count; unsigned int alloced; }; typedef struct cson_value_list cson_value_list; #define cson_value_list_empty_m {NULL/*list*/,0/*count*/,0/*alloced*/} static const cson_value_list cson_value_list_empty = cson_value_list_empty_m; struct cson_array { cson_value_list list; }; /*typedef struct cson_array cson_array;*/ #define cson_array_empty_m { cson_value_list_empty_m/*list*/ } static const cson_array cson_array_empty = cson_array_empty_m; struct cson_parser { JSON_parser p; cson_value * root; cson_value * node; cson_array stack; cson_string * ckey; int errNo; unsigned int totalKeyCount; unsigned int totalValueCount; }; typedef struct cson_parser cson_parser; static const cson_parser cson_parser_empty = { NULL/*p*/, NULL/*root*/, NULL/*node*/, cson_array_empty_m/*stack*/, NULL/*ckey*/, 0/*errNo*/, 0/*totalKeyCount*/, 0/*totalValueCount*/ }; #if 1 /* The following funcs are declared in generated code (cson_lists.h), but we need early access to their decls for the Amalgamation build. */ static unsigned int cson_value_list_reserve( cson_value_list * self, unsigned int n ); static unsigned int cson_kvp_list_reserve( cson_kvp_list * self, unsigned int n ); static int cson_kvp_list_append( cson_kvp_list * self, cson_kvp * cp ); static void cson_kvp_list_clean( cson_kvp_list * self, void (*cleaner)(cson_kvp * obj) ); #if 0 static int cson_value_list_append( cson_value_list * self, cson_value * cp ); static void cson_value_list_clean( cson_value_list * self, void (*cleaner)(cson_value * obj)); static int cson_kvp_list_visit( cson_kvp_list * self, int (*visitor)(cson_kvp * obj, void * visitorState ), void * visitorState ); static int cson_value_list_visit( cson_value_list * self, int (*visitor)(cson_value * obj, void * visitorState ), void * visitorState ); #endif #endif #if 0 # define LIST_T cson_value_list # define VALUE_T cson_value * # define VALUE_T_IS_PTR 1 # define LIST_T cson_kvp_list # define VALUE_T cson_kvp * # define VALUE_T_IS_PTR 1 #else #endif /** Allocates a new value of the specified type. Ownership is transfered to the caller, who must eventually free it by passing it to cson_value_free() or transfering ownership to a container. extra is only valid for type CSON_TYPE_STRING, and must be the length of the string to allocate + 1 byte (for the NUL). The returned value->api member will be set appropriately and val->value will be set to point to the memory allocated to hold the native value type. Use the internal CSON_CAST() family of macros to convert the cson_values to their corresponding native representation. Returns NULL on allocation error. @see cson_value_new_array() @see cson_value_new_object() @see cson_value_new_string() @see cson_value_new_integer() @see cson_value_new_double() @see cson_value_new_bool() @see cson_value_free() */ static cson_value * cson_value_new(cson_type_id t, size_t extra) { static const size_t vsz = sizeof(cson_value); const size_t sz = vsz + extra; size_t tx = 0; cson_value def = cson_value_undef; cson_value * v = NULL; char const * reason = "cson_value_new"; switch(t) { case CSON_TYPE_ARRAY: assert( 0 == extra ); def = cson_value_array_empty; tx = sizeof(cson_array); reason = "cson_value:array"; break; case CSON_TYPE_DOUBLE: assert( 0 == extra ); def = cson_value_double_empty; tx = sizeof(cson_double_t); reason = "cson_value:double"; break; case CSON_TYPE_INTEGER: assert( 0 == extra ); def = cson_value_integer_empty; #if !CSON_VOID_PTR_IS_BIG tx = sizeof(cson_int_t); #endif reason = "cson_value:int"; break; case CSON_TYPE_STRING: assert( 0 != extra ); def = cson_value_string_empty; tx = sizeof(cson_string); reason = "cson_value:string"; break; case CSON_TYPE_OBJECT: assert( 0 == extra ); def = cson_value_object_empty; tx = sizeof(cson_object); reason = "cson_value:object"; break; default: assert(0 && "Unhandled type in cson_value_new()!"); return NULL; } assert( def.api->typeID != CSON_TYPE_UNDEF ); v = (cson_value *)cson_malloc(sz+tx, reason); if( v ) { *v = def; if(tx || extra){ memset(v+1, 0, tx + extra); v->value = (void *)(v+1); } } return v; } void cson_value_free(cson_value *v) { cson_refcount_decr( v ); } #if 0 /* we might actually want this later on. */ /** Returns true if v is not NULL and has the given type ID. */ static char cson_value_is_a( cson_value const * v, cson_type_id is ) { return (v && v->api && (v->api->typeID == is)) ? 1 : 0; } #endif cson_type_id cson_value_type_id( cson_value const * v ) { return (v && v->api) ? v->api->typeID : CSON_TYPE_UNDEF; } char cson_value_is_undef( cson_value const * v ) { return ( !v || !v->api || (v->api==&cson_value_api_undef)) ? 1 : 0; } #define ISA(T,TID) char cson_value_is_##T( cson_value const * v ) { \ /*return (v && v->api) ? cson_value_is_a(v,CSON_TYPE_##TID) : 0;*/ \ return (v && (v->api == &cson_value_api_##T)) ? 1 : 0; \ } extern char bogusPlaceHolderForEmacsIndention##TID ISA(null,NULL); ISA(bool,BOOL); ISA(integer,INTEGER); ISA(double,DOUBLE); ISA(string,STRING); ISA(array,ARRAY); ISA(object,OBJECT); #undef ISA char cson_value_is_number( cson_value const * v ) { return cson_value_is_integer(v) || cson_value_is_double(v); } void cson_value_clean( cson_value * val ) { if( val && val->api && val->api->cleanup ) { if( ! cson_value_is_builtin( val ) ) { cson_counter_t const rc = val->refcount; val->api->cleanup(val); *val = cson_value_undef; val->refcount = rc; } } } static cson_value * cson_value_array_alloc() { cson_value * v = cson_value_new(CSON_TYPE_ARRAY,0); if( NULL != v ) { cson_array * ar = CSON_ARRAY(v); assert(NULL != ar); *ar = cson_array_empty; } return v; } static cson_value * cson_value_object_alloc() { cson_value * v = cson_value_new(CSON_TYPE_OBJECT,0); if( NULL != v ) { cson_object * obj = CSON_OBJ(v); assert(NULL != obj); *obj = cson_object_empty; } return v; } cson_value * cson_value_new_object() { return cson_value_object_alloc(); } cson_object * cson_new_object() { return cson_value_get_object( cson_value_new_object() ); } cson_value * cson_value_new_array() { return cson_value_array_alloc(); } cson_array * cson_new_array() { return cson_value_get_array( cson_value_new_array() ); } /** Frees kvp->key and kvp->value and sets them to NULL, but does not free kvp. If !kvp then this is a no-op. */ static void cson_kvp_clean( cson_kvp * kvp ) { if( kvp ) { if(kvp->key) { cson_value_free(kvp->key); kvp->key = NULL; } if(kvp->value) { cson_value_free( kvp->value ); kvp->value = NULL; } } } cson_string * cson_kvp_key( cson_kvp const * kvp ) { return kvp ? cson_value_get_string(kvp->key) : NULL; } cson_value * cson_kvp_value( cson_kvp const * kvp ) { return kvp ? kvp->value : NULL; } /** Calls cson_kvp_clean(kvp) and then frees kvp. */ static void cson_kvp_free( cson_kvp * kvp ) { if( kvp ) { cson_kvp_clean(kvp); cson_free(kvp,"cson_kvp"); } } /** cson_value_api::destroy_value() impl for Object values. Cleans up self-owned memory and overwrites self to have the undefined value, but does not free self. */ static void cson_value_destroy_object( cson_value * self ) { if(self && self->value) { cson_object * obj = (cson_object *)self->value; assert( self->value == obj ); cson_kvp_list_clean( &obj->kvp, cson_kvp_free ); *self = cson_value_undef; } } /** Cleans up the contents of ar->list, but does not free ar. After calling this, ar will have a length of 0. If properlyCleanValues is 1 then cson_value_free() is called on each non-NULL item, otherwise the outer list is destroyed but the individual items are assumed to be owned by someone else and are not freed. */ static void cson_array_clean( cson_array * ar, char properlyCleanValues ) { if( ar ) { unsigned int i = 0; cson_value * val = NULL; for( ; i < ar->list.count; ++i ) { val = ar->list.list[i]; if(val) { ar->list.list[i] = NULL; if( properlyCleanValues ) { cson_value_free( val ); } } } cson_value_list_reserve(&ar->list,0); ar->list = cson_value_list_empty /* Pedantic note: reserve(0) already clears the list-specific fields, but we do this just in case we ever add new fields to cson_value_list which are not used in the reserve() impl. */ ; } } /** cson_value_api::destroy_value() impl for Array values. Cleans up self-owned memory and overwrites self to have the undefined value, but does not free self. */ static void cson_value_destroy_array( cson_value * self ) { cson_array * ar = cson_value_get_array(self); if(ar) { assert( self->value == ar ); cson_array_clean( ar, 1 ); *self = cson_value_undef; } } int cson_buffer_fill_from( cson_buffer * dest, cson_data_source_f src, void * state ) { int rc; enum { BufSize = 1024 * 4 }; char rbuf[BufSize]; size_t total = 0; unsigned int rlen = 0; if( ! dest || ! src ) return cson_rc.ArgError; dest->used = 0; while(1) { rlen = BufSize; rc = src( state, rbuf, &rlen ); if( rc ) break; total += rlen; if( dest->capacity < (total+1) ) { rc = cson_buffer_reserve( dest, total + 1); if( 0 != rc ) break; } memcpy( dest->mem + dest->used, rbuf, rlen ); dest->used += rlen; if( rlen < BufSize ) break; } if( !rc && dest->used ) { assert( dest->used < dest->capacity ); dest->mem[dest->used] = 0; } return rc; } int cson_data_source_FILE( void * state, void * dest, unsigned int * n ) { FILE * f = (FILE*) state; if( ! state || ! n || !dest ) return cson_rc.ArgError; else if( !*n ) return cson_rc.RangeError; *n = (unsigned int)fread( dest, 1, *n, f ); if( !*n ) { return feof(f) ? 0 : cson_rc.IOError; } return 0; } int cson_parse_FILE( cson_value ** tgt, FILE * src, cson_parse_opt const * opt, cson_parse_info * err ) { return cson_parse( tgt, cson_data_source_FILE, src, opt, err ); } int cson_value_fetch_bool( cson_value const * val, char * v ) { /** FIXME: move the to-bool operation into cson_value_api, like we do in the C++ API. */ if( ! val || !val->api ) return cson_rc.ArgError; else { int rc = 0; char b = 0; switch( val->api->typeID ) { case CSON_TYPE_ARRAY: case CSON_TYPE_OBJECT: b = 1; break; case CSON_TYPE_STRING: { char const * str = cson_string_cstr(cson_value_get_string(val)); b = (str && *str) ? 1 : 0; break; } case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: break; case CSON_TYPE_BOOL: b = (NULL==val->value) ? 0 : 1; break; case CSON_TYPE_INTEGER: { cson_int_t i = 0; cson_value_fetch_integer( val, &i ); b = i ? 1 : 0; break; } case CSON_TYPE_DOUBLE: { cson_double_t d = 0.0; cson_value_fetch_double( val, &d ); b = (0.0==d) ? 0 : 1; break; } default: rc = cson_rc.TypeError; break; } if( v ) *v = b; return rc; } } char cson_value_get_bool( cson_value const * val ) { char i = 0; cson_value_fetch_bool( val, &i ); return i; } int cson_value_fetch_integer( cson_value const * val, cson_int_t * v ) { if( ! val || !val->api ) return cson_rc.ArgError; else { cson_int_t i = 0; int rc = 0; switch(val->api->typeID) { case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: i = 0; break; case CSON_TYPE_BOOL: { char b = 0; cson_value_fetch_bool( val, &b ); i = b; break; } case CSON_TYPE_INTEGER: { cson_int_t const * x = CSON_INT(val); if(!x) { assert( val == &CSON_SPECIAL_VALUES[CSON_VAL_INT_0] ); } i = x ? *x : 0; break; } case CSON_TYPE_DOUBLE: { cson_double_t d = 0.0; cson_value_fetch_double( val, &d ); i = (cson_int_t)d; break; } case CSON_TYPE_STRING: case CSON_TYPE_ARRAY: case CSON_TYPE_OBJECT: default: rc = cson_rc.TypeError; break; } if(!rc && v) *v = i; return rc; } } cson_int_t cson_value_get_integer( cson_value const * val ) { cson_int_t i = 0; cson_value_fetch_integer( val, &i ); return i; } int cson_value_fetch_double( cson_value const * val, cson_double_t * v ) { if( ! val || !val->api ) return cson_rc.ArgError; else { cson_double_t d = 0.0; int rc = 0; switch(val->api->typeID) { case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: d = 0; break; case CSON_TYPE_BOOL: { char b = 0; cson_value_fetch_bool( val, &b ); d = b ? 1.0 : 0.0; break; } case CSON_TYPE_INTEGER: { cson_int_t i = 0; cson_value_fetch_integer( val, &i ); d = i; break; } case CSON_TYPE_DOUBLE: { cson_double_t const* dv = CSON_DBL(val); d = dv ? *dv : 0.0; break; } default: rc = cson_rc.TypeError; break; } if(v) *v = d; return rc; } } cson_double_t cson_value_get_double( cson_value const * val ) { cson_double_t i = 0.0; cson_value_fetch_double( val, &i ); return i; } int cson_value_fetch_string( cson_value const * val, cson_string ** dest ) { if( ! val || ! dest ) return cson_rc.ArgError; else if( ! cson_value_is_string(val) ) return cson_rc.TypeError; else { if( dest ) *dest = CSON_STR(val); return 0; } } cson_string * cson_value_get_string( cson_value const * val ) { cson_string * rc = NULL; cson_value_fetch_string( val, &rc ); return rc; } char const * cson_value_get_cstr( cson_value const * val ) { return cson_string_cstr( cson_value_get_string(val) ); } int cson_value_fetch_object( cson_value const * val, cson_object ** obj ) { if( ! val ) return cson_rc.ArgError; else if( ! cson_value_is_object(val) ) return cson_rc.TypeError; else { if(obj) *obj = CSON_OBJ(val); return 0; } } cson_object * cson_value_get_object( cson_value const * v ) { cson_object * obj = NULL; cson_value_fetch_object( v, &obj ); return obj; } int cson_value_fetch_array( cson_value const * val, cson_array ** ar) { if( ! val ) return cson_rc.ArgError; else if( !cson_value_is_array(val) ) return cson_rc.TypeError; else { if(ar) *ar = CSON_ARRAY(val); return 0; } } cson_array * cson_value_get_array( cson_value const * v ) { cson_array * ar = NULL; cson_value_fetch_array( v, &ar ); return ar; } cson_kvp * cson_kvp_alloc() { cson_kvp * kvp = (cson_kvp*)cson_malloc(sizeof(cson_kvp),"cson_kvp"); if( kvp ) { *kvp = cson_kvp_empty; } return kvp; } int cson_array_append( cson_array * ar, cson_value * v ) { if( !ar || !v ) return cson_rc.ArgError; else if( (ar->list.count+1) < ar->list.count ) return cson_rc.RangeError; else { if( !ar->list.alloced || (ar->list.count == ar->list.alloced-1)) { unsigned int const n = ar->list.count ? (ar->list.count*2) : 7; if( n > cson_value_list_reserve( &ar->list, n ) ) { return cson_rc.AllocError; } } return cson_array_set( ar, ar->list.count, v ); } } #if 0 /** Removes and returns the last value from the given array, shrinking its size by 1. Returns NULL if ar is NULL, ar->list.count is 0, or the element at that index is NULL. If removeRef is true then cson_value_free() is called to remove ar's reference count for the value. In that case NULL is returned, even if the object still has live references. If removeRef is false then the caller takes over ownership of that reference count point. If removeRef is false then the caller takes over ownership of the return value, otherwise ownership is effectively determined by any remaining references for the returned value. */ static cson_value * cson_array_pop_back( cson_array * ar, char removeRef ) { if( !ar ) return NULL; else if( ! ar->list.count ) return NULL; else { unsigned int const ndx = --ar->list.count; cson_value * v = ar->list.list[ndx]; ar->list.list[ndx] = NULL; if( removeRef ) { cson_value_free( v ); v = NULL; } return v; } } #endif cson_value * cson_value_new_bool( char v ) { return v ? &CSON_SPECIAL_VALUES[CSON_VAL_TRUE] : &CSON_SPECIAL_VALUES[CSON_VAL_FALSE]; } cson_value * cson_value_true() { return &CSON_SPECIAL_VALUES[CSON_VAL_TRUE]; } cson_value * cson_value_false() { return &CSON_SPECIAL_VALUES[CSON_VAL_FALSE]; } cson_value * cson_value_null() { return &CSON_SPECIAL_VALUES[CSON_VAL_NULL]; } cson_value * cson_new_int( cson_int_t v ) { return cson_value_new_integer(v); } cson_value * cson_value_new_integer( cson_int_t v ) { if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]; else { cson_value * c = cson_value_new(CSON_TYPE_INTEGER,0); #if !defined(NDEBUG) && CSON_VOID_PTR_IS_BIG assert( sizeof(cson_int_t) <= sizeof(void *) ); #endif if( c ) { memcpy( CSON_INT(c), &v, sizeof(v) ); } return c; } } cson_value * cson_new_double( cson_double_t v ) { return cson_value_new_double(v); } cson_value * cson_value_new_double( cson_double_t v ) { if( 0.0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]; else { cson_value * c = cson_value_new(CSON_TYPE_DOUBLE,0); if( c ) { memcpy( CSON_DBL(c), &v, sizeof(v) ); } return c; } } cson_string * cson_new_string(char const * str, unsigned int len) { if( !str || !*str || !len ) return &CSON_EMPTY_HOLDER.stringValue; else { cson_value * c = cson_value_new(CSON_TYPE_STRING, len + 1/*NUL byte*/); cson_string * s = NULL; if( c ) { char * dest = NULL; s = CSON_STR(c); *s = cson_string_empty; assert( NULL != s ); s->length = len; dest = cson_string_str(s); assert( NULL != dest ); memcpy( dest, str, len ); dest[len] = 0; } return s; } } cson_value * cson_value_new_string( char const * str, unsigned int len ) { return cson_string_value( cson_new_string(str, len) ); } int cson_array_value_fetch( cson_array const * ar, unsigned int pos, cson_value ** v ) { if( !ar) return cson_rc.ArgError; if( pos >= ar->list.count ) return cson_rc.RangeError; else { if(v) *v = ar->list.list[pos]; return 0; } } cson_value * cson_array_get( cson_array const * ar, unsigned int pos ) { cson_value *v = NULL; cson_array_value_fetch(ar, pos, &v); return v; } int cson_array_length_fetch( cson_array const * ar, unsigned int * v ) { if( ! ar || !v ) return cson_rc.ArgError; else { if(v) *v = ar->list.count; return 0; } } unsigned int cson_array_length_get( cson_array const * ar ) { unsigned int i = 0; cson_array_length_fetch(ar, &i); return i; } int cson_array_reserve( cson_array * ar, unsigned int size ) { if( ! ar ) return cson_rc.ArgError; else if( size <= ar->list.alloced ) { /* We don't want to introduce a can of worms by trying to handle the cleanup from here. */ return 0; } else { return (ar->list.alloced > cson_value_list_reserve( &ar->list, size )) ? cson_rc.AllocError : 0 ; } } int cson_array_set( cson_array * ar, unsigned int ndx, cson_value * v ) { if( !ar || !v ) return cson_rc.ArgError; else if( (ndx+1) < ndx) /* overflow */return cson_rc.RangeError; else { unsigned const int len = cson_value_list_reserve( &ar->list, ndx+1 ); if( len <= ndx ) return cson_rc.AllocError; else { cson_value * old = ar->list.list[ndx]; if( old ) { if(old == v) return 0; else cson_value_free(old); } cson_refcount_incr( v ); ar->list.list[ndx] = v; if( ndx >= ar->list.count ) { ar->list.count = ndx+1; } return 0; } } } /** @internal Searchs for the given key in the given object. Returns the found item on success, NULL on error. If ndx is not NULL, it is set to the index (in obj->kvp.list) of the found item. *ndx is not modified if no entry is found. */ static cson_kvp * cson_object_search_impl( cson_object const * obj, char const * key, unsigned int * ndx ) { if( obj && key && *key && obj->kvp.count) { #if CSON_OBJECT_PROPS_SORT cson_kvp ** s = (cson_kvp**) bsearch( key, obj->kvp.list, obj->kvp.count, sizeof(cson_kvp*), cson_kvp_cmp_vs_cstr ); if( ndx && s ) { /* index of found record is required by cson_object_unset(). Calculate the offset based on s...*/ #if 0 *ndx = (((unsigned char const *)s - ((unsigned char const *)obj->kvp.list)) / sizeof(cson_kvp*)); #else *ndx = s - obj->kvp.list; #endif } return s ? *s : NULL; #else cson_kvp_list const * li = &obj->kvp; unsigned int i = 0; cson_kvp * kvp; const unsigned int klen = strlen(key); for( ; i < li->count; ++i ) { cson_string const * sKey; kvp = li->list[i]; assert( kvp && kvp->key ); sKey = cson_value_get_string(kvp->key); assert(sKey); if( sKey->length != klen ) continue; else if(0==strcmp(key,cson_string_cstr(sKey))) { if(ndx) *ndx = i; return kvp; } } #endif } return NULL; } cson_value * cson_object_get( cson_object const * obj, char const * key ) { cson_kvp * kvp = cson_object_search_impl( obj, key, NULL ); return kvp ? kvp->value : NULL; } cson_value * cson_object_get_s( cson_object const * obj, cson_string const *key ) { cson_kvp * kvp = cson_object_search_impl( obj, cson_string_cstr(key), NULL ); return kvp ? kvp->value : NULL; } #if CSON_OBJECT_PROPS_SORT static void cson_object_sort_props( cson_object * obj ) { assert( NULL != obj ); if( obj->kvp.count ) { qsort( obj->kvp.list, obj->kvp.count, sizeof(cson_kvp*), cson_kvp_cmp ); } } #endif int cson_object_unset( cson_object * obj, char const * key ) { if( ! obj || !key || !*key ) return cson_rc.ArgError; else { unsigned int ndx = 0; cson_kvp * kvp = cson_object_search_impl( obj, key, &ndx ); if( ! kvp ) { return cson_rc.NotFoundError; } assert( obj->kvp.count > 0 ); assert( obj->kvp.list[ndx] == kvp ); cson_kvp_free( kvp ); obj->kvp.list[ndx] = NULL; { /* if my brain were bigger i'd use memmove(). */ unsigned int i = ndx; for( ; i < obj->kvp.count; ++i ) { obj->kvp.list[i] = (i < (obj->kvp.alloced-1)) ? obj->kvp.list[i+1] : NULL; } } obj->kvp.list[--obj->kvp.count] = NULL; #if CSON_OBJECT_PROPS_SORT cson_object_sort_props( obj ); #endif return 0; } } int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v ) { if( !obj || !key ) return cson_rc.ArgError; else if( NULL == v ) return cson_object_unset( obj, cson_string_cstr(key) ); else { char const * cKey; cson_value * vKey; cson_kvp * kvp; vKey = cson_string_value(key); assert(vKey && (key==CSON_STR(vKey))); if( vKey == CSON_VCAST(obj) ){ return cson_rc.ArgError; } cKey = cson_string_cstr(key); kvp = cson_object_search_impl( obj, cKey, NULL ); if( kvp ) { /* "I told 'em we've already got one!" */ if( kvp->key != vKey ){ cson_value_free( kvp->key ); cson_refcount_incr(vKey); kvp->key = vKey; } if(kvp->value != v){ cson_value_free( kvp->value ); cson_refcount_incr( v ); kvp->value = v; } return 0; } if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1)) { /* reserve space */ unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6; if( n > cson_kvp_list_reserve( &obj->kvp, n ) ) { return cson_rc.AllocError; } } { /* insert new item... */ int rc = 0; kvp = cson_kvp_alloc(); if( ! kvp ) { return cson_rc.AllocError; } rc = cson_kvp_list_append( &obj->kvp, kvp ); if( 0 != rc ) { cson_kvp_free(kvp); } else { cson_refcount_incr(vKey); cson_refcount_incr(v); kvp->key = vKey; kvp->value = v; #if CSON_OBJECT_PROPS_SORT cson_object_sort_props( obj ); #endif } return rc; } } } int cson_object_set( cson_object * obj, char const * key, cson_value * v ) { if( ! obj || !key || !*key ) return cson_rc.ArgError; else if( NULL == v ) { return cson_object_unset( obj, key ); } else { cson_string * cs = cson_new_string(key,strlen(key)); if(!cs) return cson_rc.AllocError; else { int const rc = cson_object_set_s(obj, cs, v); if(rc) cson_value_free(cson_string_value(cs)); return rc; } } } cson_value * cson_object_take( cson_object * obj, char const * key ) { if( ! obj || !key || !*key ) return NULL; else { /* FIXME: this is 90% identical to cson_object_unset(), only with different refcount handling. Consolidate them. */ unsigned int ndx = 0; cson_kvp * kvp = cson_object_search_impl( obj, key, &ndx ); cson_value * rc = NULL; if( ! kvp ) { return NULL; } assert( obj->kvp.count > 0 ); assert( obj->kvp.list[ndx] == kvp ); rc = kvp->value; assert( rc ); kvp->value = NULL; cson_kvp_free( kvp ); assert( rc->refcount > 0 ); --rc->refcount; obj->kvp.list[ndx] = NULL; { /* if my brain were bigger i'd use memmove(). */ unsigned int i = ndx; for( ; i < obj->kvp.count; ++i ) { obj->kvp.list[i] = (i < (obj->kvp.alloced-1)) ? obj->kvp.list[i+1] : NULL; } } obj->kvp.list[--obj->kvp.count] = NULL; #if CSON_OBJECT_PROPS_SORT cson_object_sort_props( obj ); #endif return rc; } } /** @internal If p->node is-a Object then value is inserted into the object using p->key. In any other case cson_rc.InternalError is returned. Returns cson_rc.AllocError if an allocation fails. Returns 0 on success. On error, parsing must be ceased immediately. Ownership of val is ALWAYS TRANSFERED to this function. If this function fails, val will be cleaned up and destroyed. (This simplifies error handling in the core parser.) */ static int cson_parser_set_key( cson_parser * p, cson_value * val ) { assert( p && val ); if( p->ckey && cson_value_is_object(p->node) ) { int rc; cson_object * obj = cson_value_get_object(p->node); cson_kvp * kvp = NULL; assert( obj && (p->node->value == obj) ); /** FIXME? Use cson_object_set() instead of our custom finagling with the object? We do it this way to avoid an extra alloc/strcpy of the key data. */ if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1)) { if( obj->kvp.alloced > cson_kvp_list_reserve( &obj->kvp, obj->kvp.count ? (obj->kvp.count*2) : 5 ) ) { cson_value_free(val); return cson_rc.AllocError; } } kvp = cson_kvp_alloc(); if( ! kvp ) { cson_value_free(val); return cson_rc.AllocError; } kvp->key = cson_string_value(p->ckey)/*transfer ownership*/; assert(0 == kvp->key->refcount); cson_refcount_incr(kvp->key); p->ckey = NULL; kvp->value = val; cson_refcount_incr( val ); rc = cson_kvp_list_append( &obj->kvp, kvp ); if( 0 != rc ) { cson_kvp_free( kvp ); } else { ++p->totalValueCount; } return rc; } else { if(val) cson_value_free(val); return p->errNo = cson_rc.InternalError; } } /** @internal Pushes val into the current object/array parent node, depending on the internal state of the parser. Ownership of val is always transfered to this function, regardless of success or failure. Returns 0 on success. On error, parsing must be ceased immediately. */ static int cson_parser_push_value( cson_parser * p, cson_value * val ) { if( p->ckey ) { /* we're in Object mode */ assert( cson_value_is_object( p->node ) ); return cson_parser_set_key( p, val ); } else if( cson_value_is_array( p->node ) ) { /* we're in Array mode */ cson_array * ar = cson_value_get_array( p->node ); int rc; assert( ar && (ar == p->node->value) ); rc = cson_array_append( ar, val ); if( 0 != rc ) { cson_value_free(val); } else { ++p->totalValueCount; } return rc; } else { /* WTF? */ assert( 0 && "Internal error in cson_parser code" ); return p->errNo = cson_rc.InternalError; } } /** Callback for JSON_parser API. Reminder: it returns 0 (meaning false) on error! */ static int cson_parse_callback( void * cx, int type, JSON_value const * value ) { cson_parser * p = (cson_parser *)cx; int rc = 0; #define ALLOC_V(T,V) cson_value * v = cson_value_new_##T(V); if( ! v ) { rc = cson_rc.AllocError; break; } switch(type) { case JSON_T_ARRAY_BEGIN: case JSON_T_OBJECT_BEGIN: { cson_value * obja = (JSON_T_ARRAY_BEGIN == type) ? cson_value_new_array() : cson_value_new_object(); if( ! obja ) { p->errNo = cson_rc.AllocError; break; } if( 0 != rc ) break; if( ! p->root ) { p->root = p->node = obja; rc = cson_array_append( &p->stack, obja ); if( 0 != rc ) { /* work around a (potential) corner case in the cleanup code. */ cson_value_free( p->root ); p->root = NULL; } else { cson_refcount_incr( p->root ) /* simplifies cleanup later on. */ ; ++p->totalValueCount; } } else { rc = cson_array_append( &p->stack, obja ); if(rc) cson_value_free( obja ); else { rc = cson_parser_push_value( p, obja ); if( 0 == rc ) p->node = obja; } } break; } case JSON_T_ARRAY_END: case JSON_T_OBJECT_END: { if( 0 == p->stack.list.count ) { rc = cson_rc.RangeError; break; } #if CSON_OBJECT_PROPS_SORT if( cson_value_is_object(p->node) ) {/* kludge: the parser uses custom cson_object property insertion as a malloc/strcpy-reduction optimization. Because of that, we have to sort the property list ourselves... */ cson_object * obj = cson_value_get_object(p->node); assert( NULL != obj ); cson_object_sort_props( obj ); } #endif #if 1 /* Reminder: do not use cson_array_pop_back( &p->stack ) because that will clean up the object, and we don't want that. We just want to forget this reference to it. The object is either the root or was pushed into an object/array in the parse tree (and is owned by that object/array). */ --p->stack.list.count; assert( p->node == p->stack.list.list[p->stack.list.count] ); cson_refcount_decr( p->node ) /* p->node might be owned by an outer object but we need to remove the list's reference. For the root node we manually add a reference to avoid a special case here. Thus when we close the root node, its refcount is still 1. */; p->stack.list.list[p->stack.list.count] = NULL; if( p->stack.list.count ) { p->node = p->stack.list.list[p->stack.list.count-1]; } else { p->node = p->root; } #else /* Causing a leak? */ cson_array_pop_back( &p->stack, 1 ); if( p->stack.list.count ) { p->node = p->stack.list.list[p->stack.list.count-1]; } else { p->node = p->root; } assert( p->node && (1==p->node->refcount) ); #endif break; } case JSON_T_INTEGER: { ALLOC_V(integer, value->vu.integer_value ); rc = cson_parser_push_value( p, v ); break; } case JSON_T_FLOAT: { ALLOC_V(double, value->vu.float_value ); rc = cson_parser_push_value( p, v ); break; } case JSON_T_NULL: { rc = cson_parser_push_value( p, cson_value_null() ); break; } case JSON_T_TRUE: { rc = cson_parser_push_value( p, cson_value_true() ); break; } case JSON_T_FALSE: { rc = cson_parser_push_value( p, cson_value_false() ); break; } case JSON_T_KEY: { assert(!p->ckey); p->ckey = cson_new_string( value->vu.str.value, value->vu.str.length ); if( ! p->ckey ) { rc = cson_rc.AllocError; break; } ++p->totalKeyCount; break; } case JSON_T_STRING: { cson_value * v = cson_value_new_string( value->vu.str.value, value->vu.str.length ); rc = ( NULL == v ) ? cson_rc.AllocError : cson_parser_push_value( p, v ); break; } default: assert(0); rc = cson_rc.InternalError; break; } #undef ALLOC_V return ((p->errNo = rc)) ? 0 : 1; } /** Converts a JSON_error code to one of the cson_rc values. */ static int cson_json_err_to_rc( JSON_error jrc ) { switch(jrc) { case JSON_E_NONE: return 0; case JSON_E_INVALID_CHAR: return cson_rc.Parse_INVALID_CHAR; case JSON_E_INVALID_KEYWORD: return cson_rc.Parse_INVALID_KEYWORD; case JSON_E_INVALID_ESCAPE_SEQUENCE: return cson_rc.Parse_INVALID_ESCAPE_SEQUENCE; case JSON_E_INVALID_UNICODE_SEQUENCE: return cson_rc.Parse_INVALID_UNICODE_SEQUENCE; case JSON_E_INVALID_NUMBER: return cson_rc.Parse_INVALID_NUMBER; case JSON_E_NESTING_DEPTH_REACHED: return cson_rc.Parse_NESTING_DEPTH_REACHED; case JSON_E_UNBALANCED_COLLECTION: return cson_rc.Parse_UNBALANCED_COLLECTION; case JSON_E_EXPECTED_KEY: return cson_rc.Parse_EXPECTED_KEY; case JSON_E_EXPECTED_COLON: return cson_rc.Parse_EXPECTED_COLON; case JSON_E_OUT_OF_MEMORY: return cson_rc.AllocError; default: return cson_rc.InternalError; } } /** @internal Cleans up all contents of p but does not free p. To properly take over ownership of the parser's root node on a successful parse: - Copy p->root's pointer and set p->root to NULL. - Eventually free up p->root with cson_value_free(). If you do not set p->root to NULL, p->root will be freed along with any other items inserted into it (or under it) during the parsing process. */ static int cson_parser_clean( cson_parser * p ) { if( ! p ) return cson_rc.ArgError; else { if( p->p ) { delete_JSON_parser(p->p); p->p = NULL; } if( p->ckey ){ cson_value_free(cson_string_value(p->ckey)); } cson_array_clean( &p->stack, 1 ); if( p->root ) { cson_value_free( p->root ); } *p = cson_parser_empty; return 0; } } int cson_parse( cson_value ** tgt, cson_data_source_f src, void * state, cson_parse_opt const * opt_, cson_parse_info * info_ ) { unsigned char ch[2] = {0,0}; cson_parse_opt const opt = opt_ ? *opt_ : cson_parse_opt_empty; int rc = 0; unsigned int len = 1; cson_parse_info info = info_ ? *info_ : cson_parse_info_empty; cson_parser p = cson_parser_empty; if( ! tgt || ! src ) return cson_rc.ArgError; { JSON_config jopt = {0}; init_JSON_config( &jopt ); jopt.allow_comments = opt.allowComments; jopt.depth = opt.maxDepth; jopt.callback_ctx = &p; jopt.handle_floats_manually = 0; jopt.callback = cson_parse_callback; p.p = new_JSON_parser(&jopt); if( ! p.p ) { return cson_rc.AllocError; } } do { /* FIXME: buffer the input in multi-kb chunks. */ len = 1; ch[0] = 0; rc = src( state, ch, &len ); if( 0 != rc ) break; else if( !len /* EOF */ ) break; ++info.length; if('\n' == ch[0]) { ++info.line; info.col = 0; } if( ! JSON_parser_char(p.p, ch[0]) ) { rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) ); if(0==rc) rc = p.errNo; if(0==rc) rc = cson_rc.InternalError; info.errorCode = rc; break; } if( '\n' != ch[0]) ++info.col; } while(1); if( info_ ) { info.totalKeyCount = p.totalKeyCount; info.totalValueCount = p.totalValueCount; *info_ = info; } if( 0 != rc ) { cson_parser_clean(&p); return rc; } if( ! JSON_parser_done(p.p) ) { rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) ); cson_parser_clean(&p); if(0==rc) rc = p.errNo; if(0==rc) rc = cson_rc.InternalError; } else { cson_value * root = p.root; p.root = NULL; cson_parser_clean(&p); if( root ) { assert( (1 == root->refcount) && "Detected memory mismanagement in the parser." ); root->refcount = 0 /* HUGE KLUDGE! Avoids having one too many references in some client code, leading to a leak. Here we're accommodating a memory management workaround in the parser code which manually adds a reference to the root node to keep it from being cleaned up prematurely. */; *tgt = root; } else { /* then can happen on empty input. */ rc = cson_rc.UnknownError; } } return rc; } /** The UTF code was originally taken from sqlite3's public-domain source code (http://sqlite.org), modified only slightly for use here. This code generates some "possible data loss" warnings on MSVC, but if this code is good enough for sqlite3 then it's damned well good enough for me, so we disable that warning for Windows builds. */ /* ** This lookup table is used to help decode the first byte of ** a multi-byte UTF8 character. */ static const unsigned char cson_utfTrans1[] = { 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, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00 }; /* ** Translate a single UTF-8 character. Return the unicode value. ** ** During translation, assume that the byte that zTerm points ** is a 0x00. ** ** Write a pointer to the next unread byte back into *pzNext. ** ** Notes On Invalid UTF-8: ** ** * This routine never allows a 7-bit character (0x00 through 0x7f) to ** be encoded as a multi-byte character. Any multi-byte character that ** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd. ** ** * This routine never allows a UTF16 surrogate value to be encoded. ** If a multi-byte character attempts to encode a value between ** 0xd800 and 0xe000 then it is rendered as 0xfffd. ** ** * Bytes in the range of 0x80 through 0xbf which occur as the first ** byte of a character are interpreted as single-byte characters ** and rendered as themselves even though they are technically ** invalid characters. ** ** * This routine accepts an infinite number of different UTF8 encodings ** for unicode values 0x80 and greater. It do not change over-length ** encodings to 0xfffd as some systems recommend. */ #define READ_UTF8(zIn, zTerm, c) \ c = *(zIn++); \ if( c>=0xc0 ){ \ c = cson_utfTrans1[c-0xc0]; \ while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ if( c<0x80 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } static int cson_utf8Read( const unsigned char *z, /* First byte of UTF-8 character */ const unsigned char *zTerm, /* Pretend this byte is 0x00 */ const unsigned char **pzNext /* Write first byte past UTF-8 char here */ ){ int c; READ_UTF8(z, zTerm, c); *pzNext = z; return c; } #undef READ_UTF8 #ifdef _MSC_VER # if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ # pragma warning( pop ) # endif #endif unsigned int cson_string_length_utf8( cson_string const * str ) { if( ! str ) return 0; else { char unsigned const * pos = (char unsigned const *)cson_string_cstr(str); char unsigned const * end = pos + str->length; unsigned int rc = 0; for( ; (pos < end) && cson_utf8Read(pos, end, &pos); ++rc ) { }; return rc; } } /** Escapes the first len bytes of the given string as JSON and sends it to the given output function (which will be called often - once for each logical character). The output is also surrounded by double-quotes. A NULL str will be escaped as an empty string, though we should arguably export it as "null" (without quotes). We do this because in JavaScript (typeof null === "object"), and by outputing null here we would effectively change the data type from string to object. */ static int cson_str_to_json( char const * str, unsigned int len, char escapeFwdSlash, cson_data_dest_f f, void * state ) { if( NULL == f ) return cson_rc.ArgError; else if( !str || !*str || (0 == len) ) { /* special case for 0-length strings. */ return f( state, "\"\"", 2 ); } else { unsigned char const * pos = (unsigned char const *)str; unsigned char const * end = (unsigned char const *)(str ? (str + len) : NULL); unsigned char const * next = NULL; int ch; unsigned char clen = 0; char escChar[3] = {'\\',0,0}; enum { UBLen = 20 }; char ubuf[UBLen]; int rc = 0; rc = f(state, "\"", 1 ); for( ; (pos < end) && (0 == rc); pos += clen ) { ch = cson_utf8Read(pos, end, &next); if( 0 == ch ) break; assert( next > pos ); clen = next - pos; assert( clen ); if( 1 == clen ) { /* ASCII */ #if defined(CSON_FOSSIL_MODE) /* Workaround for fossil repo artifact f460839cff85d4e4f1360b366bb2858cef1411ea, which has what appears to be latin1-encoded text. file(1) thinks it's a FORTRAN program. */ if(0xfffd==ch){ assert(*pos != ch); /* MARKER("ch=%04x, *pos=%04x\n", ch, *pos); */ ch = *pos /* We should arguably translate to '?', and will if this problem ever comes up with a non-latin1 encoding. For latin1 this workaround incidentally corrects the output to proper UTF8-escaped characters, and only for that reason is it being kept around. */; goto assume_latin1; } #endif assert( (*pos == ch) && "Invalid UTF8" ); escChar[1] = 0; switch(ch) { case '\t': escChar[1] = 't'; break; case '\r': escChar[1] = 'r'; break; case '\n': escChar[1] = 'n'; break; case '\f': escChar[1] = 'f'; break; case '\b': escChar[1] = 'b'; break; case '/': /* Regarding escaping of forward-slashes. See the main exchange below... -------------- From: Douglas Crockford <douglas@crockford.com> To: Stephan Beal <sgbeal@googlemail.com> Subject: Re: Is escaping of forward slashes required? It is allowed, not required. It is allowed so that JSON can be safely embedded in HTML, which can freak out when seeing strings containing "</". JSON tolerates "<\/" for this reason. On 4/8/2011 2:09 PM, Stephan Beal wrote: > Hello, Jsonites, > > i'm a bit confused on a small grammatic detail of JSON: > > if i'm reading the grammar chart on http://www.json.org/ correctly, > forward slashes (/) are supposed to be escaped in JSON. However, the > JSON class provided with my browsers (Chrome and FF, both of which i > assume are fairly standards/RFC-compliant) do not escape such characters. > > Is backslash-escaping forward slashes required? If so, what is the > justification for it? (i ask because i find it unnecessary and hard to > look at.) -------------- */ if( escapeFwdSlash ) escChar[1] = '/'; break; case '\\': escChar[1] = '\\'; break; case '"': escChar[1] = '"'; break; default: break; } if( escChar[1]) { rc = f(state, escChar, 2); } else { rc = f(state, (char const *)pos, clen); } continue; } else { /* UTF: transform it to \uXXXX */ #if defined(CSON_FOSSIL_MODE) assume_latin1: #endif memset(ubuf,0,UBLen); if(ch <= 0xFFFF){ rc = sprintf(ubuf, "\\u%04x",ch); if( rc != 6 ) { rc = cson_rc.RangeError; break; } rc = f( state, ubuf, 6 ); }else{ /* encode as a UTF16 surrogate pair */ /* http://unicodebook.readthedocs.org/en/latest/unicode_encodings.html#surrogates */ ch -= 0x10000; rc = sprintf(ubuf, "\\u%04x\\u%04x", (0xd800 | (ch>>10)), (0xdc00 | (ch & 0x3ff))); if( rc != 12 ) { rc = cson_rc.RangeError; break; } rc = f( state, ubuf, 12 ); } continue; } } if( 0 == rc ) { rc = f(state, "\"", 1 ); } return rc; } } int cson_object_iter_init( cson_object const * obj, cson_object_iterator * iter ) { if( ! obj || !iter ) return cson_rc.ArgError; else { iter->obj = obj; iter->pos = 0; return 0; } } cson_kvp * cson_object_iter_next( cson_object_iterator * iter ) { if( ! iter || !iter->obj ) return NULL; else if( iter->pos >= iter->obj->kvp.count ) return NULL; else { cson_kvp * rc = iter->obj->kvp.list[iter->pos++]; while( (NULL==rc) && (iter->pos < iter->obj->kvp.count)) { rc = iter->obj->kvp.list[iter->pos++]; } return rc; } } static int cson_output_null( cson_data_dest_f f, void * state ) { if( !f ) return cson_rc.ArgError; else { return f(state, "null", 4); } } static int cson_output_bool( cson_value const * src, cson_data_dest_f f, void * state ) { if( !f ) return cson_rc.ArgError; else { char const v = cson_value_get_bool(src); return f(state, v ? "true" : "false", v ? 4 : 5); } } static int cson_output_integer( cson_value const * src, cson_data_dest_f f, void * state ) { if( !f ) return cson_rc.ArgError; else if( !cson_value_is_integer(src) ) return cson_rc.TypeError; else { enum { BufLen = 100 }; char b[BufLen]; int rc; memset( b, 0, BufLen ); rc = sprintf( b, "%"CSON_INT_T_PFMT, cson_value_get_integer(src) ) /* Reminder: snprintf() is C99 */ ; return ( rc<=0 ) ? cson_rc.RangeError : f( state, b, (unsigned int)rc ) ; } } static int cson_output_double( cson_value const * src, cson_data_dest_f f, void * state ) { if( !f ) return cson_rc.ArgError; else if( !cson_value_is_double(src) ) return cson_rc.TypeError; else { enum { BufLen = 128 /* this must be relatively large or huge doubles can cause us to overrun here, resulting in stack-smashing errors. */}; char b[BufLen]; int rc; memset( b, 0, BufLen ); rc = sprintf( b, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(src) ) /* Reminder: snprintf() is C99 */ ; if( rc<=0 ) return cson_rc.RangeError; else if(1) { /* Strip trailing zeroes before passing it on... */ unsigned int urc = (unsigned int)rc; char * pos = b + urc - 1; for( ; ('0' == *pos) && urc && (*(pos-1) != '.'); --pos, --urc ) { *pos = 0; } assert(urc && *pos); return f( state, b, urc ); } else { unsigned int urc = (unsigned int)rc; return f( state, b, urc ); } return 0; } } static int cson_output_string( cson_value const * src, char escapeFwdSlash, cson_data_dest_f f, void * state ) { if( !f ) return cson_rc.ArgError; else if( ! cson_value_is_string(src) ) return cson_rc.TypeError; else { cson_string const * str = cson_value_get_string(src); assert( NULL != str ); return cson_str_to_json(cson_string_cstr(str), str->length, escapeFwdSlash, f, state); } } /** Outputs indention spacing to f(). blanks: (0)=no indentation, (1)=1 TAB per/level, (>1)=n spaces/level depth is the current depth of the output tree, and determines how much indentation to generate. If blanks is 0 this is a no-op. Returns non-0 on error, and the error code will always come from f(). */ static int cson_output_indent( cson_data_dest_f f, void * state, unsigned char blanks, unsigned int depth ) { if( 0 == blanks ) return 0; else { #if 0 /* FIXME: stuff the indention into the buffer and make a single call to f(). */ enum { BufLen = 200 }; char buf[BufLen]; #endif unsigned int i; unsigned int x; char const ch = (1==blanks) ? '\t' : ' '; int rc = f(state, "\n", 1 ); for( i = 0; (i < depth) && (0 == rc); ++i ) { for( x = 0; (x < blanks) && (0 == rc); ++x ) { rc = f(state, &ch, 1); } } return rc; } } static int cson_output_array( cson_value const * src, cson_data_dest_f f, void * state, cson_output_opt const * fmt, unsigned int level ); static int cson_output_object( cson_value const * src, cson_data_dest_f f, void * state, cson_output_opt const * fmt, unsigned int level ); /** Main cson_output() implementation. Dispatches to a different impl depending on src->api->typeID. Returns 0 on success. */ static int cson_output_impl( cson_value const * src, cson_data_dest_f f, void * state, cson_output_opt const * fmt, unsigned int level ) { if( ! src || !f || !src->api ) return cson_rc.ArgError; else { int rc = 0; assert(fmt); switch( src->api->typeID ) { case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: rc = cson_output_null(f, state); break; case CSON_TYPE_BOOL: rc = cson_output_bool(src, f, state); break; case CSON_TYPE_INTEGER: rc = cson_output_integer(src, f, state); break; case CSON_TYPE_DOUBLE: rc = cson_output_double(src, f, state); break; case CSON_TYPE_STRING: rc = cson_output_string(src, fmt->escapeForwardSlashes, f, state); break; case CSON_TYPE_ARRAY: rc = cson_output_array( src, f, state, fmt, level ); break; case CSON_TYPE_OBJECT: rc = cson_output_object( src, f, state, fmt, level ); break; default: rc = cson_rc.TypeError; break; } return rc; } } static int cson_output_array( cson_value const * src, cson_data_dest_f f, void * state, cson_output_opt const * fmt, unsigned int level ) { if( !src || !f || !fmt ) return cson_rc.ArgError; else if( ! cson_value_is_array(src) ) return cson_rc.TypeError; else if( level > fmt->maxDepth ) return cson_rc.RangeError; else { int rc; unsigned int i; cson_value const * v; char doIndent = fmt->indentation ? 1 : 0; cson_array const * ar = cson_value_get_array(src); assert( NULL != ar ); if( 0 == ar->list.count ) { return f(state, "[]", 2 ); } else if( (1 == ar->list.count) && !fmt->indentSingleMemberValues ) doIndent = 0; rc = f(state, "[", 1); ++level; if( doIndent ) { rc = cson_output_indent( f, state, fmt->indentation, level ); } for( i = 0; (i < ar->list.count) && (0 == rc); ++i ) { v = ar->list.list[i]; if( v ) { rc = cson_output_impl( v, f, state, fmt, level ); } else { rc = cson_output_null( f, state ); } if( 0 == rc ) { if(i < (ar->list.count-1)) { rc = f(state, ",", 1); if( 0 == rc ) { rc = doIndent ? cson_output_indent( f, state, fmt->indentation, level ) : 0 /*f( state, " ", 1 )*/; } } } } --level; if( doIndent && (0 == rc) ) { rc = cson_output_indent( f, state, fmt->indentation, level ); } return (0 == rc) ? f(state, "]", 1) : rc; } } static int cson_output_object( cson_value const * src, cson_data_dest_f f, void * state, cson_output_opt const * fmt, unsigned int level ) { if( !src || !f || !fmt ) return cson_rc.ArgError; else if( ! cson_value_is_object(src) ) return cson_rc.TypeError; else if( level > fmt->maxDepth ) return cson_rc.RangeError; else { int rc; unsigned int i; cson_kvp const * kvp; char doIndent = fmt->indentation ? 1 : 0; cson_object const * obj = cson_value_get_object(src); assert( (NULL != obj) && (NULL != fmt)); if( 0 == obj->kvp.count ) { return f(state, "{}", 2 ); } else if( (1 == obj->kvp.count) && !fmt->indentSingleMemberValues ) doIndent = 0; rc = f(state, "{", 1); ++level; if( doIndent ) { rc = cson_output_indent( f, state, fmt->indentation, level ); } for( i = 0; (i < obj->kvp.count) && (0 == rc); ++i ) { kvp = obj->kvp.list[i]; if( kvp && kvp->key ) { cson_string const * sKey = cson_value_get_string(kvp->key); char const * cKey = cson_string_cstr(sKey); rc = cson_str_to_json(cKey, sKey->length, fmt->escapeForwardSlashes, f, state); if( 0 == rc ) { rc = fmt->addSpaceAfterColon ? f(state, ": ", 2 ) : f(state, ":", 1 ) ; } if( 0 == rc) { rc = ( kvp->value ) ? cson_output_impl( kvp->value, f, state, fmt, level ) : cson_output_null( f, state ); } } else { assert( 0 && "Possible internal error." ); continue /* internal error? */; } if( 0 == rc ) { if(i < (obj->kvp.count-1)) { rc = f(state, ",", 1); if( 0 == rc ) { rc = doIndent ? cson_output_indent( f, state, fmt->indentation, level ) : 0 /*f( state, " ", 1 )*/; } } } } --level; if( doIndent && (0 == rc) ) { rc = cson_output_indent( f, state, fmt->indentation, level ); } return (0 == rc) ? f(state, "}", 1) : rc; } } int cson_output( cson_value const * src, cson_data_dest_f f, void * state, cson_output_opt const * fmt ) { int rc; if(! fmt ) fmt = &cson_output_opt_empty; rc = cson_output_impl(src, f, state, fmt, 0 ); if( (0 == rc) && fmt->addNewline ) { rc = f(state, "\n", 1); } return rc; } int cson_data_dest_FILE( void * state, void const * src, unsigned int n ) { if( ! state ) return cson_rc.ArgError; else if( !src || !n ) return 0; else { return ( 1 == fwrite( src, n, 1, (FILE*) state ) ) ? 0 : cson_rc.IOError; } } int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * fmt ) { int rc = 0; if( fmt ) { rc = cson_output( src, cson_data_dest_FILE, dest, fmt ); } else { /* We normally want a newline on FILE output. */ cson_output_opt opt = cson_output_opt_empty; opt.addNewline = 1; rc = cson_output( src, cson_data_dest_FILE, dest, &opt ); } if( 0 == rc ) { fflush( dest ); } return rc; } int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt ) { if( !src || !dest ) return cson_rc.ArgError; else { FILE * f = fopen(dest,"wb"); if( !f ) return cson_rc.IOError; else { int const rc = cson_output_FILE( src, f, fmt ); fclose(f); return rc; } } } int cson_parse_filename( cson_value ** tgt, char const * src, cson_parse_opt const * opt, cson_parse_info * err ) { if( !src || !tgt ) return cson_rc.ArgError; else { FILE * f = fopen(src, "r"); if( !f ) return cson_rc.IOError; else { int const rc = cson_parse_FILE( tgt, f, opt, err ); fclose(f); return rc; } } } /** Internal type to hold state for a JSON input string. */ typedef struct cson_data_source_StringSource_ { /** Start of input string. */ char const * str; /** Current iteration position. Must initially be == str. */ char const * pos; /** Logical EOF, one-past-the-end of str. */ char const * end; } cson_data_source_StringSource_t; /** A cson_data_source_f() implementation which requires the state argument to be a properly populated (cson_data_source_StringSource_t*). */ static int cson_data_source_StringSource( void * state, void * dest, unsigned int * n ) { if( !state || !n || !dest ) return cson_rc.ArgError; else if( !*n ) return 0 /* ignore this */; else { unsigned int i; cson_data_source_StringSource_t * ss = (cson_data_source_StringSource_t*) state; unsigned char * tgt = (unsigned char *)dest; for( i = 0; (i < *n) && (ss->pos < ss->end); ++i, ++ss->pos, ++tgt ) { *tgt = *ss->pos; } *n = i; return 0; } } int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len, cson_parse_opt const * opt, cson_parse_info * err ) { if( ! tgt || !src ) return cson_rc.ArgError; else if( !*src || (len<2/*2==len of {} and []*/) ) return cson_rc.RangeError; else { cson_data_source_StringSource_t ss; ss.str = ss.pos = src; ss.end = src + len; return cson_parse( tgt, cson_data_source_StringSource, &ss, opt, err ); } } int cson_parse_buffer( cson_value ** tgt, cson_buffer const * buf, cson_parse_opt const * opt, cson_parse_info * err ) { return ( !tgt || !buf || !buf->mem || !buf->used ) ? cson_rc.ArgError : cson_parse_string( tgt, (char const *)buf->mem, buf->used, opt, err ); } int cson_buffer_reserve( cson_buffer * buf, cson_size_t n ) { if( ! buf ) return cson_rc.ArgError; else if( 0 == n ) { cson_free(buf->mem, "cson_buffer::mem"); *buf = cson_buffer_empty; return 0; } else if( buf->capacity >= n ) { return 0; } else { unsigned char * x = (unsigned char *)cson_realloc( buf->mem, n, "cson_buffer::mem" ); if( ! x ) return cson_rc.AllocError; memset( x + buf->used, 0, n - buf->used ); buf->mem = x; buf->capacity = n; ++buf->timesExpanded; return 0; } } cson_size_t cson_buffer_fill( cson_buffer * buf, char c ) { if( !buf || !buf->capacity || !buf->mem ) return 0; else { memset( buf->mem, c, buf->capacity ); return buf->capacity; } } /** cson_data_dest_f() implementation, used by cson_output_buffer(). arg MUST be a (cson_buffer*). This function appends n bytes at position arg->used, expanding the buffer as necessary. */ static int cson_data_dest_cson_buffer( void * arg, void const * data_, unsigned int n ) { if( !arg ) return cson_rc.ArgError; else if( ! n ) return 0; else { cson_buffer * sb = (cson_buffer*)arg; char const * data = (char const *)data_; cson_size_t npos = sb->used + n; unsigned int i; if( npos >= sb->capacity ) { const cson_size_t oldCap = sb->capacity; const cson_size_t asz = npos * 2; if( asz < npos ) return cson_rc.ArgError; /* overflow */ else if( 0 != cson_buffer_reserve( sb, asz ) ) return cson_rc.AllocError; assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" ); /* make sure it gets NUL terminated. */ memset( sb->mem + oldCap, 0, (sb->capacity - oldCap) ); } for( i = 0; i < n; ++i, ++sb->used ) { sb->mem[sb->used] = data[i]; } return 0; } } int cson_output_buffer( cson_value const * v, cson_buffer * buf, cson_output_opt const * opt ) { int rc = cson_output( v, cson_data_dest_cson_buffer, buf, opt ); if( 0 == rc ) { /* Ensure that the buffer is null-terminated. */ rc = cson_buffer_reserve( buf, buf->used + 1 ); if( 0 == rc ) { buf->mem[buf->used] = 0; } } return rc; } /** @internal Tokenizes an input string on a given separator. Inputs are: - (inp) = is a pointer to the pointer to the start of the input. - (separator) = the separator character - (end) = a pointer to NULL. i.e. (*end == NULL) This function scans *inp for the given separator char or a NUL char. Successive separators at the start of *inp are skipped. The effect is that, when this function is called in a loop, all neighboring separators are ignored. e.g. the string "aa.bb...cc" will tokenize to the list (aa,bb,cc) if the separator is '.' and to (aa.,...cc) if the separator is 'b'. Returns 0 (false) if it finds no token, else non-0 (true). Output: - (*inp) will be set to the first character of the next token. - (*end) will point to the one-past-the-end point of the token. If (*inp == *end) then the end of the string has been reached without finding a token. Post-conditions: - (*end == *inp) if no token is found. - (*end > *inp) if a token is found. It is intolerant of NULL values for (inp, end), and will assert() in debug builds if passed NULL as either parameter. */ static char cson_next_token( char const ** inp, char separator, char const ** end ) { char const * pos = NULL; assert( inp && end && *inp ); if( *inp == *end ) return 0; pos = *inp; if( !*pos ) { *end = pos; return 0; } for( ; *pos && (*pos == separator); ++pos) { /* skip preceeding splitters */ } *inp = pos; for( ; *pos && (*pos != separator); ++pos) { /* find next splitter */ } *end = pos; return (pos > *inp) ? 1 : 0; } int cson_object_fetch_sub2( cson_object const * obj, cson_value ** tgt, char const * path ) { if( ! obj || !path ) return cson_rc.ArgError; else if( !*path || !*(1+path) ) return cson_rc.RangeError; else return cson_object_fetch_sub(obj, tgt, path+1, *path); } int cson_object_fetch_sub( cson_object const * obj, cson_value ** tgt, char const * path, char sep ) { if( ! obj || !path ) return cson_rc.ArgError; else if( !*path || !sep ) return cson_rc.RangeError; else { char const * beg = path; char const * end = NULL; int rc; unsigned int i, len; unsigned int tokenCount = 0; cson_value * cv = NULL; cson_object const * curObj = obj; enum { BufSize = 128 }; char buf[BufSize]; memset( buf, 0, BufSize ); while( cson_next_token( &beg, sep, &end ) ) { if( beg == end ) break; else { ++tokenCount; beg = end; end = NULL; } } if( 0 == tokenCount ) return cson_rc.RangeError; beg = path; end = NULL; for( i = 0; i < tokenCount; ++i, beg=end, end=NULL ) { rc = cson_next_token( &beg, sep, &end ); assert( 1 == rc ); assert( beg != end ); assert( end > beg ); len = end - beg; if( len > (BufSize-1) ) return cson_rc.RangeError; memset( buf, 0, len + 1 ); memcpy( buf, beg, len ); buf[len] = 0; cv = cson_object_get( curObj, buf ); if( NULL == cv ) return cson_rc.NotFoundError; else if( i == (tokenCount-1) ) { if(tgt) *tgt = cv; return 0; } else if( cson_value_is_object(cv) ) { curObj = cson_value_get_object(cv); assert((NULL != curObj) && "Detected mis-management of internal memory!"); } /* TODO: arrays. Requires numeric parsing for the index. */ else { return cson_rc.NotFoundError; } } assert( i == tokenCount ); return cson_rc.NotFoundError; } } cson_value * cson_object_get_sub( cson_object const * obj, char const * path, char sep ) { cson_value * v = NULL; cson_object_fetch_sub( obj, &v, path, sep ); return v; } cson_value * cson_object_get_sub2( cson_object const * obj, char const * path ) { cson_value * v = NULL; cson_object_fetch_sub2( obj, &v, path ); return v; } /** If v is-a Object or Array then this function returns a deep clone, otherwise it returns v. In either case, the refcount of the returned value is increased by 1 by this call. */ static cson_value * cson_value_clone_ref( cson_value * v ) { cson_value * rc = NULL; #define TRY_SHARING 1 #if TRY_SHARING if(!v ) return rc; else if( cson_value_is_object(v) || cson_value_is_array(v)) { rc = cson_value_clone( v ); } else { rc = v; } #else rc = cson_value_clone(v); #endif #undef TRY_SHARING cson_value_add_reference(rc); return rc; } static cson_value * cson_value_clone_array( cson_value const * orig ) { unsigned int i = 0; cson_array const * asrc = cson_value_get_array( orig ); unsigned int alen = cson_array_length_get( asrc ); cson_value * destV = NULL; cson_array * destA = NULL; assert( orig && asrc ); destV = cson_value_new_array(); if( NULL == destV ) return NULL; destA = cson_value_get_array( destV ); assert( destA ); if( 0 != cson_array_reserve( destA, alen ) ) { cson_value_free( destV ); return NULL; } for( ; i < alen; ++i ) { cson_value * ch = cson_array_get( asrc, i ); if( NULL != ch ) { cson_value * cl = cson_value_clone_ref( ch ); if( NULL == cl ) { cson_value_free( destV ); return NULL; } if( 0 != cson_array_set( destA, i, cl ) ) { cson_value_free( cl ); cson_value_free( destV ); return NULL; } cson_value_free(cl)/*remove our artificial reference */; } } return destV; } static cson_value * cson_value_clone_object( cson_value const * orig ) { cson_object const * src = cson_value_get_object( orig ); cson_value * destV = NULL; cson_object * dest = NULL; cson_kvp const * kvp = NULL; cson_object_iterator iter = cson_object_iterator_empty; assert( orig && src ); if( 0 != cson_object_iter_init( src, &iter ) ) { return NULL; } destV = cson_value_new_object(); if( NULL == destV ) return NULL; dest = cson_value_get_object( destV ); assert( dest ); if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){ cson_value_free( destV ); return NULL; } while( (kvp = cson_object_iter_next( &iter )) ) { cson_value * key = NULL; cson_value * val = NULL; assert( kvp->key && (kvp->key->refcount>0) ); key = cson_value_clone_ref(kvp->key); val = key ? cson_value_clone_ref(kvp->value) : NULL; if( ! key || !val ){ goto error; } assert( CSON_STR(key) ); if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) ) { goto error; } /* remove our references */ cson_value_free(key); cson_value_free(val); continue; error: cson_value_free(key); cson_value_free(val); cson_value_free(destV); destV = NULL; break; } return destV; } cson_value * cson_value_clone( cson_value const * orig ) { if( NULL == orig ) return NULL; else { switch( orig->api->typeID ) { case CSON_TYPE_UNDEF: assert(0 && "This should never happen."); return NULL; case CSON_TYPE_NULL: return cson_value_null(); case CSON_TYPE_BOOL: return cson_value_new_bool( cson_value_get_bool( orig ) ); case CSON_TYPE_INTEGER: return cson_value_new_integer( cson_value_get_integer( orig ) ); break; case CSON_TYPE_DOUBLE: return cson_value_new_double( cson_value_get_double( orig ) ); break; case CSON_TYPE_STRING: { cson_string const * str = cson_value_get_string( orig ); return cson_value_new_string( cson_string_cstr( str ), cson_string_length_bytes( str ) ); } case CSON_TYPE_ARRAY: return cson_value_clone_array( orig ); case CSON_TYPE_OBJECT: return cson_value_clone_object( orig ); } assert( 0 && "We can't get this far." ); return NULL; } } cson_value * cson_string_value(cson_string const * s) { #define MT CSON_SPECIAL_VALUES[CSON_VAL_STR_EMPTY] return s ? ((s==MT.value) ? &MT : CSON_VCAST(s)) : NULL; #undef MT } cson_value * cson_object_value(cson_object const * s) { return s ? CSON_VCAST(s) : NULL; } cson_value * cson_array_value(cson_array const * s) { return s ? CSON_VCAST(s) : NULL; } void cson_free_object(cson_object *x) { if(x) cson_value_free(cson_object_value(x)); } void cson_free_array(cson_array *x) { if(x) cson_value_free(cson_array_value(x)); } void cson_free_string(cson_string *x) { if(x) cson_value_free(cson_string_value(x)); } void cson_free_value(cson_value *x) { if(x) cson_value_free(x); } #if 0 /* i'm not happy with this... */ char * cson_pod_to_string( cson_value const * orig ) { if( ! orig ) return NULL; else { enum { BufSize = 64 }; char * v = NULL; switch( orig->api->typeID ) { case CSON_TYPE_BOOL: { char const bv = cson_value_get_bool(orig); v = cson_strdup( bv ? "true" : "false", bv ? 4 : 5 ); break; } case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: { v = cson_strdup( "null", 4 ); break; } case CSON_TYPE_STRING: { cson_string const * jstr = cson_value_get_string(orig); unsigned const int slen = cson_string_length_bytes( jstr ); assert( NULL != jstr ); v = cson_strdup( cson_string_cstr( jstr ), slen ); break; } case CSON_TYPE_INTEGER: { char buf[BufSize] = {0}; if( 0 < sprintf( v, "%"CSON_INT_T_PFMT, cson_value_get_integer(orig)) ) { v = cson_strdup( buf, strlen(buf) ); } break; } case CSON_TYPE_DOUBLE: { char buf[BufSize] = {0}; if( 0 < sprintf( v, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(orig)) ) { v = cson_strdup( buf, strlen(buf) ); } break; } default: break; } return v; } } #endif #if 0 /* i'm not happy with this... */ char * cson_pod_to_string( cson_value const * orig ) { if( ! orig ) return NULL; else { enum { BufSize = 64 }; char * v = NULL; switch( orig->api->typeID ) { case CSON_TYPE_BOOL: { char const bv = cson_value_get_bool(orig); v = cson_strdup( bv ? "true" : "false", bv ? 4 : 5 ); break; } case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: { v = cson_strdup( "null", 4 ); break; } case CSON_TYPE_STRING: { cson_string const * jstr = cson_value_get_string(orig); unsigned const int slen = cson_string_length_bytes( jstr ); assert( NULL != jstr ); v = cson_strdup( cson_string_cstr( jstr ), slen ); break; } case CSON_TYPE_INTEGER: { char buf[BufSize] = {0}; if( 0 < sprintf( v, "%"CSON_INT_T_PFMT, cson_value_get_integer(orig)) ) { v = cson_strdup( buf, strlen(buf) ); } break; } case CSON_TYPE_DOUBLE: { char buf[BufSize] = {0}; if( 0 < sprintf( v, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(orig)) ) { v = cson_strdup( buf, strlen(buf) ); } break; } default: break; } return v; } } #endif unsigned int cson_value_msize(cson_value const * v) { if(!v) return 0; else if( cson_value_is_builtin(v) ) return 0; else { unsigned int rc = sizeof(cson_value); assert(NULL != v->api); switch(v->api->typeID){ case CSON_TYPE_INTEGER: assert( v != &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]); rc += sizeof(cson_int_t); break; case CSON_TYPE_DOUBLE: assert( v != &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]); rc += sizeof(cson_double_t); break; case CSON_TYPE_STRING: rc += sizeof(cson_string) + CSON_STR(v)->length + 1/*NUL*/; break; case CSON_TYPE_ARRAY:{ cson_array const * ar = CSON_ARRAY(v); cson_value_list const * li; unsigned int i = 0; assert( NULL != ar ); li = &ar->list; rc += sizeof(cson_array) + (li->alloced * sizeof(cson_value *)); for( ; i < li->count; ++i ){ cson_value const * e = ar->list.list[i]; if( e ) rc += cson_value_msize( e ); } break; } case CSON_TYPE_OBJECT:{ cson_object const * obj = CSON_OBJ(v); unsigned int i = 0; cson_kvp_list const * kl; assert(NULL != obj); kl = &obj->kvp; rc += sizeof(cson_object) + (kl->alloced * sizeof(cson_kvp*)); for( ; i < kl->count; ++i ){ cson_kvp const * kvp = kl->list[i]; assert(NULL != kvp); rc += cson_value_msize(kvp->key); rc += cson_value_msize(kvp->value); } break; } case CSON_TYPE_UNDEF: case CSON_TYPE_NULL: case CSON_TYPE_BOOL: assert( 0 && "Should have been caught by is-builtin check!" ); break; default: assert(0 && "Invalid typeID!"); return 0; #undef RCCHECK } return rc; } } int cson_object_merge( cson_object * dest, cson_object const * src, int flags ){ cson_object_iterator iter = cson_object_iterator_empty; int rc; char const replace = (flags & CSON_MERGE_REPLACE); char const recurse = !(flags & CSON_MERGE_NO_RECURSE); cson_kvp const * kvp; if((!dest || !src) || (dest==src)) return cson_rc.ArgError; rc = cson_object_iter_init( src, &iter ); if(rc) return rc; while( (kvp = cson_object_iter_next(&iter) ) ) { cson_string * key = cson_kvp_key(kvp); cson_value * val = cson_kvp_value(kvp); cson_value * check = cson_object_get_s( dest, key ); if(!check){ cson_object_set_s( dest, key, val ); continue; } else if(!replace && !recurse) continue; else if(replace && !recurse){ cson_object_set_s( dest, key, val ); continue; } else if( recurse ){ if( cson_value_is_object(check) && cson_value_is_object(val) ){ rc = cson_object_merge( cson_value_get_object(check), cson_value_get_object(val), flags ); if(rc) return rc; else continue; } else continue; } else continue; } return 0; } static cson_value * cson_guess_arg_type(char const *arg){ char * end = NULL; if(!arg || !*arg) return cson_value_null(); else if(('0'>*arg) || ('9'<*arg)){ goto do_string; } else{ /* try numbers... */ long const val = strtol(arg, &end, 10); if(!*end){ return cson_value_new_integer( (cson_int_t)val); } else if( '.' != *end ) { goto do_string; } else { double const val = strtod(arg, &end); if(!*end){ return cson_value_new_double(val); } } } do_string: return cson_value_new_string(arg, strlen(arg)); } int cson_parse_argv_flags( int argc, char const * const * argv, cson_object ** tgt, unsigned int * count ){ cson_object * o = NULL; int rc = 0; int i = 0; if(argc<1 || !argc || !tgt) return cson_rc.ArgError; o = *tgt ? *tgt : cson_new_object(); if(count) *count = 0; for( i = 0; i < argc; ++i ){ char const * arg = argv[i]; char const * key = arg; char const * pos; cson_string * k = NULL; cson_value * v = NULL; if('-' != *arg) continue; while('-'==*key) ++key; if(!*key) continue; pos = key; while( *pos && ('=' != *pos)) ++pos; k = cson_new_string(key, pos-key); if(!k){ rc = cson_rc.AllocError; break; } if(!*pos){ /** --key */ v = cson_value_true(); }else{ /** --key=...*/ assert('=' == *pos); ++pos /*skip '='*/; v = cson_guess_arg_type(pos); } if(0 != (rc=cson_object_set_s(o, k, v))){ cson_free_string(k); cson_value_free(v); break; } else if(count) ++*count; } if(o != *tgt){ if(rc) cson_free_object(o); else *tgt = o; } return rc; } #if defined(__cplusplus) } /*extern "C"*/ #endif #undef MARKER #undef CSON_OBJECT_PROPS_SORT #undef CSON_OBJECT_PROPS_SORT_USE_LENGTH #undef CSON_CAST #undef CSON_INT #undef CSON_DBL #undef CSON_STR #undef CSON_OBJ #undef CSON_ARRAY #undef CSON_VCAST #undef CSON_MALLOC_IMPL #undef CSON_FREE_IMPL #undef CSON_REALLOC_IMPL /* end file ./cson.c */ /* begin file ./cson_lists.h */ /* Auto-generated from cson_list.h. Edit at your own risk! */ unsigned int cson_value_list_reserve( cson_value_list * self, unsigned int n ) { if( !self ) return 0; else if(0 == n) { if(0 == self->alloced) return 0; cson_free(self->list, "cson_value_list_reserve"); self->list = NULL; self->alloced = self->count = 0; return 0; } else if( self->alloced >= n ) { return self->alloced; } else { size_t const sz = sizeof(cson_value *) * n; cson_value * * m = (cson_value **)cson_realloc( self->list, sz, "cson_value_list_reserve" ); if( ! m ) return self->alloced; memset( m + self->alloced, 0, (sizeof(cson_value *)*(n-self->alloced))); self->alloced = n; self->list = m; return n; } } int cson_value_list_append( cson_value_list * self, cson_value * cp ) { if( !self || !cp ) return cson_rc.ArgError; else if( self->alloced > cson_value_list_reserve(self, self->count+1) ) { return cson_rc.AllocError; } else { self->list[self->count++] = cp; return 0; } } int cson_value_list_visit( cson_value_list * self, int (*visitor)(cson_value * obj, void * visitorState ), void * visitorState ) { int rc = cson_rc.ArgError; if( self && visitor ) { unsigned int i = 0; for( rc = 0; (i < self->count) && (0 == rc); ++i ) { cson_value * obj = self->list[i]; if(obj) rc = visitor( obj, visitorState ); } } return rc; } void cson_value_list_clean( cson_value_list * self, void (*cleaner)(cson_value * obj) ) { if( self && cleaner && self->count ) { unsigned int i = 0; for( ; i < self->count; ++i ) { cson_value * obj = self->list[i]; if(obj) cleaner(obj); } } cson_value_list_reserve(self,0); } unsigned int cson_kvp_list_reserve( cson_kvp_list * self, unsigned int n ) { if( !self ) return 0; else if(0 == n) { if(0 == self->alloced) return 0; cson_free(self->list, "cson_kvp_list_reserve"); self->list = NULL; self->alloced = self->count = 0; return 0; } else if( self->alloced >= n ) { return self->alloced; } else { size_t const sz = sizeof(cson_kvp *) * n; cson_kvp * * m = (cson_kvp **)cson_realloc( self->list, sz, "cson_kvp_list_reserve" ); if( ! m ) return self->alloced; memset( m + self->alloced, 0, (sizeof(cson_kvp *)*(n-self->alloced))); self->alloced = n; self->list = m; return n; } } int cson_kvp_list_append( cson_kvp_list * self, cson_kvp * cp ) { if( !self || !cp ) return cson_rc.ArgError; else if( self->alloced > cson_kvp_list_reserve(self, self->count+1) ) { return cson_rc.AllocError; } else { self->list[self->count++] = cp; return 0; } } int cson_kvp_list_visit( cson_kvp_list * self, int (*visitor)(cson_kvp * obj, void * visitorState ), void * visitorState ) { int rc = cson_rc.ArgError; if( self && visitor ) { unsigned int i = 0; for( rc = 0; (i < self->count) && (0 == rc); ++i ) { cson_kvp * obj = self->list[i]; if(obj) rc = visitor( obj, visitorState ); } } return rc; } void cson_kvp_list_clean( cson_kvp_list * self, void (*cleaner)(cson_kvp * obj) ) { if( self && cleaner && self->count ) { unsigned int i = 0; for( ; i < self->count; ++i ) { cson_kvp * obj = self->list[i]; if(obj) cleaner(obj); } } cson_kvp_list_reserve(self,0); } /* end file ./cson_lists.h */ /* begin file ./cson_sqlite3.c */ /** @file cson_sqlite3.c This file contains the implementation code for the cson sqlite3-to-JSON API. License: the same as the cson core library. Author: Stephan Beal (http://wanderinghorse.net/home/stephan) */ #if CSON_ENABLE_SQLITE3 /* we do this here for the sake of the amalgamation build */ #include <assert.h> #include <string.h> /* strlen() */ #if 0 #include <stdio.h> #define MARKER if(1) printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); if(1) printf #else #define MARKER if(0) printf #endif #if defined(__cplusplus) extern "C" { #endif cson_value * cson_sqlite3_column_to_value( sqlite3_stmt * st, int col ) { if( ! st ) return NULL; else { #if 0 sqlite3_value * val = sqlite3_column_type(st,col); int const vtype = val ? sqlite3_value_type(val) : -1; if( ! val ) return cson_value_null(); #else int const vtype = sqlite3_column_type(st,col); #endif switch( vtype ) { case SQLITE_NULL: return cson_value_null(); case SQLITE_INTEGER: /* FIXME: for large integers fall back to Double instead. */ return cson_value_new_integer( (cson_int_t) sqlite3_column_int64(st, col) ); case SQLITE_FLOAT: return cson_value_new_double( sqlite3_column_double(st, col) ); case SQLITE_BLOB: /* arguably fall through... */ case SQLITE_TEXT: { char const * str = (char const *)sqlite3_column_text(st,col); return cson_value_new_string(str, str ? strlen(str) : 0); } default: return NULL; } } } cson_value * cson_sqlite3_column_names( sqlite3_stmt * st ) { cson_value * aryV = NULL; cson_array * ary = NULL; char const * colName = NULL; int i = 0; int rc = 0; int colCount = 0; assert(st); colCount = sqlite3_column_count(st); if( colCount <= 0 ) return NULL; aryV = cson_value_new_array(); if( ! aryV ) return NULL; ary = cson_value_get_array(aryV); assert(ary); for( i = 0; (0 ==rc) && (i < colCount); ++i ) { colName = sqlite3_column_name( st, i ); if( ! colName ) rc = cson_rc.AllocError; else { rc = cson_array_set( ary, (unsigned int)i, cson_value_new_string(colName, strlen(colName)) ); } } if( 0 == rc ) return aryV; else { cson_value_free(aryV); return NULL; } } cson_value * cson_sqlite3_row_to_object2( sqlite3_stmt * st, cson_array * colNames ) { cson_value * rootV = NULL; cson_object * root = NULL; cson_string * colName = NULL; int i = 0; int rc = 0; cson_value * currentValue = NULL; int const colCount = sqlite3_column_count(st); if( !colCount || (colCount>cson_array_length_get(colNames)) ) { return NULL; } rootV = cson_value_new_object(); if(!rootV) return NULL; root = cson_value_get_object(rootV); for( i = 0; i < colCount; ++i ) { colName = cson_value_get_string( cson_array_get( colNames, i ) ); if( ! colName ) goto error; currentValue = cson_sqlite3_column_to_value(st,i); if( ! currentValue ) currentValue = cson_value_null(); rc = cson_object_set_s( root, colName, currentValue ); if( 0 != rc ) { cson_value_free( currentValue ); goto error; } } goto end; error: cson_value_free( rootV ); rootV = NULL; end: return rootV; } cson_value * cson_sqlite3_row_to_object( sqlite3_stmt * st ) { #if 0 cson_value * arV = cson_sqlite3_column_names(st); cson_array * ar = NULL; cson_value * rc = NULL; if(!arV) return NULL; ar = cson_value_get_array(arV); assert( NULL != ar ); rc = cson_sqlite3_row_to_object2(st, ar); cson_value_free(arV); return rc; #else cson_value * rootV = NULL; cson_object * root = NULL; char const * colName = NULL; int i = 0; int rc = 0; cson_value * currentValue = NULL; int const colCount = sqlite3_column_count(st); if( !colCount ) return NULL; rootV = cson_value_new_object(); if(!rootV) return NULL; root = cson_value_get_object(rootV); for( i = 0; i < colCount; ++i ) { colName = sqlite3_column_name( st, i ); if( ! colName ) goto error; currentValue = cson_sqlite3_column_to_value(st,i); if( ! currentValue ) currentValue = cson_value_null(); rc = cson_object_set( root, colName, currentValue ); if( 0 != rc ) { cson_value_free( currentValue ); goto error; } } goto end; error: cson_value_free( rootV ); rootV = NULL; end: return rootV; #endif } cson_value * cson_sqlite3_row_to_array( sqlite3_stmt * st ) { cson_value * aryV = NULL; cson_array * ary = NULL; int i = 0; int rc = 0; int const colCount = sqlite3_column_count(st); if( ! colCount ) return NULL; aryV = cson_value_new_array(); if( ! aryV ) return NULL; ary = cson_value_get_array(aryV); rc = cson_array_reserve(ary, (unsigned int) colCount ); if( 0 != rc ) goto error; for( i = 0; i < colCount; ++i ){ cson_value * elem = cson_sqlite3_column_to_value(st,i); if( ! elem ) goto error; rc = cson_array_append(ary,elem); if(0!=rc) { cson_value_free( elem ); goto end; } } goto end; error: cson_value_free(aryV); aryV = NULL; end: return aryV; } /** Internal impl of cson_sqlite3_stmt_to_json() when the 'fat' parameter is non-0. */ static int cson_sqlite3_stmt_to_json_fat( sqlite3_stmt * st, cson_value ** tgt ) { #define RETURN(RC) { if(rootV) cson_value_free(rootV); return RC; } if( ! tgt || !st ) return cson_rc.ArgError; else { cson_value * rootV = NULL; cson_object * root = NULL; cson_value * colsV = NULL; cson_array * cols = NULL; cson_value * rowsV = NULL; cson_array * rows = NULL; cson_value * objV = NULL; int rc = 0; int const colCount = sqlite3_column_count(st); if( colCount <= 0 ) return cson_rc.ArgError; rootV = cson_value_new_object(); if( ! rootV ) return cson_rc.AllocError; colsV = cson_sqlite3_column_names(st); if( ! colsV ) { cson_value_free( rootV ); RETURN(cson_rc.AllocError); } cols = cson_value_get_array(colsV); assert(NULL != cols); root = cson_value_get_object(rootV); rc = cson_object_set( root, "columns", colsV ); if( rc ) { cson_value_free( colsV ); RETURN(rc); } rowsV = cson_value_new_array(); if( ! rowsV ) RETURN(cson_rc.AllocError); rc = cson_object_set( root, "rows", rowsV ); if( rc ) { cson_value_free( rowsV ); RETURN(rc); } rows = cson_value_get_array(rowsV); assert(rows); while( SQLITE_ROW == sqlite3_step(st) ) { objV = cson_sqlite3_row_to_object2(st, cols); if( ! objV ) RETURN(cson_rc.UnknownError); rc = cson_array_append( rows, objV ); if( rc ) { cson_value_free( objV ); RETURN(rc); } } *tgt = rootV; return 0; } #undef RETURN } /** Internal impl of cson_sqlite3_stmt_to_json() when the 'fat' parameter is 0. */ static int cson_sqlite3_stmt_to_json_slim( sqlite3_stmt * st, cson_value ** tgt ) { #define RETURN(RC) { if(rootV) cson_value_free(rootV); return RC; } if( ! tgt || !st ) return cson_rc.ArgError; else { cson_value * rootV = NULL; cson_object * root = NULL; cson_value * aryV = NULL; cson_value * rowsV = NULL; cson_array * rows = NULL; int rc = 0; int const colCount = sqlite3_column_count(st); if( colCount <= 0 ) return cson_rc.ArgError; rootV = cson_value_new_object(); if( ! rootV ) return cson_rc.AllocError; aryV = cson_sqlite3_column_names(st); if( ! aryV ) { cson_value_free( rootV ); RETURN(cson_rc.AllocError); } root = cson_value_get_object(rootV); rc = cson_object_set( root, "columns", aryV ); if( rc ) { cson_value_free( aryV ); RETURN(rc); } aryV = NULL; rowsV = cson_value_new_array(); if( ! rowsV ) RETURN(cson_rc.AllocError); rc = cson_object_set( root, "rows", rowsV ); if( 0 != rc ) { cson_value_free( rowsV ); RETURN(rc); } rows = cson_value_get_array(rowsV); assert(rows); while( SQLITE_ROW == sqlite3_step(st) ) { aryV = cson_sqlite3_row_to_array(st); if( ! aryV ) RETURN(cson_rc.UnknownError); rc = cson_array_append( rows, aryV ); if( 0 != rc ) { cson_value_free( aryV ); RETURN(rc); } } *tgt = rootV; return 0; } #undef RETURN } int cson_sqlite3_stmt_to_json( sqlite3_stmt * st, cson_value ** tgt, char fat ) { return fat ? cson_sqlite3_stmt_to_json_fat(st,tgt) : cson_sqlite3_stmt_to_json_slim(st,tgt) ; } int cson_sqlite3_sql_to_json( sqlite3 * db, cson_value ** tgt, char const * sql, char fat ) { if( !db || !tgt || !sql || !*sql ) return cson_rc.ArgError; else { sqlite3_stmt * st = NULL; int rc = sqlite3_prepare_v2( db, sql, -1, &st, NULL ); if( 0 != rc ) return cson_rc.IOError /* FIXME: Better error code? */; rc = cson_sqlite3_stmt_to_json( st, tgt, fat ); sqlite3_finalize( st ); return rc; } } int cson_sqlite3_bind_value( sqlite3_stmt * st, int ndx, cson_value const * v ) { int rc = 0; char convertErr = 0; if(!st) return cson_rc.ArgError; else if( ndx < 1 ) { rc = cson_rc.RangeError; } else if( cson_value_is_array(v) ){ cson_array * ar = cson_value_get_array(v); unsigned int len = cson_array_length_get(ar); unsigned int i; assert(NULL != ar); for( i = 0; !rc && (i < len); ++i ){ rc = cson_sqlite3_bind_value( st, (int)i+ndx, cson_array_get(ar, i)); } } else if(!v || cson_value_is_null(v)){ rc = sqlite3_bind_null(st,ndx); convertErr = 1; } else if( cson_value_is_double(v) ){ rc = sqlite3_bind_double( st, ndx, cson_value_get_double(v) ); convertErr = 1; } else if( cson_value_is_bool(v) ){ rc = sqlite3_bind_int( st, ndx, cson_value_get_bool(v) ? 1 : 0 ); convertErr = 1; } else if( cson_value_is_integer(v) ){ rc = sqlite3_bind_int64( st, ndx, cson_value_get_integer(v) ); convertErr = 1; } else if( cson_value_is_string(v) ){ cson_string const * s = cson_value_get_string(v); rc = sqlite3_bind_text( st, ndx, cson_string_cstr(s), cson_string_length_bytes(s), SQLITE_TRANSIENT); convertErr = 1; } else { rc = cson_rc.TypeError; } if(convertErr && rc) switch(rc){ case SQLITE_TOOBIG: case SQLITE_RANGE: rc = cson_rc.RangeError; break; case SQLITE_NOMEM: rc = cson_rc.AllocError; break; case SQLITE_IOERR: rc = cson_rc.IOError; break; default: rc = cson_rc.UnknownError; break; }; return rc; } #if defined(__cplusplus) } /*extern "C"*/ #endif #undef MARKER #endif /* CSON_ENABLE_SQLITE3 */ /* end file ./cson_sqlite3.c */ #endif /* FOSSIL_ENABLE_JSON */ |
Added src/cson_amalgamation.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 | #ifdef FOSSIL_ENABLE_JSON #ifndef CSON_FOSSIL_MODE #define CSON_FOSSIL_MODE #endif /* auto-generated! Do not edit! */ /* begin file include/wh/cson/cson.h */ #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED) #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1 /*#include <stdint.h> C99: fixed-size int types. */ #include <stdio.h> /* FILE decl */ /** @page page_cson cson JSON API cson (pronounced "season") is an object-oriented C API for generating and consuming JSON (http://www.json.org) data. Its main claim to fame is that it can parse JSON from, and output it to, damned near anywhere. The i/o routines use a callback function to fetch/emit JSON data, allowing clients to easily plug in their own implementations. Implementations are provided for string- and FILE-based i/o. Project home page: http://fossil.wanderinghorse.net/repos/cson Author: Stephan Beal (http://www.wanderinghorse.net/home/stephan/) License: Dual Public Domain/MIT The full license text is at the bottom of the main header file (cson.h). Examples of how to use the library are scattered throughout the API documentation, in the test.c file in the source repo, and in the wiki on the project's home page. */ #if defined(__cplusplus) extern "C" { #endif #if defined(_WIN32) || defined(_WIN64) # define CSON_ENABLE_UNIX 0 #else # define CSON_ENABLE_UNIX 1 #endif /** @typedef some_long_int_type cson_int_t Typedef for JSON-like integer types. This is (long long) where feasible, otherwise (long). */ #ifdef _WIN32 typedef __int64 cson_int_t; #define CSON_INT_T_SFMT "I64d" #define CSON_INT_T_PFMT "I64d" #elif (__STDC_VERSION__ >= 199901L) || (HAVE_LONG_LONG == 1) typedef long long cson_int_t; #define CSON_INT_T_SFMT "lld" #define CSON_INT_T_PFMT "lld" #else typedef long cson_int_t; #define CSON_INT_T_SFMT "ld" #define CSON_INT_T_PFMT "ld" #endif /** @typedef double_or_long_double cson_double_t This is the type of double value used by the library. It is only lightly tested with long double, and when using long double the memory requirements for such values goes up. Note that by default cson uses C-API defaults for numeric precision. To use a custom precision throughout the library, one needs to define the macros CSON_DOUBLE_T_SFMT and/or CSON_DOUBLE_T_PFMT macros to include their desired precision, and must build BOTH cson AND the client using these same values. For example: @code #define CSON_DOUBLE_T_PFMT ".8Lf" // for Modified Julian Day values #define HAVE_LONG_DOUBLE @endcode (Only CSON_DOUBLE_T_PFTM should be needed for most purposes.) */ #if defined(HAVE_LONG_DOUBLE) typedef long double cson_double_t; # ifndef CSON_DOUBLE_T_SFMT # define CSON_DOUBLE_T_SFMT "Lf" # endif # ifndef CSON_DOUBLE_T_PFMT # define CSON_DOUBLE_T_PFMT "Lf" # endif #else typedef double cson_double_t; # ifndef CSON_DOUBLE_T_SFMT # define CSON_DOUBLE_T_SFMT "f" # endif # ifndef CSON_DOUBLE_T_PFMT # define CSON_DOUBLE_T_PFMT "f" # endif #endif /** @def CSON_VOID_PTR_IS_BIG ONLY define this to a true value if you know that (sizeof(cson_int_t) <= sizeof(void*)) If that is the case, cson does not need to dynamically allocate integers. However, enabling this may cause compilation warnings in 32-bit builds even though the code being warned about cannot ever be called. To get around such warnings, when building on a 64-bit environment you can define this to 1 to get "big" integer support. HOWEVER, all clients must also use the same value for this macro. If i knew a halfway reliable way to determine this automatically at preprocessor-time, i would automate this. We might be able to do halfway reliably by looking for a large INT_MAX value? */ #if !defined(CSON_VOID_PTR_IS_BIG) /* Largely taken from http://predef.sourceforge.net/prearch.html See also: http://poshlib.hookatooka.com/poshlib/trac.cgi/browser/posh.h */ # if defined(_WIN64) || defined(__LP64__)/*gcc*/ \ || defined(_M_X64) || defined(__amd64__) || defined(__amd64) \ || defined(__x86_64__) || defined(__x86_64) \ || defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) \ || defined(_M_IA64) \ || defined(__sparc_v9__) || defined(__sparcv9) || defined(_ADDR64) \ || defined(__64BIT__) # define CSON_VOID_PTR_IS_BIG 1 # else # define CSON_VOID_PTR_IS_BIG 0 # endif #endif /** @def CSON_INT_T_SFMT scanf()-compatible format token for cson_int_t. */ /** @def CSON_INT_T_PFMT printf()-compatible format token for cson_int_t. */ /** @def CSON_DOUBLE_T_SFMT scanf()-compatible format token for cson_double_t. */ /** @def CSON_DOUBLE_T_PFMT printf()-compatible format token for cson_double_t. */ /** Type IDs corresponding to JavaScript/JSON types. These are only in the public API to allow O(1) client-side dispatching based on cson_value types. */ enum cson_type_id { /** The special "undefined" value constant. Its value must be 0 for internal reasons. */ CSON_TYPE_UNDEF = 0, /** The special "null" value constant. */ CSON_TYPE_NULL = 1, /** The bool value type. */ CSON_TYPE_BOOL = 2, /** The integer value type, represented in this library by cson_int_t. */ CSON_TYPE_INTEGER = 3, /** The double value type, represented in this library by cson_double_t. */ CSON_TYPE_DOUBLE = 4, /** The immutable string type. This library stores strings as immutable UTF8. */ CSON_TYPE_STRING = 5, /** The "Array" type. */ CSON_TYPE_ARRAY = 6, /** The "Object" type. */ CSON_TYPE_OBJECT = 7 }; /** Convenience typedef. */ typedef enum cson_type_id cson_type_id; /** Convenience typedef. */ typedef struct cson_value cson_value; /** @struct cson_value The core value type of this API. It is opaque to clients, and only the cson public API should be used for setting or inspecting their values. This class is opaque because stack-based usage can easily cause leaks if one does not intimately understand the underlying internal memory management (which sometimes changes). It is (as of 20110323) legal to insert a given value instance into multiple containers (they will share ownership using reference counting) as long as those insertions do not cause cycles. However, be very aware that such value re-use uses a reference to the original copy, meaning that if its value is changed once, it is changed everywhere. Also beware that multi-threaded write operations on such references leads to undefined behaviour. PLEASE read the ACHTUNGEN below... ACHTUNG #1: cson_values MUST NOT form cycles (e.g. via object or array entries). Not abiding th Holy Law Of No Cycles will lead to double-frees and the like (i.e. undefined behaviour, likely crashes due to infinite recursion or stepping on invalid (freed) pointers). ACHTUNG #2: ALL cson_values returned as non-const cson_value pointers from any public functions in the cson API are to be treated as if they are heap-allocated, and MUST be freed by client by doing ONE of: - Passing it to cson_value_free(). - Adding it to an Object or Array, in which case the object/array takes over ownership. As of 20110323, a value may be inserted into a single container multiple times, or into multiple containers, in which case they all share ownership (via reference counting) of the original value (meaning any changes to it are visible in all references to it). Each call to cson_value_new_xxx() MUST eventually be followed up by one of those options. Some cson_value_new_XXX() implementations do not actually allocate memory, but this is an internal implementation detail. Client code MUST NOT rely on this behaviour and MUST treat each object returned by such a function as if it was a freshly-allocated copy (even if their pointer addresses are the same). ACHTUNG #3: Note that ACHTUNG #2 tells us that we must always free (or transfer ownership of) all pointers returned bycson_value_new_xxx(), but that two calls to (e.g.) cson_value_new_bool(1) will (or might) return the same address. The client must not rely on the "non-allocation" policy of such special cases, and must pass each returned value to cson_value_free(), even if two of them have the same address. Some special values (e.g. null, true, false, integer 0, double 0.0, and empty strings) use shared copies and in other places reference counting is used internally to figure out when it is safe to destroy an object. @see cson_value_new_array() @see cson_value_new_object() @see cson_value_new_string() @see cson_value_new_integer() @see cson_value_new_double() @see cson_value_new_bool() @see cson_value_true() @see cson_value_false() @see cson_value_null() @see cson_value_free() @see cson_value_type_id() */ /** @var cson_rc This object defines the error codes used by cson. Library routines which return int values almost always return a value from this structure. None of the members in this struct have published values except for the OK member, which has the value 0. All other values might be incidentally defined where clients can see them, but the numbers might change from release to release, so clients should only use the symbolic names. Client code is expected to access these values via the shared cson_rc object, and use them as demonstrated here: @code int rc = cson_some_func(...); if( 0 == rc ) {...success...} else if( cson_rc.ArgError == rc ) { ... some argument was wrong ... } else if( cson_rc.AllocError == rc ) { ... allocation error ... } ... @endcode The entries named Parse_XXX are generally only returned by cson_parse() and friends. */ /** @struct cson_rc_ See \ref cson_rc for details. */ static const struct cson_rc_ { /** The generic success value. Guaranteed to be 0. */ const int OK; /** Signifies an error in one or more arguments (e.g. NULL where it is not allowed). */ const int ArgError; /** Signifies that some argument is not in a valid range. */ const int RangeError; /** Signifies that some argument is not of the correct logical cson type. */ const int TypeError; /** Signifies an input/ouput error. */ const int IOError; /** Signifies an out-of-memory error. */ const int AllocError; /** Signifies that the called code is "NYI" (Not Yet Implemented). */ const int NYIError; /** Signifies that an internal error was triggered. If it happens, please report this as a bug! */ const int InternalError; /** Signifies that the called operation is not supported in the current environment. e.g. missing support from 3rd-party or platform-specific code. */ const int UnsupportedError; /** Signifies that the request resource could not be found. */ const int NotFoundError; /** Signifies an unknown error, possibly because an underlying 3rd-party API produced an error and we have no other reasonable error code to convert it to. */ const int UnknownError; /** Signifies that the parser found an unexpected character. */ const int Parse_INVALID_CHAR; /** Signifies that the parser found an invalid keyword (possibly an unquoted string). */ const int Parse_INVALID_KEYWORD; /** Signifies that the parser found an invalid escape sequence. */ const int Parse_INVALID_ESCAPE_SEQUENCE; /** Signifies that the parser found an invalid Unicode character sequence. */ const int Parse_INVALID_UNICODE_SEQUENCE; /** Signifies that the parser found an invalid numeric token. */ const int Parse_INVALID_NUMBER; /** Signifies that the parser reached its maximum defined parsing depth before finishing the input. */ const int Parse_NESTING_DEPTH_REACHED; /** Signifies that the parser found an unclosed object or array. */ const int Parse_UNBALANCED_COLLECTION; /** Signifies that the parser found an key in an unexpected place. */ const int Parse_EXPECTED_KEY; /** Signifies that the parser expected to find a colon but found none (e.g. between keys and values in an object). */ const int Parse_EXPECTED_COLON; } cson_rc = { 0/*OK*/, 1/*ArgError*/, 2/*RangeError*/, 3/*TypeError*/, 4/*IOError*/, 5/*AllocError*/, 6/*NYIError*/, 7/*InternalError*/, 8/*UnsupportedError*/, 9/*NotFoundError*/, 10/*UnknownError*/, 11/*Parse_INVALID_CHAR*/, 12/*Parse_INVALID_KEYWORD*/, 13/*Parse_INVALID_ESCAPE_SEQUENCE*/, 14/*Parse_INVALID_UNICODE_SEQUENCE*/, 15/*Parse_INVALID_NUMBER*/, 16/*Parse_NESTING_DEPTH_REACHED*/, 17/*Parse_UNBALANCED_COLLECTION*/, 18/*Parse_EXPECTED_KEY*/, 19/*Parse_EXPECTED_COLON*/ }; /** Returns the string form of the cson_rc code corresponding to rc, or some unspecified, non-NULL string if it is an unknown code. The returned bytes are static and do not changing during the lifetime of the application. */ char const * cson_rc_string(int rc); /** @struct cson_parse_opt Client-configurable options for the cson_parse() family of functions. */ struct cson_parse_opt { /** Maximum object/array depth to traverse. */ unsigned short maxDepth; /** Whether or not to allow C-style comments. Do not rely on this option being available. If the underlying parser is replaced, this option might no longer be supported. */ char allowComments; }; typedef struct cson_parse_opt cson_parse_opt; /** Empty-initialized cson_parse_opt object. */ #define cson_parse_opt_empty_m { 25/*maxDepth*/, 0/*allowComments*/} /** A class for holding JSON parser information. It is primarily intended for finding the position of a parse error. */ struct cson_parse_info { /** 1-based line number. */ unsigned int line; /** 0-based column number. */ unsigned int col; /** Length, in bytes. */ unsigned int length; /** Error code of the parse run (0 for no error). */ int errorCode; /** The total number of object keys successfully processed by the parser. */ unsigned int totalKeyCount; /** The total number of object/array values successfully processed by the parser, including the root node. */ unsigned int totalValueCount; }; typedef struct cson_parse_info cson_parse_info; /** Empty-initialized cson_parse_info object. */ #define cson_parse_info_empty_m {1/*line*/,\ 0/*col*/, \ 0/*length*/, \ 0/*errorCode*/, \ 0/*totalKeyCount*/, \ 0/*totalValueCount*/ \ } /** Empty-initialized cson_parse_info object. */ extern const cson_parse_info cson_parse_info_empty; /** Empty-initialized cson_parse_opt object. */ extern const cson_parse_opt cson_parse_opt_empty; /** Client-configurable options for the cson_output() family of functions. */ struct cson_output_opt { /** Specifies how to indent (or not) output. The values are: (0) == no extra indentation. (1) == 1 TAB character for each level. (>1) == that number of SPACES for each level. */ unsigned char indentation; /** Maximum object/array depth to traverse. Traversing deeply can be indicative of cycles in the object/array tree, and this value is used to figure out when to abort the traversal. */ unsigned short maxDepth; /** If true, a newline will be added to generated output, else not. */ char addNewline; /** If true, a space will be added after the colon operator in objects' key/value pairs. */ char addSpaceAfterColon; /** If set to 1 then objects/arrays containing only a single value will not indent an extra level for that value (but will indent on subsequent levels if that value contains multiple values). */ char indentSingleMemberValues; /** The JSON format allows, but does not require, JSON generators to backslash-escape forward slashes. This option enables/disables that feature. According to JSON's inventor, Douglas Crockford: <quote> It is allowed, not required. It is allowed so that JSON can be safely embedded in HTML, which can freak out when seeing strings containing "</". JSON tolerates "<\/" for this reason. </quote> (from an email on 2011-04-08) The default value is 0 (because it's just damned ugly). */ char escapeForwardSlashes; }; typedef struct cson_output_opt cson_output_opt; /** Empty-initialized cson_output_opt object. */ #define cson_output_opt_empty_m { 0/*indentation*/,\ 25/*maxDepth*/, \ 0/*addNewline*/, \ 0/*addSpaceAfterColon*/, \ 0/*indentSingleMemberValues*/, \ 0/*escapeForwardSlashes*/ \ } /** Empty-initialized cson_output_opt object. */ extern const cson_output_opt cson_output_opt_empty; /** Typedef for functions which act as an input source for the cson JSON parser. The arguments are: - state: implementation-specific state needed by the function. - n: when called, *n will be the number of bytes the function should read and copy to dest. The function MUST NOT copy more than *n bytes to dest. Before returning, *n must be set to the number of bytes actually copied to dest. If that number is smaller than the original *n value, the input is assumed to be completed (thus this is not useful with non-blocking readers). - dest: the destination memory to copy the data do. Must return 0 on success, non-0 on error (preferably a value from cson_rc). The parser allows this routine to return a partial character from a UTF multi-byte character. The input routine does not need to concern itself with character boundaries. */ typedef int (*cson_data_source_f)( void * state, void * dest, unsigned int * n ); /** Typedef for functions which act as an output destination for generated JSON. The arguments are: - state: implementation-specific state needed by the function. - n: the length, in bytes, of src. - src: the source bytes which the output function should consume. The src pointer will be invalidated shortly after this function returns, so the implementation must copy or ignore the data, but not hold a copy of the src pointer. Must return 0 on success, non-0 on error (preferably a value from cson_rc). These functions are called relatively often during the JSON-output process, and should try to be fast. */ typedef int (*cson_data_dest_f)( void * state, void const * src, unsigned int n ); /** Reads JSON-formatted string data (in ASCII, UTF8, or UTF16), using the src function to fetch all input. This function fetches each input character from the source function, which is calls like src(srcState, buffer, bufferSize), and processes them. If anything is not JSON-kosher then this function fails and returns one of the non-0 cson_rc codes. This function is only intended to read root nodes of a JSON tree, either a single object or a single array, containing any number of child elements. On success, *tgt is assigned the value of the root node of the JSON input, and the caller takes over ownership of that memory. On error, *tgt is not modified and the caller need not do any special cleanup, except possibly for the input source. The opt argument may point to an initialized cson_parse_opt object which contains any settings the caller wants. If it is NULL then default settings (the values defined in cson_parse_opt_empty) are used. The info argument may be NULL. If it is not NULL then the parser populates it with information which is useful in error reporting. Namely, it contains the line/column of parse errors. The srcState argument is ignored by this function but is passed on to src, so any output-destination-specific state can be stored there and accessed via the src callback. Non-parse error conditions include: - (!tgt) or !src: cson_rc.ArgError - cson_rc.AllocError can happen at any time during the input phase Here's a complete example of using a custom input source: @code // Internal type to hold state for a JSON input string. typedef struct { char const * str; // start of input string char const * pos; // current internal cursor position char const * end; // logical EOF (one-past-the-end) } StringSource; // cson_data_source_f() impl which uses StringSource. static int cson_data_source_StringSource( void * state, void * dest, unsigned int * n ) { StringSource * ss = (StringSource*) state; unsigned int i; unsigned char * tgt = (unsigned char *)dest; if( ! ss || ! n || !dest ) return cson_rc.ArgError; else if( !*n ) return cson_rc.RangeError; for( i = 0; (i < *n) && (ss->pos < ss->end); ++i, ++ss->pos, ++tgt ) { *tgt = *ss->pos; } *n = i; return 0; } ... // Now use StringSource together with cson_parse() StringSource ss; cson_value * root = NULL; char const * json = "{\"k1\":123}"; ss.str = ss.pos = json; ss.end = json + strlen(json); int rc = cson_parse( &root, cson_data_source_StringSource, &ss, NULL, NULL ); @endcode It is recommended that clients wrap such utility code into type-safe wrapper functions which also initialize the internal state object and check the user-provided parameters for legality before passing them on to cson_parse(). For examples of this, see cson_parse_FILE() or cson_parse_string(). TODOs: - Buffer the input in larger chunks. We currently read byte-by-byte, but i'm too tired to write/test the looping code for the buffering. @see cson_parse_FILE() @see cson_parse_string() */ int cson_parse( cson_value ** tgt, cson_data_source_f src, void * srcState, cson_parse_opt const * opt, cson_parse_info * info ); /** A cson_data_source_f() implementation which requires the state argument to be a readable (FILE*) handle. */ int cson_data_source_FILE( void * state, void * dest, unsigned int * n ); /** Equivalent to cson_parse( tgt, cson_data_source_FILE, src, opt ). @see cson_parse_filename() */ int cson_parse_FILE( cson_value ** tgt, FILE * src, cson_parse_opt const * opt, cson_parse_info * info ); /** Convenience wrapper around cson_parse_FILE() which opens the given filename. Returns cson_rc.IOError if the file cannot be opened. @see cson_parse_FILE() */ int cson_parse_filename( cson_value ** tgt, char const * src, cson_parse_opt const * opt, cson_parse_info * info ); /** Uses an internal helper class to pass src through cson_parse(). See that function for the return value and argument semantics. src must be a string containing JSON code, at least len bytes long, and the parser will attempt to parse exactly len bytes from src. If len is less than 2 (the minimum length of a legal top-node JSON object) then cson_rc.RangeError is returned. */ int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len, cson_parse_opt const * opt, cson_parse_info * info ); /** Outputs the given value as a JSON-formatted string, sending all output to the given callback function. It is intended for top-level objects or arrays, but can be used with any cson_value. If opt is NULL then default options (the values defined in cson_output_opt_empty) are used. If opt->maxDepth is exceeded while traversing the value tree, cson_rc.RangeError is returned. The destState parameter is ignored by this function and is passed on to the dest function. Returns 0 on success. On error, any amount of output might have been generated before the error was triggered. Example: @code int rc = cson_output( myValue, cson_data_dest_FILE, stdout, NULL ); // basically equivalent to: cson_output_FILE( myValue, stdout, NULL ); // but note that cson_output_FILE() actually uses different defaults // for the output options. @endcode */ int cson_output( cson_value const * src, cson_data_dest_f dest, void * destState, cson_output_opt const * opt ); /** A cson_data_dest_f() implementation which requires the state argument to be a writable (FILE*) handle. */ int cson_data_dest_FILE( void * state, void const * src, unsigned int n ); /** Almost equivalent to cson_output( src, cson_data_dest_FILE, dest, opt ), with one minor difference: if opt is NULL then the default options always include the addNewline option, since that is normally desired for FILE output. @see cson_output_filename() */ int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * opt ); /** Convenience wrapper around cson_output_FILE() which writes to the given filename, destroying any existing contents. Returns cson_rc.IOError if the file cannot be opened. @see cson_output_FILE() */ int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt ); /** Returns the virtual type of v, or CSON_TYPE_UNDEF if !v. */ cson_type_id cson_value_type_id( cson_value const * v ); /** Returns true if v is null, v->api is NULL, or v holds the special undefined value. */ char cson_value_is_undef( cson_value const * v ); /** Returns true if v contains a null value. */ char cson_value_is_null( cson_value const * v ); /** Returns true if v contains a bool value. */ char cson_value_is_bool( cson_value const * v ); /** Returns true if v contains an integer value. */ char cson_value_is_integer( cson_value const * v ); /** Returns true if v contains a double value. */ char cson_value_is_double( cson_value const * v ); /** Returns true if v contains a number (double, integer) value. */ char cson_value_is_number( cson_value const * v ); /** Returns true if v contains a string value. */ char cson_value_is_string( cson_value const * v ); /** Returns true if v contains an array value. */ char cson_value_is_array( cson_value const * v ); /** Returns true if v contains an object value. */ char cson_value_is_object( cson_value const * v ); /** @struct cson_object cson_object is an opaque handle to an Object value. They are used like: @code cson_object * obj = cson_value_get_object(myValue); ... @endcode They can be created like: @code cson_value * objV = cson_value_new_object(); cson_object * obj = cson_value_get_object(objV); // obj is owned by objV and objV must eventually be freed // using cson_value_free() or added to a container // object/array (which transfers ownership to that container). @endcode @see cson_value_new_object() @see cson_value_get_object() @see cson_value_free() */ typedef struct cson_object cson_object; /** @struct cson_array cson_array is an opaque handle to an Array value. They are used like: @code cson_array * obj = cson_value_get_array(myValue); ... @endcode They can be created like: @code cson_value * arV = cson_value_new_array(); cson_array * ar = cson_value_get_array(arV); // ar is owned by arV and arV must eventually be freed // using cson_value_free() or added to a container // object/array (which transfers ownership to that container). @endcode @see cson_value_new_array() @see cson_value_get_array() @see cson_value_free() */ typedef struct cson_array cson_array; /** @struct cson_string cson-internal string type, opaque to client code. Strings in cson are immutable and allocated only by library internals, never directly by client code. The actual string bytes are to be allocated together in the same memory chunk as the cson_string object, which saves us 1 malloc() and 1 pointer member in this type (because we no longer have a direct pointer to the memory). Potential TODOs: @see cson_string_cstr() */ typedef struct cson_string cson_string; /** Converts the given value to a boolean, using JavaScript semantics depending on the concrete type of val: undef or null: false boolean: same integer, double: 0 or 0.0 == false, else true object, array: true string: length-0 string is false, else true. Returns 0 on success and assigns *v (if v is not NULL) to either 0 or 1. On error (val is NULL) then v is not modified. */ int cson_value_fetch_bool( cson_value const * val, char * v ); /** Similar to cson_value_fetch_bool(), but fetches an integer value. The conversion, if any, depends on the concrete type of val: NULL, null, undefined: *v is set to 0 and 0 is returned. string, object, array: *v is set to 0 and cson_rc.TypeError is returned. The error may normally be safely ignored, but it is provided for those wanted to know whether a direct conversion was possible. integer: *v is set to the int value and 0 is returned. double: *v is set to the value truncated to int and 0 is returned. */ int cson_value_fetch_integer( cson_value const * val, cson_int_t * v ); /** The same conversions and return values as cson_value_fetch_integer(), except that the roles of int/double are swapped. */ int cson_value_fetch_double( cson_value const * val, cson_double_t * v ); /** If cson_value_is_string(val) then this function assigns *str to the contents of the string. str may be NULL, in which case this function functions like cson_value_is_string() but returns 0 on success. Returns 0 if val is-a string, else non-0, in which case *str is not modified. The bytes are owned by the given value and may be invalidated in any of the following ways: - The value is cleaned up or freed. - An array or object containing the value peforms a re-allocation (it shrinks or grows). And thus the bytes should be consumed before any further operations on val or any container which holds it. Note that this routine does not convert non-String values to their string representations. (Adding that ability would add more overhead to every cson_value instance.) */ int cson_value_fetch_string( cson_value const * val, cson_string ** str ); /** If cson_value_is_object(val) then this function assigns *obj to the underlying object value and returns 0, otherwise non-0 is returned and *obj is not modified. obj may be NULL, in which case this function works like cson_value_is_object() but with inverse return value semantics (0==success) (and it's a few CPU cycles slower). The *obj pointer is owned by val, and will be invalidated when val is cleaned up. Achtung: for best results, ALWAYS pass a pointer to NULL as the second argument, e.g.: @code cson_object * obj = NULL; int rc = cson_value_fetch_object( val, &obj ); // Or, more simply: obj = cson_value_get_object( val ); @endcode @see cson_value_get_object() */ int cson_value_fetch_object( cson_value const * val, cson_object ** obj ); /** Identical to cson_value_fetch_object(), but works on array values. @see cson_value_get_array() */ int cson_value_fetch_array( cson_value const * val, cson_array ** tgt ); /** Simplified form of cson_value_fetch_bool(). Returns 0 if val is NULL. */ char cson_value_get_bool( cson_value const * val ); /** Simplified form of cson_value_fetch_integer(). Returns 0 if val is NULL. */ cson_int_t cson_value_get_integer( cson_value const * val ); /** Simplified form of cson_value_fetch_double(). Returns 0.0 if val is NULL. */ cson_double_t cson_value_get_double( cson_value const * val ); /** Simplified form of cson_value_fetch_string(). Returns NULL if val is-not-a string value. */ cson_string * cson_value_get_string( cson_value const * val ); /** Returns a pointer to the NULL-terminated string bytes of str. The bytes are owned by string and will be invalided when it is cleaned up. If str is NULL then NULL is returned. If the string has a length of 0 then "" is returned. @see cson_string_length_bytes() @see cson_value_get_string() */ char const * cson_string_cstr( cson_string const * str ); /** Convenience function which returns the string bytes of the given value if it is-a string, otherwise it returns NULL. Note that this does no conversion of non-string types to strings. Equivalent to cson_string_cstr(cson_value_get_string(val)). */ char const * cson_value_get_cstr( cson_value const * val ); /** Equivalent to cson_string_cmp_cstr_n(lhs, cson_string_cstr(rhs), cson_string_length_bytes(rhs)). */ int cson_string_cmp( cson_string const * lhs, cson_string const * rhs ); /** Compares lhs to rhs using memcmp()/strcmp() semantics. Generically speaking it returns a negative number if lhs is less-than rhs, 0 if they are equivalent, or a positive number if lhs is greater-than rhs. It has the following rules for equivalence: - The maximum number of bytes compared is the lesser of rhsLen and the length of lhs. If the strings do not match, but compare equal up to the just-described comparison length, the shorter string is considered to be less-than the longer one. - If lhs and rhs are both NULL, or both have a length of 0 then they will compare equal. - If lhs is null/length-0 but rhs is not then lhs is considered to be less-than rhs. - If rhs is null/length-0 but lhs is not then rhs is considered to be less-than rhs. - i have no clue if the results are exactly correct for UTF strings. */ int cson_string_cmp_cstr_n( cson_string const * lhs, char const * rhs, unsigned int rhsLen ); /** Equivalent to cson_string_cmp_cstr_n( lhs, rhs, (rhs&&*rhs)?strlen(rhs):0 ). */ int cson_string_cmp_cstr( cson_string const * lhs, char const * rhs ); /** Returns the length, in bytes, of str, or 0 if str is NULL. This is an O(1) operation. TODO: add cson_string_length_chars() (is O(N) unless we add another member to store the char length). @see cson_string_cstr() */ unsigned int cson_string_length_bytes( cson_string const * str ); /** Returns the number of UTF8 characters in str. This value will be at most as long as cson_string_length_bytes() for the same string, and less if it has multi-byte characters. Returns 0 if str is NULL. */ unsigned int cson_string_length_utf8( cson_string const * str ); /** Like cson_value_get_string(), but returns a copy of the underying string bytes, which the caller owns and must eventually free using free(). */ char * cson_value_get_string_copy( cson_value const * val ); /** Simplified form of cson_value_fetch_object(). Returns NULL if val is-not-a object value. */ cson_object * cson_value_get_object( cson_value const * val ); /** Simplified form of cson_value_fetch_array(). Returns NULL if val is-not-a array value. */ cson_array * cson_value_get_array( cson_value const * val ); /** Const-correct form of cson_value_get_array(). */ cson_array const * cson_value_get_array_c( cson_value const * val ); /** If ar is-a array and is at least (pos+1) entries long then *v (if v is not NULL) is assigned to the value at that position (which may be NULL). Ownership of the *v return value is unchanged by this call. (The containing array may share ownership of the value with other containers.) If pos is out of range, non-0 is returned and *v is not modified. If v is NULL then this function returns 0 if pos is in bounds, but does not otherwise return a value to the caller. */ int cson_array_value_fetch( cson_array const * ar, unsigned int pos, cson_value ** v ); /** Simplified form of cson_array_value_fetch() which returns NULL if ar is NULL, pos is out of bounds or if ar has no element at that position. */ cson_value * cson_array_get( cson_array const * ar, unsigned int pos ); /** Ensures that ar has allocated space for at least the given number of entries. This never shrinks the array and never changes its logical size, but may pre-allocate space in the array for storing new (as-yet-unassigned) values. Returns 0 on success, or non-zero on error: - If ar is NULL: cson_rc.ArgError - If allocation fails: cson_rc.AllocError */ int cson_array_reserve( cson_array * ar, unsigned int size ); /** If ar is not NULL, sets *v (if v is not NULL) to the length of the array and returns 0. Returns cson_rc.ArgError if ar is NULL. */ int cson_array_length_fetch( cson_array const * ar, unsigned int * v ); /** Simplified form of cson_array_length_fetch() which returns 0 if ar is NULL. */ unsigned int cson_array_length_get( cson_array const * ar ); /** Sets the given index of the given array to the given value. If ar already has an item at that index then it is cleaned up and freed before inserting the new item. ar is expanded, if needed, to be able to hold at least (ndx+1) items, and any new entries created by that expansion are empty (NULL values). On success, 0 is returned and ownership of v is transfered to ar. On error ownership of v is NOT modified, and the caller may still need to clean it up. For example, the following code will introduce a leak if this function fails: @code cson_array_append( myArray, cson_value_new_integer(42) ); @endcode Because the value created by cson_value_new_integer() has no owner and is not cleaned up. The "more correct" way to do this is: @code cson_value * v = cson_value_new_integer(42); int rc = cson_array_append( myArray, v ); if( 0 != rc ) { cson_value_free( v ); ... handle error ... } @endcode */ int cson_array_set( cson_array * ar, unsigned int ndx, cson_value * v ); /** Appends the given value to the given array, transfering ownership of v to ar. On error, ownership of v is not modified. Ownership of ar is never changed by this function. This is functionally equivalent to cson_array_set(ar,cson_array_length_get(ar),v), but this implementation has slightly different array-preallocation policy (it grows more eagerly). Returns 0 on success, non-zero on error. Error cases include: - ar or v are NULL: cson_rc.ArgError - Array cannot be expanded to hold enough elements: cson_rc.AllocError. - Appending would cause a numeric overlow in the array's size: cson_rc.RangeError. (However, you'll get an AllocError long before that happens!) On error ownership of v is NOT modified, and the caller may still need to clean it up. See cson_array_set() for the details. */ int cson_array_append( cson_array * ar, cson_value * v ); /** Creates a new cson_value from the given boolean value. Ownership of the new value is passed to the caller, who must eventually either free the value using cson_value_free() or inserting it into a container (array or object), which transfers ownership to the container. See the cson_value class documentation for more details. Semantically speaking this function Returns NULL on allocation error, but the implementation never actually allocates for this case. Nonetheless, it must be treated as if it were an allocated value. */ cson_value * cson_value_new_bool( char v ); /** Alias for cson_value_new_bool(v). */ cson_value * cson_new_bool(char v); /** Returns the special JSON "null" value. When outputing JSON, its string representation is "null" (without the quotes). See cson_value_new_bool() for notes regarding the returned value's memory. */ cson_value * cson_value_null( void ); /** Equivalent to cson_value_new_bool(1). */ cson_value * cson_value_true( void ); /** Equivalent to cson_value_new_bool(0). */ cson_value * cson_value_false( void ); /** Semantically the same as cson_value_new_bool(), but for integers. */ cson_value * cson_value_new_integer( cson_int_t v ); /** Alias for cson_value_new_integer(v). */ cson_value * cson_new_int(cson_int_t v); /** Semantically the same as cson_value_new_bool(), but for doubles. */ cson_value * cson_value_new_double( cson_double_t v ); /** Alias for cson_value_new_double(v). */ cson_value * cson_new_double(cson_double_t v); /** Semantically the same as cson_value_new_bool(), but for strings. This creates a JSON value which copies the first n bytes of str. The string will automatically be NUL-terminated. Note that if str is NULL or n is 0, this function still returns non-NULL value representing that empty string. Returns NULL on allocation error. See cson_value_new_bool() for important information about the returned memory. */ cson_value * cson_value_new_string( char const * str, unsigned int n ); /** Allocates a new "object" value and transfers ownership of it to the caller. It must eventually be destroyed, by the caller or its owning container, by passing it to cson_value_free(). Returns NULL on allocation error. Post-conditions: cson_value_is_object(value) will return true. @see cson_value_new_array() @see cson_value_free() */ cson_value * cson_value_new_object( void ); /** This works like cson_value_new_object() but returns an Object handle directly. The value handle for the returned object can be fetched with cson_object_value(theObject). Ownership is transfered to the caller, who must eventually free it by passing the Value handle (NOT the Object handle) to cson_value_free() or passing ownership to a parent container. Returns NULL on error (out of memory). */ cson_object * cson_new_object( void ); /** Identical to cson_new_object() except that it creates an Array. */ cson_array * cson_new_array( void ); /** Identical to cson_new_object() except that it creates a String. */ cson_string * cson_new_string(char const * val, unsigned int len); /** Equivalent to cson_value_free(cson_object_value(x)). */ void cson_free_object(cson_object *x); /** Equivalent to cson_value_free(cson_array_value(x)). */ void cson_free_array(cson_array *x); /** Equivalent to cson_value_free(cson_string_value(x)). */ void cson_free_string(cson_string *x); /** Allocates a new "array" value and transfers ownership of it to the caller. It must eventually be destroyed, by the caller or its owning container, by passing it to cson_value_free(). Returns NULL on allocation error. Post-conditions: cson_value_is_array(value) will return true. @see cson_value_new_object() @see cson_value_free() */ cson_value * cson_value_new_array( void ); /** Frees any resources owned by v, then frees v. If v is a container type (object or array) its children are also freed (recursively). If v is NULL, this is a no-op. This function decrements a reference count and only destroys the value if its reference count drops to 0. Reference counts are increased by either inserting the value into a container or via cson_value_add_reference(). Even if this function does not immediately destroy the value, the value must be considered, from the perspective of that client code, to have been destroyed/invalidated by this call. @see cson_value_new_object() @see cson_value_new_array() @see cson_value_add_reference() */ void cson_value_free(cson_value * v); /** Alias for cson_value_free(). */ void cson_free_value(cson_value * v); /** Functionally similar to cson_array_set(), but uses a string key as an index. Like arrays, if a value already exists for the given key, it is destroyed by this function before inserting the new value. If v is NULL then this call is equivalent to cson_object_unset(obj,key). Note that (v==NULL) is treated differently from v having the special null value. In the latter case, the key is set to the special null value. The key may be encoded as ASCII or UTF8. Results are undefined with other encodings, and the errors won't show up here, but may show up later, e.g. during output. Returns 0 on success, non-0 on error. It has the following error cases: - cson_rc.ArgError: obj or key are NULL or strlen(key) is 0. - cson_rc.AllocError: an out-of-memory error On error ownership of v is NOT modified, and the caller may still need to clean it up. For example, the following code will introduce a leak if this function fails: @code cson_object_set( myObj, "foo", cson_value_new_integer(42) ); @endcode Because the value created by cson_value_new_integer() has no owner and is not cleaned up. The "more correct" way to do this is: @code cson_value * v = cson_value_new_integer(42); int rc = cson_object_set( myObj, "foo", v ); if( 0 != rc ) { cson_value_free( v ); ... handle error ... } @endcode Potential TODOs: - Add an overload which takes a cson_value key instead. To get any value out of that we first need to be able to convert arbitrary value types to strings. We could simply to-JSON them and use those as keys. */ int cson_object_set( cson_object * obj, char const * key, cson_value * v ); /** Functionaly equivalent to cson_object_set(), but takes a cson_string() as its KEY type. The string will be reference-counted like any other values, and the key may legally be used within this same container (as a value) or others (as a key or value) at the same time. Returns 0 on success. On error, ownership (i.e. refcounts) of key and value are not modified. On success key and value will get increased refcounts unless they are replacing themselves (which is a harmless no-op). */ int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v ); /** Removes a property from an object. If obj contains the given key, it is removed and 0 is returned. If it is not found, cson_rc.NotFoundError is returned (which can normally be ignored by client code). cson_rc.ArgError is returned if obj or key are NULL or key has a length of 0. Returns 0 if the given key is found and removed. This is functionally equivalent calling cson_object_set(obj,key,NULL). */ int cson_object_unset( cson_object * obj, char const * key ); /** Searches the given object for a property with the given key. If found, it is returned. If no match is found, or any arguments are NULL, NULL is returned. The returned object is owned by obj, and may be invalidated by ANY operations which change obj's property list (i.e. add or remove properties). FIXME: allocate the key/value pairs like we do for cson_array, to get improve the lifetimes of fetched values. @see cson_object_fetch_sub() @see cson_object_get_sub() */ cson_value * cson_object_get( cson_object const * obj, char const * key ); /** Equivalent to cson_object_get() but takes a cson_string argument instead of a C-style string. */ cson_value * cson_object_get_s( cson_object const * obj, cson_string const *key ); /** Similar to cson_object_get(), but removes the value from the parent object's ownership. If no item is found then NULL is returned, else the object (now owned by the caller or possibly shared with other containers) is returned. Returns NULL if either obj or key are NULL or key has a length of 0. This function reduces the returned value's reference count but has the specific property that it does not treat refcounts 0 and 1 identically, meaning that the returned object may have a refcount of 0. This behaviour works around a corner-case where we want to extract a child element from its parent and then destroy the parent (which leaves us in an undesireable (normally) reference count state). */ cson_value * cson_object_take( cson_object * obj, char const * key ); /** Fetches a property from a child (or [great-]*grand-child) object. obj is the object to search. path is a delimited string, where the delimiter is the given separator character. This function searches for the given path, starting at the given object and traversing its properties as the path specifies. If a given part of the path is not found, then this function fails with cson_rc.NotFoundError. If it finds the given path, it returns the value by assiging *tgt to it. If tgt is NULL then this function has no side-effects but will return 0 if the given path is found within the object, so it can be used to test for existence without fetching it. Returns 0 if it finds an entry, cson_rc.NotFoundError if it finds no item, and any other non-zero error code on a "real" error. Errors include: - obj or path are NULL: cson_rc.ArgError - separator is 0, or path is an empty string or contains only separator characters: cson_rc.RangeError - There is an upper limit on how long a single path component may be (some "reasonable" internal size), and cson_rc.RangeError is returned if that length is violated. Limitations: - It has no way to fetch data from arrays this way. i could imagine, e.g., a path of "subobj.subArray.0" for subobj.subArray[0], or "0.3.1" for [0][3][1]. But i'm too lazy/tired to add this. Example usage: Assume we have a JSON structure which abstractly looks like: @code {"subobj":{"subsubobj":{"myValue":[1,2,3]}}} @endcode Out goal is to get the value of myValue. We can do that with: @code cson_value * v = NULL; int rc = cson_object_fetch_sub( object, &v, "subobj.subsubobj.myValue", '.' ); @endcode Note that because keys in JSON may legally contain a '.', the separator must be specified by the caller. e.g. the path "subobj/subsubobj/myValue" with separator='/' is equivalent the path "subobj.subsubobj.myValue" with separator='.'. The value of 0 is not legal as a separator character because we cannot distinguish that use from the real end-of-string without requiring the caller to also pass in the length of the string. Multiple successive separators in the list are collapsed into a single separator for parsing purposes. e.g. the path "a...b...c" (separator='.') is equivalent to "a.b.c". @see cson_object_get_sub() @see cson_object_get_sub2() */ int cson_object_fetch_sub( cson_object const * obj, cson_value ** tgt, char const * path, char separator ); /** Similar to cson_object_fetch_sub(), but derives the path separator character from the first byte of the path argument. e.g. the following arg equivalent: @code cson_object_fetch_sub( obj, &tgt, "foo.bar.baz", '.' ); cson_object_fetch_sub2( obj, &tgt, ".foo.bar.baz" ); @endcode */ int cson_object_fetch_sub2( cson_object const * obj, cson_value ** tgt, char const * path ); /** Convenience form of cson_object_fetch_sub() which returns NULL if the given item is not found. */ cson_value * cson_object_get_sub( cson_object const * obj, char const * path, char sep ); /** Convenience form of cson_object_fetch_sub2() which returns NULL if the given item is not found. */ cson_value * cson_object_get_sub2( cson_object const * obj, char const * path ); /** @enum CSON_MERGE_FLAGS Flags for cson_object_merge(). */ enum CSON_MERGE_FLAGS { CSON_MERGE_DEFAULT = 0, CSON_MERGE_REPLACE = 0x01, CSON_MERGE_NO_RECURSE = 0x02 }; /** "Merges" the src object's properties into dest. Each property in src is copied (using reference counting, not cloning) into dest. If dest already has the given property then behaviour depends on the flags argument: If flag has the CSON_MERGE_REPLACE bit set then this function will by default replace non-object properties with the src property. If src and dest both have the property AND it is an Object then this function operates recursively on those objects. If CSON_MERGE_NO_RECURSE is set then objects are not recursed in this manner, and will be completely replaced if CSON_MERGE_REPLACE is set. Array properties in dest are NOT recursed for merging - they are either replaced or left as-is, depending on whether flags contains he CSON_MERGE_REPLACE bit. Returns 0 on success. The error conditions are: - dest or src are NULL or (dest==src) returns cson_rc.ArgError. - dest or src contain cyclic references - this will likely cause a crash due to endless recursion. Potential TODOs: - Add a flag to copy clones, not the original values. */ int cson_object_merge( cson_object * dest, cson_object const * src, int flags ); /** An iterator type for traversing object properties. Its values must be considered private, not to be touched by client code. @see cson_object_iter_init() @see cson_object_iter_next() */ struct cson_object_iterator { /** @internal The underlying object. */ cson_object const * obj; /** @internal Current position in the property list. */ unsigned int pos; }; typedef struct cson_object_iterator cson_object_iterator; /** Empty-initialized cson_object_iterator object. */ #define cson_object_iterator_empty_m {NULL/*obj*/,0/*pos*/} /** Empty-initialized cson_object_iterator object. */ extern const cson_object_iterator cson_object_iterator_empty; /** Initializes the given iterator to point at the start of obj's properties. Returns 0 on success or cson_rc.ArgError if !obj or !iter. obj must outlive iter, or results are undefined. Results are also undefined if obj is modified while the iterator is active. @see cson_object_iter_next() */ int cson_object_iter_init( cson_object const * obj, cson_object_iterator * iter ); /** @struct cson_kvp This class represents a key/value pair and is used for storing object properties. It is opaque to client code, and the public API only uses this type for purposes of iterating over cson_object properties using the cson_object_iterator interfaces. */ typedef struct cson_kvp cson_kvp; /** Returns the next property from the given iterator's object, or NULL if the end of the property list as been reached. Note that the order of object properties is undefined by the API, and may change from version to version. The returned memory belongs to the underlying object and may be invalidated by any changes to that object. Example usage: @code cson_object_iterator it; cson_object_iter_init( myObject, &it ); // only fails if either arg is 0 cson_kvp * kvp; cson_string const * key; cson_value const * val; while( (kvp = cson_object_iter_next(&it) ) ) { key = cson_kvp_key(kvp); val = cson_kvp_value(kvp); ... } @endcode There is no need to clean up an iterator, as it holds no dynamic resources. @see cson_kvp_key() @see cson_kvp_value() */ cson_kvp * cson_object_iter_next( cson_object_iterator * iter ); /** Returns the key associated with the given key/value pair, or NULL if !kvp. The memory is owned by the object which contains the key/value pair, and may be invalidated by any modifications to that object. */ cson_string * cson_kvp_key( cson_kvp const * kvp ); /** Returns the value associated with the given key/value pair, or NULL if !kvp. The memory is owned by the object which contains the key/value pair, and may be invalidated by any modifications to that object. */ cson_value * cson_kvp_value( cson_kvp const * kvp ); /** @typedef some unsigned int type cson_size_t */ typedef unsigned int cson_size_t; /** A generic buffer class. They can be used like this: @code cson_buffer b = cson_buffer_empty; int rc = cson_buffer_reserve( &buf, 100 ); if( 0 != rc ) { ... allocation error ... } ... use buf.mem ... ... then free it up ... cson_buffer_reserve( &buf, 0 ); @endcode To take over ownership of a buffer's memory: @code void * mem = b.mem; // mem is b.capacity bytes long, but only b.used // bytes of it has been "used" by the API. b = cson_buffer_empty; @endcode The memory now belongs to the caller and must eventually be free()d. */ struct cson_buffer { /** The number of bytes allocated for this object. Use cson_buffer_reserve() to change its value. */ cson_size_t capacity; /** The number of bytes "used" by this object. It is not needed for all use cases, and management of this value (if needed) is up to the client. The cson_buffer public API does not use this member. The intention is that this can be used to track the length of strings which are allocated via cson_buffer, since they need an explicit length and/or null terminator. */ cson_size_t used; /** This is a debugging/metric-counting value intended to help certain malloc()-conscious clients tweak their memory reservation sizes. Each time cson_buffer_reserve() expands the buffer, it increments this value by 1. */ cson_size_t timesExpanded; /** The memory allocated for and owned by this buffer. Use cson_buffer_reserve() to change its size or free it. To take over ownership, do: @code void * myptr = buf.mem; buf = cson_buffer_empty; @endcode (You might also need to store buf.used and buf.capacity, depending on what you want to do with the memory.) When doing so, the memory must eventually be passed to free() to deallocate it. */ unsigned char * mem; }; /** Convenience typedef. */ typedef struct cson_buffer cson_buffer; /** An empty-initialized cson_buffer object. */ #define cson_buffer_empty_m {0/*capacity*/,0/*used*/,0/*timesExpanded*/,NULL/*mem*/} /** An empty-initialized cson_buffer object. */ extern const cson_buffer cson_buffer_empty; /** Uses cson_output() to append all JSON output to the given buffer object. The semantics for the (v, opt) parameters, and the return value, are as documented for cson_output(). buf must be a non-NULL pointer to a properly initialized buffer (see example below). Ownership of buf is not changed by calling this. On success 0 is returned and the contents of buf.mem are guaranteed to be NULL-terminated. On error the buffer might contain partial contents, and it should not be used except to free its contents. On error non-zero is returned. Errors include: - Invalid arguments: cson_rc.ArgError - Buffer cannot be expanded (runs out of memory): cson_rc.AllocError Example usage: @code cson_buffer buf = cson_buffer_empty; // optional: cson_buffer_reserve(&buf, 1024 * 10); int rc = cson_output_buffer( myValue, &buf, NULL ); if( 0 != rc ) { ... error! ... } else { ... use buffer ... puts((char const*)buf.mem); } // In both cases, we eventually need to clean up the buffer: cson_buffer_reserve( &buf, 0 ); // Or take over ownership of its memory: { char * mem = (char *)buf.mem; buf = cson_buffer_empty; ... free(mem); } @endcode @see cson_output() */ int cson_output_buffer( cson_value const * v, cson_buffer * buf, cson_output_opt const * opt ); /** This works identically to cson_parse_string(), but takes a cson_buffer object as its input. buf->used bytes of buf->mem are assumed to be valid JSON input, but it need not be NUL-terminated (we only read up to buf->used bytes). The value of buf->used is assumed to be the "string length" of buf->mem, i.e. not including the NUL terminator. Returns 0 on success, non-0 on error. See cson_parse() for the semantics of the tgt, opt, and err parameters. */ int cson_parse_buffer( cson_value ** tgt, cson_buffer const * buf, cson_parse_opt const * opt, cson_parse_info * err ); /** Reserves the given amount of memory for the given buffer object. If n is 0 then buf->mem is freed and its state is set to NULL/0 values. If buf->capacity is less than or equal to n then 0 is returned and buf is not modified. If n is larger than buf->capacity then buf->mem is (re)allocated and buf->capacity contains the new length. Newly-allocated bytes are filled with zeroes. On success 0 is returned. On error non-0 is returned and buf is not modified. buf->mem is owned by buf and must eventually be freed by passing an n value of 0 to this function. buf->used is never modified by this function unless n is 0, in which case it is reset. */ int cson_buffer_reserve( cson_buffer * buf, cson_size_t n ); /** Fills all bytes of the given buffer with the given character. Returns the number of bytes set (buf->capacity), or 0 if !buf or buf has no memory allocated to it. */ cson_size_t cson_buffer_fill( cson_buffer * buf, char c ); /** Uses a cson_data_source_f() function to buffer input into a cson_buffer. dest must be a non-NULL, initialized (though possibly empty) cson_buffer object. Its contents, if any, will be overwritten by this function, and any memory it holds might be re-used. The src function is called, and passed the state parameter, to fetch the input. If it returns non-0, this function returns that error code. src() is called, possibly repeatedly, until it reports that there is no more data. Whether or not this function succeeds, dest still owns any memory pointed to by dest->mem, and the client must eventually free it by calling cson_buffer_reserve(dest,0). dest->mem might (and possibly will) be (re)allocated by this function, so any pointers to it held from before this call might be invalidated by this call. On error non-0 is returned and dest has almost certainly been modified but its state must be considered incomplete. Errors include: - dest or src are NULL (cson_rc.ArgError) - Allocation error (cson_rc.AllocError) - src() returns an error code Whether or not the state parameter may be NULL depends on the src implementation requirements. On success dest will contain the contents read from the input source. dest->used will be the length of the read-in data, and dest->mem will point to the memory. dest->mem is automatically NUL-terminated if this function succeeds, but dest->used does not count that terminator. On error the state of dest->mem must be considered incomplete, and is not guaranteed to be NUL-terminated. Example usage: @code cson_buffer buf = cson_buffer_empty; int rc = cson_buffer_fill_from( &buf, cson_data_source_FILE, stdin ); if( rc ) { fprintf(stderr,"Error %d (%s) while filling buffer.\n", rc, cson_rc_string(rc)); cson_buffer_reserve( &buf, 0 ); return ...; } ... use the buf->mem ... ... clean up the buffer ... cson_buffer_reserve( &buf, 0 ); @endcode To take over ownership of the buffer's memory, do: @code void * mem = buf.mem; buf = cson_buffer_empty; @endcode In which case the memory must eventually be passed to free() to free it. */ int cson_buffer_fill_from( cson_buffer * dest, cson_data_source_f src, void * state ); /** Increments the reference count for the given value. This is a low-level operation and should not normally be used by client code without understanding exactly what side-effects it introduces. Mis-use can lead to premature destruction or cause a value instance to never be properly destructed (i.e. a memory leak). This function is probably only useful for the following cases: - You want to hold a reference to a value which is itself contained in one or more containers, and you need to be sure that your reference outlives the container(s) and/or that you can free your copy of the reference without invaliding any references to the same value held in containers. - You want to implement "value sharing" behaviour without using an object or array to contain the shared value. This can be used to ensure the lifetime of the shared value instance. Each sharing point adds a reference and simply passed the value to cson_value_free() when they're done. The object will be kept alive for other sharing points which added a reference. Normally any such value handles would be invalidated when the parent container(s) is/are cleaned up, but this function can be used to effectively delay the cleanup. This function, at its lowest level, increments the value's reference count by 1. To decrement the reference count, pass the value to cson_value_free(), after which the value must be considered, from the perspective of that client code, to be destroyed (though it will not be if there are still other live references to it). cson_value_free() will not _actually_ destroy the value until its reference count drops to 0. Returns 0 on success. The only error conditions are if v is NULL (cson_rc.ArgError) or if the reference increment would overflow (cson_rc.RangeError). In theory a client would get allocation errors long before the reference count could overflow (assuming those reference counts come from container insertions, as opposed to via this function). Insider notes which clients really need to know: For shared/constant value instances, such as those returned by cson_value_true() and cson_value_null(), this function has no side effects - it does not actually modify the reference count because (A) those instances are shared across all client code and (B) those objects are static and never get cleaned up. However, that is an implementation detail which client code should not rely on. In other words, if you call cson_value_add_reference() 3 times using the value returned by cson_value_true() (which is incidentally a shared cson_value instance), you must eventually call cson_value_free() 3 times to (semantically) remove those references. However, internally the reference count for that specific cson_value instance will not be modified and those objects will never be freed (they're stack-allocated). It might be interesting to note that newly-created objects have a reference count of 0 instead of 1. This is partly because if the initial reference is counted then it makes ownership problematic when inserting values into containers. e.g. consider the following code: @code // ACHTUNG: this code is hypothetical and does not reflect // what actually happens! cson_value * v = cson_value_new_integer( 42 ); // v's refcount = 1 cson_array_append( myArray, v ); // v's refcount = 2 @endcode If that were the case, the client would be forced to free his own reference after inserting it into the container (which is a bit counter-intuitive as well as intrusive). It would look a bit like the following and would have to be done after every create/insert operation: @code // ACHTUNG: this code is hypothetical and does not reflect // what actually happens! cson_array_append( myArray, v ); // v's refcount = 2 cson_value_free( v ); // v's refcount = 1 @endcode (As i said: it's counter-intuitive and intrusive.) Instead, values start with a refcount of 0 and it is only increased when the value is added to an object/array container or when this function is used to manually increment it. cson_value_free() treats a refcount of 0 or 1 equivalently, destroying the value instance. The only semantic difference between 0 and 1, for purposes of cleaning up, is that a value with a non-0 refcount has been had its refcount adjusted, whereas a 0 refcount indicates a fresh, "unowned" reference. */ int cson_value_add_reference( cson_value * v ); #if 0 /** DO NOT use this unless you know EXACTLY what you're doing. It is only in the public API to work around a couple corner cases involving extracting child elements and discarding their parents. This function sets v's reference count to the given value. It does not clean up the object if rc is 0. Returns 0 on success, non-0 on error. */ int cson_value_refcount_set( cson_value * v, unsigned short rc ); #endif /** Deeply copies a JSON value, be it an object/array or a "plain" value (e.g. number/string/boolean). If cv is not NULL then this function makes a deep clone of it and returns that clone. Ownership of the clone is identical t transfered to the caller, who must eventually free the value using cson_value_free() or add it to a container object/array to transfer ownership to the container. The returned object will be of the same logical type as orig. ACHTUNG: if orig contains any cyclic references at any depth level this function will endlessly recurse. (Having _any_ cyclic references violates this library's requirements.) Returns NULL if orig is NULL or if cloning fails. Assuming that orig is in a valid state, the only "likely" error case is that an allocation fails while constructing the clone. In other words, if cloning fails due to something other than an allocation error then either orig is in an invalid state or there is a bug. When this function clones Objects or Arrays it shares any immutable values (including object keys) between the parent and the clone. Mutable values (Objects and Arrays) are copied, however. For example, if we clone: @code { a: 1, b: 2, c:["hi"] } @endcode The cloned object and the array "c" would be a new Object/Array instances but the object keys (a,b,b) and the values of (a,b), as well as the string value within the "c" array, would be shared between the original and the clone. The "c" array itself would be deeply cloned, such that future changes to the clone are not visible to the parent, and vice versa, but immutable values within the array are shared (in this case the string "hi"). The justification for this heuristic is that immutable values can never be changed, so there is no harm in sharing them across clones. Additionally, such types can never contribute to cycles in a JSON tree, so they are safe to share this way. Objects and Arrays, on the other hand, can be modified later and can contribute to cycles, and thus the clone needs to be an independent instance. Note, however, that if this function directly passed a non-Object/Array, that value is deeply cloned. The sharing behaviour only applies when traversing Objects/Arrays. */ cson_value * cson_value_clone( cson_value const * orig ); /** Returns the value handle associated with s. The handle itself owns s, and ownership of the handle is not changed by calling this function. If the returned handle is part of a container, calling cson_value_free() on the returned handle invoked undefined behaviour (quite possibly downstream when the container tries to use it). This function only returns NULL if s is NULL. The length of the returned string is cson_string_length_bytes(). */ cson_value * cson_string_value(cson_string const * s); /** The Object form of cson_string_value(). See that function for full details. */ cson_value * cson_object_value(cson_object const * s); /** The Array form of cson_string_value(). See that function for full details. */ cson_value * cson_array_value(cson_array const * s); /** Calculates the approximate in-memory-allocated size of v, recursively if it is a container type, with the following caveats and limitations: If a given value is reference counted then it is only and multiple times within a traversed container, each reference is counted at full cost. We have no way of knowing if a given reference has been visited already and whether it should or should not be counted, so we pessimistically count them even though the _might_ not really count for the given object tree (it depends on where the other open references live). This function returns 0 if any of the following are true: - v is NULL - v is one of the special singleton values (null, bools, empty string, int 0, double 0.0) All other values require an allocation, and this will return their total memory cost, including the cson-specific internals and the native value(s). Note that because arrays and objects might have more internal slots allocated than used, the alloced size of a container does not necessarily increase when a new item is inserted into it. An interesting side-effect of this is that when cson_clone()ing an array or object, the size of the clone can actually be less than the original. */ unsigned int cson_value_msize(cson_value const * v); /** Parses command-line-style arguments into a JSON object. It expects arguments to be in any of these forms, and any number of leading dashes are treated identically: --key : Treats key as a boolean with a true value. --key=VAL : Treats VAL as either a double, integer, or string. --key= : Treats key as a JSON null (not literal NULL) value. Arguments not starting with a dash are skipped. Each key/value pair is inserted into an object. If a given key appears more than once then only the final entry is actually stored. argc and argv are expected to be values from main() (or similar, possibly adjusted to remove argv[0]). tgt must be either a pointer to NULL or a pointer to a client-provided Object. If (NULL==*tgt) then this function allocates a new object and on success it stores the new object in *tgt (it is owned by the caller). If (NULL!=*tgt) then it is assumed to be a properly allocated object. DO NOT pass a pointer to an unitialized pointer, as that will fool this function into thinking it is a valid object and Undefined Behaviour will ensue. If count is not NULL then the number of arugments parsed by this function are assigned to it. On error, count will be the number of options successfully parsed before the error was encountered. On success: - 0 is returned. - If (*tgt==NULL) then *tgt is assigned to a newly-allocated object, owned by the caller. Note that even if no arguments are parsed, the object is still created. On error: - non-0 is returned - If (*tgt==NULL) then it is not modified. - If (*tgt!=NULL) (i.e., the caller provides his own object) then it might contain partial results. */ int cson_parse_argv_flags( int argc, char const * const * argv, cson_object ** tgt, unsigned int * count ); /* LICENSE This software's source code, including accompanying documentation and demonstration applications, are licensed under the following conditions... Certain files are imported from external projects and have their own licensing terms. Namely, the JSON_parser.* files. See their files for their official licenses, but the summary is "do what you want [with them] but leave the license text and copyright in place." The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) explicitly disclaims copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2011), this software is Copyright (c) 2011 by Stephan G. Beal, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License The full text of the MIT License follows: -- Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --END OF MIT LICENSE-- For purposes of the above license, the term "Software" includes documentation and demonstration source code which accompanies this software. ("Accompanies" = is contained in the Software's primary public source code repository.) */ #if defined(__cplusplus) } /*extern "C"*/ #endif #endif /* WANDERINGHORSE_NET_CSON_H_INCLUDED */ /* end file include/wh/cson/cson.h */ /* begin file include/wh/cson/cson_sqlite3.h */ /** @file cson_sqlite3.h This file contains cson's public sqlite3-to-JSON API declarations and API documentation. If CSON_ENABLE_SQLITE3 is not defined, or is defined to 0, then including this file will have no side-effects other than defining CSON_ENABLE_SQLITE3 (if it was not defined) to 0 and defining a few include guard macros. i.e. if CSON_ENABLE_SQLITE3 is not set to a true value then the API is not visible. This API requires that <sqlite3.h> be in the INCLUDES path and that the client eventually link to (or directly embed) the sqlite3 library. */ #if !defined(WANDERINGHORSE_NET_CSON_SQLITE3_H_INCLUDED) #define WANDERINGHORSE_NET_CSON_SQLITE3_H_INCLUDED 1 #if !defined(CSON_ENABLE_SQLITE3) # if defined(DOXYGEN) #define CSON_ENABLE_SQLITE3 1 # else #define CSON_ENABLE_SQLITE3 1 # endif #endif #if CSON_ENABLE_SQLITE3 /* we do this here for the sake of the amalgamation build */ #include <sqlite3.h> #if defined(__cplusplus) extern "C" { #endif /** Converts a single value from a single 0-based column index to its JSON equivalent. On success it returns a new JSON value, which will have a different concrete type depending on the field type reported by sqlite3_column_type(st,col): Integer, double, null, or string (TEXT and BLOB data, though not all blob data is legal for a JSON string). st must be a sqlite3_step()'d row and col must be a 0-based column index within that result row. */ cson_value * cson_sqlite3_column_to_value( sqlite3_stmt * st, int col ); /** Creates a JSON Array object containing the names of all columns of the given prepared statement handle. Returns a new array value on success, which the caller owns. Its elements are in the same order as in the underlying query. On error NULL is returned. st is not traversed or freed by this function - only the column count and names are read. */ cson_value * cson_sqlite3_column_names( sqlite3_stmt * st ); /** Creates a JSON Object containing key/value pairs corresponding to the result columns in the current row of the given statement handle. st must be a sqlite3_step()'d row result. On success a new Object is returned which is owned by the caller. On error NULL is returned. cson_sqlite3_column_to_value() is used to convert each column to a JSON value, and the column names are taken from sqlite3_column_name(). */ cson_value * cson_sqlite3_row_to_object( sqlite3_stmt * st ); /** Functionally almost identical to cson_sqlite3_row_to_object(), the only difference being how the result objects gets its column names. st must be a freshly-step()'d handle holding a result row. colNames must be an Array with at least the same number of columns as st. If it has fewer, NULL is returned and this function has no side-effects. For each column in the result set, the colNames entry at the same index is used for the column key. If a given entry is-not-a String then conversion will fail and NULL will be returned. The one reason to prefer this over cson_sqlite3_row_to_object() is that this one can share the keys across multiple rows (or even other JSON containers), whereas the former makes fresh copies of the column names for each row. */ cson_value * cson_sqlite3_row_to_object2( sqlite3_stmt * st, cson_array * colNames ); /** Similar to cson_sqlite3_row_to_object(), but creates an Array value which contains the JSON-form values of the given result set row. */ cson_value * cson_sqlite3_row_to_array( sqlite3_stmt * st ); /** Converts the results of an sqlite3 SELECT statement to JSON, in the form of a cson_value object tree. st must be a prepared, but not yet traversed, SELECT query. tgt must be a pointer to NULL (see the example below). If either of those arguments are NULL, cson_rc.ArgError is returned. This walks the query results and returns a JSON object which has a different structure depending on the value of the 'fat' argument. If 'fat' is 0 then the structure is: @code { "columns":["colName1",..."colNameN"], "rows":[ [colVal0, ... colValN], [colVal0, ... colValN], ... ] } @endcode In the "non-fat" format the order of the columns and row values is guaranteed to be the same as that of the underlying query. If 'fat' is not 0 then the structure is: @code { "columns":["colName1",..."colNameN"], "rows":[ {"colName1":value1,..."colNameN":valueN}, {"colName1":value1,..."colNameN":valueN}, ... ] } @endcode In the "fat" format, the order of the "columns" entries is guaranteed to be the same as the underlying query fields, but the order of the keys in the "rows" might be different and might in fact change when passed through different JSON implementations, depending on how they implement object key/value pairs. On success it returns 0 and assigns *tgt to a newly-allocated JSON object tree (using the above structure), which the caller owns. If the query returns no rows, the "rows" value will be an empty array, as opposed to null. On error non-0 is returned and *tgt is not modified. The error code cson_rc.IOError is used to indicate a db-level error, and cson_rc.TypeError is returned if sqlite3_column_count(st) returns 0 or less (indicating an invalid or non-SELECT statement). The JSON data types are determined by the column type as reported by sqlite3_column_type(): SQLITE_INTEGER: integer SQLITE_FLOAT: double SQLITE_TEXT or SQLITE_BLOB: string, and this will only work if the data is UTF8 compatible. If the db returns a literal or SQL NULL for a value it is converted to a JSON null. If it somehow finds a column type it cannot handle, the value is also converted to a NULL in the output. Example @code cson_value * json = NULL; int rc = cson_sqlite3_stmt_to_json( myStatement, &json, 1 ); if( 0 != rc ) { ... error ... } else { cson_output_FILE( json, stdout, NULL ); cson_value_free( json ); } @endcode */ int cson_sqlite3_stmt_to_json( sqlite3_stmt * st, cson_value ** tgt, char fat ); /** A convenience wrapper around cson_sqlite3_stmt_to_json(), which takes SQL instead of a sqlite3_stmt object. It has the same return value and argument semantics as that function. */ int cson_sqlite3_sql_to_json( sqlite3 * db, cson_value ** tgt, char const * sql, char fat ); /** Binds a JSON value to a 1-based parameter index in a prepared SQL statement. v must be NULL or one of one of the types (null, string, integer, double, boolean, array). Booleans are bound as integer 0 or 1. NULL or null are bound as SQL NULL. Integers are bound as 64-bit ints. Strings are bound using sqlite3_bind_text() (as opposed to text16), but we could/should arguably bind them as blobs. If v is an Array then ndx is is used as a starting position (1-based) and each item in the array is bound to the next parameter position (starting and ndx, though the array uses 0-based offsets). TODO: add Object support for named parameters. Returns 0 on success, non-0 on error. */ int cson_sqlite3_bind_value( sqlite3_stmt * st, int ndx, cson_value const * v ); #if defined(__cplusplus) } /*extern "C"*/ #endif #endif /* CSON_ENABLE_SQLITE3 */ #endif /* WANDERINGHORSE_NET_CSON_SQLITE3_H_INCLUDED */ /* end file include/wh/cson/cson_sqlite3.h */ #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/db.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ******************************************************************************* ** ** Code for interfacing to the various databases. ** ** There are three separate database files that fossil interacts ** with: ** | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ******************************************************************************* ** ** Code for interfacing to the various databases. ** ** There are three separate database files that fossil interacts ** with: ** ** (1) The "user" database in ~/.fossil ** ** (2) The "repository" database ** ** (3) A local checkout database named "_FOSSIL_" or ".fslckout" ** and located at the root of the local copy of the source tree. ** */ #include "config.h" #if defined(_WIN32) # if USE_SEE # include <windows.h> # endif #else # include <pwd.h> #endif #if USE_SEE && !defined(SQLITE_HAS_CODEC) # define SQLITE_HAS_CODEC #endif #include <sqlite3.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <time.h> #include "db.h" #if INTERFACE /* ** An single SQL statement is represented as an instance of the following ** structure. */ struct Stmt { Blob sql; /* The SQL for this statement */ sqlite3_stmt *pStmt; /* The results of sqlite3_prepare_v2() */ |
︙ | ︙ | |||
99 100 101 102 103 104 105 | */ #define empty_Stmt_m {BLOB_INITIALIZER,NULL, NULL, NULL, 0, 0} #endif /* INTERFACE */ const struct Stmt empty_Stmt = empty_Stmt_m; /* ** Call this routine when a database error occurs. | < | < < < < < < | < < < < < < < < < < < < < < | < < < < < < | < < < | 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 | */ #define empty_Stmt_m {BLOB_INITIALIZER,NULL, NULL, NULL, 0, 0} #endif /* INTERFACE */ const struct Stmt empty_Stmt = empty_Stmt_m; /* ** Call this routine when a database error occurs. */ static void db_err(const char *zFormat, ...){ va_list ap; char *z; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); #ifdef FOSSIL_ENABLE_JSON if( g.json.isJsonMode ){ json_err( 0, z, 1 ); } else #endif /* FOSSIL_ENABLE_JSON */ if( g.xferPanic && g.cgiOutput==1 ){ cgi_reset_content(); @ error Database\serror:\s%F(z) cgi_reply(); } fossil_panic("Database error: %s", z); } /* ** All static variable that a used by only this file are gathered into ** the following structure. */ static struct DbLocalData { int nBegin; /* Nesting depth of BEGIN */ int doRollback; /* True to force a rollback */ int nCommitHook; /* Number of commit hooks */ Stmt *pAllStmt; /* List of all unfinalized statements */ int nPrepare; /* Number of calls to sqlite3_prepare_v2() */ int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */ struct sCommitHook { int (*xHook)(void); /* Functions to call at db_end_transaction() */ int sequence; /* Call functions in sequence order */ } aHook[5]; char *azDeleteOnFail[3]; /* Files to delete on a failure */ char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */ int nBeforeCommit; /* Number of entries in azBeforeCommit */ int nPriorChanges; /* sqlite3_total_changes() at transaction start */ const char *zStartFile; /* File in which transaction was started */ int iStartLine; /* Line of zStartFile where transaction started */ } db = {0, 0, 0, 0, 0, 0, }; /* ** Arrange for the given file to be deleted on a failure. */ void db_delete_on_failure(const char *zFilename){ assert( db.nDeleteOnFail<count(db.azDeleteOnFail) ); db.azDeleteOnFail[db.nDeleteOnFail++] = fossil_strdup(zFilename); } /* ** Return the transaction nesting depth. 0 means we are currently ** not in a transaction. */ |
︙ | ︙ | |||
236 237 238 239 240 241 242 | if( db.nBegin==0 ){ db_multi_exec("BEGIN"); sqlite3_commit_hook(g.db, db_verify_at_commit, 0); db.nPriorChanges = sqlite3_total_changes(g.db); db.doRollback = 0; db.zStartFile = zStartFile; db.iStartLine = iStartLine; | < < < < | | | | | | < < | | 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 | if( db.nBegin==0 ){ db_multi_exec("BEGIN"); sqlite3_commit_hook(g.db, db_verify_at_commit, 0); db.nPriorChanges = sqlite3_total_changes(g.db); db.doRollback = 0; db.zStartFile = zStartFile; db.iStartLine = iStartLine; } db.nBegin++; } /* ** Begin a new transaction for writing. */ void db_begin_write_real(const char *zStartFile, int iStartLine){ if( db.nBegin==0 ){ db_multi_exec("BEGIN IMMEDIATE"); sqlite3_commit_hook(g.db, db_verify_at_commit, 0); db.nPriorChanges = sqlite3_total_changes(g.db); db.doRollback = 0; db.zStartFile = zStartFile; db.iStartLine = iStartLine; }else{ fossil_warning("read txn at %s:%d might cause SQLITE_BUSY " "for the write txn at %s:%d", db.zStartFile, db.iStartLine, zStartFile, iStartLine); } db.nBegin++; } |
︙ | ︙ | |||
282 283 284 285 286 287 288 | if( g.fSqlTrace ) fossil_trace("-- ROLLBACK by request\n"); } db.nBegin--; if( db.nBegin==0 ){ int i; if( db.doRollback==0 && db.nPriorChanges<sqlite3_total_changes(g.db) ){ i = 0; | < < | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | if( g.fSqlTrace ) fossil_trace("-- ROLLBACK by request\n"); } db.nBegin--; if( db.nBegin==0 ){ int i; if( db.doRollback==0 && db.nPriorChanges<sqlite3_total_changes(g.db) ){ i = 0; while( db.nBeforeCommit ){ db.nBeforeCommit--; sqlite3_exec(g.db, db.azBeforeCommit[i], 0, 0, 0); sqlite3_free(db.azBeforeCommit[i]); i++; } leaf_do_pending_checks(); } for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){ int rc = db.aHook[i].xHook(); if( rc ){ db.doRollback = 1; if( g.fSqlTrace ) fossil_trace("-- ROLLBACK due to aHook[%d]\n", i); } |
︙ | ︙ | |||
363 364 365 366 367 368 369 | } } db.aHook[db.nCommitHook].sequence = sequence; db.aHook[db.nCommitHook].xHook = x; db.nCommitHook++; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | } } db.aHook[db.nCommitHook].sequence = sequence; db.aHook[db.nCommitHook].xHook = x; db.nCommitHook++; } #if INTERFACE /* ** Possible flags to db_vprepare */ #define DB_PREPARE_IGNORE_ERROR 0x001 /* Suppress errors */ #define DB_PREPARE_PERSISTENT 0x002 /* Stmt will stick around for a while */ #endif /* ** Prepare a Stmt. Assume that the Stmt is previously uninitialized. ** If the input string contains multiple SQL statements, only the first ** one is processed. All statements beyond the first are silently ignored. */ int db_vprepare(Stmt *pStmt, int flags, const char *zFormat, va_list ap){ int rc; int prepFlags = 0; char *zSql; blob_zero(&pStmt->sql); blob_vappendf(&pStmt->sql, zFormat, ap); va_end(ap); zSql = blob_str(&pStmt->sql); db.nPrepare++; if( flags & DB_PREPARE_PERSISTENT ){ prepFlags = SQLITE_PREPARE_PERSISTENT; } rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, 0); if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){ db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); } pStmt->pNext = db.pAllStmt; pStmt->pPrev = 0; if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt; db.pAllStmt = pStmt; pStmt->nStep = 0; pStmt->rc = rc; |
︙ | ︙ | |||
704 705 706 707 708 709 710 | va_start(ap, zFormat); rc = db_vprepare(pStmt, DB_PREPARE_PERSISTENT, zFormat, ap); va_end(ap); } return rc; } | < < < < < < | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | va_start(ap, zFormat); rc = db_vprepare(pStmt, DB_PREPARE_PERSISTENT, zFormat, ap); va_end(ap); } return rc; } /* Prepare a statement using text placed inside a Blob ** using blob_append_sql(). */ int db_prepare_blob(Stmt *pStmt, Blob *pSql){ int rc; char *zSql; pStmt->sql = *pSql; |
︙ | ︙ | |||
817 818 819 820 821 822 823 | } /* ** Reset or finalize a statement. */ int db_reset(Stmt *pStmt){ int rc; | | | | | | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | } /* ** Reset or finalize a statement. */ int db_reset(Stmt *pStmt){ int rc; db_stats(pStmt); rc = sqlite3_reset(pStmt->pStmt); db_check_result(rc); return rc; } int db_finalize(Stmt *pStmt){ int rc; if( pStmt->pNext ){ pStmt->pNext->pPrev = pStmt->pPrev; } if( pStmt->pPrev ){ pStmt->pPrev->pNext = pStmt->pNext; }else if( db.pAllStmt==pStmt ){ db.pAllStmt = pStmt->pNext; } pStmt->pNext = 0; pStmt->pPrev = 0; db_stats(pStmt); blob_reset(&pStmt->sql); rc = sqlite3_finalize(pStmt->pStmt); db_check_result(rc); pStmt->pStmt = 0; return rc; } /* ** Return the rowid of the most recent insert */ |
︙ | ︙ | |||
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 | ** column in the current row. The data in the blob will become ** invalid when the statement is stepped or reset. */ void db_ephemeral_blob(Stmt *pStmt, int N, Blob *pBlob){ blob_init(pBlob, sqlite3_column_blob(pStmt->pStmt, N), sqlite3_column_bytes(pStmt->pStmt, N)); } /* ** Execute a single prepared statement until it finishes. */ int db_exec(Stmt *pStmt){ int rc; while( (rc = db_step(pStmt))==SQLITE_ROW ){} rc = db_reset(pStmt); | > > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | ** column in the current row. The data in the blob will become ** invalid when the statement is stepped or reset. */ void db_ephemeral_blob(Stmt *pStmt, int N, Blob *pBlob){ blob_init(pBlob, sqlite3_column_blob(pStmt->pStmt, N), sqlite3_column_bytes(pStmt->pStmt, N)); } /* ** Check a result code. If it is not SQLITE_OK, print the ** corresponding error message and exit. */ void db_check_result(int rc){ if( rc!=SQLITE_OK ){ db_err("SQL error: %s", sqlite3_errmsg(g.db)); } } /* ** Execute a single prepared statement until it finishes. */ int db_exec(Stmt *pStmt){ int rc; while( (rc = db_step(pStmt))==SQLITE_ROW ){} rc = db_reset(pStmt); db_check_result(rc); return rc; } /* ** Print the output of one or more SQL queries on standard output. ** This routine is used for debugging purposes only. */ int db_debug(const char *zSql, ...){ Blob sql; int rc = SQLITE_OK; |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 | z = zEnd; } blob_reset(&sql); return rc; } /* | | < | > > > > > > | > < < < < < < < < < < < < < < < < | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | z = zEnd; } blob_reset(&sql); return rc; } /* ** Execute multiple SQL statements. */ int db_multi_exec(const char *zSql, ...){ Blob sql; int rc = SQLITE_OK; va_list ap; const char *z, *zEnd; sqlite3_stmt *pStmt; blob_init(&sql, 0, 0); va_start(ap, zSql); blob_vappendf(&sql, zSql, ap); va_end(ap); z = blob_str(&sql); while( rc==SQLITE_OK && z[0] ){ pStmt = 0; rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd); if( rc ){ db_err("%s: {%s}", sqlite3_errmsg(g.db), z); }else if( pStmt ){ db.nPrepare++; while( sqlite3_step(pStmt)==SQLITE_ROW ){} rc = sqlite3_finalize(pStmt); if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z); } z = zEnd; } blob_reset(&sql); return rc; } /* ** Optionally make the following changes to the database if feasible and ** convenient. Do not start a transaction for these changes, but only |
︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 | db_finalize(&s); return z; } /* ** Initialize a new database file with the given schema. If anything ** goes wrong, call db_err() to exit. | < < < | | | | | | | | < | < < < | 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | db_finalize(&s); return z; } /* ** Initialize a new database file with the given schema. If anything ** goes wrong, call db_err() to exit. */ void db_init_database( const char *zFileName, /* Name of database file to create */ const char *zSchema, /* First part of schema */ ... /* Additional SQL to run. Terminate with NULL. */ ){ sqlite3 *db; int rc; const char *zSql; va_list ap; db = db_open(zFileName); sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0); rc = sqlite3_exec(db, zSchema, 0, 0, 0); if( rc!=SQLITE_OK ){ db_err("%s", sqlite3_errmsg(db)); } va_start(ap, zSchema); while( (zSql = va_arg(ap, const char*))!=0 ){ rc = sqlite3_exec(db, zSql, 0, 0, 0); if( rc!=SQLITE_OK ){ db_err("%s", sqlite3_errmsg(db)); } } va_end(ap); sqlite3_exec(db, "COMMIT", 0, 0, 0); sqlite3_close(db); } /* ** Function to return the number of seconds since 1970. This is ** the same as strftime('%s','now') but is more compact. */ void db_now_function( |
︙ | ︙ | |||
1393 1394 1395 1396 1397 1398 1399 1400 1401 | if( zOut==0 ){ sqlite3_result_error_nomem(context); return; } decode16(zIn, zOut, nIn); sqlite3_result_blob(context, zOut, nIn/2, sqlite3_free); } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | if( zOut==0 ){ sqlite3_result_error_nomem(context); return; } decode16(zIn, zOut, nIn); sqlite3_result_blob(context, zOut, nIn/2, sqlite3_free); } /* ** Register the SQL functions that are useful both to the internal ** representation and to the "fossil sql" command. */ void db_add_aux_functions(sqlite3 *db){ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, db_checkin_mtime_function, 0, 0); sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, db_sym2rid_function, 0, 0); sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, db_sym2rid_function, 0, 0); sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0); sqlite3_create_function(db, "toLocal", 0, SQLITE_UTF8, 0, db_tolocal_function, 0, 0); sqlite3_create_function(db, "fromLocal", 0, SQLITE_UTF8, 0, db_fromlocal_function, 0, 0); sqlite3_create_function(db, "hextoblob", 1, SQLITE_UTF8, 0, db_hextoblob, 0, 0); sqlite3_create_function(db, "capunion", 1, SQLITE_UTF8, 0, 0, capability_union_step, capability_union_finalize); sqlite3_create_function(db, "fullcap", 1, SQLITE_UTF8, 0, capability_fullcap, 0, 0); sqlite3_create_function(db, "find_emailaddr", 1, SQLITE_UTF8, 0, alert_find_emailaddr_func, 0, 0); } #if USE_SEE /* ** This is a pointer to the saved database encryption key string. */ static char *zSavedKey = 0; /* ** This is the size of the saved database encryption key, in bytes. */ size_t savedKeySize = 0; /* ** This function returns the saved database encryption key -OR- zero if ** no database encryption key is saved. */ char *db_get_saved_encryption_key(){ return zSavedKey; } /* ** This function returns the size of the saved database encryption key ** -OR- zero if no database encryption key is saved. */ size_t db_get_saved_encryption_key_size(){ return savedKeySize; } /* ** This function arranges for the database encryption key to be securely ** saved in non-pagable memory (on platforms where this is possible). */ static void db_save_encryption_key( Blob *pKey ){ void *p = NULL; size_t n = 0; size_t pageSize = 0; size_t blobSize = 0; blobSize = blob_size(pKey); if( blobSize==0 ) return; fossil_get_page_size(&pageSize); assert( pageSize>0 ); if( blobSize>pageSize ){ fossil_panic("key blob too large: %u versus %u", blobSize, pageSize); } |
︙ | ︙ | |||
1675 1676 1677 1678 1679 1680 1681 | savedKeySize = 0; } /* ** This function sets the saved database encryption key to the specified ** string value, allocating or freeing the underlying memory if needed. */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < | | | | > < < | | | | | | | | | | < | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 | savedKeySize = 0; } /* ** This function sets the saved database encryption key to the specified ** string value, allocating or freeing the underlying memory if needed. */ void db_set_saved_encryption_key( Blob *pKey ){ if( zSavedKey!=NULL ){ size_t blobSize = blob_size(pKey); if( blobSize==0 ){ db_unsave_encryption_key(); }else{ if( blobSize>savedKeySize ){ fossil_panic("key blob too large: %u versus %u", blobSize, savedKeySize); } fossil_secure_zero(zSavedKey, savedKeySize); memcpy(zSavedKey, blob_str(pKey), blobSize); } }else{ db_save_encryption_key(pKey); } } #if defined(_WIN32) /* ** This function sets the saved database encryption key to one that gets ** read from the specified Fossil parent process. This is only necessary ** (or functional) on Windows. */ void db_read_saved_encryption_key_from_process( DWORD processId, /* Identifier for Fossil parent process. */ LPVOID pAddress, /* Pointer to saved key buffer in the parent process. */ SIZE_T nSize /* Size of saved key buffer in the parent process. */ ){ void *p = NULL; size_t n = 0; size_t pageSize = 0; HANDLE hProcess = NULL; fossil_get_page_size(&pageSize); assert( pageSize>0 ); if( nSize>pageSize ){ fossil_panic("key too large: %u versus %u", nSize, pageSize); } p = fossil_secure_alloc_page(&n); assert( p!=NULL ); assert( n==pageSize ); assert( n>=nSize ); hProcess = OpenProcess(PROCESS_VM_READ, FALSE, processId); if( hProcess!=NULL ){ SIZE_T nRead = 0; if( ReadProcessMemory(hProcess, pAddress, p, nSize, &nRead) ){ CloseHandle(hProcess); if( nRead==nSize ){ db_unsave_encryption_key(); zSavedKey = p; savedKeySize = n; }else{ fossil_panic("bad size read, %u out of %u bytes at %p from pid %lu", nRead, nSize, pAddress, processId); } }else{ CloseHandle(hProcess); fossil_panic("failed read, %u bytes at %p from pid %lu: %lu", nSize, pAddress, processId, GetLastError()); } }else{ fossil_panic("failed to open pid %lu: %lu", processId, GetLastError()); } } #endif /* defined(_WIN32) */ #endif /* USE_SEE */ /* ** If the database file zDbFile has a name that suggests that it is ** encrypted, then prompt for the database encryption key and return it ** in the blob *pKey. Or, if the encryption key has previously been ** requested, just return a copy of the previous result. The blob in |
︙ | ︙ | |||
2088 2089 2090 2091 2092 2093 2094 | /* ** Open a database file. Return a pointer to the new database ** connection. An error results in process abort. */ LOCAL sqlite3 *db_open(const char *zDbName){ int rc; sqlite3 *db; | < < < < < < | < < < < < < < | | | < < | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 | /* ** Open a database file. Return a pointer to the new database ** connection. An error results in process abort. */ LOCAL sqlite3 *db_open(const char *zDbName){ int rc; sqlite3 *db; if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName); if( strcmp(zDbName, g.nameOfExe)==0 ){ extern int sqlite3_appendvfs_init( sqlite3 *, char **, const sqlite3_api_routines * ); sqlite3_appendvfs_init(0,0,0); g.zVfsName = "apndvfs"; } rc = sqlite3_open_v2( zDbName, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, g.zVfsName ); if( rc!=SQLITE_OK ){ db_err("[%s]: %s", zDbName, sqlite3_errmsg(db)); } db_maybe_set_encryption_key(db, zDbName); sqlite3_busy_timeout(db, 5000); sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0); sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0); sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0); sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0); sqlite3_create_function( db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0 ); sqlite3_create_function( db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0 ); if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_STMT, db_sql_trace, 0); db_add_aux_functions(db); re_add_sql_func(db); /* The REGEXP operator */ foci_register(db); /* The "files_of_checkin" virtual table */ sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0); return db; } /* ** Detaches the zLabel database. */ void db_detach(const char *zLabel){ db_multi_exec("DETACH DATABASE %Q", zLabel); } /* ** zDbName is the name of a database file. Attach zDbName using ** the name zLabel. */ void db_attach(const char *zDbName, const char *zLabel){ Blob key; blob_init(&key, 0, 0); db_maybe_obtain_encryption_key(zDbName, &key); if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){ char *zCmd = sqlite3_mprintf("ATTACH DATABASE %Q AS %Q KEY %Q", zDbName, zLabel, blob_str(&key)); db_multi_exec(zCmd /*works-like:""*/); fossil_secure_zero(zCmd, strlen(zCmd)); sqlite3_free(zCmd); }else{ char *zCmd = sqlite3_mprintf("ATTACH DATABASE %Q AS %Q KEY ''", zDbName, zLabel); db_multi_exec(zCmd /*works-like:""*/); sqlite3_free(zCmd); #if USE_SEE if( blob_size(&key)>0 ){ sqlite3_key_v2(g.db, zLabel, blob_str(&key), -1); } #endif } |
︙ | ︙ | |||
2205 2206 2207 2208 2209 2210 2211 | */ int db_database_slot(const char *zLabel){ int iSlot = -1; int rc; Stmt q; if( g.db==0 ) return iSlot; rc = db_prepare_ignore_error(&q, "PRAGMA database_list"); | | | | | | < | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 | */ int db_database_slot(const char *zLabel){ int iSlot = -1; int rc; Stmt q; if( g.db==0 ) return iSlot; rc = db_prepare_ignore_error(&q, "PRAGMA database_list"); if( rc!=SQLITE_OK ) return iSlot; while( db_step(&q)==SQLITE_ROW ){ if( fossil_strcmp(db_column_text(&q,1),zLabel)==0 ){ iSlot = db_column_int(&q, 0); break; } } db_finalize(&q); return iSlot; } /* |
︙ | ︙ | |||
2232 2233 2234 2235 2236 2237 2238 | db_set_main_schemaname(g.db, zLabel); }else{ db_attach(zDbName, zLabel); } } /* | | > > < | < < < < | < > > > | > > > > | > | | | > > | < < | < < < < < < < < | | | | | | < < | | > > > | | < | < < < < < | < | < < < | < < | < | < | < < < < < | < < | | < < | > | < > < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | | 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 | db_set_main_schemaname(g.db, zLabel); }else{ db_attach(zDbName, zLabel); } } /* ** Close the per-user database file in ~/.fossil */ void db_close_config(){ int iSlot = db_database_slot("configdb"); if( iSlot>0 ){ db_detach("configdb"); g.zConfigDbName = 0; }else if( g.dbConfig ){ sqlite3_wal_checkpoint(g.dbConfig, 0); sqlite3_close(g.dbConfig); g.dbConfig = 0; g.zConfigDbName = 0; }else if( g.db && 0==iSlot ){ int rc; sqlite3_wal_checkpoint(g.db, 0); rc = sqlite3_close(g.db); if( g.fSqlTrace ) fossil_trace("-- db_close_config(%d)\n", rc); g.db = 0; g.zConfigDbName = 0; } } /* ** Open the user database in "~/.fossil". Create the database anew if ** it does not already exist. ** ** If the useAttach flag is 0 (the usual case) then the user database is ** opened on a separate database connection g.dbConfig. This prevents ** the ~/.fossil database from becoming locked on long check-in or sync ** operations which hold an exclusive transaction. In a few cases, though, ** it is convenient for the ~/.fossil to be attached to the main database ** connection so that we can join between the various databases. In that ** case, invoke this routine with useAttach as 1. */ int db_open_config(int useAttach, int isOptional){ char *zDbName; char *zHome; if( g.zConfigDbName ){ int alreadyAttached = db_database_slot("configdb")>0; if( useAttach==alreadyAttached ) return 1; /* Already open. */ db_close_config(); } zHome = fossil_getenv("FOSSIL_HOME"); #if defined(_WIN32) || defined(__CYGWIN__) if( zHome==0 ){ zHome = fossil_getenv("LOCALAPPDATA"); if( zHome==0 ){ zHome = fossil_getenv("APPDATA"); if( zHome==0 ){ char *zDrive = fossil_getenv("HOMEDRIVE"); char *zPath = fossil_getenv("HOMEPATH"); if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath); } } } if( zHome==0 ){ if( isOptional ) return 0; fossil_panic("cannot locate home directory - please set the " "FOSSIL_HOME, LOCALAPPDATA, APPDATA, or HOMEPATH " "environment variables"); } #else if( zHome==0 ){ zHome = fossil_getenv("HOME"); } if( zHome==0 ){ if( isOptional ) return 0; fossil_panic("cannot locate home directory - please set the " "FOSSIL_HOME or HOME environment variables"); } #endif if( file_isdir(zHome, ExtFILE)!=1 ){ if( isOptional ) return 0; fossil_panic("invalid home directory: %s", zHome); } #if defined(_WIN32) || defined(__CYGWIN__) /* . filenames give some window systems problems and many apps problems */ zDbName = mprintf("%//_fossil", zHome); #else zDbName = mprintf("%s/.fossil", zHome); #endif if( file_size(zDbName, ExtFILE)<1024*3 ){ if( file_access(zHome, W_OK) ){ if( isOptional ) return 0; fossil_panic("home directory %s must be writeable", zHome); } db_init_database(zDbName, zConfigSchema, (char*)0); } if( file_access(zDbName, W_OK) ){ if( isOptional ) return 0; fossil_panic("configuration file %s must be writeable", zDbName); } if( useAttach ){ db_open_or_attach(zDbName, "configdb"); g.dbConfig = 0; }else{ g.dbConfig = db_open(zDbName); db_set_main_schemaname(g.dbConfig, "configdb"); |
︙ | ︙ | |||
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 | /* ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. */ static int isValidLocalDb(const char *zDbName){ i64 lsize; if( file_access(zDbName, F_OK) ) return 0; lsize = file_size(zDbName, ExtFILE); if( lsize%1024!=0 || lsize<4096 ) return 0; db_open_or_attach(zDbName, "localdb"); | > | < < < < < < < < | < < < | < | | | < < < < < < < < < | | < | < < < < < < < < | > | < < | < < < < < < < < < < < < < < | < < < < < < < < < < < | < < < | > < > | < < < < | < | < < | | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 | /* ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. */ static int isValidLocalDb(const char *zDbName){ i64 lsize; char *zVFileDef; if( file_access(zDbName, F_OK) ) return 0; lsize = file_size(zDbName, ExtFILE); if( lsize%1024!=0 || lsize<4096 ) return 0; db_open_or_attach(zDbName, "localdb"); zVFileDef = db_text(0, "SELECT sql FROM localdb.sqlite_master" " WHERE name=='vfile'"); if( zVFileDef==0 ) return 0; /* If the "isexe" column is missing from the vfile table, then ** add it now. This code added on 2010-03-06. After all users have ** upgraded, this code can be safely deleted. */ if( sqlite3_strglob("* isexe *", zVFileDef)!=0 ){ db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0"); } /* If "islink"/"isLink" columns are missing from tables, then ** add them now. This code added on 2011-01-17 and 2011-08-27. ** After all users have upgraded, this code can be safely deleted. */ if( sqlite3_strglob("* islink *", zVFileDef)!=0 ){ db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0"); if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){ db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0"); } if( db_local_table_exists_but_lacks_column("undo", "isLink") ){ db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0"); } if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){ db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0"); } } fossil_free(zVFileDef); return 1; } /* ** Locate the root directory of the local repository tree. The root ** directory is found by searching for a file named "_FOSSIL_" or ".fslckout" ** that contains a valid repository database. ** ** For legacy, also look for ".fos". The use of ".fos" is deprecated ** since "fos" has negative connotations in Hungarian, we are told. ** ** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and ** try again. Once the file is found, the g.zLocalRoot variable is set ** to the root of the repository tree and this routine returns 1. If ** no database is found, then this routine return 0. ** ** This routine always opens the user database regardless of whether or ** not the repository database is found. If the _FOSSIL_ or .fslckout file ** is found, it is attached to the open database connection too. */ int db_open_local(const char *zDbName){ int i, n; char zPwd[2000]; static const char *(aDbName[]) = { "_FOSSIL_", ".fslckout", ".fos" }; if( g.localOpen ) return 1; file_getcwd(zPwd, sizeof(zPwd)-20); n = strlen(zPwd); while( n>0 ){ for(i=0; i<count(aDbName); i++){ sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]); if( isValidLocalDb(zPwd) ){ if( db_open_config(0, 1)==0 ){ return 0; /* Configuration could not be opened */ } /* Found a valid checkout database file */ g.zLocalDbName = mprintf("%s", zPwd); zPwd[n] = 0; while( n>0 && zPwd[n-1]=='/' ){ n--; zPwd[n] = 0; } g.zLocalRoot = mprintf("%s/", zPwd); g.localOpen = 1; db_open_repository(zDbName); return 1; } } n--; while( n>1 && zPwd[n]!='/' ){ n--; } while( n>1 && zPwd[n-1]=='/' ){ n--; } zPwd[n] = 0; } /* A checkout database file could not be found */ return 0; } /* ** Get the full pathname to the repository database file. The ** local database (the _FOSSIL_ or .fslckout database) must have already ** been opened before this routine is called. */ const char *db_repository_filename(void){ static char *zRepo = 0; assert( g.localOpen ); assert( g.zLocalRoot ); if( zRepo==0 ){ zRepo = db_lget("repository", 0); if( zRepo && !file_is_absolute_path(zRepo) ){ zRepo = mprintf("%s%s", g.zLocalRoot, zRepo); } } return zRepo; } /* ** Returns non-zero if the default value for the "allow-symlinks" setting ** is "on". When on Windows, this always returns false. */ int db_allow_symlinks_by_default(void){ #if defined(_WIN32) return 0; #else return 1; #endif } /* ** Returns non-zero if support for symlinks is currently enabled. */ int db_allow_symlinks(void){ return g.allowSymlinks; } /* ** Open the repository database given by zDbName. If zDbName==NULL then ** get the name from the already open local database. */ void db_open_repository(const char *zDbName){ if( g.repositoryOpen ) return; if( zDbName==0 ){ if( g.localOpen ){ zDbName = db_repository_filename(); } if( zDbName==0 ){ db_err("unable to find the name of a repository database"); } } if( file_access(zDbName, R_OK) || file_size(zDbName, ExtFILE)<1024 ){ if( file_access(zDbName, F_OK) ){ #ifdef FOSSIL_ENABLE_JSON g.json.resultCode = FSL_JSON_E_DB_NOT_FOUND; #endif fossil_fatal("repository does not exist or" " is in an unreadable directory: %s", zDbName); }else if( file_access(zDbName, R_OK) ){ |
︙ | ︙ | |||
2673 2674 2675 2676 2677 2678 2679 | } } g.zRepositoryName = mprintf("%s", zDbName); db_open_or_attach(g.zRepositoryName, "repository"); g.repositoryOpen = 1; sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION, &g.iRepoDataVers); | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 | } } g.zRepositoryName = mprintf("%s", zDbName); db_open_or_attach(g.zRepositoryName, "repository"); g.repositoryOpen = 1; sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION, &g.iRepoDataVers); /* Cache "allow-symlinks" option, because we'll need it on every stat call */ g.allowSymlinks = db_get_boolean("allow-symlinks", db_allow_symlinks_by_default()); g.zAuxSchema = db_get("aux-schema",""); g.eHashPolicy = db_get_int("hash-policy",-1); if( g.eHashPolicy<0 ){ g.eHashPolicy = hname_default_policy(); db_set_int("hash-policy", g.eHashPolicy, 0); } /* Make a change to the CHECK constraint on the BLOB table for ** version 2.0 and later. */ rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */ } /* ** Return true if there have been any changes to the repository ** database since it was opened. ** ** Changes to "config" and "localdb" and "temp" do not count. ** This routine only returns true if there have been changes ** to "repository". */ int db_repository_has_changed(void){ unsigned int v; if( !g.repositoryOpen ) return 0; sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION, &v); return g.iRepoDataVers != v; } /* ** Flags for the db_find_and_open_repository() function. */ #if INTERFACE #define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ #define OPEN_ANY_SCHEMA 0x002 /* Do not error if schema is wrong */ #endif /* ** Try to find the repository and open it. Use the -R or --repository ** option to locate the repository. If no such option is available, then ** use the repository of the open checkout if there is one. ** ** Error out if the repository cannot be opened. */ void db_find_and_open_repository(int bFlags, int nArgUsed){ const char *zRep = find_repository_option(); if( zRep && file_isdir(zRep, ExtFILE)==1 ){ goto rep_not_found; |
︙ | ︙ | |||
2812 2813 2814 2815 2816 2817 2818 | } db_open_repository(zRep); if( g.repositoryOpen ){ if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema(); return; } rep_not_found: | | < < < < < | 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 | } db_open_repository(zRep); if( g.repositoryOpen ){ if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema(); return; } rep_not_found: if( (bFlags & OPEN_OK_NOT_FOUND)==0 ){ #ifdef FOSSIL_ENABLE_JSON g.json.resultCode = FSL_JSON_E_DB_NOT_FOUND; #endif if( nArgUsed==0 ){ fossil_fatal("use --repository or -R to specify the repository database"); }else{ fossil_fatal("specify the repository name as a command-line argument"); |
︙ | ︙ | |||
2868 2869 2870 2871 2872 2873 2874 | /* ** COMMAND: test-move-repository ** ** Usage: %fossil test-move-repository PATHNAME ** ** Change the location of the repository database on a local check-out. | | | | < | 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 | /* ** COMMAND: test-move-repository ** ** Usage: %fossil test-move-repository PATHNAME ** ** Change the location of the repository database on a local check-out. ** Use this command to avoid having to close and reopen a checkout ** when relocating the repository database. */ void move_repo_cmd(void){ Blob repo; char *zRepo; if( g.argc!=3 ){ usage("PATHNAME"); } file_canonical_name(g.argv[2], &repo, 0); zRepo = blob_str(&repo); if( file_access(zRepo, F_OK) ){ fossil_fatal("no such file: %s", zRepo); } if( db_open_local(zRepo)==0 ){ fossil_fatal("not in a local checkout"); return; } db_open_or_attach(zRepo, "test_repo"); db_lset("repository", blob_str(&repo)); db_record_repository_filename(blob_str(&repo)); db_close(1); } /* ** Open the local database. If unable, exit with an error. */ void db_must_be_within_tree(void){ if( find_repository_option() ){ fossil_fatal("the \"%s\" command only works from within an open check-out", g.argv[1]); } if( db_open_local(0)==0 ){ fossil_fatal("current directory is not within an open checkout"); } db_open_repository(0); db_verify_schema(); } /* ** Close the database connection. ** ** Check for unfinalized statements and report errors if the reportErrors ** argument is true. Ignore unfinalized statements when false. */ void db_close(int reportErrors){ sqlite3_stmt *pStmt; if( g.db==0 ) return; if( g.fSqlStats ){ int cur, hiwtr; sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0); fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr); sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0); fprintf(stderr, "-- LOOKASIDE_HIT %10d\n", hiwtr); sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &cur,&hiwtr,0); |
︙ | ︙ | |||
2947 2948 2949 2950 2951 2952 2953 | sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0); fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr); fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare); } while( db.pAllStmt ){ db_finalize(db.pAllStmt); } | | < | | < < | < < < < | 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 | sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0); fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr); fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare); } while( db.pAllStmt ){ db_finalize(db.pAllStmt); } if( db.nBegin && reportErrors ){ fossil_warning("Transaction started at %s:%d never commits", db.zStartFile, db.iStartLine); db_end_transaction(1); } pStmt = 0; g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */ sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0); g.dbIgnoreErrors--; db_close_config(); /* If the localdb has a lot of unused free space, ** then VACUUM it as we shut down. */ if( db_database_slot("localdb")>=0 ){ int nFree = db_int(0, "PRAGMA localdb.freelist_count"); int nTotal = db_int(0, "PRAGMA localdb.page_count"); if( nFree>nTotal/4 ){ db_multi_exec("VACUUM localdb;"); } } if( g.db ){ int rc; sqlite3_wal_checkpoint(g.db, 0); rc = sqlite3_close(g.db); if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc); if( rc==SQLITE_BUSY && reportErrors ){ while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){ fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); } } g.db = 0; } g.repositoryOpen = 0; g.localOpen = 0; assert( g.dbConfig==0 ); assert( g.zConfigDbName==0 ); backoffice_run_if_needed(); } /* ** Close the database as quickly as possible without unnecessary processing. */ void db_panic_close(void){ if( g.db ){ int rc; sqlite3_wal_checkpoint(g.db, 0); rc = sqlite3_close(g.db); if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc); } g.db = 0; g.repositoryOpen = 0; g.localOpen = 0; } /* |
︙ | ︙ | |||
3051 3052 3053 3054 3055 3056 3057 | } if( zUser==0 ){ zUser = fossil_getenv("USERNAME"); } if( zUser==0 ){ zUser = "root"; } | < | | | | < | 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 | } if( zUser==0 ){ zUser = fossil_getenv("USERNAME"); } if( zUser==0 ){ zUser = "root"; } db_multi_exec( "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser ); db_multi_exec( "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))" " WHERE login=%Q", zUser ); if( !setupUserOnly ){ db_multi_exec( "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('nobody','','gjorz','Nobody');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('developer','','dei','Dev');" "INSERT OR IGNORE INTO user(login,pw,cap,info)" " VALUES('reader','','kptw','Reader');" ); } } /* ** Return a pointer to a string that contains the RHS of an IN operator ** that will select CONFIG table names that are in the list of control ** settings. */ |
︙ | ︙ | |||
3123 3124 3125 3126 3127 3128 3129 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ const char *zDefaultUser /* Default user for the repository */ ){ char *zDate; Blob hash; Blob manifest; | < | 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ const char *zDefaultUser /* Default user for the repository */ ){ char *zDate; Blob hash; Blob manifest; db_set("content-schema", CONTENT_SCHEMA, 0); db_set("aux-schema", AUX_SCHEMA_MAX, 0); db_set("rebuilt", get_version(), 0); db_set("admin-log", "1", 0); db_set("access-log", "1", 0); db_multi_exec( "INSERT INTO config(name,value,mtime)" |
︙ | ︙ | |||
3182 3183 3184 3185 3186 3187 3188 | " mtime = (SELECT u2.mtime FROM settingSrc.user u2" " WHERE u2.login = user.login)," " photo = (SELECT u2.photo FROM settingSrc.user u2" " WHERE u2.login = user.login)" " WHERE user.login IN ('anonymous','nobody','developer','reader');" ); } | < | 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 | " mtime = (SELECT u2.mtime FROM settingSrc.user u2" " WHERE u2.login = user.login)," " photo = (SELECT u2.photo FROM settingSrc.user u2" " WHERE u2.login = user.login)" " WHERE user.login IN ('anonymous','nobody','developer','reader');" ); } if( zInitialDate ){ int rid; blob_zero(&manifest); blob_appendf(&manifest, "C initial\\sempty\\scheck-in\n"); zDate = date_in_standard_format(zInitialDate); blob_appendf(&manifest, "D %s\n", zDate); |
︙ | ︙ | |||
3207 3208 3209 3210 3211 3212 3213 | blob_reset(&hash); rid = content_put(&manifest); manifest_crosslink(rid, &manifest, MC_NONE); } } /* | | | 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 | blob_reset(&hash); rid = content_put(&manifest); manifest_crosslink(rid, &manifest, MC_NONE); } } /* ** COMMAND: new* ** COMMAND: init ** ** Usage: %fossil new ?OPTIONS? FILENAME ** or: %fossil init ?OPTIONS? FILENAME ** ** Create a repository for a new project in the file named FILENAME. ** This command is distinct from "clone". The "clone" command makes |
︙ | ︙ | |||
3232 3233 3234 3235 3236 3237 3238 | ** page, either directly or indirectly, will be copied. Normal users and ** their associated permissions will not be copied; however, the system ** default users "anonymous", "nobody", "reader", "developer", and their ** associated permissions will be copied. ** ** Options: ** --template FILE Copy settings from repository file | | | < < < < | < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < | | 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 | ** page, either directly or indirectly, will be copied. Normal users and ** their associated permissions will not be copied; however, the system ** default users "anonymous", "nobody", "reader", "developer", and their ** associated permissions will be copied. ** ** Options: ** --template FILE Copy settings from repository file ** --admin-user|-A USERNAME Select given USERNAME as admin user ** --date-override DATETIME Use DATETIME as time of the initial check-in ** --sha1 Use a initial hash policy of "sha1" ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. ** ** See also: clone */ void create_repository_cmd(void){ char *zPassword; const char *zTemplate; /* Repository from which to copy settings */ const char *zDate; /* Date of the initial check-in */ const char *zDefaultUser; /* Optional name of the default user */ int bUseSha1 = 0; /* True to set the hash-policy to sha1 */ zTemplate = find_option("template",0,1); zDate = find_option("date-override",0,1); zDefaultUser = find_option("admin-user","A",1); bUseSha1 = find_option("sha1",0,0)!=0; /* We should be done with options.. */ verify_all_options(); if( g.argc!=3 ){ usage("REPOSITORY-NAME"); } if( -1 != file_size(g.argv[2], ExtFILE) ){ fossil_fatal("file already exists: %s", g.argv[2]); } db_create_repository(g.argv[2]); db_open_repository(g.argv[2]); db_open_config(0, 0); if( zTemplate ) db_attach(zTemplate, "settingSrc"); db_begin_transaction(); if( bUseSha1 ){ g.eHashPolicy = HPOLICY_SHA1; db_set_int("hash-policy", HPOLICY_SHA1, 0); } if( zDate==0 ) zDate = "now"; db_initial_setup(zTemplate, zDate, zDefaultUser); db_end_transaction(0); if( zTemplate ) db_detach("settingSrc"); fossil_print("project-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); } /* ** SQL functions for debugging. ** ** The print() function writes its arguments on stdout, but only ** if the -sqlprint command-line option is turned on. */ LOCAL void db_sql_print( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; if( g.fSqlPrint ){ for(i=0; i<argc; i++){ char c = i==argc-1 ? '\n' : ' '; fossil_print("%s%c", sqlite3_value_text(argv[i]), c); } } } LOCAL int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){ sqlite3_stmt *pStmt = (sqlite3_stmt*)pP; char *zSql; int n; const char *zArg = (const char*)pX; if( zArg[0]=='-' ) return 0; zSql = sqlite3_expanded_sql(pStmt); n = (int)strlen(zSql); fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";"); sqlite3_free(zSql); return 0; } /* ** Implement the user() SQL function. user() takes no arguments and ** returns the user ID of the current user. |
︙ | ︙ | |||
3439 3440 3441 3442 3443 3444 3445 | assert( rc==0 || rc==1 ); if( sqlite3_value_type(argv[2-rc])==SQLITE_NULL ) rc = 1-rc; sqlite3_result_value(context, argv[2-rc]); } } /* | < < < < < < < < < < < < < < < < | | 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 | assert( rc==0 || rc==1 ); if( sqlite3_value_type(argv[2-rc])==SQLITE_NULL ) rc = 1-rc; sqlite3_result_value(context, argv[2-rc]); } } /* ** Convert the input string into a artifact hash. Make a notation in the ** CONCEALED table so that the hash can be undo using the db_reveal() ** function at some later time. ** ** The value returned is stored in static space and will be overwritten ** on subsequent calls. ** ** If zContent is already a well-formed artifact hash, then return a copy |
︙ | ︙ | |||
3534 3535 3536 3537 3538 3539 3540 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; } return 0; } /* ** Swap the g.db and g.dbConfig connections so that the various db_* routines | | | | | | 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; } return 0; } /* ** Swap the g.db and g.dbConfig connections so that the various db_* routines ** work on the ~/.fossil database instead of on the repository database. ** Be sure to swap them back after doing the operation. ** ** If the ~/.fossil database has already been opened as the main database or ** is attached to the main database, no connection swaps are required so this ** routine is a no-op. */ void db_swap_connections(void){ /* ** When swapping the main database connection with the config database ** connection, the config database connection must be open (not simply ** attached); otherwise, the swap would end up leaving the main database ** connection invalid, defeating the very purpose of this routine. This |
︙ | ︙ | |||
3590 3591 3592 3593 3594 3595 3596 | while( cacheEntry!=0 ){ if( fossil_strcmp(cacheEntry->zName, zName)==0 ){ zVersionedSetting = fossil_strdup(cacheEntry->zValue); break; } cacheEntry = cacheEntry->next; } | | | 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 | while( cacheEntry!=0 ){ if( fossil_strcmp(cacheEntry->zName, zName)==0 ){ zVersionedSetting = fossil_strdup(cacheEntry->zValue); break; } cacheEntry = cacheEntry->next; } /* Attempt to read value from file in checkout if there wasn't a cache hit. */ if( cacheEntry==0 ){ Blob versionedPathname; Blob setting; blob_zero(&versionedPathname); blob_zero(&setting); blob_appendf(&versionedPathname, "%s.fossil-settings/%s", g.zLocalRoot, zName); |
︙ | ︙ | |||
3629 3630 3631 3632 3633 3634 3635 | blob_append(&versionedPathname, ".no-warn", -1); if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ noWarn = 1; } } blob_reset(&versionedPathname); if( found ){ | < | 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 | blob_append(&versionedPathname, ".no-warn", -1); if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ noWarn = 1; } } blob_reset(&versionedPathname); if( found ){ blob_trim(&setting); /* Avoid non-obvious problems with line endings ** on boolean properties */ zVersionedSetting = fossil_strdup(blob_str(&setting)); } blob_reset(&setting); /* Store result in cache, which can be the value or 0 if not found */ cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry)); |
︙ | ︙ | |||
3675 3676 3677 3678 3679 3680 3681 | ** setting is returned instead. If zName is a versioned setting, then ** versioned value takes priority. */ char *db_get(const char *zName, const char *zDefault){ char *z = 0; const Setting *pSetting = db_find_setting(zName, 0); if( g.repositoryOpen ){ | < < | < < < | < < < < | < < < < < | < < < < | < < < < < < < < < < < < < < < < | | < | < | < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 | ** setting is returned instead. If zName is a versioned setting, then ** versioned value takes priority. */ char *db_get(const char *zName, const char *zDefault){ char *z = 0; const Setting *pSetting = db_find_setting(zName, 0); if( g.repositoryOpen ){ z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName); } if( z==0 && g.zConfigDbName ){ db_swap_connections(); z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } if( pSetting!=0 && pSetting->versionable ){ /* This is a versionable setting, try and get the info from a ** checked out file */ z = db_get_versioned(zName, z); } if( z==0 ){ if( zDefault==0 && pSetting && pSetting->def[0] ){ z = fossil_strdup(pSetting->def); }else{ z = fossil_strdup(zDefault); } } return z; } char *db_get_mtime(const char *zName, const char *zFormat, const char *zDefault){ char *z = 0; if( g.repositoryOpen ){ z = db_text(0, "SELECT mtime FROM config WHERE name=%Q", zName); } if( z==0 ){ z = fossil_strdup(zDefault); }else if( zFormat!=0 ){ z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z); } return z; } void db_set(const char *zName, const char *zValue, int globalFlag){ db_begin_transaction(); if( globalFlag ){ db_swap_connections(); db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", zName, zValue); db_swap_connections(); }else{ db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", zName, zValue); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_end_transaction(0); } void db_unset(const char *zName, int globalFlag){ db_begin_transaction(); if( globalFlag ){ db_swap_connections(); db_multi_exec("DELETE FROM global_config WHERE name=%Q", zName); db_swap_connections(); }else{ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } db_end_transaction(0); } int db_is_global(const char *zName){ int rc = 0; if( g.zConfigDbName ){ db_swap_connections(); rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName); db_swap_connections(); } return rc; } int db_get_int(const char *zName, int dflt){ int v = dflt; int rc; if( g.repositoryOpen ){ Stmt q; db_prepare(&q, "SELECT value FROM config WHERE name=%Q", zName); rc = db_step(&q); if( rc==SQLITE_ROW ){ v = db_column_int(&q, 0); } db_finalize(&q); }else{ rc = SQLITE_DONE; } if( rc==SQLITE_DONE && g.zConfigDbName ){ db_swap_connections(); v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } return v; } void db_set_int(const char *zName, int value, int globalFlag){ if( globalFlag ){ db_swap_connections(); db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", zName, value); db_swap_connections(); }else{ db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%d,now())", zName, value); } if( globalFlag && g.repositoryOpen ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } } int db_get_boolean(const char *zName, int dflt){ char *zVal = db_get(zName, dflt ? "on" : "off"); if( is_truth(zVal) ) return 1; if( is_false(zVal) ) return 0; return dflt; } int db_get_versioned_boolean(const char *zName, int dflt){ char *zVal = db_get_versioned(zName, 0); if( zVal==0 ) return dflt; if( is_truth(zVal) ) return 1; if( is_false(zVal) ) return 0; return dflt; } char *db_lget(const char *zName, const char *zDefault){ return db_text(zDefault, "SELECT value FROM vvar WHERE name=%Q", zName); } void db_lset(const char *zName, const char *zValue){ db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%Q)", zName, zValue); } int db_lget_int(const char *zName, int dflt){ return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName); } void db_lset_int(const char *zName, int value){ db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value); } /* Va-args versions of db_get(), db_set(), and db_unset() */ char *db_get_mprintf(const char *zDefault, const char *zFormat, ...){ va_list ap; char *zName; char *zResult; va_start(ap, zFormat); zName = vmprintf(zFormat, ap); va_end(ap); zResult = db_get(zName, zDefault); fossil_free(zName); return zResult; } void db_set_mprintf(const char *zNew, int iGlobal, const char *zFormat, ...){ va_list ap; char *zName; va_start(ap, zFormat); zName = vmprintf(zFormat, ap); va_end(ap); db_set(zName, zNew, iGlobal); fossil_free(zName); } void db_unset_mprintf(int iGlobal, const char *zFormat, ...){ va_list ap; char *zName; va_start(ap, zFormat); zName = vmprintf(zFormat, ap); va_end(ap); db_unset(zName, iGlobal); fossil_free(zName); } #if INTERFACE /* Manifest generation flags */ #define MFESTFLG_RAW 0x01 #define MFESTFLG_UUID 0x02 #define MFESTFLG_TAGS 0x04 #endif /* INTERFACE */ |
︙ | ︙ | |||
4001 4002 4003 4004 4005 4006 4007 | ** The repository filename %s is recorded as an entry with a "name" field ** of the following form: ** ** repo:%s ** ** The value field is set to 1. ** | | | < < < < < | | | < | < < < < < < < < < | > < < < < < < | | < < < | | | < < < < < < < < < < | | < < < < < < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | | | < < < < < < | < < < < < < < < < < < < < < < < < < < | | < < < > > | > > > > | | > | | < < < | < < | | < > | | < > | | | | > > > | < < < < | | | > > > | < | > | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | | | | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 | ** The repository filename %s is recorded as an entry with a "name" field ** of the following form: ** ** repo:%s ** ** The value field is set to 1. ** ** If running from a local checkout, also record the root of the checkout ** as follows: ** ** ckout:%s ** ** Where %s is the checkout root. The value is the repository file. */ void db_record_repository_filename(const char *zName){ char *zRepoSetting; char *zCkoutSetting; Blob full; if( zName==0 ){ if( !g.localOpen ) return; zName = db_repository_filename(); } file_canonical_name(zName, &full, 0); (void)filename_collation(); /* Initialize before connection swap */ db_swap_connections(); zRepoSetting = mprintf("repo:%q", blob_str(&full)); db_multi_exec( "DELETE FROM global_config WHERE name %s = %Q;", filename_collation(), zRepoSetting ); db_multi_exec( "INSERT OR IGNORE INTO global_config(name,value)" "VALUES(%Q,1);", zRepoSetting ); fossil_free(zRepoSetting); if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){ Blob localRoot; file_canonical_name(g.zLocalRoot, &localRoot, 1); zCkoutSetting = mprintf("ckout:%q", blob_str(&localRoot)); db_multi_exec( "DELETE FROM global_config WHERE name %s = %Q;", filename_collation(), zCkoutSetting ); db_multi_exec( "REPLACE INTO global_config(name, value)" "VALUES(%Q,%Q);", zCkoutSetting, blob_str(&full) ); db_swap_connections(); db_optional_sql("repository", "DELETE FROM config WHERE name %s = %Q;", filename_collation(), zCkoutSetting ); db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" "VALUES(%Q,1,now());", zCkoutSetting ); fossil_free(zCkoutSetting); blob_reset(&localRoot); }else{ db_swap_connections(); } blob_reset(&full); } /* ** COMMAND: open ** ** Usage: %fossil open FILENAME ?VERSION? ?OPTIONS? ** ** Open a connection to the local repository in FILENAME. A checkout ** for the repository is created with its root at the working directory. ** If VERSION is specified then that version is checked out. Otherwise ** the latest version is checked out. No files other than "manifest" ** and "manifest.uuid" are modified if the --keep option is present. ** ** Options: ** --empty Initialize checkout as being empty, but still connected ** with the local repository. If you commit this checkout, ** it will become a new "initial" commit in the repository. ** --keep Only modify the manifest and manifest.uuid files ** --nested Allow opening a repository inside an opened checkout ** --force-missing Force opening a repository with missing content ** ** See also: close */ void cmd_open(void){ int emptyFlag; int keepFlag; int forceMissingFlag; int allowNested; int allowSymlinks; static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 }; url_proxy_options(); emptyFlag = find_option("empty",0,0)!=0; keepFlag = find_option("keep",0,0)!=0; forceMissingFlag = find_option("force-missing",0,0)!=0; allowNested = find_option("nested",0,0)!=0; /* We should be done with options.. */ verify_all_options(); if( g.argc!=3 && g.argc!=4 ){ usage("REPOSITORY-FILENAME ?VERSION?"); } if( !allowNested && db_open_local(0) ){ fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot); } db_open_repository(g.argv[2]); /* Figure out which revision to open. */ if( !emptyFlag ){ if( g.argc==4 ){ g.zOpenRevision = g.argv[3]; }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){ g.zOpenRevision = db_get("main-branch", "trunk"); } } if( g.zOpenRevision ){ /* Since the repository is open and we know the revision now, ** refresh the allow-symlinks flag. Since neither the local ** checkout nor the configuration database are open at this ** point, this should always return the versioned setting, ** if any, or the default value, which is negative one. The ** value negative one, in this context, means that the code ** below should fallback to using the setting value from the ** repository or global configuration databases only. */ allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1); }else{ allowSymlinks = -1; /* Use non-versioned settings only. */ } #if defined(_WIN32) || defined(__CYGWIN__) # define LOCALDB_NAME "./_FOSSIL_" #else # define LOCALDB_NAME "./.fslckout" #endif db_init_database(LOCALDB_NAME, zLocalSchema, #ifdef FOSSIL_LOCAL_WAL "COMMIT; PRAGMA journal_mode=WAL; BEGIN;", #endif (char*)0); db_delete_on_failure(LOCALDB_NAME); db_open_local(0); if( allowSymlinks>=0 ){ /* Use the value from the versioned setting, which was read ** prior to opening the local checkout (i.e. which is most ** likely empty and does not actually contain any versioned ** setting files yet). Normally, this value would be given ** first priority within db_get_boolean(); however, this is ** a special case because we know the on-disk files may not ** exist yet. */ g.allowSymlinks = allowSymlinks; }else{ /* Since the local checkout may not have any files at this ** point, this will probably be the setting value from the ** repository or global configuration databases. */ g.allowSymlinks = db_get_boolean("allow-symlinks", db_allow_symlinks_by_default()); } db_lset("repository", g.argv[2]); db_record_repository_filename(g.argv[2]); db_lset_int("checkout", 0); azNewArgv[0] = g.argv[0]; g.argv = azNewArgv; if( !emptyFlag ){ g.argc = 3; if( g.zOpenRevision ){ azNewArgv[g.argc-1] = g.zOpenRevision; }else{ azNewArgv[g.argc-1] = "--latest"; } if( keepFlag ){ azNewArgv[g.argc++] = "--keep"; } if( forceMissingFlag ){ azNewArgv[g.argc++] = "--force-missing"; } checkout_cmd(); } g.argc = 2; info_cmd(); } /* ** Print the current value of a setting identified by the pSetting ** pointer. */ void print_setting(const Setting *pSetting){ Stmt q; if( g.repositoryOpen ){ db_prepare(&q, "SELECT '(local)', value FROM config WHERE name=%Q" " UNION ALL " "SELECT '(global)', value FROM global_config WHERE name=%Q", pSetting->name, pSetting->name ); }else{ db_prepare(&q, "SELECT '(global)', value FROM global_config WHERE name=%Q", pSetting->name ); } if( db_step(&q)==SQLITE_ROW ){ fossil_print("%-20s %-8s %s\n", pSetting->name, db_column_text(&q, 0), db_column_text(&q, 1)); }else{ fossil_print("%-20s\n", pSetting->name); } if( pSetting->versionable && g.localOpen ){ /* Check to see if this is overridden by a versionable settings file */ Blob versionedPathname; blob_zero(&versionedPathname); blob_appendf(&versionedPathname, "%s.fossil-settings/%s", g.zLocalRoot, pSetting->name); if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", pSetting->name); } } db_finalize(&q); } #if INTERFACE /* ** Define all settings, which can be controlled via the set/unset ** command. ** ** var is the name of the internal configuration name for db_(un)set. ** If var is 0, the settings name is used. ** ** width is the length for the edit field on the behavior page, 0 ** is used for on/off checkboxes. ** ** The behaviour page doesn't use a special layout. It lists all ** set-commands and displays the 'set'-help as info. */ struct Setting { const char *name; /* Name of the setting */ const char *var; /* Internal variable name used by db_set() */ int width; /* Width of display. 0 for boolean values. */ int versionable; /* Is this setting versionable? */ int forceTextArea; /* Force using a text area for display? */ const char *def; /* Default value */ }; #endif /* INTERFACE */ /* ** SETTING: access-log boolean default=off ** ** When the access-log setting is enabled, all login attempts (successful ** and unsuccessful) on the web interface are recorded in the "access" table ** of the repository. */ /* ** SETTING: admin-log boolean default=off ** ** When the admin-log setting is enabled, configuration changes are recorded ** in the "admin_log" table of the repository. */ #if defined(_WIN32) /* ** SETTING: allow-symlinks boolean default=off versionable ** ** When allow-symlinks is OFF, symbolic links in the repository are followed ** and treated no differently from real files. When allow-symlinks is ON, ** the object to which the symbolic link points is ignored, and the content ** of the symbolic link that is stored in the repository is the name of the ** object to which the symbolic link points. */ #endif #if !defined(_WIN32) /* ** SETTING: allow-symlinks boolean default=on versionable ** ** When allow-symlinks is OFF, symbolic links in the repository are followed ** and treated no differently from real files. When allow-symlinks is ON, ** the object to which the symbolic link points is ignored, and the content ** of the symbolic link that is stored in the repository is the name of the ** object to which the symbolic link points. */ #endif /* ** SETTING: auto-captcha boolean default=on variable=autocaptcha ** If enabled, the /login page provides a button that will automatically ** fill in the captcha password. This makes things easier for human users, ** at the expense of also making logins easier for malicious robots. */ /* ** SETTING: auto-hyperlink boolean default=on ** Use javascript to enable hyperlinks on web pages ** for all users (regardless of the "h" privilege) if the ** User-Agent string in the HTTP header look like it came ** from real person, not a spider or bot. */ /* ** SETTING: auto-shun boolean default=on ** If enabled, automatically pull the shunning list ** from a server to which the client autosyncs. */ /* ** SETTING: autosync width=16 default=on ** This setting can take either a boolean value or "pullonly" ** If enabled, automatically pull prior to commit ** or update and automatically push after commit or ** tag or branch creation. If the value is "pullonly" ** then only pull operations occur automatically. */ /* ** SETTING: autosync-tries width=16 default=1 ** If autosync is enabled setting this to a value greater ** than zero will cause autosync to try no more than this ** number of attempts if there is a sync failure. */ /* ** SETTING: backoffice-nodelay boolean default=off ** If backoffice-nodelay is true, then the backoffice processing ** will never invoke sleep(). If it has nothing useful to do, ** it simply exits. */ /* ** SETTING: backoffice-logfile width=40 ** If backoffice-logfile is not an empty string and is a valid ** filename, then a one-line message is appended to that file ** every time the backoffice runs. This can be used for debugging, ** to ensure that backoffice is running appropriately. */ /* ** SETTING: binary-glob width=40 versionable block-text ** The VALUE of this setting is a comma or newline-separated list of ** GLOB patterns that should be treated as binary files ** for committing and merging purposes. Example: *.jpg */ #if defined(_WIN32)||defined(__CYGWIN__)||defined(__DARWIN__) /* ** SETTING: case-sensitive boolean default=off ** If TRUE, the files whose names differ only in case ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to |
︙ | ︙ | |||
4547 4548 4549 4550 4551 4552 4553 | ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to ** TRUE for unix and FALSE for Cygwin, Mac and Windows. */ #endif /* ** SETTING: clean-glob width=40 versionable block-text | | > | | < < < < < < < < < < < < < < < < < < < < < < < < | | < | | | < < < < < | | | | | > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > | | > | < | | < < | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < > | | > | | | | | < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < < | | | < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 | ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to ** TRUE for unix and FALSE for Cygwin, Mac and Windows. */ #endif /* ** SETTING: clean-glob width=40 versionable block-text ** The VALUE of this setting is a comma or newline-separated list of GLOB ** patterns specifying files that the "clean" command will ** delete without prompting or allowing undo. ** Example: *.a,*.lib,*.o */ /* ** SETTING: clearsign boolean default=off ** When enabled, fossil will attempt to sign all commits ** with gpg. When disabled, commits will be unsigned. */ /* ** SETTING: crlf-glob width=40 versionable block-text ** The value is a comma or newline-separated list of GLOB patterns for ** text files in which it is ok to have CR, CR+LF or mixed ** line endings. Set to "*" to disable CR+LF checking. ** The crnl-glob setting is a compatibility alias. */ /* ** SETTING: crnl-glob width=40 versionable block-text ** This is an alias for the crlf-glob setting. */ /* ** SETTING: default-perms width=16 default=u ** Permissions given automatically to new users. For more ** information on permissions see the Users page in Server ** Administration of the HTTP UI. */ /* ** SETTING: diff-binary boolean default=on ** If enabled, permit files that may be binary ** or that match the "binary-glob" setting to be used with ** external diff programs. If disabled, skip these files. */ /* ** SETTING: diff-command width=40 ** The value is an external command to run when performing a diff. ** If undefined, the internal text diff will be used. */ /* ** SETTING: dont-push boolean default=off ** If enabled, prevent this repository from pushing from client to ** server. This can be used as an extra precaution to prevent ** accidental pushes to a public server from a private clone. */ /* ** SETTING: dotfiles boolean versionable default=off ** If enabled, include --dotfiles option for all compatible commands. */ /* ** SETTING: editor width=32 ** The value is an external command that will launch the ** text editor command used for check-in comments. */ /* ** SETTING: empty-dirs width=40 versionable block-text ** The value is a comma or newline-separated list of pathnames. On ** update and checkout commands, if no file or directory ** exists with that name, an empty directory will be ** created. */ /* ** SETTING: encoding-glob width=40 versionable block-text ** The value is a comma or newline-separated list of GLOB ** patterns specifying files that the "commit" command will ** ignore when issuing warnings about text files that may ** use another encoding than ASCII or UTF-8. Set to "*" ** to disable encoding checking. */ #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) /* ** SETTING: exec-rel-paths boolean default=on ** When executing certain external commands (e.g. diff and ** gdiff), use relative paths. */ #endif #if !defined(FOSSIL_ENABLE_EXEC_REL_PATHS) /* ** SETTING: exec-rel-paths boolean default=off ** When executing certain external commands (e.g. diff and ** gdiff), use relative paths. */ #endif /* ** SETTING: gdiff-command width=40 default=gdiff ** The value is an external command to run when performing a graphical ** diff. If undefined, text diff will be used. */ /* ** SETTING: gmerge-command width=40 ** The value is a graphical merge conflict resolver command operating ** on four files. Examples: ** ** kdiff3 "%baseline" "%original" "%merge" -o "%output" ** xxdiff "%original" "%baseline" "%merge" -M "%output" ** meld "%baseline" "%original" "%merge" "%output" */ /* ** SETTING: hash-digits width=5 default=10 ** The number of hexadecimal digits of the SHA3 hash to display. */ /* ** SETTING: http-port width=16 default=8080 ** The default TCP/IP port number to use by the "server" ** and "ui" commands. */ /* ** SETTING: https-login boolean default=off ** If true, then the Fossil web server will redirect unencrypted ** login screen requests to HTTPS. */ /* ** SETTING: ignore-glob width=40 versionable block-text ** The value is a comma or newline-separated list of GLOB ** patterns specifying files that the "add", "addremove", ** "clean", and "extras" commands will ignore. ** ** Example: *.log customCode.c notes.txt */ /* ** SETTING: keep-glob width=40 versionable block-text ** The value is a comma or newline-separated list of GLOB ** patterns specifying files that the "clean" command will keep. */ /* ** SETTING: localauth boolean default=off ** If enabled, require that HTTP connections from ** 127.0.0.1 be authenticated by password. If ** false, all HTTP requests from localhost have ** unrestricted access to the repository. */ /* ** SETTING: main-branch width=40 default=trunk ** The value is the primary branch for the project. */ /* ** SETTING: manifest width=5 versionable ** If enabled, automatically create files "manifest" and "manifest.uuid" ** in every checkout. ** ** Optionally use combinations of characters 'r' for "manifest", ** 'u' for "manifest.uuid" and 't' for "manifest.tags". The SQLite ** and Fossil repositories both require manifests. */ /* ** SETTING: max-loadavg width=25 default=0.0 ** Some CPU-intensive web pages (ex: /zip, /tarball, /blame) ** are disallowed if the system load average goes above this ** value. "0.0" means no limit. This only works on unix. ** Only local settings of this value make a difference since ** when running as a web-server, Fossil does not open the ** global configuration database. */ /* ** SETTING: max-upload width=25 default=250000 ** A limit on the size of uplink HTTP requests. */ /* ** SETTING: mtime-changes boolean default=on ** Use file modification times (mtimes) to detect when ** files have been modified. If disabled, all managed files ** are hashed to detect changes, which can be slow for large ** projects. */ #if FOSSIL_ENABLE_LEGACY_MV_RM /* ** SETTING: mv-rm-files boolean default=off ** If enabled, the "mv" and "rename" commands will also move ** the associated files within the checkout -AND- the "rm" ** and "delete" commands will also remove the associated ** files from within the checkout. */ #endif /* ** SETTING: pgp-command width=40 ** Command used to clear-sign manifests at check-in. ** Default value is "gpg --clearsign -o" */ /* ** SETTING: proxy width=32 default=off ** URL of the HTTP proxy. If undefined or "off" then ** the "http_proxy" environment variable is consulted. ** If the http_proxy environment variable is undefined ** then a direct HTTP connection is used. */ /* ** SETTING: relative-paths boolean default=on ** When showing changes and extras, report paths relative ** to the current working directory. */ /* ** SETTING: repo-cksum boolean default=on ** Compute checksums over all files in each checkout as a double-check ** of correctness. Disable this on large repositories for a performance ** improvement. */ /* ** SETTING: self-register boolean default=off ** Allow users to register themselves through the HTTP UI. ** This is useful if you want to see other names than ** "Anonymous" in e.g. ticketing system. On the other hand ** users can not be deleted. */ /* ** SETTING: ssh-command width=40 ** The command used to talk to a remote machine with the "ssh://" protocol. */ /* ** SETTING: ssl-ca-location width=40 ** The full pathname to a file containing PEM encoded ** CA root certificates, or a directory of certificates ** with filenames formed from the certificate hashes as ** required by OpenSSL. ** ** If set, this will override the OS default list of ** OpenSSL CAs. If unset, the default list will be used. ** Some platforms may add additional certificates. ** Checking your platform behaviour is required if the ** exact contents of the CA root is critical for your ** application. */ /* ** SETTING: ssl-identity width=40 ** The full pathname to a file containing a certificate ** and private key in PEM format. Create by concatenating ** the certificate and private key files. ** ** This identity will be presented to SSL servers to ** authenticate this client, in addition to the normal ** password authentication. */ #ifdef FOSSIL_ENABLE_TCL /* ** SETTING: tcl boolean default=off ** If enabled Tcl integration commands will be added to the TH1 ** interpreter, allowing arbitrary Tcl expressions and ** scripts to be evaluated from TH1. Additionally, the Tcl ** interpreter will be able to evaluate arbitrary TH1 ** expressions and scripts. */ /* ** SETTING: tcl-setup width=40 versionable block-text ** This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. */ #endif /* FOSSIL_ENABLE_TCL */ #ifdef FOSSIL_ENABLE_TH1_DOCS /* ** SETTING: th1-docs boolean default=off ** If enabled, this allows embedded documentation files to contain ** arbitrary TH1 scripts that are evaluated on the server. If native ** Tcl integration is also enabled, this setting has the ** potential to allow anybody with check-in privileges to ** do almost anything that the associated operating system ** user account could do. Extreme caution should be used ** when enabling this setting. */ #endif #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** SETTING: th1-hooks boolean default=off ** If enabled, special TH1 commands will be called before and ** after any Fossil command or web page. */ #endif /* ** SETTING: th1-setup width=40 versionable block-text ** This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. */ /* ** SETTING: th1-uri-regexp width=40 versionable block-text ** Specify which URI's are allowed in HTTP requests from ** TH1 scripts. If empty, no HTTP requests are allowed ** whatsoever. */ /* ** SETTING: uv-sync boolean default=off ** If true, automatically send unversioned files as part ** of a "fossil clone" or "fossil sync" command. The ** default is false, in which case the -u option is ** needed to clone or sync unversioned files. */ /* ** SETTING: web-browser width=30 ** A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. */ /* ** Look up a control setting by its name. Return a pointer to the Setting ** object, or NULL if there is no such setting. ** ** If allowPrefix is true, then the Setting returned is the first one for ** which zName is a prefix of the Setting name. |
︙ | ︙ | |||
5070 5071 5072 5073 5074 5075 5076 | ** file exists. ** ** The "unset" command clears a setting. ** ** Settings can have both a "local" repository-only value and "global" value ** that applies to all repositories. The local values are stored in the ** "config" table of the repository and the global values are stored in the | > | | | | | > | < | < < < < < < < < < < | | | < | < < < < < < < < < < | < | 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 | ** file exists. ** ** The "unset" command clears a setting. ** ** Settings can have both a "local" repository-only value and "global" value ** that applies to all repositories. The local values are stored in the ** "config" table of the repository and the global values are stored in the ** $HOME/.fossil file on unix or in the %LOCALAPPDATA%/_fossil file on Windows. ** If both a local and a global value exists for a setting, the local value ** takes precedence. This command normally operates on the local settings. ** Use the --global option to change global settings. ** ** Options: ** --global set or unset the given property globally instead of ** setting or unsetting it for the open repository only. ** ** --exact only consider exact name matches. ** ** See also: configuration */ void setting_cmd(void){ int i; int globalFlag = find_option("global","g",0)!=0; int exactFlag = find_option("exact",0,0)!=0; int unsetFlag = g.argv[1][0]=='u'; int nSetting; const Setting *aSetting = setting_info(&nSetting); find_repository_option(); verify_all_options(); db_open_config(1, 0); if( !globalFlag ){ db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0); } if( !g.repositoryOpen ){ globalFlag = 1; } if( unsetFlag && g.argc!=3 ){ usage("PROPERTY ?-global?"); } if( g.argc==2 ){ for(i=0; i<nSetting; i++){ print_setting(&aSetting[i]); } }else if( g.argc==3 || g.argc==4 ){ const char *zName = g.argv[2]; int n = (int)strlen(zName); const Setting *pSetting = db_find_setting(zName, !exactFlag); if( pSetting==0 ){ fossil_fatal("no such setting: %s", zName); } if( globalFlag && fossil_strcmp(pSetting->name, "manifest")==0 ){ fossil_fatal("cannot set 'manifest' globally"); } if( unsetFlag || g.argc==4 ){ int isManifest = fossil_strcmp(pSetting->name, "manifest")==0; if( n!=strlen(pSetting[0].name) && pSetting[1].name && fossil_strncmp(pSetting[1].name, zName, n)==0 ){ Blob x; int i; blob_init(&x,0,0); for(i=0; pSetting[i].name; i++){ if( fossil_strncmp(pSetting[i].name,zName,n)!=0 ) break; blob_appendf(&x, " %s", pSetting[i].name); } fossil_fatal("ambiguous setting \"%s\" - might be:%s", zName, blob_str(&x)); } if( globalFlag && isManifest ){ fossil_fatal("cannot set 'manifest' globally"); } if( unsetFlag ){ db_unset(pSetting->name, globalFlag); }else{ db_set(pSetting->name, g.argv[3], globalFlag); } if( isManifest && g.localOpen ){ manifest_to_disk(db_lget_int("checkout", 0)); } }else{ while( pSetting->name ){ if( exactFlag ){ if( fossil_strcmp(pSetting->name,zName)!=0 ) break; }else{ if( fossil_strncmp(pSetting->name,zName,n)!=0 ) break; } print_setting(pSetting); pSetting++; } } }else{ usage("?PROPERTY? ?VALUE? ?-global?"); } } |
︙ | ︙ | |||
5221 5222 5223 5224 5225 5226 5227 | double rDiff; if( g.argc!=3 ) usage("TIMESTAMP"); sqlite3_open(":memory:", &g.db); rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]); fossil_print("Time differences: %s\n", db_timespan_name(rDiff)); sqlite3_close(g.db); g.db = 0; | < < | | | | | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 | double rDiff; if( g.argc!=3 ) usage("TIMESTAMP"); sqlite3_open(":memory:", &g.db); rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]); fossil_print("Time differences: %s\n", db_timespan_name(rDiff)); sqlite3_close(g.db); g.db = 0; } /* ** COMMAND: test-without-rowid ** ** Usage: %fossil test-without-rowid FILENAME... ** ** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID ** optimization. FILENAME can also be the ~/.fossil file or a local ** .fslckout or _FOSSIL_ file. ** ** The purpose of this command is for testing the WITHOUT ROWID capabilities ** of SQLite. There is no big advantage to using WITHOUT ROWID in Fossil. ** ** Options: ** --dryrun | -n No changes. Just print what would happen. */ void test_without_rowid(void){ int i, j; Stmt q; Blob allSql; int dryRun = find_option("dry-run", "n", 0)!=0; for(i=2; i<g.argc; i++){ db_open_or_attach(g.argv[i], "main"); blob_init(&allSql, "BEGIN;\n", -1); db_prepare(&q, "SELECT name, sql FROM main.sqlite_master " " WHERE type='table' AND sql NOT LIKE '%%WITHOUT ROWID%%'" " AND name IN ('global_config','shun','concealed','config'," " 'plink','tagxref','backlink','vcache');" ); while( db_step(&q)==SQLITE_ROW ){ const char *zTName = db_column_text(&q, 0); const char *zOrigSql = db_column_text(&q, 1); |
︙ | ︙ | |||
5299 5300 5301 5302 5303 5304 5305 | /* ** Make sure the adminlog table exists. Create it if it does not */ void create_admin_log_table(void){ static int once = 0; if( once ) return; | < | | | | | | | | | | < | 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 | /* ** Make sure the adminlog table exists. Create it if it does not */ void create_admin_log_table(void){ static int once = 0; if( once ) return; once = 1; db_multi_exec( "CREATE TABLE IF NOT EXISTS repository.admin_log(\n" " id INTEGER PRIMARY KEY,\n" " time INTEGER, -- Seconds since 1970\n" " page TEXT, -- path of page\n" " who TEXT, -- User who made the change\n" " what TEXT -- What changed\n" ")" ); } /* ** Write a message into the admin_event table, if admin logging is ** enabled via the admin-log configuration option. */ void admin_log(const char *zFormat, ...){ |
︙ | ︙ | |||
5341 5342 5343 5344 5345 5346 5347 | } /* ** COMMAND: test-database-names ** ** Print the names of the various database files: ** (1) The main repository database | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 | } /* ** COMMAND: test-database-names ** ** Print the names of the various database files: ** (1) The main repository database ** (2) The local checkout database ** (3) The global configuration database */ void test_database_name_cmd(void){ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); fossil_print("Repository database: %s\n", g.zRepositoryName); fossil_print("Local database: %s\n", g.zLocalDbName); fossil_print("Config database: %s\n", g.zConfigDbName); } |
Deleted src/default.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/default_css.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 | // This is the template file for the default CSS for Fossil. Lines // beginning with "//" are stripped out by the pre-processor and never // reach the web browser. // // Each repository skin has skin-specific CSS. The rules contained in this // file are appended to the skin-CSS as required. Each rule is evaluated // separately and is only appended to the final CSS if there is not an // overriding rule with the same selector in the skin-CSS. // div.sidebox { float: right; background-color: white; border-width: medium; border-style: double; margin: 10px; } div.sideboxTitle { display: inline; font-weight: bold; } div.sideboxDescribed { display: inline; font-weight: bold; } span.disabled { color: red; } table.timelineTable { border-spacing: 0px 2px; } .timelineDate { white-space: nowrap; } span.timelineDisabled { font-style: italic; font-size: small; } tr.timelineCurrent { padding: .1em .2em; border: 1px dashed #446979; box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.5); } tr.timelineSelected { padding: .1em .2em; border: 2px solid lightgray; background-color: #ffc; box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.5); } tr.timelineSelected td { border-radius: 0; border-width: 0; } tr.timelineCurrent td { border-radius: 0; border-width: 0; } span.timelineLeaf { font-weight: bold; } span.timelineHistDsp { font-weight: bold; } td.timelineTime { vertical-align: top; text-align: right; white-space: nowrap; } td.timelineGraph { width: 20px; text-align: left; vertical-align: top; } span.timelineCompactComment { cursor: pointer; } span.timelineEllipsis { cursor: pointer; } .timelineModernCell, .timelineColumnarCell, .timelineDetailCell { vertical-align: top; text-align: left; padding: 0.75em; border-radius: 1em; } .timelineModernCell[id], .timelineColumnarCell[id], .timelineDetailCell[id] { background-color: #efefef; } .timelineModernDetail { font-size: 80%; text-align: right; float: right; opacity: 0.75; margin-top: 0.5em; margin-left: 1em; } .tl-canvas { margin: 0 6px 0 10px; } .tl-rail { width: 18px; } .tl-mergeoffset { width: 2px; } .tl-nodemark { margin-top: 5px; } .tl-node { width: 10px; height: 10px; border: 1px solid #000; background: #fff; cursor: pointer; } .tl-node.leaf:after { content: ''; position: absolute; top: 3px; left: 3px; width: 4px; height: 4px; background: #000; } .tl-node.sel:after { content: ''; position: absolute; top: 2px; left: 2px; width: 6px; height: 6px; background: red; } .tl-arrow { width: 0; height: 0; transform: scale(.999); border: 0 solid transparent; } .tl-arrow.u { margin-top: -1px; border-width: 0 3px; border-bottom: 7px solid #000; } .tl-arrow.u.sm { border-bottom: 5px solid #000; } .tl-line { background: #000; width: 2px; } .tl-arrow.merge { height: 1px; border-width: 2px 0; } .tl-arrow.merge.l { border-right: 3px solid #000; } .tl-arrow.merge.r { border-left: 3px solid #000; } .tl-line.merge { width: 1px; } .tl-arrow.warp { margin-left: 1px; border-width: 3px 0; border-left: 7px solid #600000; } .tl-line.warp { background: #600000; } span.tagDsp { font-weight: bold; } span.wikiError { font-weight: bold; color: red; } span.infoTagCancelled { font-weight: bold; text-decoration: line-through; } span.infoTag { font-weight: bold; } span.wikiTagCancelled { text-decoration: line-through; } div.columns { padding: 0 2em 0 2em; max-width: 1000px; } div.columns > ul { margin: 0; padding: 0 0 0 1em; } div.columns > ul li:first-child { margin-top:0px; } .columns li { break-inside: avoid; page-break-inside: avoid; } .filetree { margin: 1em 0; line-height: 1.5; } .filetree > ul { display: inline-block; } .filetree ul { margin: 0; padding: 0; list-style: none; } .filetree ul.collapsed { display: none; } .filetree ul ul { position: relative; margin: 0 0 0 21px; } .filetree li { position: relative; margin: 0; padding: 0; } .filetree li li:before { content: ''; position: absolute; top: -.8em; left: -14px; width: 14px; height: 1.5em; border-left: 2px solid #aaa; border-bottom: 2px solid #aaa; } .filetree li > ul:before { content: ''; position: absolute; top: -1.5em; bottom: 0; left: -35px; border-left: 2px solid #aaa; } .filetree li.last > ul:before { display: none; } .filetree a { position: relative; z-index: 1; display: table-cell; min-height: 16px; padding-left: 21px; background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); background-position: center left; background-repeat: no-repeat; } ul.browser { list-style-type: none; padding: 10px; margin: 0px; white-space: nowrap; } ul.browser li.file { background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); background-repeat: no-repeat; background-position: 0px center; padding-left: 20px; padding-top: 2px; } ul.browser li.dir { background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); background-repeat: no-repeat; background-position: 0px center; padding-left: 20px; padding-top: 2px; } div.filetreeline { display: table; width: 100%; white-space: nowrap; } .filetree .dir > div.filetreeline > a { background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); } div.filetreeage { display: table-cell; padding-left: 3em; text-align: right; } div.filetreeline:hover { background-color: #eee; } table.login_out { text-align: left; margin-right: 10px; margin-left: 10px; margin-top: 10px; } div.captcha { text-align: center; padding: 1ex; } table.captcha { margin: auto; padding: 10px; border-width: 4px; border-style: double; border-color: black; } pre.captcha { font-size: 50%; } td.login_out_label { text-align: center; } span.loginError { color: red; } span.note { font-weight: bold; } span.textareaLabel { font-weight: bold; } table.usetupLayoutTable { outline-style: none; padding: 0; margin: 25px; } td.usetupColumnLayout { vertical-align: top } table.usetupUserList { outline-style: double; outline-width: 1px; padding: 10px; } th.usetupListUser { text-align: right; padding-right: 20px; } th.usetupListCap { text-align: center; padding-right: 15px; } th.usetupListCon { text-align: left; } td.usetupListUser { text-align: right; padding-right: 20px; white-space:nowrap; } td.usetupListCap { text-align: center; padding-right: 15px; } td.usetupListCon { text-align: left } div.ueditCapBox { margin-right: 20px; margin-bottom: 20px; } td.usetupEditLabel { text-align: right; vertical-align: top; white-space: nowrap; } span.ueditInheritNobody { color: green; padding: .2em; } span.ueditInheritDeveloper { color: red; padding: .2em; } span.ueditInheritReader { color: black; padding: .2em; } span.ueditInheritAnonymous { color: blue; padding: .2em; } span.capability { font-weight: bold; } span.usertype { font-weight: bold; } span.usertype:before { content:"'"; } span.usertype:after { content:"'"; } div.selectedText { font-weight: bold; color: blue; background-color: #d5d5ff; border: 1px blue solid; } p.missingPriv { color: blue; } span.wikiruleHead { font-weight: bold; } td.tktDspLabel { text-align: right; } td.tktDspValue { text-align: left; vertical-align: top; background-color: #d0d0d0; } span.tktError { color: red; font-weight: bold; } table.rpteditex { float: right; margin: 0; padding: 0; width: 125px; text-align: center; border-collapse: collapse; border-spacing: 0; } table.report { border-collapse:collapse; border: 1px solid #999; margin: 1em 0 1em 0; cursor: pointer; } td.rpteditex { border-width: thin; border-color: #000000; border-style: solid; } div.endContent { clear: both; } p.generalError { color: red; } p.tktsetupError { color: red; font-weight: bold; } p.xfersetupError { color: red; font-weight: bold; } p.thmainError { color: red; font-weight: bold; } span.thTrace { color: red; } p.reportError { color: red; font-weight: bold; } blockquote.reportError { color: red; font-weight: bold; } p.noMoreShun { color: blue; } p.shunned { color: blue; } span.brokenlink { color: red; } ul.filelist { margin-top: 3px; line-height: 100%; } ul.filelist li { padding-top: 1px; } table.sbsdiffcols { width: 90%; border-spacing: 0; font-size: xx-small; } table.sbsdiffcols td { padding: 0; vertical-align: top; } table.sbsdiffcols pre { margin: 0; padding: 0; border: 0; font-size: inherit; background: inherit; color: inherit; } div.difflncol { padding-right: 1em; text-align: right; color: #a0a0a0; } div.difftxtcol { width: 45em; overflow-x: auto; } div.diffmkrcol { padding: 0 1em; } span.diffchng { background-color: #c0c0ff; } span.diffadd { background-color: #c0ffc0; } span.diffrm { background-color: #ffc8c8; } span.diffhr { display: inline-block; margin: .5em 0 1em; color: #0000ff; } span.diffln { color: #a0a0a0; } span.modpending { color: #b03800; font-style: italic; } pre.th1result { white-space: pre-wrap; word-wrap: break-word; } pre.th1error { white-space: pre-wrap; word-wrap: break-word; color: red; } pre.textPlain { white-space: pre-wrap; word-wrap: break-word; } .statistics-report-graph-line { background-color: #446979; } .statistics-report-table-events th { padding: 0 1em 0 1em; } .statistics-report-table-events td { padding: 0.1em 1em 0.1em 1em; } .statistics-report-row-year { text-align: left; } .statistics-report-week-number-label { text-align: right; font-size: 0.8em; } .statistics-report-week-of-year-list { font-size: 0.8em; } #usetupEditCapability { font-weight: bold; } table.adminLogTable { text-align: left; } .adminLogTable .adminTime { text-align: left; vertical-align: top; white-space: nowrap; } .fileage table { border-spacing: 0; } .fileage tr:hover { background-color: #eee; } .fileage td { vertical-align: top; text-align: left; border-top: 1px solid #ddd; padding-top: 3px; } .fileage td:first-child { white-space: nowrap; } .fileage td:nth-child(2) { padding-left: 1em; padding-right: 1em; } .fileage td:nth-child(3) { word-wrap: break-word; max-width: 50%; } .brlist table { border-spacing: 0; } .brlist table th { text-align: left; padding: 0px 1em 0.5ex 0px; vertical-align: bottom; } .brlist table td { padding: 0px 2em 0px 0px; white-space: nowrap; } th.sort:after { margin-left: .4em; cursor: pointer; text-shadow: 0 0 0 #000; } th.sort.none:after { content: '\2666'; } th.sort.asc:after { content: '\2193'; } th.sort.desc:after { content: '\2191'; } span.snippet>mark { background-color: inherit; font-weight: bold; } div.searchForm { text-align: center; } p.searchEmpty { font-style: italic; } .clutter { display: none; } table.label-value th { vertical-align: top; text-align: right; padding: 0.2ex 1ex; } table.forum_post { margin-top: 1ex; margin-bottom: 1ex; margin-left: 0; margin-right: 0; border-spacing: 0; } span.forum_author { color: #888; font-size: 75%; } span.forum_author::after { content: " | "; } span.forum_age { color: #888; font-size: 85%; } span.forum_buttons { font-size: 85%; } span.forum_buttons::before { color: #888; content: " | "; } span.forum_npost { color: #888; font-size: 75%; } table.forumeditform td { vertical-align: top; border-collapse: collapse; padding: 1px; } div.forum_body p { margin-top: 0; } td.form_label { vertical-align: top; text-align: right; } .debug { background-color: #ffc; border: 2px solid #ff0; } div.forumEdit { border: 1px solid black; padding-left: 1ex; padding-right: 1ex; } div.forumHier, div.forumTime { border: 1px solid black; padding-left: 1ex; padding-right: 1ex; margin-top: 1ex; } div.forumSel { background-color: #cef; } div.forumObs { color: #bbb; } #capabilitySummary { text-align: center; } #capabilitySummary td { padding-left: 3ex; padding-right: 3ex; } #capabilitySummary th { padding-left: 1ex; padding-right: 1ex; } .capsumOff { background-color: #bbb; } .capsumRead { background-color: #bfb; } .capsumWrite { background-color: #ffb; } label { white-space: nowrap; } |
Changes to src/delta.c.
︙ | ︙ | |||
202 203 204 205 206 207 208 | return v; } /* ** Return the number digits in the base-64 representation of a positive integer */ static int digit_count(int v){ | | < | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | return v; } /* ** Return the number digits in the base-64 representation of a positive integer */ static int digit_count(int v){ unsigned int i, x; for(i=1, x=64; v>=x; i++, x <<= 6){} return i; } #ifdef __GNUC__ # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else |
︙ | ︙ | |||
378 379 380 381 382 383 384 | /* Compute the hash table used to locate matching sections in the ** source file. */ nHash = lenSrc/NHASH; collide = fossil_malloc( nHash*2*sizeof(int) ); memset(collide, -1, nHash*2*sizeof(int)); landmark = &collide[nHash]; | | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | /* Compute the hash table used to locate matching sections in the ** source file. */ nHash = lenSrc/NHASH; collide = fossil_malloc( nHash*2*sizeof(int) ); memset(collide, -1, nHash*2*sizeof(int)); landmark = &collide[nHash]; for(i=0; i<lenSrc-NHASH; i+=NHASH){ int hv = hash_once(&zSrc[i]) % nHash; collide[i/NHASH] = landmark[hv]; landmark[hv] = i/NHASH; } /* Begin scanning the target file and generating copy commands and ** literal sections of the delta. */ base = 0; /* We have already generated everything before zOut[base] */ while( base+NHASH<lenOut ){ int iSrc, iBlock; unsigned int bestCnt, bestOfst=0, bestLitsz=0; hash_init(&h, &zOut[base]); i = 0; /* Trying to match a landmark against zOut[base+i] */ bestCnt = 0; while( 1 ){ int hv; |
︙ | ︙ | |||
448 449 450 451 452 453 454 | cnt = j+k+1; litsz = i-k; /* Number of bytes of literal text before the copy */ DEBUG2( printf("MATCH %d bytes at %d: [%s] litsz=%d\n", cnt, ofst, print16(&zSrc[ofst]), litsz); ) /* sz will hold the number of bytes needed to encode the "insert" ** command and the copy command, not counting the "insert" text */ sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3; | | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | cnt = j+k+1; litsz = i-k; /* Number of bytes of literal text before the copy */ DEBUG2( printf("MATCH %d bytes at %d: [%s] litsz=%d\n", cnt, ofst, print16(&zSrc[ofst]), litsz); ) /* sz will hold the number of bytes needed to encode the "insert" ** command and the copy command, not counting the "insert" text */ sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3; if( cnt>=sz && cnt>bestCnt ){ /* Remember this match only if it is the best so far and it ** does not increase the file size */ bestCnt = cnt; bestOfst = iSrc-k; bestLitsz = litsz; DEBUG2( printf("... BEST SO FAR\n"); ) } |
︙ | ︙ | |||
480 481 482 483 484 485 486 | } base += bestCnt; putInt(bestCnt, &zDelta); *(zDelta++) = '@'; putInt(bestOfst, &zDelta); DEBUG2( printf("copy %d bytes from %d\n", bestCnt, bestOfst); ) *(zDelta++) = ','; | | | | | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | } base += bestCnt; putInt(bestCnt, &zDelta); *(zDelta++) = '@'; putInt(bestOfst, &zDelta); DEBUG2( printf("copy %d bytes from %d\n", bestCnt, bestOfst); ) *(zDelta++) = ','; if( bestOfst + bestCnt -1 > lastRead ){ lastRead = bestOfst + bestCnt - 1; DEBUG2( printf("lastRead becomes %d\n", lastRead); ) } bestCnt = 0; break; } /* If we reach this point, it means no match is found so far */ if( base+i+NHASH>=lenOut ){ /* We have reached the end of the file and have not found any ** matches. Do an "insert" for everything that does not match */ putInt(lenOut-base, &zDelta); *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], lenOut-base); zDelta += lenOut-base; base = lenOut; break; } /* Advance the hash by one character. Keep looking for a match */ hash_next(&h, zOut[base+i+NHASH]); i++; } } /* Output a final "insert" record to get all the text at the end of ** the file that does not match anything in the source file. */ if( base<lenOut ){ putInt(lenOut-base, &zDelta); *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], lenOut-base); zDelta += lenOut-base; } /* Output the final checksum record. */ putInt(checksum(zOut, lenOut), &zDelta); |
︙ | ︙ | |||
598 599 600 601 602 603 604 | zDelta++; lenDelta--; DEBUG1( printf("COPY %d from %d\n", cnt, ofst); ) total += cnt; if( total>limit ){ /* ERROR: copy exceeds output file size */ return -1; } | | | | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | zDelta++; lenDelta--; DEBUG1( printf("COPY %d from %d\n", cnt, ofst); ) total += cnt; if( total>limit ){ /* ERROR: copy exceeds output file size */ return -1; } if( ofst+cnt > lenSrc ){ /* ERROR: copy extends past end of input */ return -1; } memcpy(zOut, &zSrc[ofst], cnt); zOut += cnt; break; } case ':': { zDelta++; lenDelta--; total += cnt; if( total>limit ){ /* ERROR: insert command gives an output larger than predicted */ return -1; } DEBUG1( printf("INSERT %d\n", cnt); ) if( cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } memcpy(zOut, zDelta, cnt); zOut += cnt; zDelta += cnt; lenDelta -= cnt; |
︙ | ︙ | |||
687 688 689 690 691 692 693 | zDelta++; lenDelta--; nCopy += cnt; break; } case ':': { zDelta++; lenDelta--; nInsert += cnt; | | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 | zDelta++; lenDelta--; nCopy += cnt; break; } case ':': { zDelta++; lenDelta--; nInsert += cnt; if( cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } zDelta += cnt; lenDelta -= cnt; break; } |
︙ | ︙ |
Changes to src/deltacmd.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 | if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[2]); } if( blob_read_from_file(&target, g.argv[3], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[3]); } blob_delta_create(&orig, &target, &delta); | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[2]); } if( blob_read_from_file(&target, g.argv[3], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[3]); } blob_delta_create(&orig, &target, &delta); if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){ fossil_fatal("cannot write %s", g.argv[4]); } blob_reset(&orig); blob_reset(&target); blob_reset(&delta); } |
︙ | ︙ | |||
141 142 143 144 145 146 147 | *pTarget = out; return len; } /* ** COMMAND: test-delta-apply ** | | | < | | 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 | *pTarget = out; return len; } /* ** COMMAND: test-delta-apply ** ** Usage: %fossil test-delta-apply FILE1 DELTA ** ** Apply DELTA to FILE1 and output the result. */ void delta_apply_cmd(void){ Blob orig, target, delta; if( g.argc!=5 ){ usage("ORIGIN DELTA TARGET"); } if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[2]); } if( blob_read_from_file(&delta, g.argv[3], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[3]); } blob_delta_apply(&orig, &delta, &target); if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){ fossil_fatal("cannot write %s", g.argv[4]); } blob_reset(&orig); blob_reset(&target); blob_reset(&delta); } |
︙ | ︙ |
Deleted src/deltafunc.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/descendants.c.
︙ | ︙ | |||
157 158 159 160 161 162 163 | TAG_CLOSED ); } } /* ** Load the record ID rid and up to |N|-1 closest ancestors into | | < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | < < < < | | 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 | TAG_CLOSED ); } } /* ** Load the record ID rid and up to |N|-1 closest ancestors into ** the "ok" table. If N is zero, no limit. */ void compute_ancestors(int rid, int N, int directOnly){ if( !N ){ N = -1; }else if( N<0 ){ N = -N; } db_multi_exec( "WITH RECURSIVE " " ancestor(rid, mtime) AS (" " SELECT %d, mtime FROM event WHERE objid=%d " " UNION " " SELECT plink.pid, event.mtime" " FROM ancestor, plink, event" " WHERE plink.cid=ancestor.rid" " AND event.objid=plink.pid %s" " ORDER BY mtime DESC LIMIT %d" " )" "INSERT INTO ok" " SELECT rid FROM ancestor;", rid, rid, directOnly ? "AND plink.isPrim" : "", N ); } /* ** Compute all direct ancestors (merge ancestors do not count) ** for the check-in rid and put them in a table named "ancestor". ** Label each generation with consecutive integers going backwards |
︙ | ︙ | |||
291 292 293 294 295 296 297 | static int prevVid = -1; static Stmt q; if( prevVid!=vid ){ prevVid = vid; db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "DELETE FROM ok;"); | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | static int prevVid = -1; static Stmt q; if( prevVid!=vid ){ prevVid = vid; db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "DELETE FROM ok;"); compute_ancestors(vid, 100000000, 1); } db_static_prepare(&q, "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event" " WHERE mlink.mid=event.objid" " AND +mlink.mid IN ok" " AND mlink.fid=:fid"); db_bind_int(&q, ":fid", fid); |
︙ | ︙ | |||
341 342 343 344 345 346 347 | ** ** Usage: %fossil descendants ?CHECKIN? ?OPTIONS? ** ** Find all leaf descendants of the check-in specified or if the argument ** is omitted, of the check-in currently checked out. ** ** Options: | | | | | | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | ** ** Usage: %fossil descendants ?CHECKIN? ?OPTIONS? ** ** Find all leaf descendants of the check-in specified or if the argument ** is omitted, of the check-in currently checked out. ** ** Options: ** -R|--repository FILE Extract info from repository FILE ** -W|--width <num> Width of lines (default is to auto-detect). ** Must be >20 or 0 (= no limit, resulting in a ** single line per entry). ** ** See also: finfo, info, leaves */ void descendants_cmd(void){ Stmt q; int base, width; const char *zWidth; db_find_and_open_repository(0,0); |
︙ | ︙ | |||
380 381 382 383 384 385 386 | compute_leaves(base, 0); db_prepare(&q, "%s" " AND event.objid IN (SELECT rid FROM leaves)" " ORDER BY event.mtime DESC", timeline_query_for_tty() ); | | | | | | | | | | | < | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | compute_leaves(base, 0); db_prepare(&q, "%s" " AND event.objid IN (SELECT rid FROM leaves)" " ORDER BY event.mtime DESC", timeline_query_for_tty() ); print_timeline(&q, 0, width, 0); db_finalize(&q); } /* ** COMMAND: leaves* ** ** Usage: %fossil leaves ?OPTIONS? ** ** Find leaves of all branches. By default show only open leaves. ** The -a|--all flag causes all leaves (closed and open) to be shown. ** The -c|--closed flag shows only closed leaves. ** ** The --recompute flag causes the content of the "leaf" table in the ** repository database to be recomputed. ** ** Options: ** -a|--all show ALL leaves ** --bybranch order output by branch name ** -c|--closed show only closed leaves ** -m|--multiple show only cases with multiple leaves on a single branch ** --recompute recompute the "leaf" table in the repository DB ** -W|--width <num> Width of lines (default is to auto-detect). Must be ** >39 or 0 (= no limit, resulting in a single line per ** entry). ** ** See also: descendants, finfo, info, branch */ void leaves_cmd(void){ Stmt q; Blob sql; int showAll = find_option("all", "a", 0)!=0; int showClosed = find_option("closed", "c", 0)!=0; int recomputeFlag = find_option("recompute",0,0)!=0; int byBranch = find_option("bybranch",0,0)!=0; int multipleFlag = find_option("multiple","m",0)!=0; const char *zWidth = find_option("width","W",1); char *zLastBr = 0; int n, width; char zLineNo[10]; if( multipleFlag ) byBranch = 1; if( zWidth ){ width = atoi(zWidth); if( (width!=0) && (width<=39) ){ fossil_fatal("-W|--width value must be >39 or 0"); } |
︙ | ︙ | |||
490 491 492 493 494 495 496 | blob_reset(&sql); n = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zId = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); const char *zCom = db_column_text(&q, 3); const char *zBr = db_column_text(&q, 7); | | < < < < < < < < < < < | < | < < < < < < < < < < < < < < | < < < < < | | | < < < < | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | blob_reset(&sql); n = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zId = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); const char *zCom = db_column_text(&q, 3); const char *zBr = db_column_text(&q, 7); char *z; if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){ fossil_print("*** %s ***\n", zBr); fossil_free(zLastBr); zLastBr = fossil_strdup(zBr); if( multipleFlag ) n = 0; } n++; sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n); fossil_print("%6s ", zLineNo); z = mprintf("%s [%S] %s", zDate, zId, zCom); comment_print(z, zCom, 7, width, g.comFmtFlags); fossil_free(z); } fossil_free(zLastBr); db_finalize(&q); } /* ** WEBPAGE: leaves ** ** Show leaf check-ins in a timeline. By default only open leaves ** are listed. ** ** A "leaf" is a check-in with no children in the same branch. A ** "closed leaf" is a leaf that has a "closed" tag. An "open leaf" ** is a leaf without a "closed" tag. ** ** Query parameters: ** ** all Show all leaves ** closed Show only closed leaves */ void leaves_page(void){ Blob sql; Stmt q; int showAll = P("all")!=0; int showClosed = P("closed")!=0; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( !showAll ){ style_submenu_element("All", "leaves?all"); } if( !showClosed ){ style_submenu_element("Closed", "leaves?closed"); } if( showClosed || showAll ){ style_submenu_element("Open", "leaves"); } style_header("Leaves"); login_anonymous_available(); #if 0 style_sidebox_begin("Nomenclature:", "33%"); @ <ol> @ <li> A <div class="sideboxDescribed">leaf</div> @ is a check-in with no descendants in the same branch.</li> @ <li> An <div class="sideboxDescribed">open leaf</div> @ is a leaf that does not have a "closed" tag |
︙ | ︙ | |||
609 610 611 612 613 614 615 | blob_append(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND blob.rid IN leaf"); if( showClosed ){ blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid")); }else if( !showAll ){ blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); } | < < < < < < < < < < < < < | | | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | blob_append(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND blob.rid IN leaf"); if( showClosed ){ blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid")); }else if( !showAll ){ blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); } db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_sql_text(&sql)); blob_reset(&sql); www_print_timeline(&q, TIMELINE_LEAFONLY, 0, 0, 0, 0); db_finalize(&q); @ <br /> style_footer(); } #if INTERFACE /* Flag parameters to compute_uses_file() */ #define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */ #endif |
︙ | ︙ |
Changes to src/diff.c.
1 2 3 4 5 6 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) | | < > > | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | | < < < < < | 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 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to compute a "diff" between two ** text files. */ #include "config.h" #include "diff.h" #include <assert.h> #if INTERFACE /* ** Flag parameters to the text_diff() routine used to control the formatting ** of the diff output. */ #define DIFF_CONTEXT_MASK ((u64)0x0000ffff) /* Lines of context. Default if 0 */ #define DIFF_WIDTH_MASK ((u64)0x00ff0000) /* side-by-side column width */ #define DIFF_IGNORE_EOLWS ((u64)0x01000000) /* Ignore end-of-line whitespace */ #define DIFF_IGNORE_ALLWS ((u64)0x03000000) /* Ignore all whitespace */ #define DIFF_SIDEBYSIDE ((u64)0x04000000) /* Generate a side-by-side diff */ #define DIFF_VERBOSE ((u64)0x08000000) /* Missing shown as empty files */ #define DIFF_BRIEF ((u64)0x10000000) /* Show filenames only */ #define DIFF_HTML ((u64)0x20000000) /* Render for HTML */ #define DIFF_LINENO ((u64)0x40000000) /* Show line numbers */ #define DIFF_NUMSTAT ((u64)0x80000000) /* Show line count of changes */ #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */ #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */ #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */ #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */ #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */ /* ** These error messages are shared in multiple locations. They are defined ** here for consistency. */ #define DIFF_CANNOT_COMPUTE_BINARY \ "cannot compute difference between binary files\n" #define DIFF_CANNOT_COMPUTE_SYMLINK \ "cannot compute difference between symlink and regular file\n" #define DIFF_TOO_MANY_CHANGES \ "more than 10,000 changes\n" #define DIFF_WHITESPACE_ONLY \ "whitespace changes only\n" /* ** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes) */ #define LENGTH_MASK_SZ 13 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) #endif /* INTERFACE */ /* ** Information about each line of a file being diffed. ** ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length ** of the line. If any line is longer than LENGTH_MASK characters, ** the file is considered binary. */ typedef struct DLine DLine; struct DLine { const char *z; /* The text of the line */ unsigned int h; /* Hash of the line */ unsigned short indent; /* Indent of the line. Only !=0 with -w/-Z option */ unsigned short n; /* number of bytes */ unsigned int iNext; /* 1+(Index of next line with same the same hash) */ /* an array of DLine elements serves two purposes. The fields ** above are one per line of input text. But each entry is also ** a bucket in a hash table, as follows: */ unsigned int iHash; /* 1+(first entry in the hash chain) */ }; /* ** Length of a dline */ #define LENGTH(X) ((X)->n) /* ** A context for running a raw diff. ** ** The aEdit[] array describes the raw diff. Each triple of integers in ** aEdit[] means: ** ** (1) COPY: Number of lines aFrom and aTo have in common |
︙ | ︙ | |||
172 173 174 175 176 177 178 | int *aEdit; /* Array of copy/delete/insert triples */ int nEdit; /* Number of integers (3x num of triples) in aEdit[] */ int nEditAlloc; /* Space allocated for aEdit[] */ DLine *aFrom; /* File on left side of the diff */ int nFrom; /* Number of lines in aFrom[] */ DLine *aTo; /* File on right side of the diff */ int nTo; /* Number of lines in aTo[] */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | int *aEdit; /* Array of copy/delete/insert triples */ int nEdit; /* Number of integers (3x num of triples) in aEdit[] */ int nEditAlloc; /* Space allocated for aEdit[] */ DLine *aFrom; /* File on left side of the diff */ int nFrom; /* Number of lines in aFrom[] */ DLine *aTo; /* File on right side of the diff */ int nTo; /* Number of lines in aTo[] */ int (*same_fn)(const DLine*,const DLine*); /* comparison function */ }; /* ** Count the number of lines in the input string. Include the last line ** in the count even if it lacks the \n terminator. If an empty string ** is specified, the number of lines is zero. For the purposes of this ** function, a string is considered empty if it contains no characters ** -OR- it contains only NUL characters. */ static int count_lines( const char *z, int n, int *pnLine ){ int nLine; const char *zNL, *z2; for(nLine=0, z2=z; (zNL = strchr(z2,'\n'))!=0; z2=zNL+1, nLine++){} |
︙ | ︙ | |||
247 248 249 250 251 252 253 | static DLine *break_into_lines( const char *z, int n, int *pnLine, u64 diffFlags ){ int nLine, i, k, nn, s, x; | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | static DLine *break_into_lines( const char *z, int n, int *pnLine, u64 diffFlags ){ int nLine, i, k, nn, s, x; unsigned int h, h2; DLine *a; const char *zNL; if( count_lines(z, n, &nLine)==0 ){ return 0; } assert( nLine>0 || z[0]=='\0' ); |
︙ | ︙ | |||
276 277 278 279 280 281 282 283 | } a[i].z = z; k = nn; if( diffFlags & DIFF_STRIP_EOLCR ){ if( k>0 && z[k-1]=='\r' ){ k--; } } a[i].n = k; if( diffFlags & DIFF_IGNORE_EOLWS ){ | > | | < < | | > < < | | < > < < < > | | | < | | > | > < < < < | | | | | | | | | > > | > > > > > > > > > > > > > | > | | > | > > > | | > | | | | > > | | > | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | } a[i].z = z; k = nn; if( diffFlags & DIFF_STRIP_EOLCR ){ if( k>0 && z[k-1]=='\r' ){ k--; } } a[i].n = k; s = 0; if( diffFlags & DIFF_IGNORE_EOLWS ){ while( k>0 && fossil_isspace(z[k-1]) ){ k--; } } if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ int numws = 0; while( s<k && fossil_isspace(z[s]) ){ s++; } for(h=0, x=s; x<k; x++){ char c = z[x]; if( fossil_isspace(c) ){ ++numws; }else{ h += c; h *= 0x9e3779b1; } } k -= numws; }else{ for(h=0, x=s; x<k; x++){ h += z[x]; h *= 0x9e3779b1; } } a[i].indent = s; a[i].h = h = (h<<LENGTH_MASK_SZ) | (k-s); h2 = h % nLine; a[i].iNext = a[h2].iHash; a[h2].iHash = i+1; z += nn+1; n -= nn+1; i++; }while( zNL[0]!='\0' && zNL[1]!='\0' ); assert( i==nLine ); /* Return results */ *pnLine = nLine; return a; } /* ** Return true if two DLine elements are identical. */ static int same_dline(const DLine *pA, const DLine *pB){ return pA->h==pB->h && memcmp(pA->z,pB->z, pA->h&LENGTH_MASK)==0; } /* ** Return true if two DLine elements are identical, ignoring ** all whitespace. The indent field of pA/pB already points ** to the first non-space character in the string. */ static int same_dline_ignore_allws(const DLine *pA, const DLine *pB){ int a = pA->indent, b = pB->indent; if( pA->h==pB->h ){ while( a<pA->n || b<pB->n ){ if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 0; while( a<pA->n && fossil_isspace(pA->z[a])) ++a; while( b<pB->n && fossil_isspace(pB->z[b])) ++b; } return pA->n-a == pB->n-b; } return 0; } /* ** Return true if the regular expression *pRe matches any of the ** N dlines */ static int re_dline_match( ReCompiled *pRe, /* The regular expression to be matched */ DLine *aDLine, /* First of N DLines to compare against */ int N /* Number of DLines to check */ ){ while( N-- ){ if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){ return 1; } aDLine++; } return 0; } /* ** Append a single line of context-diff output to pOut. */ static void appendDiffLine( Blob *pOut, /* Where to write the line of output */ char cPrefix, /* One of " ", "+", or "-" */ DLine *pLine, /* The line to be output */ int html, /* True if generating HTML. False for plain text */ ReCompiled *pRe /* Colorize only if line matches this Regex */ ){ blob_append(pOut, &cPrefix, 1); if( html ){ if( pRe && re_dline_match(pRe, pLine, 1)==0 ){ cPrefix = ' '; }else if( cPrefix=='+' ){ blob_append(pOut, "<span class=\"diffadd\">", -1); }else if( cPrefix=='-' ){ blob_append(pOut, "<span class=\"diffrm\">", -1); } htmlize_to_blob(pOut, pLine->z, pLine->n); if( cPrefix!=' ' ){ blob_append(pOut, "</span>", -1); } }else{ blob_append(pOut, pLine->z, pLine->n); } blob_append(pOut, "\n", 1); } /* ** Add two line numbers to the beginning of an output line for a context ** diff. One or the other of the two numbers might be zero, which means ** to leave that number field blank. The "html" parameter means to format ** the output for HTML. */ static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){ if( html ) blob_append(pOut, "<span class=\"diffln\">", -1); if( lnA>0 ){ blob_appendf(pOut, "%6d ", lnA); }else{ blob_append(pOut, " ", 7); } if( lnB>0 ){ blob_appendf(pOut, "%6d ", lnB); }else{ blob_append(pOut, " ", 8); } if( html ) blob_append(pOut, "</span>", -1); } /* ** Given a raw diff p[] in which the p->aEdit[] array has been filled ** in, compute a context diff into pOut. */ static void contextDiff( DContext *p, /* The difference */ Blob *pOut, /* Output a context diff to here */ ReCompiled *pRe, /* Only show changes that match this regex */ u64 diffFlags /* Flags controlling the diff format */ ){ DLine *A; /* Left side of the diff */ DLine *B; /* Right side of the diff */ int a = 0; /* Index of next line in A[] */ int b = 0; /* Index of next line in B[] */ int *R; /* Array of COPY/DELETE/INSERT triples */ int r; /* Index into R[] */ int nr; /* Number of COPY/DELETE/INSERT triples to process */ int mxr; /* Maximum value for r */ int na, nb; /* Number of lines shown from A and B */ int i, j; /* Loop counters */ int m; /* Number of lines to output */ int skip; /* Number of lines to skip */ static int nChunk = 0; /* Number of diff chunks seen so far */ int nContext; /* Number of lines of context */ int showLn; /* Show line numbers */ int html; /* Render as HTML */ int showDivider = 0; /* True to show the divider between diff blocks */ nContext = diff_context_lines(diffFlags); showLn = (diffFlags & DIFF_LINENO)!=0; html = (diffFlags & DIFF_HTML)!=0; A = p->aFrom; B = p->aTo; R = p->aEdit; mxr = p->nEdit; while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } for(r=0; r<mxr; r += 3*nr){ /* Figure out how many triples to show in a single block */ for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){} /* printf("r=%d nr=%d\n", r, nr); */ /* If there is a regex, skip this block (generate no diff output) ** if the regex matches or does not match both insert and delete. ** Only display the block if one side matches but the other side does ** not. */ if( pRe ){ int hideBlock = 1; int xa = a, xb = b; for(i=0; hideBlock && i<nr; i++){ int c1, c2; xa += R[r+i*3]; xb += R[r+i*3]; c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]); c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]); hideBlock = c1==c2; xa += R[r+i*3+1]; xb += R[r+i*3+2]; } if( hideBlock ){ a = xa; b = xb; continue; } } /* For the current block comprising nr triples, figure out ** how many lines of A and B are to be displayed */ if( R[r]>nContext ){ na = nb = nContext; skip = R[r] - nContext; |
︙ | ︙ | |||
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | ** the previous block. */ nChunk++; if( showLn ){ if( !showDivider ){ /* Do not show a top divider */ showDivider = 1; }else{ blob_appendf(pOut, "%.80c\n", '.'); } }else{ /* * If the patch changes an empty file or results in an empty file, * the block header must use 0,0 as position indicator and not 1,0. * Otherwise, patch would be confused and may reject the diff. */ blob_appendf(pOut,"@@ -%d,%d +%d,%d @@", | > > > > | | > | | | | | | | | | | < < < | | < < | > > > | | > | | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | ** the previous block. */ nChunk++; if( showLn ){ if( !showDivider ){ /* Do not show a top divider */ showDivider = 1; }else if( html ){ blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.'); }else{ blob_appendf(pOut, "%.80c\n", '.'); } if( html ) blob_appendf(pOut, "<span id=\"chunk%d\"></span>", nChunk); }else{ if( html ) blob_appendf(pOut, "<span class=\"diffln\">"); /* * If the patch changes an empty file or results in an empty file, * the block header must use 0,0 as position indicator and not 1,0. * Otherwise, patch would be confused and may reject the diff. */ blob_appendf(pOut,"@@ -%d,%d +%d,%d @@", na ? a+skip+1 : 0, na, nb ? b+skip+1 : 0, nb); if( html ) blob_appendf(pOut, "</span>"); blob_append(pOut, "\n", 1); } /* Show the initial common area */ a += skip; b += skip; m = R[r] - skip; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html); appendDiffLine(pOut, ' ', &A[a+j], html, 0); } a += m; b += m; /* Show the differences */ for(i=0; i<nr; i++){ m = R[r+i*3+1]; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html); appendDiffLine(pOut, '-', &A[a+j], html, pRe); } a += m; m = R[r+i*3+2]; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, 0, b+j+1, html); appendDiffLine(pOut, '+', &B[b+j], html, pRe); } b += m; if( i<nr-1 ){ m = R[r+i*3+3]; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html); appendDiffLine(pOut, ' ', &A[a+j], html, 0); } b += m; a += m; } } /* Show the final common area */ assert( nr==i ); m = R[r+nr*3]; if( m>nContext ) m = nContext; for(j=0; j<m; j++){ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html); appendDiffLine(pOut, ' ', &A[a+j], html, 0); } } } /* ** Status of a single output line */ typedef struct SbsLine SbsLine; struct SbsLine { Blob *apCols[5]; /* Array of pointers to output columns */ int width; /* Maximum width of a column in the output */ unsigned char escHtml; /* True to escape html characters */ int iStart; /* Write zStart prior to character iStart */ const char *zStart; /* A <span> tag */ int iEnd; /* Write </span> prior to character iEnd */ int iStart2; /* Write zStart2 prior to character iStart2 */ const char *zStart2; /* A <span> tag */ int iEnd2; /* Write </span> prior to character iEnd2 */ ReCompiled *pRe; /* Only colorize matching lines, if not NULL */ }; /* ** Column indices for SbsLine.apCols[] */ #define SBS_LNA 0 /* Left line number */ #define SBS_TXTA 1 /* Left text */ #define SBS_MKR 2 /* Middle separator column */ #define SBS_LNB 3 /* Right line number */ #define SBS_TXTB 4 /* Right text */ /* ** Append newlines to all columns. */ static void sbsWriteNewlines(SbsLine *p){ int i; for( i=p->escHtml ? SBS_LNA : SBS_TXTB; i<=SBS_TXTB; i++ ){ blob_append(p->apCols[i], "\n", 1); } } /* ** Append n spaces to the column. */ static void sbsWriteSpace(SbsLine *p, int n, int col){ blob_appendf(p->apCols[col], "%*s", n, ""); } /* ** Write the text of pLine into column iCol of p. ** ** If outputting HTML, write the full line. Otherwise, only write the ** width characters. Translate tabs into spaces. Add newlines if col ** is SBS_TXTB. Translate HTML characters if escHtml is true. Pad the ** rendering to width bytes if col is SBS_TXTA and escHtml is false. ** ** This comment contains multibyte unicode characters (ü, Æ, ð) in order ** to test the ability of the diff code to handle such characters. */ static void sbsWriteText(SbsLine *p, DLine *pLine, int col){ Blob *pCol = p->apCols[col]; int n = pLine->n; int i; /* Number of input characters consumed */ int k; /* Cursor position */ int needEndSpan = 0; const char *zIn = pLine->z; int w = p->width; int colorize = p->escHtml; if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){ colorize = 0; } for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){ char c = zIn[i]; if( colorize ){ if( i==p->iStart ){ int x = strlen(p->zStart); blob_append(pCol, p->zStart, x); needEndSpan = 1; if( p->iStart2 ){ p->iStart = p->iStart2; p->zStart = p->zStart2; p->iStart2 = 0; } }else if( i==p->iEnd ){ blob_append(pCol, "</span>", 7); needEndSpan = 0; if( p->iEnd2 ){ p->iEnd = p->iEnd2; p->iEnd2 = 0; } } } if( c=='\t' && !p->escHtml ){ blob_append(pCol, " ", 1); while( (k&7)!=7 && (p->escHtml || k<w) ){ blob_append(pCol, " ", 1); k++; } }else if( c=='\r' || c=='\f' ){ blob_append(pCol, " ", 1); }else if( c=='<' && p->escHtml ){ blob_append(pCol, "<", 4); }else if( c=='&' && p->escHtml ){ blob_append(pCol, "&", 5); }else if( c=='>' && p->escHtml ){ blob_append(pCol, ">", 4); }else if( c=='"' && p->escHtml ){ blob_append(pCol, """, 6); }else{ blob_append(pCol, &zIn[i], 1); if( (c&0xc0)==0x80 ) k--; } } if( needEndSpan ){ blob_append(pCol, "</span>", 7); } if( col==SBS_TXTB ){ sbsWriteNewlines(p); }else if( !p->escHtml ){ sbsWriteSpace(p, w-k, SBS_TXTA); } } /* ** Append a column to the final output blob. */ static void sbsWriteColumn(Blob *pOut, Blob *pCol, int col){ blob_appendf(pOut, "<td><div class=\"diff%scol\">\n" "<pre>\n" "%s" "</pre>\n" "</div></td>\n", (col % 3) ? (col == SBS_MKR ? "mkr" : "txt") : "ln", blob_str(pCol) ); } /* ** Append a separator line to column iCol */ static void sbsWriteSep(SbsLine *p, int len, int col){ char ch = '.'; if( len<1 ){ len = 1; ch = ' '; } blob_appendf(p->apCols[col], "<span class=\"diffhr\">%.*c</span>\n", len, ch); } /* ** Append the appropriate marker into the center column of the diff. */ static void sbsWriteMarker(SbsLine *p, const char *zTxt, const char *zHtml){ blob_append(p->apCols[SBS_MKR], p->escHtml ? zHtml : zTxt, -1); } /* ** Append a line number to the column. */ static void sbsWriteLineno(SbsLine *p, int ln, int col){ if( p->escHtml ){ blob_appendf(p->apCols[col], "%d", ln+1); }else{ char zLn[7]; sqlite3_snprintf(7, zLn, "%5d ", ln+1); blob_appendf(p->apCols[col], "%s ", zLn); } } /* ** The two text segments zLeft and zRight are known to be different on ** both ends, but they might have a common segment in the middle. If ** they do not have a common segment, return 0. If they do have a large ** common segment, return 1 and before doing so set: ** |
︙ | ︙ | |||
568 569 570 571 572 573 574 | static int textLCS( const char *zLeft, int nA, /* String on the left */ const char *zRight, int nB, /* String on the right */ int *aLCS /* Identify bounds of LCS here */ ){ const unsigned char *zA = (const unsigned char*)zLeft; /* left string */ const unsigned char *zB = (const unsigned char*)zRight; /* right string */ | | | | < | > | | < < < < < < < < < | < < < | < | | < > | < < < < < | | > | < < < > | < > | > > > > > > | | > > > > > | < | < < | < < | | | | < < < < < < < < < < | < < < < < < < < < | | | | | > | > > | | > < > | | < | > < < < < < < < | < | < < < < < < < < < < < < | > > > | < < < | | | < < < < < < < | | < | | | | < | < < > > | | < > | < < < | > | > | < > < > > > > < | < | | | < | | > | | | > > > > > > | | > | | | > > | | | | > > > | | | | > | | < | > | > > > | > > > > > > > > > > | | > > > > > > > > | > > | | | | < | < | < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < | < < < < | < | | | < | < < < < | < < < < < < < < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | < | | | | | < > > > > < < < < < < < < < | < < < > | | < < < < > > | | | < < | < < < < < < | > > > | > > > > > > > > > > > > > > > > | < < < < | | > | | | < > > | | | | | | | | > | | | > > | > > > > | > > > > > > > > > > > > > > > | > | | | > | < | > > < > | | > | | < | < < > > > > | < > > | > > > > > > > > > > > > > > > | > > > | | > > > > > > | > > > < | | | | < | < < | < | > > > | > | < < < < | < | | | < < | | < < < | < | | | | | | > > > > > > > > > > > > | | > > > > | > > > > > > | < | > | < | | < < > > | > > > | > > | > > > | < > > > > > | | | | | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 | static int textLCS( const char *zLeft, int nA, /* String on the left */ const char *zRight, int nB, /* String on the right */ int *aLCS /* Identify bounds of LCS here */ ){ const unsigned char *zA = (const unsigned char*)zLeft; /* left string */ const unsigned char *zB = (const unsigned char*)zRight; /* right string */ int nt; /* Number of target points */ int ti[3]; /* Index for start of each 4-byte target */ unsigned int target[3]; /* 4-byte alignment targets */ unsigned int probe; /* probe to compare against target */ int iAS, iAE, iBS, iBE; /* Range of common segment */ int i, j; /* Loop counters */ int rc = 0; /* Result code. 1 for success */ if( nA<6 || nB<6 ) return 0; memset(aLCS, 0, sizeof(int)*4); ti[0] = i = nB/2-2; target[0] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3]; probe = 0; if( nB<16 ){ nt = 1; }else{ ti[1] = i = nB/4-2; target[1] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3]; ti[2] = i = (nB*3)/4-2; target[2] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3]; nt = 3; } probe = (zA[0]<<16) | (zA[1]<<8) | zA[2]; for(i=3; i<nA; i++){ probe = (probe<<8) | zA[i]; for(j=0; j<nt; j++){ if( probe==target[j] ){ iAS = i-3; iAE = i+1; iBS = ti[j]; iBE = ti[j]+4; while( iAE<nA && iBE<nB && zA[iAE]==zB[iBE] ){ iAE++; iBE++; } while( iAS>0 && iBS>0 && zA[iAS-1]==zB[iBS-1] ){ iAS--; iBS--; } if( iAE-iAS > aLCS[1] - aLCS[0] ){ aLCS[0] = iAS; aLCS[1] = iAE; aLCS[2] = iBS; aLCS[3] = iBE; rc = 1; } } } } return rc; } /* ** Try to shift iStart as far as possible to the left. */ static void sbsShiftLeft(SbsLine *p, const char *z){ int i, j; while( (i=p->iStart)>0 && z[i-1]==z[i] ){ for(j=i+1; j<p->iEnd && z[j-1]==z[j]; j++){} if( j<p->iEnd ) break; p->iStart--; p->iEnd--; } } /* ** Simplify iStart and iStart2: ** ** * If iStart is a null-change then move iStart2 into iStart ** * Make sure any null-changes are in canonoical form. ** * Make sure all changes are at character boundaries for ** multi-byte characters. */ static void sbsSimplifyLine(SbsLine *p, const char *z){ if( p->iStart2==p->iEnd2 ){ p->iStart2 = p->iEnd2 = 0; }else if( p->iStart2 ){ while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--; while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++; } if( p->iStart==p->iEnd ){ p->iStart = p->iStart2; p->iEnd = p->iEnd2; p->zStart = p->zStart2; p->iStart2 = 0; p->iEnd2 = 0; } if( p->iStart==p->iEnd ){ p->iStart = p->iEnd = -1; }else if( p->iStart>0 ){ while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--; while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++; } } /* ** Write out lines that have been edited. Adjust the highlight to cover ** only those parts of the line that actually changed. */ static void sbsWriteLineChange( SbsLine *p, /* The SBS output line */ DLine *pLeft, /* Left line of the change */ int lnLeft, /* Line number for the left line */ DLine *pRight, /* Right line of the change */ int lnRight /* Line number of the right line */ ){ int nLeft; /* Length of left line in bytes */ int nRight; /* Length of right line in bytes */ int nShort; /* Shortest of left and right */ int nPrefix; /* Length of common prefix */ int nSuffix; /* Length of common suffix */ const char *zLeft; /* Text of the left line */ const char *zRight; /* Text of the right line */ int nLeftDiff; /* nLeft - nPrefix - nSuffix */ int nRightDiff; /* nRight - nPrefix - nSuffix */ int aLCS[4]; /* Bounds of common middle segment */ static const char zClassRm[] = "<span class=\"diffrm\">"; static const char zClassAdd[] = "<span class=\"diffadd\">"; static const char zClassChng[] = "<span class=\"diffchng\">"; nLeft = pLeft->n; zLeft = pLeft->z; nRight = pRight->n; zRight = pRight->z; nShort = nLeft<nRight ? nLeft : nRight; nPrefix = 0; while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ nPrefix++; } if( nPrefix<nShort ){ while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--; } nSuffix = 0; if( nPrefix<nShort ){ while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ nSuffix++; } if( nSuffix<nShort ){ while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--; } if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; } /* If the prefix and suffix overlap, that means that we are dealing with ** a pure insertion or deletion of text that can have multiple alignments. ** Try to find an alignment to begins and ends on whitespace, or on ** punctuation, rather than in the middle of a name or number. */ if( nPrefix+nSuffix > nShort ){ int iBest = -1; int iBestVal = -1; int i; int nLong = nLeft<nRight ? nRight : nLeft; int nGap = nLong - nShort; for(i=nShort-nSuffix; i<=nPrefix; i++){ int iVal = 0; char c = zLeft[i]; if( fossil_isspace(c) ){ iVal += 5; }else if( !fossil_isalnum(c) ){ iVal += 2; } c = zLeft[i+nGap-1]; if( fossil_isspace(c) ){ iVal += 5; }else if( !fossil_isalnum(c) ){ iVal += 2; } if( iVal>iBestVal ){ iBestVal = iVal; iBest = i; } } nPrefix = iBest; nSuffix = nShort - nPrefix; } /* A single chunk of text inserted on the right */ if( nPrefix+nSuffix==nLeft ){ sbsWriteLineno(p, lnLeft, SBS_LNA); p->iStart2 = p->iEnd2 = 0; p->iStart = p->iEnd = -1; sbsWriteText(p, pLeft, SBS_TXTA); if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){ sbsWriteMarker(p, " ", ""); }else{ sbsWriteMarker(p, " | ", "|"); } sbsWriteLineno(p, lnRight, SBS_LNB); p->iStart = nPrefix; p->iEnd = nRight - nSuffix; p->zStart = zClassAdd; sbsWriteText(p, pRight, SBS_TXTB); return; } /* A single chunk of text deleted from the left */ if( nPrefix+nSuffix==nRight ){ /* Text deleted from the left */ sbsWriteLineno(p, lnLeft, SBS_LNA); p->iStart2 = p->iEnd2 = 0; p->iStart = nPrefix; p->iEnd = nLeft - nSuffix; p->zStart = zClassRm; sbsWriteText(p, pLeft, SBS_TXTA); sbsWriteMarker(p, " | ", "|"); sbsWriteLineno(p, lnRight, SBS_LNB); p->iStart = p->iEnd = -1; sbsWriteText(p, pRight, SBS_TXTB); return; } /* At this point we know that there is a chunk of text that has ** changed between the left and the right. Check to see if there ** is a large unchanged section in the middle of that changed block. */ nLeftDiff = nLeft - nSuffix - nPrefix; nRightDiff = nRight - nSuffix - nPrefix; if( p->escHtml && nLeftDiff >= 6 && nRightDiff >= 6 && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS) ){ sbsWriteLineno(p, lnLeft, SBS_LNA); p->iStart = nPrefix; p->iEnd = nPrefix + aLCS[0]; if( aLCS[2]==0 ){ sbsShiftLeft(p, pLeft->z); p->zStart = zClassRm; }else{ p->zStart = zClassChng; } p->iStart2 = nPrefix + aLCS[1]; p->iEnd2 = nLeft - nSuffix; p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; sbsSimplifyLine(p, zLeft); sbsWriteText(p, pLeft, SBS_TXTA); sbsWriteMarker(p, " | ", "|"); sbsWriteLineno(p, lnRight, SBS_LNB); p->iStart = nPrefix; p->iEnd = nPrefix + aLCS[2]; if( aLCS[0]==0 ){ sbsShiftLeft(p, pRight->z); p->zStart = zClassAdd; }else{ p->zStart = zClassChng; } p->iStart2 = nPrefix + aLCS[3]; p->iEnd2 = nRight - nSuffix; p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; sbsSimplifyLine(p, zRight); sbsWriteText(p, pRight, SBS_TXTB); return; } /* If all else fails, show a single big change between left and right */ sbsWriteLineno(p, lnLeft, SBS_LNA); p->iStart2 = p->iEnd2 = 0; p->iStart = nPrefix; p->iEnd = nLeft - nSuffix; p->zStart = zClassChng; sbsWriteText(p, pLeft, SBS_TXTA); sbsWriteMarker(p, " | ", "|"); sbsWriteLineno(p, lnRight, SBS_LNB); p->iEnd = nRight - nSuffix; sbsWriteText(p, pRight, SBS_TXTB); } /* ** Minimum of two values */ static int minInt(int a, int b){ return a<b ? a : b; } /* ** Return the number between 0 and 100 that is smaller the closer pA and ** pB match. Return 0 for a perfect match. Return 100 if pA and pB are ** completely different. ** ** The current algorithm is as follows: ** ** (1) Remove leading and trailing whitespace. ** (2) Truncate both strings to at most 250 characters ** (3) Find the length of the longest common subsequence ** (4) Longer common subsequences yield lower scores. */ static int match_dline(DLine *pA, DLine *pB){ const char *zA; /* Left string */ const char *zB; /* right string */ int nA; /* Bytes in zA[] */ int nB; /* Bytes in zB[] */ int avg; /* Average length of A and B */ int i, j, k; /* Loop counters */ int best = 0; /* Longest match found so far */ int score; /* Final score. 0..100 */ unsigned char c; /* Character being examined */ unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */ unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */ zA = pA->z; zB = pB->z; nA = pA->n; nB = pB->n; while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; } while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; } while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; } while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; } if( nA>250 ) nA = 250; if( nB>250 ) nB = 250; avg = (nA+nB)/2; if( avg==0 ) return 0; if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; memset(aFirst, 0xff, sizeof(aFirst)); zA--; zB--; /* Make both zA[] and zB[] 1-indexed */ for(i=nB; i>0; i--){ c = (unsigned char)zB[i]; aNext[i] = aFirst[c]; aFirst[c] = i; } best = 0; for(i=1; i<=nA-best; i++){ c = (unsigned char)zA[i]; for(j=aFirst[c]; j<nB-best && memcmp(&zA[i],&zB[j],best)==0; j = aNext[j]){ int limit = minInt(nA-i, nB-j); for(k=best; k<=limit && zA[k+i]==zB[k+j]; k++){} if( k>best ) best = k; } } score = (best>avg) ? 0 : (avg - best)*100/avg; #if 0 fprintf(stderr, "A: [%.*s]\nB: [%.*s]\nbest=%d avg=%d score=%d\n", nA, zA+1, nB, zB+1, best, avg, score); #endif /* Return the result */ return score; } /* ** There is a change block in which nLeft lines of text on the left are ** converted into nRight lines of text on the right. This routine computes ** how the lines on the left line up with the lines on the right. ** ** The return value is a buffer of unsigned characters, obtained from ** fossil_malloc(). (The caller needs to free the return value using ** fossil_free().) Entries in the returned array have values as follows: ** ** 1. Delete the next line of pLeft. ** 2. Insert the next line of pRight. ** 3. The next line of pLeft changes into the next line of pRight. ** 4. Delete one line from pLeft and add one line to pRight. ** ** Values larger than three indicate better matches. ** ** The length of the returned array will be just large enough to cause ** all elements of pLeft and pRight to be consumed. ** ** Algorithm: Wagner's minimum edit-distance algorithm, modified by ** adding a cost to each match based on how well the two rows match ** each other. Insertion and deletion costs are 50. Match costs ** are between 0 and 100 where 0 is a perfect match 100 is a complete ** mismatch. */ static unsigned char *sbsAlignment( DLine *aLeft, int nLeft, /* Text on the left */ DLine *aRight, int nRight, /* Text on the right */ u64 diffFlags /* Flags passed into the original diff */ ){ int i, j, k; /* Loop counters */ int *a; /* One row of the Wagner matrix */ int *pToFree; /* Space that needs to be freed */ unsigned char *aM; /* Wagner result matrix */ int nMatch, iMatch; /* Number of matching lines and match score */ int mnLen; /* MIN(nLeft, nRight) */ int mxLen; /* MAX(nLeft, nRight) */ int aBuf[100]; /* Stack space for a[] if nRight not to big */ aM = fossil_malloc( (nLeft+1)*(nRight+1) ); if( nLeft==0 ){ memset(aM, 2, nRight); return aM; } if( nRight==0 ){ memset(aM, 1, nLeft); return aM; } /* This algorithm is O(N**2). So if N is too big, bail out with a ** simple (but stupid and ugly) result that doesn't take too long. */ mnLen = nLeft<nRight ? nLeft : nRight; if( nLeft*nRight>100000 && (diffFlags & DIFF_SLOW_SBS)==0 ){ memset(aM, 4, mnLen); if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen); return aM; } if( nRight < count(aBuf)-1 ){ pToFree = 0; a = aBuf; }else{ a = pToFree = fossil_malloc( sizeof(a[0])*(nRight+1) ); } /* Compute the best alignment */ for(i=0; i<=nRight; i++){ aM[i] = 2; a[i] = i*50; } aM[0] = 0; for(j=1; j<=nLeft; j++){ int p = a[0]; a[0] = p+50; aM[j*(nRight+1)] = 1; for(i=1; i<=nRight; i++){ int m = a[i-1]+50; int d = 2; if( m>a[i]+50 ){ m = a[i]+50; d = 1; } if( m>p ){ int score = match_dline(&aLeft[j-1], &aRight[i-1]); if( (score<=63 || (i<j+1 && i>j-1)) && m>p+score ){ m = p+score; d = 3 | score*4; } } p = a[i]; a[i] = m; aM[j*(nRight+1)+i] = d; } } /* Compute the lowest-cost path back through the matrix */ i = nRight; j = nLeft; k = (nRight+1)*(nLeft+1)-1; nMatch = iMatch = 0; while( i+j>0 ){ unsigned char c = aM[k]; if( c>=3 ){ assert( i>0 && j>0 ); i--; j--; nMatch++; iMatch += (c>>2); aM[k] = 3; }else if( c==2 ){ assert( i>0 ); i--; }else{ assert( j>0 ); j--; } k--; aM[k] = aM[j*(nRight+1)+i]; } k++; i = (nRight+1)*(nLeft+1) - k; memmove(aM, &aM[k], i); /* If: ** (1) the alignment is more than 25% longer than the longest side, and ** (2) the average match cost exceeds 15 ** Then this is probably an alignment that will be difficult for humans ** to read. So instead, just show all of the right side inserted followed ** by all of the left side deleted. ** ** The coefficients for conditions (1) and (2) above are determined by ** experimentation. */ mxLen = nLeft>nRight ? nLeft : nRight; if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ memset(aM, 4, mnLen); if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen); } /* Return the result */ fossil_free(pToFree); return aM; } /* ** R[] is an array of six integer, two COPY/DELETE/INSERT triples for a ** pair of adjacent differences. Return true if the gap between these ** two differences is so small that they should be rendered as a single ** edit. */ static int smallGap(int *R){ return R[3]<=2 || R[3]<=(R[1]+R[2]+R[4]+R[5])/8; } /* ** Given a diff context in which the aEdit[] array has been filled ** in, compute a side-by-side diff into pOut. */ static void sbsDiff( DContext *p, /* The computed diff */ Blob *pOut, /* Write the results here */ ReCompiled *pRe, /* Only show changes that match this regex */ u64 diffFlags /* Flags controlling the diff */ ){ DLine *A; /* Left side of the diff */ DLine *B; /* Right side of the diff */ int a = 0; /* Index of next line in A[] */ int b = 0; /* Index of next line in B[] */ int *R; /* Array of COPY/DELETE/INSERT triples */ int r; /* Index into R[] */ int nr; /* Number of COPY/DELETE/INSERT triples to process */ int mxr; /* Maximum value for r */ int na, nb; /* Number of lines shown from A and B */ int i, j; /* Loop counters */ int m, ma, mb;/* Number of lines to output */ int skip; /* Number of lines to skip */ static int nChunk = 0; /* Number of chunks of diff output seen so far */ SbsLine s; /* Output line buffer */ int nContext; /* Lines of context above and below each change */ int showDivider = 0; /* True to show the divider */ Blob aCols[5]; /* Array of column blobs */ memset(&s, 0, sizeof(s)); s.width = diff_width(diffFlags); nContext = diff_context_lines(diffFlags); s.escHtml = (diffFlags & DIFF_HTML)!=0; if( s.escHtml ){ for(i=SBS_LNA; i<=SBS_TXTB; i++){ blob_zero(&aCols[i]); s.apCols[i] = &aCols[i]; } }else{ for(i=SBS_LNA; i<=SBS_TXTB; i++){ s.apCols[i] = pOut; } } s.pRe = pRe; s.iStart = -1; s.iStart2 = 0; s.iEnd = -1; A = p->aFrom; B = p->aTo; R = p->aEdit; mxr = p->nEdit; while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } for(r=0; r<mxr; r += 3*nr){ /* Figure out how many triples to show in a single block */ for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){} /* printf("r=%d nr=%d\n", r, nr); */ /* If there is a regex, skip this block (generate no diff output) ** if the regex matches or does not match both insert and delete. ** Only display the block if one side matches but the other side does ** not. */ if( pRe ){ int hideBlock = 1; int xa = a, xb = b; for(i=0; hideBlock && i<nr; i++){ int c1, c2; xa += R[r+i*3]; xb += R[r+i*3]; c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]); c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]); hideBlock = c1==c2; xa += R[r+i*3+1]; xb += R[r+i*3+2]; } if( hideBlock ){ a = xa; b = xb; continue; } } /* For the current block comprising nr triples, figure out ** how many lines of A and B are to be displayed */ if( R[r]>nContext ){ na = nb = nContext; skip = R[r] - nContext; }else{ na = nb = R[r]; skip = 0; } for(i=0; i<nr; i++){ na += R[r+i*3+1]; nb += R[r+i*3+2]; } if( R[r+nr*3]>nContext ){ na += nContext; nb += nContext; }else{ na += R[r+nr*3]; nb += R[r+nr*3]; } for(i=1; i<nr; i++){ na += R[r+i*3]; nb += R[r+i*3]; } /* Draw the separator between blocks */ if( showDivider ){ if( s.escHtml ){ char zLn[10]; sqlite3_snprintf(sizeof(zLn), zLn, "%d", a+skip+1); sbsWriteSep(&s, strlen(zLn), SBS_LNA); sbsWriteSep(&s, s.width, SBS_TXTA); sbsWriteSep(&s, 0, SBS_MKR); sqlite3_snprintf(sizeof(zLn), zLn, "%d", b+skip+1); sbsWriteSep(&s, strlen(zLn), SBS_LNB); sbsWriteSep(&s, s.width, SBS_TXTB); }else{ blob_appendf(pOut, "%.*c\n", s.width*2+16, '.'); } } showDivider = 1; nChunk++; if( s.escHtml ){ blob_appendf(s.apCols[SBS_LNA], "<span id=\"chunk%d\"></span>", nChunk); } /* Show the initial common area */ a += skip; b += skip; m = R[r] - skip; for(j=0; j<m; j++){ sbsWriteLineno(&s, a+j, SBS_LNA); s.iStart = s.iEnd = -1; sbsWriteText(&s, &A[a+j], SBS_TXTA); sbsWriteMarker(&s, " ", ""); sbsWriteLineno(&s, b+j, SBS_LNB); sbsWriteText(&s, &B[b+j], SBS_TXTB); } a += m; b += m; /* Show the differences */ for(i=0; i<nr; i++){ unsigned char *alignment; ma = R[r+i*3+1]; /* Lines on left but not on right */ mb = R[r+i*3+2]; /* Lines on right but not on left */ /* If the gap between the current diff and then next diff within the ** same block is not too great, then render them as if they are a ** single diff. */ while( i<nr-1 && smallGap(&R[r+i*3]) ){ i++; m = R[r+i*3]; ma += R[r+i*3+1] + m; mb += R[r+i*3+2] + m; } alignment = sbsAlignment(&A[a], ma, &B[b], mb, diffFlags); for(j=0; ma+mb>0; j++){ if( alignment[j]==1 ){ /* Delete one line from the left */ sbsWriteLineno(&s, a, SBS_LNA); s.iStart = 0; s.zStart = "<span class=\"diffrm\">"; s.iEnd = LENGTH(&A[a]); sbsWriteText(&s, &A[a], SBS_TXTA); sbsWriteMarker(&s, " <", "<"); sbsWriteNewlines(&s); assert( ma>0 ); ma--; a++; }else if( alignment[j]==3 ){ /* The left line is changed into the right line */ sbsWriteLineChange(&s, &A[a], a, &B[b], b); assert( ma>0 && mb>0 ); ma--; mb--; a++; b++; }else if( alignment[j]==2 ){ /* Insert one line on the right */ if( !s.escHtml ){ sbsWriteSpace(&s, s.width + 7, SBS_TXTA); } sbsWriteMarker(&s, " > ", ">"); sbsWriteLineno(&s, b, SBS_LNB); s.iStart = 0; s.zStart = "<span class=\"diffadd\">"; s.iEnd = LENGTH(&B[b]); sbsWriteText(&s, &B[b], SBS_TXTB); assert( mb>0 ); mb--; b++; }else{ /* Delete from the left and insert on the right */ sbsWriteLineno(&s, a, SBS_LNA); s.iStart = 0; s.zStart = "<span class=\"diffrm\">"; s.iEnd = LENGTH(&A[a]); sbsWriteText(&s, &A[a], SBS_TXTA); sbsWriteMarker(&s, " | ", "|"); sbsWriteLineno(&s, b, SBS_LNB); s.iStart = 0; s.zStart = "<span class=\"diffadd\">"; s.iEnd = LENGTH(&B[b]); sbsWriteText(&s, &B[b], SBS_TXTB); ma--; mb--; a++; b++; } } fossil_free(alignment); if( i<nr-1 ){ m = R[r+i*3+3]; for(j=0; j<m; j++){ sbsWriteLineno(&s, a+j, SBS_LNA); s.iStart = s.iEnd = -1; sbsWriteText(&s, &A[a+j], SBS_TXTA); sbsWriteMarker(&s, " ", ""); sbsWriteLineno(&s, b+j, SBS_LNB); sbsWriteText(&s, &B[b+j], SBS_TXTB); } b += m; a += m; } } /* Show the final common area */ assert( nr==i ); m = R[r+nr*3]; if( m>nContext ) m = nContext; for(j=0; j<m; j++){ sbsWriteLineno(&s, a+j, SBS_LNA); s.iStart = s.iEnd = -1; sbsWriteText(&s, &A[a+j], SBS_TXTA); sbsWriteMarker(&s, " ", ""); sbsWriteLineno(&s, b+j, SBS_LNB); sbsWriteText(&s, &B[b+j], SBS_TXTB); } } if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){ blob_append(pOut, "<table class=\"sbsdiffcols\"><tr>\n", -1); for(i=SBS_LNA; i<=SBS_TXTB; i++){ sbsWriteColumn(pOut, s.apCols[i], i); blob_reset(s.apCols[i]); } blob_append(pOut, "</tr></table>\n", -1); } } /* ** Compute the optimal longest common subsequence (LCS) using an ** exhaustive search. This version of the LCS is only used for ** shorter input strings since runtime is O(N*N) where N is the ** input string length. */ |
︙ | ︙ | |||
2398 2399 2400 2401 2402 2403 2404 | int i, j; /* Loop counters */ int k; /* Length of a candidate subsequence */ int iSXb = iS1; /* Best match so far */ int iSYb = iS2; /* Best match so far */ for(i=iS1; i<iE1-mxLength; i++){ for(j=iS2; j<iE2-mxLength; j++){ | | | | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 | int i, j; /* Loop counters */ int k; /* Length of a candidate subsequence */ int iSXb = iS1; /* Best match so far */ int iSYb = iS2; /* Best match so far */ for(i=iS1; i<iE1-mxLength; i++){ for(j=iS2; j<iE2-mxLength; j++){ if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue; if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){ continue; } k = 1; while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){ k++; } if( k>mxLength ){ iSXb = i; iSYb = j; mxLength = k; } |
︙ | ︙ | |||
2450 2451 2452 2453 2454 2455 2456 | ){ int i, j, k; /* Loop counters */ int n; /* Loop limit */ DLine *pA, *pB; /* Pointers to lines */ int iSX, iSY, iEX, iEY; /* Current match */ int skew = 0; /* How lopsided is the match */ int dist = 0; /* Distance of match from center */ | | < < < < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 | ){ int i, j, k; /* Loop counters */ int n; /* Loop limit */ DLine *pA, *pB; /* Pointers to lines */ int iSX, iSY, iEX, iEY; /* Current match */ int skew = 0; /* How lopsided is the match */ int dist = 0; /* Distance of match from center */ int mid; /* Center of the span */ int iSXb, iSYb, iEXb, iEYb; /* Best match so far */ int iSXp, iSYp, iEXp, iEYp; /* Previous match */ sqlite3_int64 bestScore; /* Best score so far */ sqlite3_int64 score; /* Score for current candidate LCS */ int span; /* combined width of the input sequences */ span = (iE1 - iS1) + (iE2 - iS2); bestScore = -10000; score = 0; iSXb = iSXp = iS1; iEXb = iEXp = iS1; iSYb = iSYp = iS2; iEYb = iEYp = iS2; mid = (iE1 + iS1)/2; for(i=iS1; i<iE1; i++){ int limit = 0; j = p->aTo[p->aFrom[i].h % p->nTo].iHash; while( j>0 && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1])) ){ if( limit++ > 10 ){ j = 0; break; } j = p->aTo[j-1].iNext; } if( j==0 ) continue; assert( i>=iSXb && i>=iSXp ); if( i<iEXb && j>=iSYb && j<iEYb ) continue; if( i<iEXp && j>=iSYp && j<iEYp ) continue; iSX = i; iSY = j-1; pA = &p->aFrom[iSX-1]; pB = &p->aTo[iSY-1]; n = minInt(iSX-iS1, iSY-iS2); for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){} iSX -= k; iSY -= k; iEX = i+1; iEY = j; pA = &p->aFrom[iEX]; pB = &p->aTo[iEY]; n = minInt(iE1-iEX, iE2-iEY); for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){} iEX += k; iEY += k; skew = (iSX-iS1) - (iSY-iS2); if( skew<0 ) skew = -skew; dist = (iSX+iEX)/2 - mid; if( dist<0 ) dist = -dist; score = (iEX - iSX)*(sqlite3_int64)span - (skew + dist); if( score>bestScore ){ bestScore = score; iSXb = iSX; iSYb = iSY; iEXb = iEX; iEYb = iEY; }else if( iEX>iEXp ){ iSXp = iSX; iSYp = iSY; iEXp = iEX; iEYp = iEY; } } if( iSXb==iEXb && (iE1-iS1)*(iE2-iS2)<400 ){ /* If no common sequence is found using the hashing heuristic and ** the input is not too big, use the expensive exact solution */ optimalLCS(p, iS1, iE1, iS2, iE2, piSX, piEX, piSY, piEY); }else{ *piSX = iSXb; *piSY = iSYb; *piEX = iEXb; |
︙ | ︙ | |||
2573 2574 2575 2576 2577 2578 2579 | expandEdit(p, p->nEdit*2 + 15); if( p->aEdit==0 ) return; } p->aEdit[p->nEdit++] = nCopy; p->aEdit[p->nEdit++] = nDel; p->aEdit[p->nEdit++] = nIns; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 | expandEdit(p, p->nEdit*2 + 15); if( p->aEdit==0 ) return; } p->aEdit[p->nEdit++] = nCopy; p->aEdit[p->nEdit++] = nDel; p->aEdit[p->nEdit++] = nIns; } /* ** Do a single step in the difference. Compute a sequence of ** copy/delete/insert steps that will convert lines iS1 through iE1-1 of ** the input into lines iS2 through iE2-1 of the output and write ** that sequence into the difference context. ** |
︙ | ︙ | |||
2720 2721 2722 2723 2724 2725 2726 | appendTriple(p, 0, iE1-iS1, 0); return; } /* Find the longest matching segment between the two sequences */ longestCommonSequence(p, iS1, iE1, iS2, iE2, &iSX, &iEX, &iSY, &iEY); | | < < | 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 | appendTriple(p, 0, iE1-iS1, 0); return; } /* Find the longest matching segment between the two sequences */ longestCommonSequence(p, iS1, iE1, iS2, iE2, &iSX, &iEX, &iSY, &iEY); if( iEX>iSX ){ /* A common segment has been found. ** Recursively diff either side of the matching segment */ diff_step(p, iS1, iSX, iS2, iSY); if( iEX>iSX ){ appendTriple(p, iEX - iSX, 0, 0); } diff_step(p, iEX, iE1, iEY, iE2); |
︙ | ︙ | |||
2758 2759 2760 2761 2762 2763 2764 | */ static void diff_all(DContext *p){ int mnE, iS, iE1, iE2; /* Carve off the common header and footer */ iE1 = p->nFrom; iE2 = p->nTo; | | | | 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 | */ static void diff_all(DContext *p){ int mnE, iS, iE1, iE2; /* Carve off the common header and footer */ iE1 = p->nFrom; iE2 = p->nTo; while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){ iE1--; iE2--; } mnE = iE1<iE2 ? iE1 : iE2; for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){} /* do the difference */ if( iS>0 ){ appendTriple(p, iS, 0, 0); } diff_step(p, iS, iE1, iS, iE2); if( iE1<p->nFrom ){ |
︙ | ︙ | |||
2832 2833 2834 2835 2836 2837 2838 | lnFrom += cpy; lnTo += cpy; /* Shift insertions toward the beginning of the file */ while( cpy>0 && del==0 && ins>0 ){ DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */ DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */ | | | | | | < < | < < | | < < | < < < < < < < | | | < < < < < < < < < < < < < < < < < < < | < | < | < < | | < | | < < | < | > | | | | | | | | | | | | | < < < < | < < < < < < < < < < < < < < < | < < < < < < | < < < < < < | < < | | | | | | | | | | | | | | < < < | | | | < | < < < < < < | < | < < | | | | < | < < < < < < < < < < | | < | < < < < < < < < < < < < < < < < | | | > > > > > > > > > > > > > > > > > > > > > > > | < < < > > | < < | | < < < < < < < < < < < | > < > | < | > < < | > | < | | 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 | lnFrom += cpy; lnTo += cpy; /* Shift insertions toward the beginning of the file */ while( cpy>0 && del==0 && ins>0 ){ DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */ DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */ if( p->same_fn(pTop, pBtm)==0 ) break; if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; lnFrom--; lnTo--; p->aEdit[r]--; p->aEdit[r+3]++; cpy--; } /* Shift insertions toward the end of the file */ while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){ DLine *pTop = &p->aTo[lnTo]; /* First line inserted */ DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */ if( p->same_fn(pTop, pBtm)==0 ) break; if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break; lnFrom++; lnTo++; p->aEdit[r]++; p->aEdit[r+3]--; cpy++; } /* Shift deletions toward the beginning of the file */ while( cpy>0 && del>0 && ins==0 ){ DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */ DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */ if( p->same_fn(pTop, pBtm)==0 ) break; if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; lnFrom--; lnTo--; p->aEdit[r]--; p->aEdit[r+3]++; cpy--; } /* Shift deletions toward the end of the file */ while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){ DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */ DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */ if( p->same_fn(pTop, pBtm)==0 ) break; if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break; lnFrom++; lnTo++; p->aEdit[r]++; p->aEdit[r+3]--; cpy++; } lnFrom += del; lnTo += ins; } } /* ** Extract the number of lines of context from diffFlags. Supply an ** appropriate default if no context width is specified. */ int diff_context_lines(u64 diffFlags){ int n = diffFlags & DIFF_CONTEXT_MASK; if( n==0 && (diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5; return n; } /* ** Extract the width of columns for side-by-side diff. Supply an ** appropriate default if no width is given. */ int diff_width(u64 diffFlags){ int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); if( w==0 ) w = 80; return w; } /* ** Append the error message to pOut. */ void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){ if( diffFlags & DIFF_HTML ){ blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg); }else{ blob_append(pOut, msg, -1); } } /* ** Generate a report of the differences between files pA and pB. ** If pOut is not NULL then a unified diff is appended there. It ** is assumed that pOut has already been initialized. If pOut is ** NULL, then a pointer to an array of integers is returned. ** The integers come in triples. For each triple, ** the elements are the number of lines copied, the number of ** lines deleted, and the number of lines inserted. The vector ** is terminated by a triple of all zeros. ** ** This diff utility does not work on binary files. If a binary ** file is encountered, 0 is returned and pOut is written with ** text "cannot compute difference between binary files". */ int *text_diff( Blob *pA_Blob, /* FROM file */ Blob *pB_Blob, /* TO file */ Blob *pOut, /* Write diff here if not NULL */ ReCompiled *pRe, /* Only output changes where this Regexp matches */ u64 diffFlags /* DIFF_* flags defined above */ ){ int ignoreWs; /* Ignore whitespace */ DContext c; if( diffFlags & DIFF_INVERT ){ Blob *pTemp = pA_Blob; pA_Blob = pB_Blob; pB_Blob = pTemp; } ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0; blob_to_utf8_no_bom(pA_Blob, 0); blob_to_utf8_no_bom(pB_Blob, 0); /* Prepare the input files */ memset(&c, 0, sizeof(c)); if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ c.same_fn = same_dline_ignore_allws; }else{ c.same_fn = same_dline; } c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), &c.nFrom, diffFlags); c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), &c.nTo, diffFlags); if( c.aFrom==0 || c.aTo==0 ){ fossil_free(c.aFrom); fossil_free(c.aTo); if( pOut ){ diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags); } return 0; } /* Compute the difference */ diff_all(&c); if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){ fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags); return 0; } if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){ int i, m, n; int *a = c.aEdit; int mx = c.nEdit; for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; } if( n>10000 ){ fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); return 0; } } if( (diffFlags & DIFF_NOOPT)==0 ){ diff_optimize(&c); } if( pOut ){ if( diffFlags & DIFF_NUMSTAT ){ int nDel = 0, nIns = 0, i; for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){ nDel += c.aEdit[i+1]; nIns += c.aEdit[i+2]; } blob_appendf(pOut, "%10d %10d", nIns, nDel); }else if( diffFlags & DIFF_SIDEBYSIDE ){ sbsDiff(&c, pOut, pRe, diffFlags); }else{ contextDiff(&c, pOut, pRe, diffFlags); } fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); return 0; }else{ /* If a context diff is not requested, then return the ** array of COPY/DELETE/INSERT triples. */ free(c.aFrom); free(c.aTo); return c.aEdit; } } /* ** Process diff-related command-line options and return an appropriate ** "diffFlags" integer. ** ** --brief Show filenames only DIFF_BRIEF ** -c|--context N N lines of context. DIFF_CONTEXT_MASK ** --html Format for HTML DIFF_HTML ** --invert Invert the diff DIFF_INVERT ** -n|--linenum Show line numbers DIFF_LINENO ** --noopt Disable optimization DIFF_NOOPT ** --numstat Show change counts DIFF_NUMSTAT ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR ** --unified Unified diff. ~DIFF_SIDEBYSIDE ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS ** -W|--width N N character lines. DIFF_WIDTH_MASK ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS */ u64 diff_options(void){ u64 diffFlags = 0; const char *z; int f; if( find_option("ignore-trailing-space","Z",0)!=0 ){ diffFlags = DIFF_IGNORE_EOLWS; } if( find_option("ignore-all-space","w",0)!=0 ){ diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ } if( find_option("strip-trailing-cr",0,0)!=0 ){ diffFlags |= DIFF_STRIP_EOLCR; } if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE; if( find_option("yy",0,0)!=0 ){ diffFlags |= DIFF_SIDEBYSIDE | DIFF_SLOW_SBS; } if( find_option("unified",0,0)!=0 ) diffFlags &= ~DIFF_SIDEBYSIDE; if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>=0 ){ if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK; diffFlags |= f + DIFF_CONTEXT_EX; } if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){ f *= DIFF_CONTEXT_MASK+1; if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK; diffFlags |= f; } if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML; if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO; if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT; if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT; if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT; if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF; return diffFlags; } /* ** COMMAND: test-rawdiff ** ** Usage: %fossil test-rawdiff FILE1 FILE2 ** ** Show a minimal sequence of Copy/Delete/Insert operations needed to convert ** FILE1 into FILE2. This command is intended for use in testing and debugging ** the built-in difference engine of Fossil. */ void test_rawdiff_cmd(void){ Blob a, b; int r; int i; int *R; u64 diffFlags = diff_options(); if( g.argc<4 ) usage("FILE1 FILE2 ..."); blob_read_from_file(&a, g.argv[2], ExtFILE); for(i=3; i<g.argc; i++){ if( i>3 ) fossil_print("-------------------------------\n"); blob_read_from_file(&b, g.argv[i], ExtFILE); R = text_diff(&a, &b, 0, 0, diffFlags); for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); } /* free(R); */ blob_reset(&b); } } /* ** COMMAND: test-diff ** ** Usage: %fossil [options] FILE1 FILE2 ** ** Print the difference between two files. The usual diff options apply. */ void test_diff_cmd(void){ Blob a, b, out; u64 diffFlag; const char *zRe; /* Regex filter for diff output */ ReCompiled *pRe = 0; /* Regex filter for diff output */ if( find_option("tk",0,0)!=0 ){ diff_tk("test-diff", 2); return; } find_option("i",0,0); find_option("v",0,0); zRe = find_option("regexp","e",1); if( zRe ){ const char *zErr = re_compile(&pRe, zRe, 0); if( zErr ) fossil_fatal("regex error: %s", zErr); } diffFlag = diff_options(); verify_all_options(); if( g.argc!=4 ) usage("FILE1 FILE2"); diff_print_filenames(g.argv[2], g.argv[3], diffFlag); blob_read_from_file(&a, g.argv[2], ExtFILE); blob_read_from_file(&b, g.argv[3], ExtFILE); blob_zero(&out); text_diff(&a, &b, &out, pRe, diffFlag); blob_write_to_file(&out, "-"); re_free(pRe); } /************************************************************************** ** The basic difference engine is above. What follows is the annotation ** engine. Both are in the same file since they share many components. */ |
︙ | ︙ | |||
3289 3290 3291 3292 3293 3294 3295 | ** will release it when it is finished with it. */ static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){ int i; memset(p, 0, sizeof(*p)); if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ | | | | 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 | ** will release it when it is finished with it. */ static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){ int i; memset(p, 0, sizeof(*p)); if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ p->c.same_fn = same_dline_ignore_allws; }else{ p->c.same_fn = same_dline; } p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo, diffFlags); if( p->c.aTo==0 ){ return 1; } p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo ); |
︙ | ︙ | |||
3406 3407 3408 3409 3410 3411 3412 | if( zLimit ){ if( strcmp(zLimit,"none")==0 ){ iLimit = 0; mxTime = 0; }else if( sqlite3_strglob("*[0-9]s", zLimit)==0 ){ iLimit = 0; | < | | 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 | if( zLimit ){ if( strcmp(zLimit,"none")==0 ){ iLimit = 0; mxTime = 0; }else if( sqlite3_strglob("*[0-9]s", zLimit)==0 ){ iLimit = 0; mxTime = current_time_in_milliseconds() + 1000.0*atof(zLimit); }else{ iLimit = atoi(zLimit); if( iLimit<=0 ) iLimit = 30; mxTime = 0; } }else{ /* Default limit is as much as we can do in 1.000 seconds */ |
︙ | ︙ | |||
3496 3497 3498 3499 3500 3501 3502 | } p->nVers++; cnt++; } if( p->nVers==0 ){ if( zRevision ){ | | < | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 | } p->nVers++; cnt++; } if( p->nVers==0 ){ if( zRevision ){ fossil_fatal("file %s does not exist in check-in %s", zFilename, zRevision); }else{ fossil_fatal("no history for file: %s", zFilename); } } db_finalize(&q); db_end_transaction(0); |
︙ | ︙ | |||
3553 3554 3555 3556 3557 3558 3559 | ** or removed by any subsequent check-in. ** ** Query parameters: ** ** checkin=ID The check-in at which to start the annotation ** filename=FILENAME The filename. ** filevers=BOOLEAN Show file versions rather than check-in versions | | | | | | | | | | 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 | ** or removed by any subsequent check-in. ** ** Query parameters: ** ** checkin=ID The check-in at which to start the annotation ** filename=FILENAME The filename. ** filevers=BOOLEAN Show file versions rather than check-in versions ** limit=LIMIT Limit the amount of analysis: ** "none" No limit ** "Xs" As much as can be computed in X seconds ** "N" N versions ** log=BOOLEAN Show a log of versions analyzed ** origin=ID The origin checkin. If unspecified, the root ** check-in over the entire repository is used. ** Specify "origin=trunk" or similar for a reverse ** annotation ** w=BOOLEAN Ignore whitespace */ void annotation_page(void){ int i; const char *zLimit; /* Depth limit */ u64 annFlags = DIFF_STRIP_EOLCR; int showLog; /* True to display the log */ |
︙ | ︙ | |||
3587 3588 3589 3590 3591 3592 3593 | unsigned clr1, clr2, clr; int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ /* Gather query parameters */ login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( exclude_spiders() ) return; | | < < | 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 | unsigned clr1, clr2, clr; int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ /* Gather query parameters */ login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( exclude_spiders() ) return; load_control(); zFilename = P("filename"); zRevision = PD("checkin",0); zOrigin = P("origin"); zLimit = P("limit"); showLog = PB("log"); fileVers = PB("filevers"); ignoreWs = PB("w"); if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; /* compute the annotation */ annotate_file(&ann, zFilename, zRevision, zLimit, zOrigin, annFlags); zCI = ann.aVers[0].zMUuid; /* generate the web page */ style_header("Annotation For %h", zFilename); if( bBlame ){ url_initialize(&url, "blame"); }else{ url_initialize(&url, "annotate"); } url_add_parameter(&url, "checkin", P("checkin")); |
︙ | ︙ | |||
3639 3640 3641 3642 3643 3644 3645 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ clr = gradient_color(clr1, clr2, ann.nVers-1, i); ann.aVers[i].zBgColor = mprintf("#%06x", clr); } @ <div id="annotation_log" style='display:%s(showLog?"block":"none");'> if( zOrigin ){ | | | | | | | | 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ clr = gradient_color(clr1, clr2, ann.nVers-1, i); ann.aVers[i].zBgColor = mprintf("#%06x", clr); } @ <div id="annotation_log" style='display:%s(showLog?"block":"none");'> if( zOrigin ){ zLink = href("%R/finfo?name=%t&ci=%!S&orig=%!S",zFilename,zCI,zOrigin); }else{ zLink = href("%R/finfo?name=%t&ci=%!S",zFilename,zCI); } @ <h2>Versions of %z(zLink)%h(zFilename)</a> analyzed:</h2> @ <ol> for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ @ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate) @ check-in %z(href("%R/info/%!S",p->zMUuid))%S(p->zMUuid)</a> @ artifact %z(href("%R/artifact/%!S",p->zFUuid))%S(p->zFUuid)</a> @ </span> } @ </ol> @ <hr /> @ </div> if( !ann.bMoreToDo ){ assert( ann.origId==0 ); /* bMoreToDo always set for a point-to-point */ @ <h2>Origin for each line in @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a> @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2> }else if( ann.origId>0 ){ @ <h2>Lines of @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a> @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a> @ that are changed by the sequence of edits moving toward @ check-in %z(href("%R/info/%!S",zOrigin))%S(zOrigin)</a>:</h2> }else{ @ <h2>Lines added by the %d(ann.nVers) most recent ancestors of @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a> @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2> } @ <pre> szHash = 10; for(i=0; i<ann.nOrig; i++){ int iVers = ann.aOrig[i].iVers; char *z = (char*)ann.aOrig[i].z; |
︙ | ︙ | |||
3712 3713 3714 3715 3716 3717 3718 | sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%*s%4d:",szHash+12,"",i+1); } } @ %s(zPrefix) %h(z) } @ </pre> | | | | 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 | sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%*s%4d:",szHash+12,"",i+1); } } @ %s(zPrefix) %h(z) } @ </pre> style_footer(); } /* ** COMMAND: annotate ** COMMAND: blame ** COMMAND: praise ** ** Usage: %fossil annotate|blame|praise ?OPTIONS? FILENAME ** ** Output the text of a file with markings to show when each line of the file ** was last modified. The version currently checked out is shown by default. ** Other versions may be specified using the -r option. The "annotate" command ** shows line numbers and omits the username. The "blame" and "praise" commands |
︙ | ︙ | |||
3742 3743 3744 3745 3746 3747 3748 | ** removed by any subsequent check-in. ** ** Options: ** --filevers Show file version numbers rather than ** check-in versions ** -r|--revision VERSION The specific check-in containing the file ** -l|--log List all versions analyzed | | | | | | 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 | ** removed by any subsequent check-in. ** ** Options: ** --filevers Show file version numbers rather than ** check-in versions ** -r|--revision VERSION The specific check-in containing the file ** -l|--log List all versions analyzed ** -n|--limit LIMIT Limit the amount of analysis: ** N Up to N versions ** Xs As much as possible in X seconds ** none No limit ** -o|--origin VERSION The origin check-in. By default this is the ** root of the repository. Set to "trunk" or ** similar for a reverse annotation. ** -w|--ignore-all-space Ignore white space when comparing lines ** -Z|--ignore-trailing-space Ignore whitespace at line end ** ** See also: info, finfo, timeline */ void annotate_cmd(void){ const char *zRevision; /* Revision name, or NULL for current check-in */ Annotator ann; /* The annotation of the file */ int i; /* Loop counter */ const char *zLimit; /* The value to the -n|--limit option */ const char *zOrig; /* The value for -o|--origin */ |
︙ | ︙ |
Deleted src/diff.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/diff.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 | # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line # to this file, then runs this file using "tclsh" in order to display the # graphical diff in a separate window. A typical "set fossilcmd" line # looks like this: # # set fossilcmd {| "./fossil" diff --html -y -i -v} # # This header comment is stripped off by the "mkbuiltin.c" program. # set prog { package require Tk | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line # to this file, then runs this file using "tclsh" in order to display the # graphical diff in a separate window. A typical "set fossilcmd" line # looks like this: # # set fossilcmd {| "./fossil" diff --html -y -i -v} # # This header comment is stripped off by the "mkbuiltin.c" program. # set prog { package require Tk array set CFG { TITLE {Fossil Diff} LN_COL_BG #dddddd LN_COL_FG #444444 TXT_COL_BG #ffffff TXT_COL_FG #000000 MKR_COL_BG #444444 MKR_COL_FG #dddddd CHNG_BG #d0d0ff ADD_BG #c0ffc0 RM_BG #ffc0c0 HR_FG #888888 HR_PAD_TOP 4 HR_PAD_BTM 8 FN_BG #444444 FN_FG #ffffff FN_PAD 5 ERR_FG #ee0000 PADX 5 WIDTH 80 HEIGHT 45 LB_HEIGHT 25 } if {![namespace exists ttk]} { interp alias {} ::ttk::scrollbar {} ::scrollbar interp alias {} ::ttk::menubutton {} ::menubutton } proc dehtml {x} { set x [regsub -all {<[^>]*>} $x {}] |
︙ | ︙ | |||
99 100 101 102 103 104 105 | fconfigure $in -encoding utf-8 set difftxt [split [read $in] \n] close $in } set N [llength $difftxt] set ii 0 set nDiffs 0 | < < | | | > > | < < < | < < < < < | | | | < > | < < | | | < < < | < < | < | | < < < | < < | < < < | > | | < < < < < | < < < < | | > | | < < > > > | < < | < < < < < < | < < < < < | | | | < | > > | | | | < | | | < < | | < < < < < < < | | < < | 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 | fconfigure $in -encoding utf-8 set difftxt [split [read $in] \n] close $in } set N [llength $difftxt] set ii 0 set nDiffs 0 array set widths {txt 0 ln 0 mkr 0} while {[set line [getLine $difftxt $N ii]] != -1} { set fn2 {} if {![regexp {^=+ (.*?) =+ versus =+ (.*?) =+$} $line all fn fn2] && ![regexp {^=+ (.*?) =+$} $line all fn] } { continue } set errMsg "" set line [getLine $difftxt $N ii] if {[string compare -length 6 $line "<table"] && ![regexp {<p[^>]*>(.+)} $line - errMsg]} { continue } incr nDiffs set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}] .wfiles.lb insert end $fn foreach c [cols] { if {$nDiffs > 1} { $c insert end \n - } if {[colType $c] eq "txt"} { $c insert end $fn\n fn if {$fn2!=""} {set fn $fn2} } else { $c insert end \n fn } $c insert end \n - if {$errMsg ne ""} continue while {[getLine $difftxt $N ii] ne "<pre>"} continue set type [colType $c] set str {} while {[set line [getLine $difftxt $N ii]] ne "</pre>"} { set len [string length [dehtml $line]] if {$len > $widths($type)} { set widths($type) $len } append str $line\n } set re {<span class="diff([a-z]+)">([^<]*)</span>} # Use \r as separator since it can't appear in the diff output (it gets # converted to a space). set str [regsub -all $re $str "\r\\1\r\\2\r"] foreach {pre class mid} [split $str \r] { if {$class ne ""} { $c insert end [dehtml $pre] - [dehtml $mid] [list $class -] } else { $c insert end [dehtml $pre] - } } } if {$errMsg ne ""} { foreach c {.txtA .txtB} {$c insert end [string trim $errMsg] err} foreach c [cols] {$c insert end \n -} } } foreach c [cols] { set type [colType $c] if {$type ne "txt"} { $c config -width $widths($type) |
︙ | ︙ | |||
413 414 415 416 417 418 419 | text .mkr foreach c [cols] { set keyPrefix [string toupper [colType $c]]_COL_ if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}} $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \ -padx $CFG(PADX) -yscroll sync-y | | | < < | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | text .mkr foreach c [cols] { set keyPrefix [string toupper [colType $c]]_COL_ if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}} $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \ -padx $CFG(PADX) -yscroll sync-y $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \ -foreground $CFG(HR_FG) $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD) bindtags $c ". $c Text all" bind $c <1> {focus %W} } ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal |
︙ | ︙ |
Changes to src/diffcmd.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** This file contains code used to implement the "diff" command */ #include "config.h" #include "diffcmd.h" #include <assert.h> | < < < < < < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** This file contains code used to implement the "diff" command */ #include "config.h" #include "diffcmd.h" #include <assert.h> /* ** Use the right null device for the platform. */ #if defined(_WIN32) # define NULL_DEVICE "NUL" #else # define NULL_DEVICE "/dev/null" |
︙ | ︙ | |||
108 109 110 111 112 113 114 115 | if( p->zName ){ p->nUsed++; return 1; } return 0; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < | > > | < < | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < > > > > > > > > > > > > > > | < > | | | > > > | > | | | | > < | | | | | 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 | if( p->zName ){ p->nUsed++; return 1; } return 0; } /* ** Print the "Index:" message that patches wants to see at the top of a diff. */ void diff_print_index(const char *zFile, u64 diffFlags){ if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT))==0 ){ char *z = mprintf("Index: %s\n%.66c\n", zFile, '='); fossil_print("%s", z); fossil_free(z); } } /* ** Print the +++/--- filename lines for a diff operation. */ void diff_print_filenames(const char *zLeft, const char *zRight, u64 diffFlags){ char *z = 0; if( diffFlags & DIFF_BRIEF ){ /* no-op */ }else if( diffFlags & DIFF_SIDEBYSIDE ){ int w = diff_width(diffFlags); int n1 = strlen(zLeft); int n2 = strlen(zRight); int x; if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ if( n1>w*2 ) n1 = w*2; x = w*2+17 - (n1+2); z = mprintf("%.*c %.*s %.*c\n", x/2, '=', n1, zLeft, (x+1)/2, '='); }else{ if( w<20 ) w = 20; if( n1>w-10 ) n1 = w - 10; if( n2>w-10 ) n2 = w - 10; z = mprintf("%.*c %.*s %.*c versus %.*c %.*s %.*c\n", (w-n1+10)/2, '=', n1, zLeft, (w-n1+1)/2, '=', (w-n2)/2, '=', n2, zRight, (w-n2+1)/2, '='); } }else{ z = mprintf("--- %s\n+++ %s\n", zLeft, zRight); } fossil_print("%s", z); fossil_free(z); } /* ** Show the difference between two files, one in memory and one on disk. ** ** The difference is the set of edits needed to transform pFile1 into ** zFile2. The content of pFile1 is in memory. zFile2 exists on disk. ** ** If fSwapDiff is 1, show the set of edits to transform zFile2 into pFile1 ** instead of the opposite. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ void diff_file( Blob *pFile1, /* In memory content to compare from */ int isBin1, /* Does the 'from' content appear to be binary */ const char *zFile2, /* On disk content to compare to */ const char *zName, /* Display name of the file */ const char *zDiffCmd, /* Command for comparison */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Include binary files for external diff */ u64 diffFlags, /* Flags to control the diff */ int fSwapDiff /* Diff from Zfile2 to Pfile1 */ ){ if( zDiffCmd==0 ){ Blob out; /* Diff output text */ Blob file2; /* Content of zFile2 */ const char *zName2; /* Name of zFile2 for display */ /* Read content of zFile2 into memory */ blob_zero(&file2); if( file_size(zFile2, ExtFILE)<0 ){ zName2 = NULL_DEVICE; }else{ blob_read_from_file(&file2, zFile2, ExtFILE); zName2 = zName; } /* Compute and output the differences */ if( diffFlags & DIFF_BRIEF ){ if( blob_compare(pFile1, &file2) ){ fossil_print("CHANGED %s\n", zName); } }else{ blob_zero(&out); if( fSwapDiff ){ text_diff(&file2, pFile1, &out, 0, diffFlags); }else{ text_diff(pFile1, &file2, &out, 0, diffFlags); } if( blob_size(&out) ){ if( diffFlags & DIFF_NUMSTAT ){ fossil_print("%s %s\n", blob_str(&out), zName); }else{ diff_print_filenames(zName, zName2, diffFlags); fossil_print("%s\n", blob_str(&out)); } } blob_reset(&out); } /* Release memory resources */ blob_reset(&file2); }else{ int cnt = 0; Blob nameFile1; /* Name of temporary file to old pFile1 content */ Blob cmd; /* Text of command to run */ if( !fIncludeBinary ){ Blob file2; if( isBin1 ){ fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); return; } if( zBinGlob ){ Glob *pBinary = glob_create(zBinGlob); if( glob_match(pBinary, zName) ){ fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); glob_free(pBinary); return; } glob_free(pBinary); } |
︙ | ︙ | |||
637 638 639 640 641 642 643 | return; } blob_reset(&file2); } /* Construct a temporary file to hold pFile1 based on the name of ** zFile2 */ | | | < < | < < | < < > | | | | | | | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | return; } blob_reset(&file2); } /* Construct a temporary file to hold pFile1 based on the name of ** zFile2 */ blob_zero(&nameFile1); do{ blob_reset(&nameFile1); blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++); }while( file_access(blob_str(&nameFile1),F_OK)==0 ); blob_write_to_file(pFile1, blob_str(&nameFile1)); /* Construct the external diff command */ blob_zero(&cmd); blob_append(&cmd, zDiffCmd, -1); if( fSwapDiff ){ blob_append_escaped_arg(&cmd, zFile2); blob_append_escaped_arg(&cmd, blob_str(&nameFile1)); }else{ blob_append_escaped_arg(&cmd, blob_str(&nameFile1)); blob_append_escaped_arg(&cmd, zFile2); } /* Run the external diff command */ fossil_system(blob_str(&cmd)); /* Delete the temporary file and clean up memory used */ file_delete(blob_str(&nameFile1)); blob_reset(&nameFile1); blob_reset(&cmd); } } /* ** Show the difference between two files, both in memory. |
︙ | ︙ | |||
686 687 688 689 690 691 692 693 | ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ void diff_file_mem( Blob *pFile1, /* In memory content to compare from */ Blob *pFile2, /* In memory content to compare to */ const char *zName, /* Display name of the file */ | > > > > > | | | | | | | | | | | | > > > > > > | | | < < < < < < < < < < | | | | | | | > > < < < < < < < < < < < < < < < < < < < | > > > | | < | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 | ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ void diff_file_mem( Blob *pFile1, /* In memory content to compare from */ Blob *pFile2, /* In memory content to compare to */ int isBin1, /* Does the 'from' content appear to be binary */ int isBin2, /* Does the 'to' content appear to be binary */ const char *zName, /* Display name of the file */ const char *zDiffCmd, /* Command for comparison */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Include binary files for external diff */ u64 diffFlags /* Diff flags */ ){ if( diffFlags & DIFF_BRIEF ) return; if( zDiffCmd==0 ){ Blob out; /* Diff output text */ blob_zero(&out); text_diff(pFile1, pFile2, &out, 0, diffFlags); if( diffFlags & DIFF_NUMSTAT ){ fossil_print("%s %s\n", blob_str(&out), zName); }else{ diff_print_filenames(zName, zName, diffFlags); fossil_print("%s\n", blob_str(&out)); } /* Release memory resources */ blob_reset(&out); }else{ Blob cmd; Blob temp1; Blob temp2; Blob prefix1; Blob prefix2; if( !fIncludeBinary ){ if( isBin1 || isBin2 ){ fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); return; } if( zBinGlob ){ Glob *pBinary = glob_create(zBinGlob); if( glob_match(pBinary, zName) ){ fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); glob_free(pBinary); return; } glob_free(pBinary); } } /* Construct a prefix for the temporary file names */ blob_zero(&prefix1); blob_zero(&prefix2); blob_appendf(&prefix1, "%s-v1", zName); blob_appendf(&prefix2, "%s-v2", zName); /* Construct a temporary file names */ file_tempname(&temp1, blob_str(&prefix1)); file_tempname(&temp2, blob_str(&prefix2)); blob_write_to_file(pFile1, blob_str(&temp1)); blob_write_to_file(pFile2, blob_str(&temp2)); /* Construct the external diff command */ blob_zero(&cmd); blob_append(&cmd, zDiffCmd, -1); blob_append_escaped_arg(&cmd, blob_str(&temp1)); blob_append_escaped_arg(&cmd, blob_str(&temp2)); /* Run the external diff command */ fossil_system(blob_str(&cmd)); /* Delete the temporary file and clean up memory used */ file_delete(blob_str(&temp1)); file_delete(blob_str(&temp2)); blob_reset(&prefix1); blob_reset(&prefix2); blob_reset(&temp1); blob_reset(&temp2); blob_reset(&cmd); } } /* ** Run a diff between the version zFrom and files on disk. zFrom might ** be NULL which means to simply show the difference between the edited ** files on disk and the check-out on which they are based. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_against_disk( const char *zFrom, /* Version to difference from */ const char *zDiffCmd, /* Use this diff command. NULL for built-in */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Treat file names matching this as binary */ u64 diffFlags, /* Flags controlling diff output */ FileDirList *pFileDir /* Which files to diff */ ){ int vid; Blob sql; Stmt q; int asNewFile; /* Treat non-existant files as empty files */ int isNumStat; /* True for --numstat */ asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0; isNumStat = (diffFlags & DIFF_NUMSTAT)!=0; vid = db_lget_int("checkout", 0); vfile_check_signature(vid, CKSIG_ENOTFILE); blob_zero(&sql); db_begin_transaction(); if( zFrom ){ int rid = name_to_typed_rid(zFrom, "ci"); if( !is_a_version(rid) ){ |
︙ | ︙ | |||
847 848 849 850 851 852 853 | " FROM vfile" " WHERE vid=%d" " AND (deleted OR chnged OR rid==0)" " ORDER BY pathname /*scan*/", vid ); } | < < < < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | " FROM vfile" " WHERE vid=%d" " AND (deleted OR chnged OR rid==0)" " ORDER BY pathname /*scan*/", vid ); } db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); int isDeleted = db_column_int(&q, 1); int isChnged = db_column_int(&q,2); int isNew = db_column_int(&q,3); |
︙ | ︙ | |||
873 874 875 876 877 878 879 | blob_zero(&fname); file_relative_name(zPathname, &fname, 1); }else{ blob_set(&fname, g.zLocalRoot); blob_append(&fname, zPathname, -1); } zFullName = blob_str(&fname); | < < < < < > | | < < | < | | < > > > > | < < < | > | > > > > | | > > | > | > > > | < < | < | < | > | < < | > | | > | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | blob_zero(&fname); file_relative_name(zPathname, &fname, 1); }else{ blob_set(&fname, g.zLocalRoot); blob_append(&fname, zPathname, -1); } zFullName = blob_str(&fname); if( isDeleted ){ if( !isNumStat ){ fossil_print("DELETED %s\n", zPathname); } if( !asNewFile ){ showDiff = 0; zFullName = NULL_DEVICE; } }else if( file_access(zFullName, F_OK) ){ if( !isNumStat ){ fossil_print("MISSING %s\n", zPathname); } if( !asNewFile ){ showDiff = 0; } }else if( isNew ){ if( !isNumStat ){ fossil_print("ADDED %s\n", zPathname); } srcid = 0; if( !asNewFile ){ showDiff = 0; } }else if( isChnged==3 ){ if( !isNumStat ){ fossil_print("ADDED_BY_MERGE %s\n", zPathname); } srcid = 0; if( !asNewFile ){ showDiff = 0; } }else if( isChnged==5 ){ if( !isNumStat ){ fossil_print("ADDED_BY_INTEGRATE %s\n", zPathname); } srcid = 0; if( !asNewFile ){ showDiff = 0; } } if( showDiff ){ Blob content; int isBin; if( !isLink != !file_islink(zFullName) ){ diff_print_index(zPathname, diffFlags); diff_print_filenames(zPathname, zPathname, diffFlags); fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); continue; } if( srcid>0 ){ content_get(srcid, &content); }else{ blob_zero(&content); } isBin = fIncludeBinary ? 0 : looks_like_binary(&content); diff_print_index(zPathname, diffFlags); diff_file(&content, isBin, zFullName, zPathname, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0); blob_reset(&content); } blob_reset(&fname); } db_finalize(&q); db_end_transaction(1); /* ROLLBACK */ } /* ** Run a diff between the undo buffer and files on disk. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_against_undo( const char *zDiffCmd, /* Use this diff command. NULL for built-in */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Treat file names matching this as binary */ u64 diffFlags, /* Flags controlling diff output */ FileDirList *pFileDir /* List of files and directories to diff */ ){ Stmt q; Blob content; db_prepare(&q, "SELECT pathname, content FROM undo"); blob_init(&content, 0, 0); while( db_step(&q)==SQLITE_ROW ){ char *zFullName; const char *zFile = (const char*)db_column_text(&q, 0); if( !file_dir_match(pFileDir, zFile) ) continue; zFullName = mprintf("%s%s", g.zLocalRoot, zFile); db_column_blob(&q, 1, &content); diff_file(&content, 0, zFullName, zFile, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0); fossil_free(zFullName); blob_reset(&content); } db_finalize(&q); } /* ** Show the difference between two files identified by ManifestFile ** entries. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_manifest_entry( struct ManifestFile *pFrom, struct ManifestFile *pTo, const char *zDiffCmd, const char *zBinGlob, int fIncludeBinary, u64 diffFlags ){ Blob f1, f2; int isBin1, isBin2; int rid; const char *zName; if( pFrom ){ zName = pFrom->zName; }else if( pTo ){ zName = pTo->zName; }else{ zName = DIFF_NO_NAME; } if( diffFlags & DIFF_BRIEF ) return; diff_print_index(zName, diffFlags); if( pFrom ){ rid = uuid_to_rid(pFrom->zUuid, 0); content_get(rid, &f1); }else{ blob_zero(&f1); } if( pTo ){ rid = uuid_to_rid(pTo->zUuid, 0); content_get(rid, &f2); }else{ blob_zero(&f2); } isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1); isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2); diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); blob_reset(&f1); blob_reset(&f2); } /* ** Output the differences between two check-ins. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_two_versions( const char *zFrom, const char *zTo, const char *zDiffCmd, const char *zBinGlob, int fIncludeBinary, u64 diffFlags, FileDirList *pFileDir ){ Manifest *pFrom, *pTo; ManifestFile *pFromFile, *pToFile; int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; pFrom = manifest_get_by_name(zFrom, 0); manifest_file_rewind(pFrom); pFromFile = manifest_file_next(pFrom,0); pTo = manifest_get_by_name(zTo, 0); manifest_file_rewind(pTo); pToFile = manifest_file_next(pTo,0); while( pFromFile || pToFile ){ int cmp; if( pFromFile==0 ){ cmp = +1; }else if( pToFile==0 ){ cmp = -1; }else{ cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); } if( cmp<0 ){ if( file_dir_match(pFileDir, pFromFile->zName) ){ if( (diffFlags & DIFF_NUMSTAT)==0 ){ fossil_print("DELETED %s\n", pFromFile->zName); } if( asNewFlag ){ diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } } pFromFile = manifest_file_next(pFrom,0); }else if( cmp>0 ){ if( file_dir_match(pFileDir, pToFile->zName) ){ if( (diffFlags & DIFF_NUMSTAT)==0 ){ fossil_print("ADDED %s\n", pToFile->zName); } if( asNewFlag ){ diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } } pToFile = manifest_file_next(pTo,0); }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ /* No changes */ (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ pFromFile = manifest_file_next(pFrom,0); pToFile = manifest_file_next(pTo,0); }else{ if( file_dir_match(pFileDir, pToFile->zName) ){ if( diffFlags & DIFF_BRIEF ){ fossil_print("CHANGED %s\n", pFromFile->zName); }else{ diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } } pFromFile = manifest_file_next(pFrom,0); pToFile = manifest_file_next(pTo,0); } } manifest_destroy(pFrom); |
︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 | ** (3) Delete the temp file. */ void diff_tk(const char *zSubCmd, int firstArg){ int i; Blob script; const char *zTempFile = 0; char *zCmd; | < < | < < < < < < | | | > > > > > > > > > > > > > > > | | < < < < < < < < < < < | | | > > | | > > | | < | | | | | > > | | < < < | < | | < < | | | < < | | | | < | < < < | | | | < < | | | | | < < > | | > > > > > > < | > | > > > > > > < < | | | | < < < > | > > > > | 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 | ** (3) Delete the temp file. */ void diff_tk(const char *zSubCmd, int firstArg){ int i; Blob script; const char *zTempFile = 0; char *zCmd; blob_zero(&script); blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v", g.nameOfExe, zSubCmd); find_option("html",0,0); find_option("side-by-side","y",0); find_option("internal","i",0); find_option("verbose","v",0); /* The undocumented --script FILENAME option causes the Tk script to ** be written into the FILENAME instead of being run. This is used ** for testing and debugging. */ zTempFile = find_option("script",0,1); for(i=firstArg; i<g.argc; i++){ const char *z = g.argv[i]; if( sqlite3_strglob("*}*",z) ){ blob_appendf(&script, " {%/}", z); }else{ int j; blob_append(&script, " ", 1); for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]); } } blob_appendf(&script, "}\n%s", builtin_file("diff.tcl", 0)); if( zTempFile ){ blob_write_to_file(&script, zTempFile); fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile); }else{ #if defined(FOSSIL_ENABLE_TCL) Th_FossilInit(TH_INIT_DEFAULT); if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script), blob_size(&script), 1, 1, 0)==TCL_OK ){ blob_reset(&script); return; } /* * If evaluation of the Tcl script fails, the reason may be that Tk * could not be found by the loaded Tcl, or that Tcl cannot be loaded * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback * to using the external "tclsh", if available. */ #endif zTempFile = write_blob_to_temp_file(&script); zCmd = mprintf("tclsh \"%s\"", zTempFile); fossil_system(zCmd); file_delete(zTempFile); fossil_free(zCmd); } blob_reset(&script); } /* ** Returns non-zero if files that may be binary should be used with external ** diff programs. */ int diff_include_binary_files(void){ const char* zArgIncludeBinary = find_option("diff-binary", 0, 1); /* Command line argument have priority on settings */ if( zArgIncludeBinary ){ return is_truth(zArgIncludeBinary); }else{ return db_get_boolean("diff-binary", 1); } } /* ** Returns the GLOB pattern for file names that should be treated as binary ** by the diff subsystem, if any. */ const char *diff_get_binary_glob(void){ const char *zBinGlob = find_option("binary", 0, 1); if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); return zBinGlob; } /* ** COMMAND: diff ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show the unsaved changes ** currently in the working check-out. ** ** If the "--from VERSION" or "-r VERSION" option is used it specifies ** the source check-in for the diff operation. If not specified, the ** source check-in is the base check-in for the current check-out. ** ** If the "--to VERSION" option appears, it specifies the check-in from ** which the second version of the file or files is taken. If there is ** no "--to" option then the (possibly edited) files in the current check-out ** are used. ** ** The "--checkin VERSION" option shows the changes made by ** check-in VERSION relative to its primary parent. ** ** The "-i" command-line option forces the use of the internal diff logic ** rather than any external diff program that might be configured using ** the "setting" command. If no external diff program is configured, then ** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff". ** ** The "-N" or "--new-file" option causes the complete text of added or ** deleted files to be displayed. ** ** The "--diff-binary" option enables or disables the inclusion of binary files ** when using an external diff program. ** ** The "--binary" option causes files matching the glob PATTERN to be treated ** as binary when considering if they should be used with external diff program. ** This option overrides the "binary-glob" setting. ** ** Options: ** --binary PATTERN Treat files that match the glob PATTERN as binary ** --branch BRANCH Show diff of all changes on BRANCH ** --brief Show filenames only ** --checkin VERSION Show diff of all changes in VERSION ** --command PROG External diff program - overrides "diff-command" ** --context|-c N Use N lines of context ** --diff-binary BOOL Include binary files when using external commands ** --exec-abs-paths Force absolute path names with external commands. ** --exec-rel-paths Force relative path names with external commands. ** --from|-r VERSION Select VERSION as source for the diff ** --internal|-i Use internal diff logic ** --new-file|-N Show complete text of added and deleted files ** --numstat Show only the number of lines delete and added ** --side-by-side|-y Side-by-side diff ** --strip-trailing-cr Strip trailing CR ** --tk Launch a Tcl/Tk GUI for display ** --to VERSION Select VERSION as target for the diff ** --undo Diff against the "undo" buffer ** --unified Unified diff ** -v|--verbose Output complete text of added or deleted files ** -w|--ignore-all-space Ignore white space when comparing lines ** -W|--width <num> Width of lines in side-by-side diff ** -Z|--ignore-trailing-space Ignore changes to end-of-line whitespace */ void diff_cmd(void){ int isGDiff; /* True for gdiff. False for normal diff */ int isInternDiff; /* True for internal diff */ int verboseFlag; /* True if -v or --verbose flag is used */ const char *zFrom; /* Source version number */ const char *zTo; /* Target version number */ const char *zCheckin; /* Check-in version number */ const char *zBranch; /* Branch to diff */ const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ const char *zBinGlob = 0; /* Treat file names matching this as binary */ int fIncludeBinary = 0; /* Include binary files for external diff */ int againstUndo = 0; /* Diff against files in the undo buffer */ u64 diffFlags = 0; /* Flags to control the DIFF */ FileDirList *pFileDir = 0; /* Restrict the diff to these files */ if( find_option("tk",0,0)!=0 ){ diff_tk("diff", 2); return; } isGDiff = g.argv[1][0]=='g'; isInternDiff = find_option("internal","i",0)!=0; zFrom = find_option("from", "r", 1); zTo = find_option("to", 0, 1); zCheckin = find_option("checkin", 0, 1); zBranch = find_option("branch", 0, 1); againstUndo = find_option("undo",0,0)!=0; diffFlags = diff_options(); verboseFlag = find_option("verbose","v",0)!=0; if( !verboseFlag ){ verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */ } if( verboseFlag ) diffFlags |= DIFF_VERBOSE; if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ fossil_fatal("cannot use --undo together with --from, --to, --checkin," " or --branch"); } if( zBranch ){ if( zTo || zFrom || zCheckin ){ fossil_fatal("cannot use --from, --to, or --checkin with --branch"); } zTo = zBranch; zFrom = mprintf("root:%s", zBranch); } if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){ fossil_fatal("cannot use --checkin together with --from or --to"); } if( zTo==0 || againstUndo ){ db_must_be_within_tree(); }else if( zFrom==0 ){ fossil_fatal("must use --from if --to is present"); }else{ db_find_and_open_repository(0, 0); } if( !isInternDiff ){ zDiffCmd = find_option("command", 0, 1); if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff); } zBinGlob = diff_get_binary_glob(); fIncludeBinary = diff_include_binary_files(); determine_exec_relative_option(1); verify_all_options(); if( g.argc>=3 ){ int i; Blob fname; pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) ); memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1)); |
︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | "SELECT uuid FROM blob, plink" " WHERE plink.cid=%d AND plink.isprim AND plink.pid=blob.rid", ridTo); if( zFrom==0 ){ fossil_fatal("check-in %s has no parent", zTo); } } | < | > | > | > < < < < < < < < < | | 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 | "SELECT uuid FROM blob, plink" " WHERE plink.cid=%d AND plink.isprim AND plink.pid=blob.rid", ridTo); if( zFrom==0 ){ fossil_fatal("check-in %s has no parent", zTo); } } if( againstUndo ){ if( db_lget_int("undo_available",0)==0 ){ fossil_print("No undo or redo is available\n"); return; } diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, pFileDir); }else if( zTo==0 ){ diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, pFileDir); }else{ diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, pFileDir); } if( pFileDir ){ int i; for(i=0; pFileDir[i].zName; i++){ if( pFileDir[i].nUsed==0 && strcmp(pFileDir[0].zName,".")!=0 && !file_isdir(g.argv[i+2], ExtFILE) ){ fossil_fatal("not found: '%s'", g.argv[i+2]); } fossil_free(pFileDir[i].zName); } fossil_free(pFileDir); } } /* ** WEBPAGE: vpatch ** URL: /vpatch?from=FROM&to=TO ** ** Show a patch that goes from check-in FROM to check-in TO. */ void vpatch_page(void){ const char *zFrom = P("from"); const char *zTo = P("to"); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( zFrom==0 || zTo==0 ) fossil_redirect_home(); cgi_set_content_type("text/plain"); diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0); } |
Changes to src/dispatch.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | ** An instance of this object defines everything we need to know about an ** individual command, webpage, or setting. */ struct CmdOrPage { const char *zName; /* Name. Webpages start with "/". Commands do not */ void (*xFunc)(void); /* Implementation function, or NULL for settings */ const char *zHelp; /* Raw help text */ | < | | | | | | | | | < < < < < < | 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 | ** An instance of this object defines everything we need to know about an ** individual command, webpage, or setting. */ struct CmdOrPage { const char *zName; /* Name. Webpages start with "/". Commands do not */ void (*xFunc)(void); /* Implementation function, or NULL for settings */ const char *zHelp; /* Raw help text */ unsigned int eCmdFlags; /* Flags */ }; /*************************************************************************** ** These macros must match similar macros in mkindex.c ** Allowed values for CmdOrPage.eCmdFlags. */ #define CMDFLAG_1ST_TIER 0x0001 /* Most important commands */ #define CMDFLAG_2ND_TIER 0x0002 /* Obscure and seldom used commands */ #define CMDFLAG_TEST 0x0004 /* Commands for testing only */ #define CMDFLAG_WEBPAGE 0x0008 /* Web pages */ #define CMDFLAG_COMMAND 0x0010 /* A command */ #define CMDFLAG_SETTING 0x0020 /* A setting */ #define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */ #define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */ #define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */ /**************************************************************************/ /* Values for the 2nd parameter to dispatch_name_search() */ #define CMDFLAG_ANY 0x0038 /* Match anything */ #define CMDFLAG_PREFIX 0x0200 /* Prefix match is ok */ #endif /* INTERFACE */ |
︙ | ︙ | |||
78 79 80 81 82 83 84 | ** ** The page_index.h file is generated by the mkindex program which scans all ** source code files looking for header comments on the functions that ** implement command and webpages. */ #include "page_index.h" #define MX_COMMAND count(aCommand) | < | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | ** ** The page_index.h file is generated by the mkindex program which scans all ** source code files looking for header comments on the functions that ** implement command and webpages. */ #include "page_index.h" #define MX_COMMAND count(aCommand) /* ** Given a command, webpage, or setting name in zName, find the corresponding ** CmdOrPage object and return a pointer to that object in *ppCmd. ** ** The eType field is CMDFLAG_COMMAND to look up commands, CMDFLAG_WEBPAGE to ** look up webpages, CMDFLAG_SETTING to look up settings, or CMDFLAG_ANY to look |
︙ | ︙ | |||
128 129 130 131 132 133 134 | * exactly one entry with this prefix and the requested type. */ for( mid=-1; lwr<MX_COMMAND && strncmp(zName, aCommand[lwr].zName, nName)==0; ++lwr ){ if( aCommand[lwr].eCmdFlags & eType ){ if( mid<0 ){ mid = lwr; /* Potential ambiguous prefix */ }else{ | < | < | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | * exactly one entry with this prefix and the requested type. */ for( mid=-1; lwr<MX_COMMAND && strncmp(zName, aCommand[lwr].zName, nName)==0; ++lwr ){ if( aCommand[lwr].eCmdFlags & eType ){ if( mid<0 ){ mid = lwr; /* Potential ambiguous prefix */ }else{ return 2; /* Confirmed ambiguous prefix */ } } } if( mid>=0 ){ *ppCmd = &aCommand[mid]; return 0; /* Prefix match */ } |
︙ | ︙ | |||
203 204 205 206 207 208 209 | zName = ""; }else{ if( *z ){ *z++ = 0; } zValue = ""; } if( fossil_islower(zName[0]) ){ cgi_replace_query_parameter(zName, zValue); | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < > | < < < | < < < < < < < < < < < | < < | < < | < < < < | < < < < < < < < | < < < < < | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | < < < | < < < < < | > > > < | < < < < > > > > > > > | > > | > | < < < < < < < | < > > | < | < | < < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < | < | | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < > < < < < < < < < < < < < | | < < < < < < < < < < < < | | | < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | < < < < | | < | < < < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | zName = ""; }else{ if( *z ){ *z++ = 0; } zValue = ""; } if( fossil_islower(zName[0]) ){ cgi_replace_query_parameter(zName, zValue); } } return 0; } /* ** Fill Blob with a space-separated list of all command names that ** match the prefix zPrefix. */ void dispatch_matching_names(const char *zPrefix, Blob *pList){ int i; int nPrefix = (int)strlen(zPrefix); for(i=FOSSIL_FIRST_CMD; i<MX_COMMAND; i++){ if( strncmp(zPrefix, aCommand[i].zName, nPrefix)==0 ){ blob_appendf(pList, " %s", aCommand[i].zName); } } } /* ** Attempt to reformat plain-text help into HTML for display on a webpage. ** ** The HTML output is appended to Blob pHtml, which should already be ** initialized. */ static void help_to_html(const char *zHelp, Blob *pHtml){ char *s; char *d; char *z; /* Transform "%fossil" into just "fossil" */ z = s = d = mprintf("%s", zHelp); while( *s ){ if( *s=='%' && strncmp(s, "%fossil", 7)==0 ){ s++; }else{ *d++ = *s++; } } *d = 0; blob_appendf(pHtml, "<pre>\n%h\n</pre>\n", z); fossil_free(z); } /* ** COMMAND: test-all-help ** ** Usage: %fossil test-all-help ?OPTIONS? ** ** Show help text for commands and pages. Useful for proof-reading. ** Defaults to just the CLI commands. Specify --www to see only the ** web pages, or --everything to see both commands and pages. ** ** Options: ** -e|--everything Show all commands and pages. ** -t|--test Include test- commands ** -w|--www Show WWW pages. ** -s|--settings Show settings. ** -h|--html Transform output to HTML. */ void test_all_help_cmd(void){ int i; int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER; int useHtml = find_option("html","h",0)!=0; if( find_option("www","w",0) ){ mask = CMDFLAG_WEBPAGE; } if( find_option("everything","e",0) ){ mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER | CMDFLAG_WEBPAGE; } if( find_option("settings","s",0) ){ mask = CMDFLAG_SETTING; } if( find_option("test","t",0) ){ mask |= CMDFLAG_TEST; } if( useHtml ) fossil_print("<!--\n"); fossil_print("Help text for:\n"); if( mask & CMDFLAG_1ST_TIER ) fossil_print(" * Commands\n"); if( mask & CMDFLAG_2ND_TIER ) fossil_print(" * Auxiliary commands\n"); if( mask & CMDFLAG_TEST ) fossil_print(" * Test commands\n"); if( mask & CMDFLAG_WEBPAGE ) fossil_print(" * Web pages\n"); if( mask & CMDFLAG_SETTING ) fossil_print(" * Settings\n"); if( useHtml ){ fossil_print("-->\n"); fossil_print("<!-- start_all_help -->\n"); }else{ fossil_print("---\n"); } for(i=0; i<MX_COMMAND; i++){ if( (aCommand[i].eCmdFlags & mask)==0 ) continue; fossil_print("# %s\n", aCommand[i].zName); if( useHtml ){ Blob html; blob_zero(&html); help_to_html(aCommand[i].zHelp, &html); fossil_print("%s\n\n", blob_str(&html)); blob_reset(&html); }else{ fossil_print("%s\n\n", aCommand[i].zHelp); } } if( useHtml ){ fossil_print("<!-- end_all_help -->\n"); }else{ fossil_print("---\n"); } version_cmd(); } /* ** WEBPAGE: help ** URL: /help?name=CMD ** ** Show the built-in help text for CMD. CMD can be a command-line interface ** command or a page name from the web interface or a setting. */ void help_page(void){ const char *zCmd = P("cmd"); if( zCmd==0 ) zCmd = P("name"); if( zCmd && *zCmd ){ int rc; const CmdOrPage *pCmd = 0; style_header("Help: %s", zCmd); style_submenu_element("Command-List", "%s/help", g.zTop); rc = dispatch_name_search(zCmd, CMDFLAG_ANY, &pCmd); if( *zCmd=='/' ){ /* Some of the webpages require query parameters in order to work. ** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */ @ <h1>The "%h(zCmd)" page:</h1> }else if( rc==0 && (pCmd->eCmdFlags & CMDFLAG_SETTING)!=0 ){ @ <h1>The "%h(pCmd->zName)" setting:</h1> }else{ @ <h1>The "%h(zCmd)" command:</h1> } if( rc==1 ){ @ unknown command: %h(zCmd) }else if( rc==2 ){ @ ambiguous command prefix: %h(zCmd) }else{ if( pCmd->zHelp[0]==0 ){ @ No help available for "%h(pCmd->zName)" }else{ @ <blockquote> help_to_html(pCmd->zHelp, cgi_output_blob()); @ </blockquote> } } }else{ int i; style_header("Help"); @ <a name='commands'></a> @ <h1>Available commands:</h1> @ <div class="columns" style="column-width: 12ex;"> @ <ul> for(i=0; i<MX_COMMAND; i++){ const char *z = aCommand[i].zName; const char *zBoldOn = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"<b>" :""; const char *zBoldOff = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"</b>":""; if( '/'==*z || strncmp(z,"test",4)==0 ) continue; if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)!=0 ) continue; @ <li><a href="%R/help?cmd=%s(z)">%s(zBoldOn)%s(z)%s(zBoldOff)</a></li> } @ </ul></div> @ <a name='webpages'></a> @ <h1>Available web UI pages:</h1> @ <div class="columns" style="column-width: 18ex;"> @ <ul> for(i=0; i<MX_COMMAND; i++){ const char *z = aCommand[i].zName; if( '/'!=*z ) continue; if( aCommand[i].zHelp[0] ){ @ <li><a href="%R/help?cmd=%s(z)">%s(z+1)</a></li> }else{ @ <li>%s(z+1)</li> } } @ </ul></div> @ <a name='unsupported'></a> @ <h1>Unsupported commands:</h1> @ <div class="columns" style="column-width: 20ex;"> @ <ul> for(i=0; i<MX_COMMAND; i++){ const char *z = aCommand[i].zName; if( strncmp(z,"test",4)!=0 ) continue; if( aCommand[i].zHelp[0] ){ @ <li><a href="%R/help?cmd=%s(z)">%s(z)</a></li> }else{ @ <li>%s(z)</li> } } @ </ul></div> @ <a name='settings'></a> @ <h1>Settings:</h1> @ <div class="columns" style="column-width: 20ex;"> @ <ul> for(i=0; i<MX_COMMAND; i++){ const char *z = aCommand[i].zName; if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)==0 ) continue; if( aCommand[i].zHelp[0] ){ @ <li><a href="%R/help?cmd=%s(z)">%s(z)</a></li> }else{ @ <li>%s(z)</li> } } @ </ul></div> } style_footer(); } /* ** WEBPAGE: test-all-help ** ** Show all help text on a single page. Useful for proof-reading. */ void test_all_help_page(void){ int i; style_header("All Help Text"); for(i=0; i<MX_COMMAND; i++){ if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue; @ <h2>%s(aCommand[i].zName):</h2> @ <blockquote> help_to_html(aCommand[i].zHelp, cgi_output_blob()); @ </blockquote> } style_footer(); } static void multi_column_list(const char **azWord, int nWord){ int i, j, len; int mxLen = 0; int nCol; int nRow; |
︙ | ︙ | |||
1096 1097 1098 1099 1100 1101 1102 | multi_column_list(aCmd, nCmd); } /* ** List of commands starting with zPrefix, or all commands if zPrefix is NULL. */ | | < < < | > | | > | | | | | < | < < < | < | | > | | < | | | | | < | | < < < < < < < < < < < < > > > | < > > | < | | > > | | | | | | | < < < < < < < | < < < < | | | | < < < > < < | < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < | | | > > | > > < < < < < | | < < | | > > | < > > | < < > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | multi_column_list(aCmd, nCmd); } /* ** List of commands starting with zPrefix, or all commands if zPrefix is NULL. */ static void command_list(const char *zPrefix, int cmdMask){ int i, nCmd; int nPrefix = zPrefix ? strlen(zPrefix) : 0; const char *aCmd[MX_COMMAND]; for(i=nCmd=0; i<MX_COMMAND; i++){ const char *z = aCommand[i].zName; if( (aCommand[i].eCmdFlags & cmdMask)==0 ) continue; if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue; aCmd[nCmd++] = aCommand[i].zName; } multi_column_list(aCmd, nCmd); } /* ** Documentation on universal command-line options. */ /* @-comment: # */ static const char zOptions[] = @ Command-line options common to all commands: @ @ --args FILENAME Read additional arguments and options from FILENAME @ --cgitrace Active CGI tracing @ --comfmtflags VALUE Set comment formatting flags to VALUE @ --errorlog FILENAME Log errors to FILENAME @ --help Show help on the command rather than running it @ --httptrace Trace outbound HTTP requests @ --localtime Display times using the local timezone @ --no-th-hook Do not run TH1 hooks @ --quiet Reduce the amount of output @ --sqlstats Show SQL usage statistics when done @ --sqltrace Trace all SQL commands @ --sshtrace Trace SSH activity @ --ssl-identity NAME Set the SSL identity to NAME @ --systemtrace Trace calls to system() @ --user|-U USER Make the default user be USER @ --utc Display times using UTC @ --vfs NAME Cause SQLite to use the NAME VFS ; /* ** COMMAND: help ** ** Usage: %fossil help TOPIC ** or: %fossil TOPIC --help ** ** Display information on how to use TOPIC, which may be a command, webpage, or ** setting. Webpage names begin with "/". To display a list of available ** topics, use one of: ** ** %fossil help Show common commands ** %fossil help -a|--all Show both common and auxiliary commands ** %fossil help -o|--options Show command-line options common to all cmds ** %fossil help -s|--setting Show setting names ** %fossil help -t|--test Show test commands only ** %fossil help -x|--aux Show auxiliary commands only ** %fossil help -w|--www Show list of webpages */ void help_cmd(void){ int rc; int isPage = 0; const char *z; const char *zCmdOrPage; const char *zCmdOrPagePlural; const CmdOrPage *pCmd = 0; if( g.argc<3 ){ z = g.argv[0]; fossil_print( "Usage: %s help TOPIC\n" "Common commands: (use \"%s help help\" for more options)\n", z, z); command_list(0, CMDFLAG_1ST_TIER); version_cmd(); return; } if( find_option("options","o",0) ){ fossil_print("%s", zOptions); return; } if( find_option("all","a",0) ){ command_list(0, CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER); return; } else if( find_option("www","w",0) ){ command_list(0, CMDFLAG_WEBPAGE); return; } else if( find_option("aux","x",0) ){ command_list(0, CMDFLAG_2ND_TIER); return; } else if( find_option("test","t",0) ){ command_list(0, CMDFLAG_TEST); return; } else if( find_option("setting","s",0) ){ command_list(0, CMDFLAG_SETTING); return; } isPage = ('/' == *g.argv[2]) ? 1 : 0; if(isPage){ zCmdOrPage = "page"; zCmdOrPagePlural = "pages"; }else{ zCmdOrPage = "command or setting"; zCmdOrPagePlural = "commands and settings"; } rc = dispatch_name_search(g.argv[2], CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd); if( rc==1 ){ fossil_print("unknown %s: %s\nConsider using:\n", zCmdOrPage, g.argv[2]); fossil_print(" fossil help -a ;# show all commands\n"); fossil_print(" fossil help -w ;# show all web-pages\n"); fossil_print(" fossil help -s ;# show all settings\n"); fossil_exit(1); }else if( rc==2 ){ fossil_print("ambiguous %s prefix: %s\nMatching %s:\n", zCmdOrPage, g.argv[2], zCmdOrPagePlural); command_list(g.argv[2], 0xff); fossil_exit(1); } z = pCmd->zHelp; if( z==0 ){ fossil_fatal("no help available for the %s %s", pCmd->zName, zCmdOrPage); } if( pCmd->eCmdFlags & CMDFLAG_SETTING ){ fossil_print("Setting: \"%s\"%s\n\n", pCmd->zName, (pCmd->eCmdFlags & CMDFLAG_VERSIONABLE)!=0 ? " (versionable)" : "" ); } while( *z ){ if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ fossil_print("%s", g.argv[0]); z += 7; }else{ putchar(*z); z++; } } putchar('\n'); } /* ** Return a pointer to the setting information array. ** ** This routine provides access to the aSetting2[] array which is created ** by the mkindex utility program and included with <page_index.h>. */ const Setting *setting_info(int *pnCount){ if( pnCount ) *pnCount = (int)(sizeof(aSetting)/sizeof(aSetting[0])) - 1; return aSetting; } |
Changes to src/doc.c.
1 2 3 4 5 6 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ |
︙ | ︙ | |||
36 37 38 39 40 41 42 | int i; int n; const unsigned char *x; /* A table of mimetypes based on file content prefixes */ static const struct { | | | < < < | | | | | < < | | < < < < | | 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 | int i; int n; const unsigned char *x; /* A table of mimetypes based on file content prefixes */ static const struct { const char *zPrefix; /* The file prefix */ int size; /* Length of the prefix */ const char *zMimetype; /* The corresponding mimetype */ } aMime[] = { { "GIF87a", 6, "image/gif" }, { "GIF89a", 6, "image/gif" }, { "\211PNG\r\n\032\n", 8, "image/png" }, { "\377\332\377", 3, "image/jpeg" }, { "\377\330\377", 3, "image/jpeg" }, }; if( !looks_like_binary(pBlob) ) { return 0; /* Plain text */ } x = (const unsigned char*)blob_buffer(pBlob); n = blob_size(pBlob); for(i=0; i<count(aMime); i++){ if( n>=aMime[i].size && memcmp(x, aMime[i].zPrefix, aMime[i].size)==0 ){ return aMime[i].zMimetype; } } return "unknown/unknown"; } /* A table of mimetypes based on file suffixes. ** Suffixes must be in sorted order so that we can do a binary ** search to find the mime-type */ static const struct { const char *zSuffix; /* The file suffix */ int size; /* Length of the suffix */ const char *zMimetype; /* The corresponding mimetype */ } aMime[] = { { "ai", 2, "application/postscript" }, |
︙ | ︙ | |||
154 155 156 157 158 159 160 | { "ips", 3, "application/x-ipscript" }, { "ipx", 3, "application/x-ipix" }, { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, { "jar", 3, "application/java-archive" }, { "jpe", 3, "image/jpeg" }, { "jpeg", 4, "image/jpeg" }, { "jpg", 3, "image/jpeg" }, | | < < < < < < | 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 | { "ips", 3, "application/x-ipscript" }, { "ipx", 3, "application/x-ipix" }, { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, { "jar", 3, "application/java-archive" }, { "jpe", 3, "image/jpeg" }, { "jpeg", 4, "image/jpeg" }, { "jpg", 3, "image/jpeg" }, { "js", 2, "application/x-javascript" }, { "kar", 3, "audio/midi" }, { "latex", 5, "application/x-latex" }, { "lha", 3, "application/octet-stream" }, { "lsp", 3, "application/x-lisp" }, { "lzh", 3, "application/octet-stream" }, { "m", 1, "text/plain" }, { "m3u", 3, "audio/x-mpegurl" }, { "man", 3, "text/plain" }, { "markdown", 8, "text/x-markdown" }, { "md", 2, "text/x-markdown" }, { "me", 2, "application/x-troff-me" }, { "mesh", 4, "model/mesh" }, { "mid", 3, "audio/midi" }, { "midi", 4, "audio/midi" }, { "mif", 3, "application/x-mif" }, { "mime", 4, "www/mime" }, { "mkd", 3, "text/x-markdown" }, { "mov", 3, "video/quicktime" }, { "movie", 5, "video/x-sgi-movie" }, { "mp2", 3, "audio/mpeg" }, { "mp3", 3, "audio/mpeg" }, { "mp4", 3, "video/mp4" }, { "mpe", 3, "video/mpeg" }, |
︙ | ︙ | |||
203 204 205 206 207 208 209 | { "ogm", 3, "application/ogg" }, { "pbm", 3, "image/x-portable-bitmap" }, { "pdb", 3, "chemical/x-pdb" }, { "pdf", 3, "application/pdf" }, { "pgm", 3, "image/x-portable-graymap" }, { "pgn", 3, "application/x-chess-pgn" }, { "pgp", 3, "application/pgp" }, | < | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | { "ogm", 3, "application/ogg" }, { "pbm", 3, "image/x-portable-bitmap" }, { "pdb", 3, "chemical/x-pdb" }, { "pdf", 3, "application/pdf" }, { "pgm", 3, "image/x-portable-graymap" }, { "pgn", 3, "application/x-chess-pgn" }, { "pgp", 3, "application/pgp" }, { "pl", 2, "application/x-perl" }, { "pm", 2, "application/x-perl" }, { "png", 3, "image/png" }, { "pnm", 3, "image/x-portable-anymap" }, { "pot", 3, "application/mspowerpoint" }, { "potx", 4, "application/vnd.openxmlformats-" "officedocument.presentationml.template"}, |
︙ | ︙ | |||
281 282 283 284 285 286 287 | { "ustar", 5, "application/x-ustar" }, { "vb", 2, "text/plain" }, { "vcd", 3, "application/x-cdlink" }, { "vda", 3, "application/vda" }, { "viv", 3, "video/vnd.vivo" }, { "vivo", 4, "video/vnd.vivo" }, { "vrml", 4, "model/vrml" }, | < < | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | { "ustar", 5, "application/x-ustar" }, { "vb", 2, "text/plain" }, { "vcd", 3, "application/x-cdlink" }, { "vda", 3, "application/vda" }, { "viv", 3, "video/vnd.vivo" }, { "vivo", 4, "video/vnd.vivo" }, { "vrml", 4, "model/vrml" }, { "wav", 3, "audio/x-wav" }, { "wax", 3, "audio/x-ms-wax" }, { "wiki", 4, "text/x-fossil-wiki" }, { "wma", 3, "audio/x-ms-wma" }, { "wmv", 3, "video/x-ms-wmv" }, { "wmx", 3, "video/x-ms-wmx" }, { "wrl", 3, "model/vrml" }, { "wvx", 3, "video/x-ms-wvx" }, { "xbm", 3, "image/x-xbitmap" }, |
︙ | ︙ | |||
321 322 323 324 325 326 327 | fossil_panic("mimetypes out of sequence: %s before %s", aMime[i-1].zSuffix, aMime[i].zSuffix); } } } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | fossil_panic("mimetypes out of sequence: %s before %s", aMime[i-1].zSuffix, aMime[i].zSuffix); } } } /* ** Guess the mime-type of a document based on its name. */ const char *mimetype_from_name(const char *zName){ const char *z; int i; int first, last; int len; char zSuffix[20]; |
︙ | ︙ | |||
457 458 459 460 461 462 463 | #endif z = zName; for(i=0; zName[i]; i++){ if( zName[i]=='.' ) z = &zName[i+1]; } len = strlen(z); | | < < < < | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | #endif z = zName; for(i=0; zName[i]; i++){ if( zName[i]=='.' ) z = &zName[i+1]; } len = strlen(z); if( len<sizeof(zSuffix)-1 ){ sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z); for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]); first = 0; last = count(aMime) - 1; while( first<=last ){ int c; i = (first+last)/2; c = fossil_strcmp(zSuffix, aMime[i].zSuffix); if( c==0 ) return aMime[i].zMimetype; |
︙ | ︙ | |||
495 496 497 498 499 500 501 | ** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test" ** filename is special and verifies the integrity of the mimetype table. ** It should return "ok". */ void mimetype_test_cmd(void){ int i; mimetype_verify(); | < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | ** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test" ** filename is special and verifies the integrity of the mimetype table. ** It should return "ok". */ void mimetype_test_cmd(void){ int i; mimetype_verify(); for(i=2; i<g.argc; i++){ fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i])); } } /* ** WEBPAGE: mimetype_list ** ** Show the built-in table used to guess embedded document mimetypes ** from file suffixes. */ void mimetype_list_page(void){ int i; mimetype_verify(); style_header("Mimetype List"); @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename @ suffixes and the following table to guess at the appropriate mimetype @ for each document.</p> @ <table class='sortable mimetypetable' border=1 cellpadding=0 \ @ data-column-types='tt' data-init-sort='1'> @ <thead> @ <tr><th>Suffix<th>Mimetype @ </thead> @ <tbody> for(i=0; i<count(aMime); i++){ @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr> } @ </tbody></table> style_table_sorter(); style_footer(); } /* ** Check to see if the file in the pContent blob is "embedded HTML". Return ** true if it is, and fill pTitle with the document title. ** ** An "embedded HTML" file is HTML that lacks a header and a footer. The |
︙ | ︙ | |||
598 599 600 601 602 603 604 | int seenTitle = 0; while( fossil_isspace(zIn[0]) ) zIn++; if( fossil_strnicmp(zIn,"<div",4)!=0 ) return 0; zIn += 4; while( zIn[0] ){ if( fossil_isspace(zIn[0]) ) zIn++; | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | int seenTitle = 0; while( fossil_isspace(zIn[0]) ) zIn++; if( fossil_strnicmp(zIn,"<div",4)!=0 ) return 0; zIn += 4; while( zIn[0] ){ if( fossil_isspace(zIn[0]) ) zIn++; if( zIn[0]=='>' ) return 0; zAttr = zIn; while( fossil_isalnum(zIn[0]) || zIn[0]=='-' ) zIn++; nAttr = (int)(zIn - zAttr); while( fossil_isspace(zIn[0]) ) zIn++; if( zIn[0]!='=' ) continue; zIn++; while( fossil_isspace(zIn[0]) ) zIn++; |
︙ | ︙ | |||
627 628 629 630 631 632 633 | } if( nAttr==5 && fossil_strnicmp(zAttr,"class",5)==0 ){ if( nValue!=10 || fossil_strnicmp(zValue,"fossil-doc",10)!=0 ) return 0; seenClass = 1; if( seenTitle ) return 1; } if( nAttr==10 && fossil_strnicmp(zAttr,"data-title",10)==0 ){ | < < < | < < < < | < < < < < < < | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | } if( nAttr==5 && fossil_strnicmp(zAttr,"class",5)==0 ){ if( nValue!=10 || fossil_strnicmp(zValue,"fossil-doc",10)!=0 ) return 0; seenClass = 1; if( seenTitle ) return 1; } if( nAttr==10 && fossil_strnicmp(zAttr,"data-title",10)==0 ){ blob_append(pTitle, zValue, nValue); seenTitle = 1; if( seenClass ) return 1; } } return seenClass; } /* ** Look for a file named zName in the check-in with RID=vid. Load the content ** of that file into pContent and return the RID for the file. Or return 0 ** if the file is not found or could not be loaded. */ int doc_load_content(int vid, const char *zName, Blob *pContent){ int writable = db_is_writeable("repository"); int rid; /* The RID of the file being loaded */ if( writable ){ db_end_transaction(0); db_begin_write(); } if( !db_table_exists("repository", "vcache") || !writable ){ db_multi_exec( "CREATE %s TABLE IF NOT EXISTS vcache(\n" |
︙ | ︙ | |||
690 691 692 693 694 695 696 697 | " WHERE vid=%d AND fname=%Q", vid, zName); if( rid && content_get(rid, pContent)==0 ){ rid = 0; } return rid; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < | < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | < < < < < | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | " WHERE vid=%d AND fname=%Q", vid, zName); if( rid && content_get(rid, pContent)==0 ){ rid = 0; } return rid; } /* ** Transfer content to the output. During the transfer, when text of ** the following form is seen: ** ** href="$ROOT/ ** action="$ROOT/ ** ** Convert $ROOT to the root URI of the repository. Allow ' in place of " ** and any case for href or action. */ static void convert_href_and_output(Blob *pIn){ int i, base; int n = blob_size(pIn); char *z = blob_buffer(pIn); for(base=0, i=7; i<n; i++){ if( z[i]=='$' && strncmp(&z[i],"$ROOT/", 6)==0 && (z[i-1]=='\'' || z[i-1]=='"') && i-base>=9 && (fossil_strnicmp(&z[i-7]," href=", 6)==0 || fossil_strnicmp(&z[i-9]," action=", 8)==0) ){ blob_append(cgi_output_blob(), &z[base], i-base); blob_appendf(cgi_output_blob(), "%R"); base = i+5; } } blob_append(cgi_output_blob(), &z[base], i-base); } /* ** WEBPAGE: uv ** WEBPAGE: doc ** URL: /uv/FILE ** URL: /doc/CHECKIN/FILE ** ** CHECKIN can be either tag or hash prefix or timestamp identifying a ** particular check, or the name of a branch (meaning the most recent ** check-in on that branch) or one of various magic words: ** ** "tip" means the most recent check-in ** ** "ckout" means the current check-out, if the server is run from ** within a check-out, otherwise it is the same as "tip" ** ** FILE is the name of a file to delivered up as a webpage. FILE is relative ** to the root of the source tree of the repository. The FILE must ** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read ** directly from disk and need not be a managed file. ** ** The "ckout" CHECKIN is intended for development - to provide a mechanism ** for looking at what a file will look like using the /doc webpage after ** it gets checked in. ** ** The file extension is used to decide how to render the file. ** ** If FILE ends in "/" then the names "FILE/index.html", "FILE/index.wiki", ** and "FILE/index.md" are tried in that order. If the binary was compiled ** with TH1 embedded documentation support and the "th1-docs" setting is ** enabled, the name "FILE/index.th1" is also tried. If none of those are |
︙ | ︙ | |||
941 942 943 944 945 946 947 | #ifdef FOSSIL_ENABLE_TH1_DOCS , "index.th1" #endif }; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } | < < < < < < < < < < < < | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | #ifdef FOSSIL_ENABLE_TH1_DOCS , "index.th1" #endif }; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } blob_init(&title, 0, 0); zDfltTitle = isUV ? "" : "Documentation"; db_begin_transaction(); while( rid==0 && (++nMiss)<=count(azSuffix) ){ zName = P("name"); if( isUV ){ if( zName==0 ) zName = "index.wiki"; i = 0; }else{ if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki"; for(i=0; zName[i] && zName[i]!='/'; i++){} zCheckin = mprintf("%.*s", i, zName); if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){ zCheckin = "tip"; } } if( nMiss==count(azSuffix) ){ zName = "404.md"; }else if( zName[i]==0 ){ assert( nMiss>=0 && nMiss<count(azSuffix) ); zName = azSuffix[nMiss]; }else if( !isUV ){ zName += i; } while( zName[0]=='/' ){ zName++; } |
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 | } }else{ goto doc_not_found; } } if( isUV ){ if( db_table_exists("repository","unversioned") ){ | < < | | | | | | | | < < | | < | | > | < < | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | } }else{ goto doc_not_found; } } if( isUV ){ if( db_table_exists("repository","unversioned") ){ Stmt q; db_prepare(&q, "SELECT hash, mtime FROM unversioned" " WHERE name=%Q", zName); if( db_step(&q)==SQLITE_ROW ){ etag_check(ETAG_HASH, db_column_text(&q,0)); etag_last_modified(db_column_int64(&q,1)); } db_finalize(&q); if( unversioned_content(zName, &filebody)==0 ){ rid = 1; zDfltTitle = zName; } } }else if( fossil_strcmp(zCheckin,"ckout")==0 ){ /* Read from the local checkout */ char *zFullpath; db_must_be_within_tree(); zFullpath = mprintf("%s/%s", g.zLocalRoot, zName); if( file_isfile(zFullpath, RepoFILE) && blob_read_from_file(&filebody, zFullpath, RepoFILE)>0 ){ rid = 1; /* Fake RID just to get the loop to end */ } |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | Th_Store("doc_name", zName); if( vid ){ Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'" " FROM blob WHERE rid=%d", vid)); Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event" " WHERE objid=%d AND type='ci'", vid)); } | > > > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 | Th_Store("doc_name", zName); if( vid ){ Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'" " FROM blob WHERE rid=%d", vid)); Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event" " WHERE objid=%d AND type='ci'", vid)); } if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){ Blob tail; style_adunit_config(ADUNIT_RIGHT_OK); if( wiki_find_title(&filebody, &title, &tail) ){ style_header("%s", blob_str(&title)); wiki_convert(&tail, 0, WIKI_BUTTONS); }else{ style_header("%s", zDfltTitle); wiki_convert(&filebody, 0, WIKI_BUTTONS); } style_footer(); }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){ Blob tail = BLOB_INITIALIZER; markdown_to_html(&filebody, &title, &tail); if( blob_size(&title)>0 ){ style_header("%s", blob_str(&title)); }else{ style_header("%s", nMiss>=count(azSuffix)? "Not Found" : zDfltTitle); } convert_href_and_output(&tail); style_footer(); }else if( fossil_strcmp(zMime, "text/plain")==0 ){ style_header("%s", zDfltTitle); @ <blockquote><pre> @ %h(blob_str(&filebody)) @ </pre></blockquote> style_footer(); }else if( fossil_strcmp(zMime, "text/html")==0 && doc_is_embedded_html(&filebody, &title) ){ if( blob_size(&title)==0 ) blob_append(&title,zName,-1); style_header("%s", blob_str(&title)); convert_href_and_output(&filebody); style_footer(); #ifdef FOSSIL_ENABLE_TH1_DOCS }else if( Th_AreDocsEnabled() && fossil_strcmp(zMime, "application/x-th1")==0 ){ int raw = P("raw")!=0; if( !raw ){ Blob tail; blob_zero(&tail); if( wiki_find_title(&filebody, &title, &tail) ){ style_header("%s", blob_str(&title)); Th_Render(blob_str(&tail)); blob_reset(&tail); }else{ style_header("%h", zName); Th_Render(blob_str(&filebody)); } }else{ Th_Render(blob_str(&filebody)); } if( !raw ){ style_footer(); } #endif }else{ cgi_set_content_type(zMime); cgi_set_content(&filebody); } if( nMiss>=count(azSuffix) ) cgi_set_status(404, "Not Found"); db_end_transaction(0); return; /* Jump here when unable to locate the document */ doc_not_found: db_end_transaction(0); if( isUV && P("name")==0 ){ uvlist_page(); return; } cgi_set_status(404, "Not Found"); style_header("Not Found"); @ <p>Document %h(zOrigName) not found if( fossil_strcmp(zCheckin,"ckout")!=0 ){ @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a> } style_footer(); return; } /* ** The default logo. */ static const unsigned char aLogo[] = { |
︙ | ︙ | |||
1197 1198 1199 1200 1201 1202 1203 | blob_init(&bgimg, (char*)aBackground, sizeof(aBackground)); } cgi_set_content_type(zMime); cgi_set_content(&bgimg); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | blob_init(&bgimg, (char*)aBackground, sizeof(aBackground)); } cgi_set_content_type(zMime); cgi_set_content(&bgimg); } /* ** WEBPAGE: docsrch ** ** Search for documents that match a user-supplied full-text search pattern. ** If no pattern is specified (by the s= query parameter) then the user ** is prompted to enter a search string. ** ** Query parameters: ** ** s=PATTERN Search for PATTERN */ void doc_search_page(void){ login_check_credentials(); style_header("Document Search"); search_screen(SRCH_DOC, 0); style_footer(); } |
Changes to src/encode.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | ** Make the given string safe for HTML by converting every "<" into "<", ** every ">" into ">" and every "&" into "&". Return a pointer ** to a new string obtained from malloc(). ** ** We also encode " as " and ' as ' so they can appear as an argument ** to markup. */ | | | | < | | | | | | | | | | < < < < < | < | 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 | ** Make the given string safe for HTML by converting every "<" into "<", ** every ">" into ">" and every "&" into "&". Return a pointer ** to a new string obtained from malloc(). ** ** We also encode " as " and ' as ' so they can appear as an argument ** to markup. */ char *htmlize(const char *zIn, int n){ int c; int i = 0; int count = 0; char *zOut; if( n<0 ) n = strlen(zIn); while( i<n && (c = zIn[i])!=0 ){ switch( c ){ case '<': count += 4; break; case '>': count += 4; break; case '&': count += 5; break; case '"': count += 6; break; case '\'': count += 5; break; default: count++; break; } i++; } i = 0; zOut = fossil_malloc( count+1 ); while( n-->0 && (c = *zIn)!=0 ){ switch( c ){ case '<': zOut[i++] = '&'; zOut[i++] = 'l'; zOut[i++] = 't'; zOut[i++] = ';'; break; |
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 | zOut[i++] = '9'; zOut[i++] = ';'; break; default: zOut[i++] = c; break; } } zOut[i] = 0; | > | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | zOut[i++] = '9'; zOut[i++] = ';'; break; default: zOut[i++] = c; break; } zIn++; } zOut[i] = 0; return zOut; } /* ** Append HTML-escaped text to a Blob. */ void htmlize_to_blob(Blob *p, const char *zIn, int n){ int c, i, j; |
︙ | ︙ | |||
130 131 132 133 134 135 136 | j = i+1; break; case '\'': if( j<i ) blob_append(p, zIn+j, i-j); blob_append(p, "'", 5); j = i+1; break; | < < < < < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | j = i+1; break; case '\'': if( j<i ) blob_append(p, zIn+j, i-j); blob_append(p, "'", 5); j = i+1; break; } } if( j<i ) blob_append(p, zIn+j, i-j); } /* |
︙ | ︙ | |||
209 210 211 212 213 214 215 | ** representation of the character. The "/" character is not encoded ** by this routine. */ char *urlize(const char *z, int n){ return EncodeHttp(z, n, 0); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | ** representation of the character. The "/" character is not encoded ** by this routine. */ char *urlize(const char *z, int n){ return EncodeHttp(z, n, 0); } /* ** Convert a single HEX digit to an integer */ static int AsciiToHex(int c){ if( c>='a' && c<='f' ){ c += 10 - 'a'; }else if( c>='A' && c<='F' ){ |
︙ | ︙ | |||
353 354 355 356 357 358 359 | } /* ** Decode a fossilized string in-place. */ void defossilize(char *z){ int i, j, c; | | | < | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | } /* ** Decode a fossilized string in-place. */ void defossilize(char *z){ int i, j, c; for(i=0; (c=z[i])!=0 && c!='\\'; i++){} if( c==0 ) return; for(j=i; (c=z[i])!=0; i++){ if( c=='\\' && z[i+1] ){ i++; switch( z[i] ){ case 'n': c = '\n'; break; case 's': c = ' '; break; case 't': c = '\t'; break; |
︙ | ︙ | |||
416 417 418 419 420 421 422 | || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } } return c; } /* | | < < < < < < < < | < | | < | < > | < < < < < | | | < < < < < < < | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } } return c; } /* ** Encode a UTF8 string for JSON. All special characters are escaped. */ void blob_append_json_string(Blob *pBlob, const char *zStr){ const unsigned char *z; char *zOut; u32 c; int n, i, j; z = (const unsigned char*)zStr; n = 0; while( (c = fossil_utf8_read(&z))!=0 ){ if( c=='\\' || c=='"' ){ n += 2; }else if( c<' ' || c>=0x7f ){ if( c=='\n' || c=='\r' ){ n += 2; }else{ n += 6; } }else{ n++; } } i = blob_size(pBlob); blob_resize(pBlob, i+n); zOut = blob_buffer(pBlob); z = (const unsigned char*)zStr; while( (c = fossil_utf8_read(&z))!=0 ){ if( c=='\\' ){ zOut[i++] = '\\'; zOut[i++] = c; }else if( c<' ' || c>=0x7f ){ zOut[i++] = '\\'; if( c=='\n' ){ zOut[i++] = 'n'; }else if( c=='\r' ){ zOut[i++] = 'r'; }else{ zOut[i++] = 'u'; for(j=3; j>=0; j--){ zOut[i+j] = "0123456789abcdef"[c&0xf]; c >>= 4; } i += 4; } }else{ zOut[i++] = c; } } zOut[i] = 0; } /* ** The characters used for HTTP base64 encoding. */ static unsigned char zBase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
︙ | ︙ | |||
705 706 707 708 709 710 711 | /* ** Return true if the input string contains only valid base-16 digits. ** If any invalid characters appear in the string, return false. */ int validate16(const char *zIn, int nIn){ int i; if( nIn<0 ) nIn = (int)strlen(zIn); | < < < | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | /* ** Return true if the input string contains only valid base-16 digits. ** If any invalid characters appear in the string, return false. */ int validate16(const char *zIn, int nIn){ int i; if( nIn<0 ) nIn = (int)strlen(zIn); for(i=0; i<nIn; i++, zIn++){ if( zDecode[zIn[0]&0xff]>63 ){ return zIn[0]==0; } } return 1; } |
︙ | ︙ |
Changes to src/etag.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** in the ETag include: ** ** (1) The mtime on the Fossil executable ** (2) The last change to the CONFIG table ** (3) The last change to the EVENT table ** (4) The value of the display cookie ** (5) A hash value supplied by the page generator | < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** in the ETag include: ** ** (1) The mtime on the Fossil executable ** (2) The last change to the CONFIG table ** (3) The last change to the EVENT table ** (4) The value of the display cookie ** (5) A hash value supplied by the page generator ** ** Item (1) is always included in the ETag. The other elements are ** optional. Because (1) is always included as part of the ETag, all ** outstanding ETags can be invalidated by touching the fossil executable. ** ** A page generator routine invokes etag_check() exactly once, with ** arguments that indicates which of the above elements to include in the |
︙ | ︙ | |||
60 61 62 63 64 65 66 | /* ** Things to monitor */ #define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */ #define ETAG_DATA 0x02 /* Output depends on the EVENT table */ #define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */ #define ETAG_HASH 0x08 /* Output depends on a hash */ | < < < < < < < < < < < < < < < < < < < < > < < < < | | < < > > | | < | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | 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 | /* ** Things to monitor */ #define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */ #define ETAG_DATA 0x02 /* Output depends on the EVENT table */ #define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */ #define ETAG_HASH 0x08 /* Output depends on a hash */ #endif static char zETag[33]; /* The generated ETag */ static int iMaxAge = 0; /* The max-age parameter in the reply */ static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */ /* ** Generate an ETag */ void etag_check(unsigned eFlags, const char *zHash){ sqlite3_int64 mtime; const char *zIfNoneMatch; char zBuf[50]; assert( zETag[0]==0 ); /* Only call this routine once! */ iMaxAge = 86400; md5sum_init(); /* Always include the mtime of the executable as part of the hash */ mtime = file_mtime(g.nameOfExe, ExtFILE); sqlite3_snprintf(sizeof(zBuf),zBuf,"mtime: %lld\n", mtime); md5sum_step_text(zBuf, -1); if( (eFlags & ETAG_HASH)!=0 && zHash ){ md5sum_step_text("hash: ", -1); md5sum_step_text(zHash, -1); md5sum_step_text("\n", 1); iMaxAge = 0; }else if( eFlags & ETAG_DATA ){ int iKey = db_int(0, "SELECT max(rcvid) FROM rcvfrom"); sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey); md5sum_step_text("data: ", -1); md5sum_step_text(zBuf, -1); md5sum_step_text("\n", 1); iMaxAge = 60; }else if( eFlags & ETAG_CONFIG ){ int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'"); sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey); md5sum_step_text("data: ", -1); md5sum_step_text(zBuf, -1); md5sum_step_text("\n", 1); iMaxAge = 3600; } /* Include the display cookie */ if( eFlags & ETAG_COOKIE ){ md5sum_step_text("display-cookie: ", -1); md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1); md5sum_step_text("\n", 1); iMaxAge = 0; } /* Generate the ETag */ memcpy(zETag, md5sum_finish(0), 33); /* Check to see if the generated ETag matches If-None-Match and ** generate a 304 reply if it does. */ zIfNoneMatch = P("HTTP_IF_NONE_MATCH"); if( zIfNoneMatch==0 ) return; if( strcmp(zIfNoneMatch,zETag)!=0 ) return; /* If we get this far, it means that the content has ** not changed and we can do a 304 reply */ cgi_reset_content(); cgi_set_status(304, "Not Modified"); cgi_reply(); db_close(0); fossil_exit(0); } /* ** Accept a new Last-Modified time. This routine should be called by ** page generators that know a valid last-modified time. This routine ** might generate a 304 Not Modified reply and exit(), never returning. ** Or, if not, it will cause a Last-Modified: header to be included in the ** reply. */ void etag_last_modified(sqlite3_int64 mtime){ const char *zIfModifiedSince; sqlite3_int64 x; assert( iEtagMtime==0 ); /* Only call this routine once */ assert( mtime>0 ); /* Only call with a valid mtime */ iEtagMtime = mtime; /* Check to see the If-Modified-Since constraint is satisfied */ zIfModifiedSince = P("HTTP_IF_MODIFIED_SINCE"); if( zIfModifiedSince==0 ) return; x = cgi_rfc822_parsedate(zIfModifiedSince); if( x<mtime ) return; #if 0 /* If the Fossil executable is more recent than If-Modified-Since, ** go ahead and regenerate the resource. */ if( file_mtime(g.nameOfExe, ExtFILE)>x ) return; #endif /* If we reach this point, it means that the resource has not changed ** and that we should generate a 304 Not Modified reply */ cgi_reset_content(); cgi_set_status(304, "Not Modified"); cgi_reply(); db_close(0); fossil_exit(0); } /* Return the ETag, if there is one. */ const char *etag_tag(void){ return zETag; } /* Return the recommended max-age */ int etag_maxage(void){ return iMaxAge; } /* Return the last-modified time in seconds since 1970. Or return 0 if ** there is no last-modified time. */ sqlite3_int64 etag_mtime(void){ return iEtagMtime; } /* ** COMMAND: test-etag ** ** Usage: fossil test-etag -key KEY-NUMBER -hash HASH ** ** Generate an etag given a KEY-NUMBER and/or a HASH. ** ** KEY-NUMBER is some combination of: |
︙ | ︙ | |||
266 267 268 269 270 271 272 | db_find_and_open_repository(0, 0); zKey = find_option("key",0,1); zHash = find_option("hash",0,1); if( zKey ) iKey = atoi(zKey); etag_check(iKey, zHash); fossil_print("%s\n", etag_tag()); } | < < < < < < < < | 206 207 208 209 210 211 212 | db_find_and_open_repository(0, 0); zKey = find_option("key",0,1); zHash = find_option("hash",0,1); if( zKey ) iKey = atoi(zKey); etag_check(iKey, zHash); fossil_print("%s\n", etag_tag()); } |
Changes to src/event.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | ** v=BOOLEAN Show details if TRUE. Default is FALSE. Optional. ** ** Display an existing tech-note identified by its ID, optionally at a ** specific version, and optionally with additional details. */ void event_page(void){ int rid = 0; /* rid of the event artifact */ | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | ** v=BOOLEAN Show details if TRUE. Default is FALSE. Optional. ** ** Display an existing tech-note identified by its ID, optionally at a ** specific version, and optionally with additional details. */ void event_page(void){ int rid = 0; /* rid of the event artifact */ char *zUuid; /* UUID corresponding to rid */ const char *zId; /* Event identifier */ const char *zVerbose; /* Value of verbose option */ char *zETime; /* Time of the tech-note */ char *zATime; /* Time the artifact was created */ int specRid; /* rid specified by aid= parameter */ int prevRid, nextRid; /* Previous or next edits of this tech-note */ Manifest *pTNote; /* Parsed technote artifact */ |
︙ | ︙ | |||
108 109 110 111 112 113 114 | if( db_step(&q1)==SQLITE_ROW ){ prevRid = db_column_int(&q1, 0); } break; } } db_finalize(&q1); | < | < | 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 | if( db_step(&q1)==SQLITE_ROW ){ prevRid = db_column_int(&q1, 0); } break; } } db_finalize(&q1); if( rid==0 || (specRid!=0 && specRid!=rid) ){ style_header("No Such Tech-Note"); @ Cannot locate a technical note called <b>%h(zId)</b>. style_footer(); return; } zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zVerbose = P("v"); if( !zVerbose ){ zVerbose = P("verbose"); } if( !zVerbose ){ zVerbose = P("detail"); /* deprecated */ } verboseFlag = (zVerbose!=0) && !is_false(zVerbose); /* Extract the event content. */ pTNote = manifest_get(rid, CFTYPE_EVENT, 0); if( pTNote==0 ){ fossil_fatal("Object #%d is not a tech-note", rid); } zMimetype = wiki_filter_mimetypes(PD("mimetype",pTNote->zMimetype)); blob_init(&fullbody, pTNote->zWiki, -1); blob_init(&title, 0, 0); |
︙ | ︙ | |||
211 212 213 214 215 216 217 | }else{ @ <div> } blob_init(&comment, pTNote->zComment, -1); wiki_convert(&comment, 0, WIKI_INLINE); blob_reset(&comment); @ </div> | | | < | | 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 | }else{ @ <div> } blob_init(&comment, pTNote->zComment, -1); wiki_convert(&comment, 0, WIKI_INLINE); blob_reset(&comment); @ </div> @ </blockquote><hr /> } if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){ wiki_convert(&fullbody, 0, 0); }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){ cgi_append_content(blob_buffer(&tail), blob_size(&tail)); }else{ @ <pre> @ %h(blob_str(&fullbody)) @ </pre> } zFullId = db_text(0, "SELECT SUBSTR(tagname,7)" " FROM tag" " WHERE tagname GLOB 'event-%q*'", zId); attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>"); style_footer(); manifest_destroy(pTNote); } /* ** Add or update a new tech note to the repository. rid is id of ** the prior version of this technote, if any. ** |
︙ | ︙ | |||
270 271 272 273 274 275 276 | zDate = date_in_standard_format("now"); blob_appendf(&event, "D %s\n", zDate); free(zDate); zETime[10] = 'T'; blob_appendf(&event, "E %s %s\n", zETime, zId); zETime[10] = ' '; | < < < > > > | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | zDate = date_in_standard_format("now"); blob_appendf(&event, "D %s\n", zDate); free(zDate); zETime[10] = 'T'; blob_appendf(&event, "E %s %s\n", zETime, zId); zETime[10] = ' '; if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&event, "P %s\n", zUuid); free(zUuid); } if( zMimetype && zMimetype[0] ){ blob_appendf(&event, "N %s\n", zMimetype); } if( zClr && zClr[0] ){ blob_appendf(&event, "T +bgcolor * %F\n", zClr); } if( zTags && zTags[0] ){ Blob tags, one; int i, j; Stmt q; |
︙ | ︙ | |||
327 328 329 330 331 332 333 | blob_appendf(&event, "U %F\n", login_name()); } blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody); md5sum_blob(&event, &cksum); blob_appendf(&event, "Z %b\n", &cksum); blob_reset(&cksum); nrid = content_put(&event); | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | blob_appendf(&event, "U %F\n", login_name()); } blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody); md5sum_blob(&event, &cksum); blob_appendf(&event, "Z %b\n", &cksum); blob_reset(&cksum); nrid = content_put(&event); db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); if( manifest_crosslink(nrid, &event, MC_NONE)==0 ){ db_end_transaction(1); return 0; } assert( blob_is_reset(&event) ); content_deltify(rid, &nrid, 1, 0); db_end_transaction(0); |
︙ | ︙ | |||
358 359 360 361 362 363 364 | ** w=TEXT Complete text of the technote. ** t=TEXT Time of the technote on the timeline (ISO 8601) ** c=TEXT Timeline comment ** g=TEXT Tags associated with this technote ** mimetype=TEXT Mimetype for w= text ** newclr Use a background color ** clr=TEXT Background color to use if newclr | < < < < | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | ** w=TEXT Complete text of the technote. ** t=TEXT Time of the technote on the timeline (ISO 8601) ** c=TEXT Timeline comment ** g=TEXT Tags associated with this technote ** mimetype=TEXT Mimetype for w= text ** newclr Use a background color ** clr=TEXT Background color to use if newclr */ void eventedit_page(void){ char *zTag; int rid = 0; Blob event; const char *zId; int n; |
︙ | ︙ | |||
415 416 417 418 419 420 421 | /* Need both check-in and wiki-write or wiki-create privileges in order ** to edit/create an event. */ if( !g.perm.Write || (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ login_needed(g.anon.Write && (rid ? g.anon.WrWiki : g.anon.NewWiki)); return; } | < < < < < < < < < < | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | /* Need both check-in and wiki-write or wiki-create privileges in order ** to edit/create an event. */ if( !g.perm.Write || (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ login_needed(g.anon.Write && (rid ? g.anon.WrWiki : g.anon.NewWiki)); return; } /* Figure out the color */ if( rid ){ zClr = db_text("", "SELECT bgcolor FROM event WHERE objid=%d", rid); }else{ zClr = ""; isNew = 1; } if( P("newclr") ){ zClr = PD("clr",zClr); if( zClr[0] ) zClrFlag = " checked"; |
︙ | ︙ | |||
466 467 468 469 470 471 472 | " AND tagxref.tagid=tag.tagid" " AND tag.tagname GLOB 'sym-*'", rid ); } } zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); | | > | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | " AND tagxref.tagid=tag.tagid" " AND tag.tagname GLOB 'sym-*'", rid ); } } zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){ login_verify_csrf_secret(); if ( !event_commit_common(rid, zId, zBody, zETime, zMimetype, zComment, zTags, zClrFlag[0] ? zClr : 0) ){ style_header("Error"); @ Internal error: Fossil tried to make an invalid artifact for @ the edited technote. style_footer(); return; } cgi_redirectf("%R/technote?name=%T", zId); } if( P("cancel")!=0 ){ cgi_redirectf("%R/technote?name=%T", zId); return; |
︙ | ︙ | |||
509 510 511 512 513 514 515 | wiki_convert(&com, 0, WIKI_INLINE|WIKI_NOBADLINKS); @ </td></tr></table> @ </blockquote> @ <p><b>Page content preview:</b><p> @ <blockquote> blob_init(&event, 0, 0); blob_append(&event, zBody, -1); | < | | | | | | < | | | | | | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | wiki_convert(&com, 0, WIKI_INLINE|WIKI_NOBADLINKS); @ </td></tr></table> @ </blockquote> @ <p><b>Page content preview:</b><p> @ <blockquote> blob_init(&event, 0, 0); blob_append(&event, zBody, -1); wiki_render_by_mimetype(&event, zMimetype); @ </blockquote><hr /> blob_reset(&event); } for(n=2, z=zBody; z[0]; z++){ if( z[0]=='\n' ) n++; } if( n<20 ) n = 20; if( n>40 ) n = 40; @ <form method="post" action="%R/technoteedit"><div> login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zId)" /> @ <table border="0" cellspacing="10"> @ <tr><th align="right" valign="top">Timestamp (UTC):</th> @ <td valign="top"> @ <input type="text" name="t" size="25" value="%h(zETime)" /> @ </td></tr> @ <tr><th align="right" valign="top">Timeline Comment:</th> @ <td valign="top"> @ <textarea name="c" class="technoteedit" cols="80" @ rows="3" wrap="virtual">%h(zComment)</textarea> @ </td></tr> @ <tr><th align="right" valign="top">Timeline Background Color:</th> @ <td valign="top"> @ <input type='checkbox' name='newclr'%s(zClrFlag) /> @ Use custom color: \ @ <input type='color' name='clr' value='%s(zClr[0]?zClr:"#c0f0ff")'> @ </td></tr> @ <tr><th align="right" valign="top">Tags:</th> @ <td valign="top"> @ <input type="text" name="g" size="40" value="%h(zTags)" /> @ </td></tr> @ <tr><th align="right" valign="top">Markup Style:</th> @ <td valign="top"> mimetype_option_menu(zMimetype); @ </td></tr> @ <tr><th align="right" valign="top">Page Content:</th> @ <td valign="top"> @ <textarea name="w" class="technoteedit" cols="80" @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea> @ </td></tr> @ <tr><td colspan="2"> @ <input type="submit" name="cancel" value="Cancel" /> @ <input type="submit" name="preview" value="Preview" /> if( P("preview") ){ @ <input type="submit" name="submit" value="Submit" /> } @ </td></tr></table> @ </div></form> style_footer(); } /* ** Add a new tech note to the repository. The timestamp is ** given by the zETime parameter. rid must be zero to create ** a new page. If no previous page with the name zPageName exists ** and isNew is false, then this routine throws an error. |
︙ | ︙ |
Changes to src/export.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | */ static struct { const char *zTrunkName; /* Name of trunk branch */ } gexport; #if INTERFACE /* | | > | > > > > > | | | | | 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 | */ static struct { const char *zTrunkName; /* Name of trunk branch */ } gexport; #if INTERFACE /* ** struct mark_t ** holds information for translating between git commits ** and fossil commits. ** -git_name: This is the mark name that identifies the commit to git. ** It will always begin with a ':'. ** -rid: The unique object ID that identifies this commit within the ** repository database. ** -uuid: The SHA-1/SHA-3 of artifact corresponding to rid. */ struct mark_t{ char *name; int rid; char uuid[65]; }; #endif /* ** Output a "committer" record for the given user. ** NOTE: the given user name may be an email itself. */ |
︙ | ︙ | |||
161 162 163 164 165 166 167 | printf(" %s <%s>", zName, zEmail); free(zName); free(zEmail); db_reset(&q); } | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | printf(" %s <%s>", zName, zEmail); free(zName); free(zEmail); db_reset(&q); } #define REFREPLACEMENT '_' /* ** Output a sanitized git named reference. ** https://git-scm.com/docs/git-check-ref-format ** This implementation assumes we are only printing ** the branch or tag part of the reference. */ |
︙ | ︙ | |||
202 203 204 205 206 207 208 | case '^': case ':': case '?': case '*': case '[': case '\\': zEncoded[w]=REFREPLACEMENT; | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | case '^': case ':': case '?': case '*': case '[': case '\\': zEncoded[w]=REFREPLACEMENT; break; } } /* Cannot begin with a . or / */ if( zEncoded[0]=='.' || zEncoded[0] == '/' ) zEncoded[0]=REFREPLACEMENT; if( i>0 ){ i--; w--; /* Or end with a . or / */ |
︙ | ︙ | |||
289 290 291 292 293 294 295 | return NULL; } } return zMark; } /* | < | > > | | | | < | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | return NULL; } } return zMark; } /* ** parse_mark() ** Create a new (mark,rid,uuid) entry in the 'xmark' table given a line ** from a marks file. Return the cross-ref information as a struct mark_t ** in *mark. ** This function returns -1 in the case that the line is blank, malformed, or ** the rid/uuid named in 'line' does not match what is in the repository ** database. Otherwise, 0 is returned. ** mark->name is dynamically allocated, and owned by the caller. */ int parse_mark(char *line, struct mark_t *mark){ char *cur_tok; char type_; cur_tok = strtok(line, " \t"); if( !cur_tok || strlen(cur_tok)<2 ){ return -1; |
︙ | ︙ | |||
353 354 355 356 357 358 359 | /* insert a cross-ref into the 'xmark' table */ insert_commit_xref(mark->rid, mark->name, mark->uuid); return 0; } /* | > | | | | | | < | | | < | | | | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | /* insert a cross-ref into the 'xmark' table */ insert_commit_xref(mark->rid, mark->name, mark->uuid); return 0; } /* ** import_marks() ** Import the marks specified in file 'f' into the 'xmark' table. ** If 'blobs' is non-null, insert all blob marks into it. ** If 'vers' is non-null, insert all commit marks into it. ** If 'unused_marks' is non-null, upon return of this function, all values ** x >= *unused_marks are free to use as marks, i.e. they do not clash with ** any marks appearing in the marks file. ** Each line in the file must be at most 100 characters in length. This ** seems like a reasonable maximum for a 40-character uuid, and 1-13 ** character rid. ** The function returns -1 if any of the lines in file 'f' are malformed, ** or the rid/uuid information doesn't match what is in the repository ** database. Otherwise, 0 is returned. */ int import_marks(FILE* f, Bag *blobs, Bag *vers, unsigned int *unused_mark){ char line[101]; while(fgets(line, sizeof(line), f)){ struct mark_t mark; if( strlen(line)==100 && line[99]!='\n' ){ /* line too long */ |
︙ | ︙ | |||
445 446 447 448 449 450 451 | do{ export_mark(f, rid, 'c'); }while( (rid = bag_next(vers, rid))!=0 ); } } } | | | | | | | | < < < < < | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | do{ export_mark(f, rid, 'c'); }while( (rid = bag_next(vers, rid))!=0 ); } } } /* ** COMMAND: export ** ** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY? ** ** Write an export of all check-ins to standard output. The export is ** written in the git-fast-export file format assuming the --git option is ** provided. The git-fast-export format is currently the only VCS ** interchange format supported, though other formats may be added in ** the future. ** ** Run this command within a checkout. Or use the -R or --repository ** option to specify a Fossil repository to be exported. ** ** Only check-ins are exported using --git. Git does not support tickets ** or wiki or tech notes or attachments, so none of those are exported. ** ** If the "--import-marks FILE" option is used, it contains a list of ** rids to skip. ** ** If the "--export-marks FILE" option is used, the rid of all commits and ** blobs written on exit for use with "--import-marks" on the next run. ** ** Options: ** --export-marks FILE export rids of exported data to FILE ** --import-marks FILE read rids of data to ignore from FILE ** --rename-trunk NAME use NAME as name of exported trunk branch ** --repository|-R REPOSITORY export the given REPOSITORY ** ** See also: import */ void export_cmd(void){ Stmt q, q2, q3; Bag blobs, vers; unsigned int unused_mark = 1; const char *markfile_in; const char *markfile_out; |
︙ | ︙ | |||
505 506 507 508 509 510 511 | db_find_and_open_repository(0, 2); verify_all_options(); if( g.argc!=2 && g.argc!=3 ){ usage("--git ?REPOSITORY?"); } db_multi_exec("CREATE TEMPORARY TABLE oldblob(rid INTEGER PRIMARY KEY)"); db_multi_exec("CREATE TEMPORARY TABLE oldcommit(rid INTEGER PRIMARY KEY)"); | | < | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | db_find_and_open_repository(0, 2); verify_all_options(); if( g.argc!=2 && g.argc!=3 ){ usage("--git ?REPOSITORY?"); } db_multi_exec("CREATE TEMPORARY TABLE oldblob(rid INTEGER PRIMARY KEY)"); db_multi_exec("CREATE TEMPORARY TABLE oldcommit(rid INTEGER PRIMARY KEY)"); db_multi_exec("CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT)"); db_multi_exec("CREATE INDEX xmark_trid ON xmark(trid)"); if( markfile_in!=0 ){ Stmt qb,qc; FILE *f; int rid; f = fossil_fopen(markfile_in, "r"); |
︙ | ︙ | |||
753 754 755 756 757 758 759 | ** tid INTEGER PRIMARY KEY, -- Check-in id ** tseq INT -- integer total order on check-ins. ** ); ** ** This table contains all check-ins of the repository in topological ** order. "Topological order" means that every parent check-in comes ** before all of its children. Topological order is *almost* the same | | | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 | ** tid INTEGER PRIMARY KEY, -- Check-in id ** tseq INT -- integer total order on check-ins. ** ); ** ** This table contains all check-ins of the repository in topological ** order. "Topological order" means that every parent check-in comes ** before all of its children. Topological order is *almost* the same ** thing as "ORDER BY event.mtime". Differences only arrise when there ** are timewarps. In as much as Git hates timewarps, we have to compute ** a correct topological order when doing an export. ** ** Since mtime is a usually already nearly in topological order, the ** algorithm is to start with mtime, then make adjustments as necessary ** for timewarps. This is not a great algorithm for the general case, ** but it is very fast for the overwhelmingly common case where there |
︙ | ︙ | |||
834 835 836 837 838 839 840 | */ void test_topological_sort(void){ int n; db_find_and_open_repository(0, 0); n = topological_sort_checkins(1); fossil_print("%d reorderings required\n", n); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 833 834 835 836 837 838 839 | */ void test_topological_sort(void){ int n; db_find_and_open_repository(0, 0); n = topological_sort_checkins(1); fossil_print("%d reorderings required\n", n); } |
Deleted src/extcgi.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/file.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | # include <sys/utime.h> #else # include <sys/time.h> #endif #if INTERFACE | | > > | | < > | | | < | | < | 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 | # include <sys/utime.h> #else # include <sys/time.h> #endif #if INTERFACE /* Many APIs take a eFType argument which must be one of ExtFILE, RepoFILE, ** or SymFILE. ** ** The difference is in the handling of symbolic links. RepoFILE should be ** used for files that are under management by a Fossil repository. ExtFILE ** should be used for files that are not under management. SymFILE is for ** a few special cases such as the "fossil test-tarball" command when we never ** want to follow symlinks. ** ** If RepoFILE is used and if the allow-symlinks setting is true and if ** the object is a symbolic link, then the object is treated like an ordinary ** file whose content is name of the object to which the symbolic link ** points. ** ** If ExtFILE is used or allow-symlinks is false, then operations on a ** symbolic link are the same as operations on the object to which the ** symbolic link points. ** ** SymFILE is like RepoFILE except that it always uses the target filename of ** a symbolic link as the content, instead of the content of the object ** that the symlink points to. SymFILE acts as if allow-symlinks is always ON. */ #define ExtFILE 0 /* Always follow symlinks */ #define RepoFILE 1 /* Follow symlinks if and only if allow-symlinks is OFF */ #define SymFILE 2 /* Never follow symlinks */ #include <dirent.h> #if defined(_WIN32) # define DIR _WDIR |
︙ | ︙ | |||
132 133 134 135 136 137 138 | const char *zFilename, /* name of file or directory to inspect. */ struct fossilStat *buf, /* pointer to buffer where info should go. */ int eFType /* Look at symlink itself if RepoFILE and enabled. */ ){ int rc; void *zMbcs = fossil_utf8_to_path(zFilename, 0); #if !defined(_WIN32) | | < < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | const char *zFilename, /* name of file or directory to inspect. */ struct fossilStat *buf, /* pointer to buffer where info should go. */ int eFType /* Look at symlink itself if RepoFILE and enabled. */ ){ int rc; void *zMbcs = fossil_utf8_to_path(zFilename, 0); #if !defined(_WIN32) if( eFType>=RepoFILE && (eFType==SymFILE || db_allow_symlinks()) ){ rc = lstat(zMbcs, buf); }else{ rc = stat(zMbcs, buf); } #else rc = win32_stat(zMbcs, buf, eFType); #endif fossil_path_free(zMbcs); return rc; |
︙ | ︙ | |||
202 203 204 205 206 207 208 | /* ** Return the mode bits for a file. Return -1 if the file does not ** exist. If zFilename is NULL return the size of the most recently ** stat-ed file. */ int file_mode(const char *zFilename, int eFType){ | | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | /* ** Return the mode bits for a file. Return -1 if the file does not ** exist. If zFilename is NULL return the size of the most recently ** stat-ed file. */ int file_mode(const char *zFilename, int eFType){ return getStat(zFilename, eFType) ? -1 : fx.fileStat.st_mode; } /* ** Return TRUE if either of the following are true: ** ** (1) zFilename is an ordinary file ** |
︙ | ︙ | |||
241 242 243 244 245 246 247 | void symlink_create(const char *zTargetFile, const char *zLinkFile){ #if !defined(_WIN32) if( db_allow_symlinks() ){ int i, nName; char *zName, zBuf[1000]; nName = strlen(zLinkFile); | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | void symlink_create(const char *zTargetFile, const char *zLinkFile){ #if !defined(_WIN32) if( db_allow_symlinks() ){ int i, nName; char *zName, zBuf[1000]; nName = strlen(zLinkFile); if( nName>=sizeof(zBuf) ){ zName = mprintf("%s", zLinkFile); }else{ zName = zBuf; memcpy(zName, zLinkFile, nName+1); } nName = file_simplify_name(zName, nName, 0); for(i=1; i<nName; i++){ |
︙ | ︙ | |||
295 296 297 298 299 300 301 | ** If eFType is ExtFile then symbolic links are followed and so this ** routine can only return PERM_EXE and PERM_REG. ** ** On windows, this routine returns only PERM_REG. */ int file_perm(const char *zFilename, int eFType){ #if !defined(_WIN32) | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | ** If eFType is ExtFile then symbolic links are followed and so this ** routine can only return PERM_EXE and PERM_REG. ** ** On windows, this routine returns only PERM_REG. */ int file_perm(const char *zFilename, int eFType){ #if !defined(_WIN32) if( !getStat(zFilename, RepoFILE) ){ if( S_ISREG(fx.fileStat.st_mode) && ((S_IXUSR)&fx.fileStat.st_mode)!=0 ) return PERM_EXE; else if( db_allow_symlinks() && S_ISLNK(fx.fileStat.st_mode) ) return PERM_LNK; } #endif return PERM_REG; |
︙ | ︙ | |||
317 318 319 320 321 322 323 | return file_perm(zFilename, eFType)==PERM_EXE; } /* ** Return TRUE if the named file is a symlink and symlinks are allowed. ** Return false for all other cases. ** | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | return file_perm(zFilename, eFType)==PERM_EXE; } /* ** Return TRUE if the named file is a symlink and symlinks are allowed. ** Return false for all other cases. ** ** This routines RepoFILE - that zFilename is always a file under management. ** ** On Windows, always return False. */ int file_islink(const char *zFilename){ return file_perm(zFilename, RepoFILE)==PERM_LNK; } /* ** Return 1 if zFilename is a directory. Return 0 if zFilename ** does not exist. Return 2 if zFilename exists but is something ** other than a directory. */ int file_isdir(const char *zFilename, int eFType){ int rc; |
︙ | ︙ | |||
421 422 423 424 425 426 427 | }else{ rc = 2; /* It exists and is something else. */ } free(zFN); return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | }else{ rc = 2; /* It exists and is something else. */ } free(zFN); return rc; } /* ** Wrapper around the access() system call. */ int file_access(const char *zFilename, int flags){ int rc; void *zMbcs = fossil_utf8_to_path(zFilename, 0); |
︙ | ︙ | |||
492 493 494 495 496 497 498 | #ifdef _WIN32 rc = win32_chdir(zPath, bChroot); #else rc = chdir(zPath); if( !rc && bChroot ){ rc = chroot(zPath); if( !rc ) rc = chdir("/"); | < | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | #ifdef _WIN32 rc = win32_chdir(zPath, bChroot); #else rc = chdir(zPath); if( !rc && bChroot ){ rc = chroot(zPath); if( !rc ) rc = chdir("/"); } #endif fossil_path_free(zPath); return rc; } /* |
︙ | ︙ | |||
552 553 554 555 556 557 558 | const char *zTail = file_tail(z); if( zTail && zTail!=z ){ return mprintf("%.*s", (int)(zTail-z-1), z); }else{ return 0; } } | < < < < < < < < < < < < < < < < < < < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | const char *zTail = file_tail(z); if( zTail && zTail!=z ){ return mprintf("%.*s", (int)(zTail-z-1), z); }else{ return 0; } } /* ** Rename a file or directory. ** Returns zero upon success. */ int file_rename( const char *zFrom, |
︙ | ︙ | |||
614 615 616 617 618 619 620 | out = fossil_fopen(zTo, "wb"); if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo); while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){ fwrite(zBuf, 1, got, out); } fclose(in); fclose(out); | < | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | out = fossil_fopen(zTo, "wb"); if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo); while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){ fwrite(zBuf, 1, got, out); } fclose(in); fclose(out); } /* ** COMMAND: test-file-copy ** ** Usage: %fossil test-file-copy SOURCE DESTINATION ** |
︙ | ︙ | |||
645 646 647 648 649 650 651 | ** zFilename is a symbolic link, it is the object that zFilename points ** to that is modified. */ int file_setexe(const char *zFilename, int onoff){ int rc = 0; #if !defined(_WIN32) struct stat buf; | | < < < | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | ** zFilename is a symbolic link, it is the object that zFilename points ** to that is modified. */ int file_setexe(const char *zFilename, int onoff){ int rc = 0; #if !defined(_WIN32) struct stat buf; if( fossil_stat(zFilename, &buf, RepoFILE)!=0 || S_ISLNK(buf.st_mode) ){ return 0; } if( onoff ){ int targetMode = (buf.st_mode & 0444)>>2; if( (buf.st_mode & 0100)==0 ){ chmod(zFilename, buf.st_mode | targetMode); rc = 1; |
︙ | ︙ | |||
733 734 735 736 737 738 739 | char *z = fossil_utf8_to_path(zFilename, 0); rc = unlink(zFilename); #endif fossil_path_free(z); return rc; } | < < < < < < < < < < < < < < < < < < < < | | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | char *z = fossil_utf8_to_path(zFilename, 0); rc = unlink(zFilename); #endif fossil_path_free(z); return rc; } /* ** Create a directory called zName, if it does not already exist. ** If forceFlag is 1, delete any prior non-directory object ** with the same name. ** ** Return the number of errors. */ int file_mkdir(const char *zName, int eFType, int forceFlag){ int rc = file_isdir(zName, eFType); if( rc==2 ){ if( !forceFlag ) return 1; file_delete(zName); } if( rc!=1 ){ #if defined(_WIN32) wchar_t *zMbcs = fossil_utf8_to_path(zName, 1); rc = _wmkdir(zMbcs); #else char *zMbcs = fossil_utf8_to_path(zName, 1); rc = mkdir(zName, 0755); #endif fossil_path_free(zMbcs); return rc; } return 0; } |
︙ | ︙ | |||
800 801 802 803 804 805 806 | int nName, rc = 0; char *zName; nName = strlen(zFilename); zName = mprintf("%s", zFilename); nName = file_simplify_name(zName, nName, 0); while( nName>0 && zName[nName-1]!='/' ){ nName--; } | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 | int nName, rc = 0; char *zName; nName = strlen(zFilename); zName = mprintf("%s", zFilename); nName = file_simplify_name(zName, nName, 0); while( nName>0 && zName[nName-1]!='/' ){ nName--; } if( nName ){ zName[nName-1] = 0; if( file_isdir(zName, eFType)!=1 ){ rc = file_mkfolder(zName, eFType, forceFlag, errorReturn); if( rc==0 ){ if( file_mkdir(zName, eFType, forceFlag) && file_isdir(zName, eFType)!=1 ){ if( errorReturn <= 0 ){ fossil_fatal_recursive("unable to create directory %s", zName); } rc = errorReturn; } } } } free(zName); return rc; } /* ** Removes the directory named in the argument, if it exists. The directory ** must be empty and cannot be the current directory or the root directory. ** ** Returns zero upon success. */ int file_rmdir(const char *zName){ int rc = file_isdir(zName, RepoFILE); if( rc==2 ) return 1; /* cannot remove normal file */ if( rc==1 ){ #if defined(_WIN32) wchar_t *zMbcs = fossil_utf8_to_path(zName, 1); rc = _wrmdir(zMbcs); #else char *zMbcs = fossil_utf8_to_path(zName, 1); rc = rmdir(zName); #endif fossil_path_free(zMbcs); return rc; } return 0; } /* ** Return true if the filename given is a valid filename for ** a file in a repository. Valid filenames follow all of the ** following rules: ** ** * Does not begin with "/" ** * Does not contain any path element named "." or ".." |
︙ | ︙ | |||
1037 1038 1039 1040 1041 1042 1043 | if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0; } } } if( z[i-1]=='/' ) return 0; return 1; } | < < < < < < < < < < < < < < < < < | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0; } } } if( z[i-1]=='/' ) return 0; return 1; } /* ** If the last component of the pathname in z[0]..z[j-1] is something ** other than ".." then back it out and return true. If the last ** component is empty or if it is ".." then return false. */ static int backup_dir(const char *z, int *pJ){ |
︙ | ︙ | |||
1087 1088 1089 1090 1091 1092 1093 | ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. */ int file_simplify_name(char *z, int n, int slash){ int i = 1, j; assert( z!=0 ); if( n<0 ) n = strlen(z); | < | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. */ int file_simplify_name(char *z, int n, int slash){ int i = 1, j; assert( z!=0 ); if( n<0 ) n = strlen(z); /* On windows and cygwin convert all \ characters to / * and remove extended path prefix if present */ #if defined(_WIN32) || defined(__CYGWIN__) for(j=0; j<n; j++){ if( z[j]=='\\' ) z[j] = '/'; } |
︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 | } /* ** COMMAND: test-simplify-name ** ** Usage: %fossil test-simplify-name FILENAME... ** | | < < < < < < < < < < < | < < < < | < < < < | | < | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 | } /* ** COMMAND: test-simplify-name ** ** Usage: %fossil test-simplify-name FILENAME... ** ** Print the simplified versions of each FILENAME. */ void cmd_test_simplify_name(void){ int i; char *z; for(i=2; i<g.argc; i++){ z = mprintf("%s", g.argv[i]); fossil_print("[%s] -> ", z); file_simplify_name(z, -1, 0); fossil_print("[%s]\n", z); fossil_free(z); } } /* ** Get the current working directory. ** ** On windows, the name is converted from unicode to UTF8 and all '\\' ** characters are converted to '/'. No conversions are needed on ** unix. */ void file_getcwd(char *zBuf, int nBuf){ #ifdef _WIN32 win32_getcwd(zBuf, nBuf); #else if( getcwd(zBuf, nBuf-1)==0 ){ if( errno==ERANGE ){ fossil_panic("pwd too big: max %d", nBuf-1); }else{ fossil_panic("cannot find current working directory; %s", strerror(errno)); } } #endif } /* ** Return true if zPath is an absolute pathname. Return false ** if it is relative. */ int file_is_absolute_path(const char *zPath){ |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | ** Compute a canonical pathname for a file or directory. ** Make the name absolute if it is relative. ** Remove redundant / characters ** Remove all /./ path elements. ** Convert /A/../ to just / ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. | < < | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 | ** Compute a canonical pathname for a file or directory. ** Make the name absolute if it is relative. ** Remove redundant / characters ** Remove all /./ path elements. ** Convert /A/../ to just / ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. */ void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ blob_zero(pOut); if( file_is_absolute_path(zOrigName) ){ blob_appendf(pOut, "%/", zOrigName); }else{ char zPwd[2000]; |
︙ | ︙ | |||
1274 1275 1276 1277 1278 1279 1280 | } } #endif blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut), slash)); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > < | 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 | } } #endif blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut), slash)); } /* ** Emits the effective or raw stat() information for the specified ** file or directory, optionally preserving the trailing slash and ** resetting the cached stat() information. */ static void emitFileStat( const char *zPath, int slash, int reset ){ char zBuf[200]; char *z; Blob x; int rc; sqlite3_int64 iMtime; struct fossilStat testFileStat; memset(zBuf, 0, sizeof(zBuf)); blob_zero(&x); file_canonical_name(zPath, &x, slash); fossil_print("[%s] -> [%s]\n", zPath, blob_buffer(&x)); blob_reset(&x); memset(&testFileStat, 0, sizeof(struct fossilStat)); rc = fossil_stat(zPath, &testFileStat, 0); fossil_print(" stat_rc = %d\n", rc); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size); fossil_print(" stat_size = %s\n", zBuf); z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z); fossil_free(z); fossil_print(" stat_mtime = %s\n", zBuf); fossil_print(" stat_mode = 0%o\n", testFileStat.st_mode); memset(&testFileStat, 0, sizeof(struct fossilStat)); rc = fossil_stat(zPath, &testFileStat, 1); |
︙ | ︙ | |||
1526 1527 1528 1529 1530 1531 1532 | fossil_print(" file_mtime(RepoFILE) = %s\n", zBuf); fossil_print(" file_mode(RepoFILE) = 0%o\n", file_mode(zPath,RepoFILE)); fossil_print(" file_isfile(RepoFILE) = %d\n", file_isfile(zPath,RepoFILE)); fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zPath)); fossil_print(" file_islink = %d\n", file_islink(zPath)); fossil_print(" file_isexe(RepoFILE) = %d\n", file_isexe(zPath,RepoFILE)); fossil_print(" file_isdir(RepoFILE) = %d\n", file_isdir(zPath,RepoFILE)); | < < < < < > | < < | > < | > > < < < < < < < < < < < < < | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 | fossil_print(" file_mtime(RepoFILE) = %s\n", zBuf); fossil_print(" file_mode(RepoFILE) = 0%o\n", file_mode(zPath,RepoFILE)); fossil_print(" file_isfile(RepoFILE) = %d\n", file_isfile(zPath,RepoFILE)); fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zPath)); fossil_print(" file_islink = %d\n", file_islink(zPath)); fossil_print(" file_isexe(RepoFILE) = %d\n", file_isexe(zPath,RepoFILE)); fossil_print(" file_isdir(RepoFILE) = %d\n", file_isdir(zPath,RepoFILE)); if( reset ) resetStat(); } /* ** COMMAND: test-file-environment ** ** Usage: %fossil test-file-environment FILENAME... ** ** Display the effective file handling subsystem "settings" and then ** display file system information about the files specified, if any. ** ** Options: ** ** --allow-symlinks BOOLEAN Temporarily turn allow-symlinks on/off ** --open-config Open the configuration database first. ** --slash Trailing slashes, if any, are retained. ** --reset Reset cached stat() info for each file. */ void cmd_test_file_environment(void){ int i; int slashFlag = find_option("slash",0,0)!=0; int resetFlag = find_option("reset",0,0)!=0; const char *zAllow = find_option("allow-symlinks",0,1); if( find_option("open-config", 0, 0)!=0 ){ Th_OpenConfig(1); } db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); fossil_print("filenames_are_case_sensitive() = %d\n", filenames_are_case_sensitive()); fossil_print("db_allow_symlinks_by_default() = %d\n", db_allow_symlinks_by_default()); if( zAllow ){ g.allowSymlinks = !is_false(zAllow); } fossil_print("db_allow_symlinks() = %d\n", db_allow_symlinks()); for(i=2; i<g.argc; i++){ emitFileStat(g.argv[i], slashFlag, resetFlag); } } /* ** COMMAND: test-canonical-name ** ** Usage: %fossil test-canonical-name FILENAME... |
︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 | char *zFull; int (*xCmp)(const char*,const char*,int); blob_zero(pOut); if( !g.localOpen ){ if( absolute && !file_is_absolute_path(zOrigName) ){ if( errFatal ){ | | | | | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 | char *zFull; int (*xCmp)(const char*,const char*,int); blob_zero(pOut); if( !g.localOpen ){ if( absolute && !file_is_absolute_path(zOrigName) ){ if( errFatal ){ fossil_fatal("relative to absolute needs open checkout tree: %s", zOrigName); } return 0; }else{ /* ** The original path may be relative or absolute; however, without ** an open checkout tree, the only things we can do at this point ** is return it verbatim or generate a fatal error. The caller is ** probably expecting a tree-relative path name will be returned; ** however, most places where this function is called already check ** if the local checkout tree is open, either directly or indirectly, ** which would make this situation impossible. Alternatively, they ** could check the returned path using the file_is_absolute_path() ** function. */ blob_appendf(pOut, "%s", zOrigName); return 1; } |
︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 | return 1; } if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){ blob_reset(&localRoot); blob_reset(&full); if( errFatal ){ | | | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | return 1; } if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){ blob_reset(&localRoot); blob_reset(&full); if( errFatal ){ fossil_fatal("file outside of checkout tree: %s", zOrigName); } return 0; } if( absolute ){ if( !file_is_absolute_path(zOrigName) ){ blob_append(pOut, zLocalRoot, nLocalRoot); } |
︙ | ︙ | |||
1841 1842 1843 1844 1845 1846 1847 | /* ** COMMAND: test-tree-name ** ** Test the operation of the tree name generator. ** ** Options: | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 | /* ** COMMAND: test-tree-name ** ** Test the operation of the tree name generator. ** ** Options: ** --absolute Return an absolute path instead of a relative one. ** --case-sensitive B Enable or disable case-sensitive filenames. B is ** a boolean: "yes", "no", "true", "false", etc. */ void cmd_test_tree_name(void){ int i; Blob x; int absoluteFlag = find_option("absolute",0,0)!=0; db_find_and_open_repository(0,0); blob_zero(&x); for(i=2; i<g.argc; i++){ if( file_tree_name(g.argv[i], &x, absoluteFlag, 1) ){ fossil_print("%s\n", blob_buffer(&x)); blob_reset(&x); } } } /* ** Parse a URI into scheme, host, port, and path. */ void file_parse_uri( const char *zUri, Blob *pScheme, Blob *pHost, |
︙ | ︙ | |||
1934 1935 1936 1937 1938 1939 1940 | blob_set(pPath, &zUri[i]); }else{ blob_set(pPath, "/"); } } /* | | < < < < < < < < < < < | > < < < | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | blob_set(pPath, &zUri[i]); }else{ blob_set(pPath, "/"); } } /* ** Construct a random temporary filename into pBuf starting with zPrefix. */ void file_tempname(Blob *pBuf, const char *zPrefix){ #if defined(_WIN32) const char *azDirs[] = { 0, /* GetTempPath */ 0, /* TEMP */ 0, /* TMP */ ".", }; char *z; #else static const char *azDirs[] = { 0, /* TMPDIR */ "/var/tmp", "/usr/tmp", "/tmp", "/temp", ".", }; #endif static const unsigned char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; unsigned int i; const char *zDir = "."; int cnt = 0; char zRand[16]; #if defined(_WIN32) wchar_t zTmpPath[MAX_PATH]; if( GetTempPathW(MAX_PATH, zTmpPath) ){ azDirs[0] = fossil_path_to_utf8(zTmpPath); /* Removing trailing \ from the temp path */ |
︙ | ︙ | |||
2001 2002 2003 2004 2005 2006 2007 | for(i=0; i<count(azDirs); i++){ if( azDirs[i]==0 ) continue; if( !file_isdir(azDirs[i], ExtFILE) ) continue; zDir = azDirs[i]; break; } | < < < < < < < < < < < < < < < < < < < < | < < | | | | | < < | < < < < < < | | < < < < < < < < < < < | | 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 | for(i=0; i<count(azDirs); i++){ if( azDirs[i]==0 ) continue; if( !file_isdir(azDirs[i], ExtFILE) ) continue; zDir = azDirs[i]; break; } do{ blob_zero(pBuf); if( cnt++>20 ) fossil_panic("cannot generate a temporary filename"); sqlite3_randomness(15, zRand); for(i=0; i<15; i++){ zRand[i] = (char)zChars[ ((unsigned char)zRand[i])%(sizeof(zChars)-1) ]; } zRand[15] = 0; blob_appendf(pBuf, "%s/%s-%s.txt", zDir, zPrefix ? zPrefix : "", zRand); }while( file_size(blob_str(pBuf), ExtFILE)>=0 ); #if defined(_WIN32) fossil_path_free((char *)azDirs[0]); fossil_path_free((char *)azDirs[1]); fossil_path_free((char *)azDirs[2]); /* Change all \ characters in the windows path into / so that they can ** be safely passed to a subcommand, such as by gdiff */ z = blob_buffer(pBuf); for(i=0; z[i]; i++) if( z[i]=='\\' ) z[i] = '/'; #else fossil_path_free((char *)azDirs[0]); #endif } /* ** Compute a temporary filename in zDir. The filename is based on ** the current time. */ char *file_time_tempname(const char *zDir, const char *zSuffix){ struct tm *tm; unsigned int r; static unsigned int cnt = 0; time_t t; t = time(0); tm = gmtime(&t); sqlite3_randomness(sizeof(r), &r); return mprintf("%s/%04d%02d%02d%02d%02d%02d%04d%06d%s", zDir, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, cnt++, r%1000000, zSuffix); } /* ** COMMAND: test-tempname ** Usage: fossil test-name [--time SUFFIX] BASENAME ... ** ** Generate temporary filenames derived from BASENAME. Use the --time ** option to generate temp names based on the time of day. */ void file_test_tempname(void){ int i; const char *zSuffix = find_option("time",0,1); Blob x = BLOB_INITIALIZER; char *z; verify_all_options(); for(i=2; i<g.argc; i++){ if( zSuffix ){ z = file_time_tempname(g.argv[i], zSuffix); fossil_print("%s\n", z); fossil_free(z); }else{ file_tempname(&x, g.argv[i]); fossil_print("%s\n", blob_str(&x)); blob_reset(&x); } } } |
︙ | ︙ | |||
2167 2168 2169 2170 2171 2172 2173 | rc = putenv(zString); /* NOTE: Cannot free the string on POSIX. */ /* fossil_free(zString); */ #endif return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | rc = putenv(zString); /* NOTE: Cannot free the string on POSIX. */ /* fossil_free(zString); */ #endif return rc; } /* ** Like fopen() but always takes a UTF8 argument. ** ** This function assumes ExtFILE. In other words, symbolic links ** are always followed. */ FILE *fossil_fopen(const char *zName, const char *zMode){ #ifdef _WIN32 wchar_t *uMode = fossil_utf8_to_unicode(zMode); wchar_t *uName = fossil_utf8_to_path(zName, 0); FILE *f = _wfopen(uName, uMode); fossil_path_free(uName); fossil_unicode_free(uMode); #else FILE *f = fopen(zName, zMode); #endif return f; } /* ** Return non-NULL if zFilename contains pathname elements that ** are reserved on Windows. The returned string is the disallowed ** path element. */ const char *file_is_win_reserved(const char *zPath){ static const char *azRes[] = { "CON", "PRN", "AUX", "NUL", "COM", "LPT" }; static char zReturn[5]; int i; while( zPath[0] ){ for(i=0; i<count(azRes); i++){ if( sqlite3_strnicmp(zPath, azRes[i], 3)==0 && ((i>=4 && fossil_isdigit(zPath[3]) && (zPath[4]=='/' || zPath[4]=='.' || zPath[4]==0)) |
︙ | ︙ | |||
2345 2346 2347 2348 2349 2350 2351 | void file_test_valid_for_windows(void){ int i; for(i=2; i<g.argc; i++){ fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | < < < < < < | 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 | void file_test_valid_for_windows(void){ int i; for(i=2; i<g.argc; i++){ fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]); } } /* ** Remove surplus "/" characters from the beginning of a full pathname. ** Extra leading "/" characters are benign on unix. But on Windows ** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil" ** into "C:/fossil/xyz.fossil". Cygwin should behave as Windows here. */ const char *file_cleanup_fullpath(const char *z){ #if defined(_WIN32) || defined(__CYGWIN__) if( z[0]=='/' && fossil_isalpha(z[1]) && z[2]==':' && z[3]=='/' ) z++; #else while( z[0]=='/' && z[1]=='/' ) z++; #endif return z; } /* ** Count the number of objects (files and subdirectores) in a given ** directory. Return the count. Return -1 of the object is not a ** directory. */ int file_directory_size(const char *zDir, const char *zGlob, int omitDotFiles){ void *zNative; DIR *d; int n = -1; zNative = fossil_utf8_to_path(zDir,1); d = opendir(zNative); if( d ){ struct dirent *pEntry; n = 0; while( (pEntry=readdir(d))!=0 ){ if( pEntry->d_name[0]==0 ) continue; if( omitDotFiles && pEntry->d_name[0]=='.' ) continue; if( zGlob ){ char *zUtf8 = fossil_path_to_utf8(pEntry->d_name); int rc = sqlite3_strglob(zGlob, zUtf8); fossil_path_free(zUtf8); if( rc ) continue; } n++; |
︙ | ︙ | |||
2464 2465 2466 2467 2468 2469 2470 | if( g.argc!=3 && g.argc!=4 ){ usage("NAME [GLOB] [-nodots]"); } zDir = g.argv[2]; zGlob = g.argc==4 ? g.argv[3] : 0; fossil_print("%d\n", file_directory_size(zDir, zGlob, omitDotFiles)); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1693 1694 1695 1696 1697 1698 1699 | if( g.argc!=3 && g.argc!=4 ){ usage("NAME [GLOB] [-nodots]"); } zDir = g.argv[2]; zGlob = g.argc==4 ? g.argv[3] : 0; fossil_print("%d\n", file_directory_size(zDir, zGlob, omitDotFiles)); } |
Deleted src/fileedit.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/finfo.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | ** in time. The default mode is -l. ** ** For the -l|--log mode: If "-b|--brief" is specified one line per revision ** is printed, otherwise the full comment is printed. The "-n|--limit N" ** and "--offset P" options limits the output to the first N changes ** after skipping P changes. ** | < < < < < < | | | < | | | | | | | < < | > | | | | 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 | ** in time. The default mode is -l. ** ** For the -l|--log mode: If "-b|--brief" is specified one line per revision ** is printed, otherwise the full comment is printed. The "-n|--limit N" ** and "--offset P" options limits the output to the first N changes ** after skipping P changes. ** ** In the -s mode prints the status as <status> <revision>. This is ** a quick status and does not check for up-to-date-ness of the file. ** ** In the -p mode, there's an optional flag "-r|--revision REVISION". ** The specified version (or the latest checked out version) is printed ** to stdout. The -p mode is another form of the "cat" command. ** ** Options: ** -b|--brief display a brief (one line / revision) summary ** --case-sensitive B Enable or disable case-sensitive filenames. B is a ** boolean: "yes", "no", "true", "false", etc. ** -l|--log select log mode (the default) ** -n|--limit N Display the first N changes (default unlimited). ** N<=0 means no limit. ** --offset P skip P changes ** -p|--print select print mode ** -r|--revision R print the given revision (or ckout, if none is given) ** to stdout (only in print mode) ** -s|--status select status mode (print a status indicator for FILE) ** -W|--width <num> Width of lines (default is to auto-detect). Must be ** >22 or 0 (= no limit, resulting in a single line per ** entry). ** ** See also: artifact, cat, descendants, info, leaves */ void finfo_cmd(void){ db_must_be_within_tree(); if( find_option("status","s",0) ){ Stmt q; Blob line; Blob fname; int vid; /* We should be done with options.. */ verify_all_options(); if( g.argc!=3 ) usage("-s|--status FILENAME"); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("no checkout to finfo files in"); } vfile_check_signature(vid, CKSIG_ENOTFILE); file_tree_name(g.argv[2], &fname, 0, 1); db_prepare(&q, "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" " FROM vfile WHERE vfile.pathname=%B %s", &fname, filename_collation()); |
︙ | ︙ | |||
142 143 144 145 146 147 148 | fossil_fatal("no history for file: %b", &fname); } content_get(rid, &record); } blob_write_to_file(&record, "-"); blob_reset(&record); blob_reset(&fname); | < < < < < < < < < < < < < < < < < < < < < < | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | fossil_fatal("no history for file: %b", &fname); } content_get(rid, &record); } blob_write_to_file(&record, "-"); blob_reset(&record); blob_reset(&fname); }else{ Blob line; Stmt q; Blob fname; int rid; const char *zFilename; const char *zLimit; |
︙ | ︙ | |||
227 228 229 230 231 232 233 | " AND event.objid=ci.rid" " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", TAG_BRANCH, zFilename, filename_collation(), iLimit, iOffset ); blob_zero(&line); if( iBrief ){ | | | | < | | | < < < < < < < < < | < < | < | < < < < < < < | | < < | | < | | < | | < | | < < < | > > > | | | < < < < < < | < < < < < < < | > > > | | | | | | < < < < | < < < < < < < < < | | < | | < < < < | < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < | < < | | > | | < | < | | | | | < | < | | | | | < | | | | | < < < < < < | | < < < < | | < | | < | < < | | | | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | > | < < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < < < < < | < | | | | | < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 | " AND event.objid=ci.rid" " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", TAG_BRANCH, zFilename, filename_collation(), iLimit, iOffset ); blob_zero(&line); if( iBrief ){ fossil_print("History of %s\n", blob_str(&fname)); } while( db_step(&q)==SQLITE_ROW ){ const char *zFileUuid = db_column_text(&q, 0); const char *zCiUuid = db_column_text(&q,1); const char *zDate = db_column_text(&q, 2); const char *zCom = db_column_text(&q, 3); const char *zUser = db_column_text(&q, 4); const char *zBr = db_column_text(&q, 5); char *zOut; if( zBr==0 ) zBr = "trunk"; if( iBrief ){ fossil_print("%s ", zDate); zOut = mprintf( "[%S] %s (user: %s, artifact: [%S], branch: %s)", zCiUuid, zCom, zUser, zFileUuid, zBr); comment_print(zOut, zCom, 11, iWidth, g.comFmtFlags); fossil_free(zOut); }else{ blob_reset(&line); blob_appendf(&line, "%S ", zCiUuid); blob_appendf(&line, "%.10s ", zDate); blob_appendf(&line, "%8.8s ", zUser); blob_appendf(&line, "%8.8s ", zBr); blob_appendf(&line,"%-39.39s", zCom ); comment_print(blob_str(&line), zCom, 0, iWidth, g.comFmtFlags); } } db_finalize(&q); blob_reset(&fname); } } /* ** COMMAND: cat ** ** Usage: %fossil cat FILENAME ... ?OPTIONS? ** ** Print on standard output the content of one or more files as they exist ** in the repository. The version currently checked out is shown by default. ** Other versions may be specified using the -r option. ** ** Options: ** -R|--repository FILE Extract artifacts from repository FILE ** -r VERSION The specific check-in containing the file ** ** See also: finfo */ void cat_cmd(void){ int i; Blob content, fname; const char *zRev; db_find_and_open_repository(0, 0); zRev = find_option("r","r",1); /* We should be done with options.. */ verify_all_options(); for(i=2; i<g.argc; i++){ file_tree_name(g.argv[i], &fname, 0, 1); blob_zero(&content); historical_blob(zRev, blob_str(&fname), &content, 1); blob_write_to_file(&content, "-"); blob_reset(&fname); blob_reset(&content); } } /* Values for the debug= query parameter to finfo */ #define FINFO_DEBUG_MLINK 0x01 /* ** WEBPAGE: finfo ** URL: /finfo?name=FILENAME ** ** Show the change history for a single file. ** ** Additional query parameters: ** ** a=DATETIME Only show changes after DATETIME ** b=DATETIME Only show changes before DATETIME ** m=HASH Mark this particular file version ** n=NUM Show the first NUM changes only ** brbg Background color by branch name ** ubg Background color by user name ** ci=UUID Ancestors of a particular check-in ** orig=UUID If both ci and orig are supplied, only show those ** changes on a direct path from orig to ci. ** showid Show RID values for debugging ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, and it may also name a ** timezone offset from UTC as "-HH:MM" (westward) or "+HH:MM" ** (eastward). Either no timezone suffix or "Z" means UTC. */ void finfo_page(void){ Stmt q; const char *zFilename; char zPrevDate[20]; const char *zA; const char *zB; int n; int baseCheckin; int origCheckin = 0; int fnid; Blob title; Blob sql; HQuery url; GraphContext *pGraph; int brBg = P("brbg")!=0; int uBg = P("ubg")!=0; int fDebug = atoi(PD("debug","0")); int fShowId = P("showid")!=0; Stmt qparent; int iTableId = timeline_tableid(); int tmFlags = 0; /* Viewing mode */ const char *zStyle; /* Viewing mode name */ const char *zMark; /* Mark this version of the file */ int selRid = 0; /* RID of the marked file version */ login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("File History"); login_anonymous_available(); tmFlags = timeline_ss_submenu(); if( tmFlags & TIMELINE_COLUMNAR ){ zStyle = "Columnar"; }else if( tmFlags & TIMELINE_COMPACT ){ zStyle = "Compact"; }else if( tmFlags & TIMELINE_VERBOSE ){ zStyle = "Verbose"; }else{ zStyle = "Modern"; } url_initialize(&url, "finfo"); if( brBg ) url_add_parameter(&url, "brbg", 0); if( uBg ) url_add_parameter(&url, "ubg", 0); baseCheckin = name_to_rid_www("ci"); zPrevDate[0] = 0; zFilename = PD("name",""); cookie_render(); fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); if( fnid==0 ){ @ No such file: %h(zFilename) style_footer(); return; } if( g.perm.Admin ){ style_submenu_element("MLink Table", "%R/mlink?name=%t", zFilename); } if( baseCheckin ){ if( P("orig")!=0 ){ origCheckin = name_to_typed_rid(P("orig"),"ci"); path_shortest_stored_in_ancestor_table(origCheckin, baseCheckin); }else{ compute_direct_ancestors(baseCheckin); } } url_add_parameter(&url, "name", zFilename); blob_zero(&sql); blob_append_sql(&sql, "SELECT" " datetime(min(event.mtime),toLocal())," /* Date of change */ " coalesce(event.ecomment, event.comment)," /* Check-in comment */ " coalesce(event.euser, event.user)," /* User who made chng */ " mlink.pid," /* Parent file rid */ " mlink.fid," /* File rid */ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ " blob.uuid," /* Current file uuid */ " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */ " event.bgcolor," /* Background color */ " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" " AND tagxref.rid=mlink.mid)," /* Branchname */ " mlink.mid," /* check-in ID */ " mlink.pfnid," /* Previous filename */ " blob.size" /* File size */ " FROM mlink, event, blob" " WHERE mlink.fnid=%d" " AND event.objid=mlink.mid" " AND mlink.fid=blob.rid", TAG_BRANCH, fnid ); if( (zA = P("a"))!=0 ){ blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zA); url_add_parameter(&url, "a", zA); } if( (zB = P("b"))!=0 ){ blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zB); url_add_parameter(&url, "b", zB); } if( baseCheckin ){ blob_append_sql(&sql, " AND mlink.mid IN (SELECT rid FROM ancestor)" " GROUP BY mlink.fid" ); }else{ /* We only want each version of a file to appear on the graph once, ** at its earliest appearance. All the other times that it gets merged ** into this or that branch can be ignored. An exception is for when ** files are deleted (when they have mlink.fid==0). If the same file ** is deleted in multiple places, we want to show each deletion, so ** use a "fake fid" which is derived from the parent-fid for grouping. ** The same fake-fid must be used on the graph. */ blob_append_sql(&sql, " GROUP BY" " CASE WHEN mlink.fid>0 THEN mlink.fid ELSE mlink.pid+1000000000 END" ); } blob_append_sql(&sql, " ORDER BY event.mtime DESC /*sort*/"); if( (n = atoi(PD("n","0")))>0 ){ blob_append_sql(&sql, " LIMIT %d", n); url_add_parameter(&url, "n", P("n")); } db_prepare(&q, "%s", blob_sql_text(&sql)); if( P("showsql")!=0 ){ @ <p>SQL: %h(blob_str(&sql))</p> } zMark = P("m"); if( zMark ){ selRid = symbolic_name_to_rid(zMark, "*"); } blob_reset(&sql); blob_zero(&title); if( baseCheckin ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); char *zLink = href("%R/info/%!S", zUuid); if( origCheckin ){ blob_appendf(&title, "Changes to file "); }else if( n>0 ){ blob_appendf(&title, "First %d ancestors of file ", n); }else{ blob_appendf(&title, "Ancestors of file "); } blob_appendf(&title,"<a href='%R/finfo?name=%T'>%h</a>", zFilename, zFilename); if( fShowId ) blob_appendf(&title, " (%d)", fnid); blob_append(&title, origCheckin ? " between " : " from ", -1); blob_appendf(&title, "check-in %z%S</a>", zLink, zUuid); if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin); fossil_free(zUuid); if( origCheckin ){ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", origCheckin); zLink = href("%R/info/%!S", zUuid); blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid); fossil_free(zUuid); } }else{ blob_appendf(&title, "History of "); hyperlinked_path(zFilename, &title, 0, "tree", ""); if( fShowId ) blob_appendf(&title, " (%d)", fnid); } @ <h2>%b(&title)</h2> blob_reset(&title); pGraph = graph_init(); @ <table id="timelineTable%d(iTableId)" class="timelineTable"> if( baseCheckin ){ db_prepare(&qparent, "SELECT DISTINCT pid FROM mlink" " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" " AND pmid IN (SELECT rid FROM ancestor)" " ORDER BY isaux /*sort*/" ); }else{ db_prepare(&qparent, "SELECT DISTINCT pid FROM mlink" " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" " ORDER BY isaux /*sort*/" ); } while( db_step(&q)==SQLITE_ROW ){ const char *zDate = db_column_text(&q, 0); const char *zCom = db_column_text(&q, 1); const char *zUser = db_column_text(&q, 2); int fpid = db_column_int(&q, 3); int frid = db_column_int(&q, 4); const char *zPUuid = db_column_text(&q, 5); const char *zUuid = db_column_text(&q, 6); const char *zCkin = db_column_text(&q,7); const char *zBgClr = db_column_text(&q, 8); const char *zBr = db_column_text(&q, 9); int fmid = db_column_int(&q, 10); int pfnid = db_column_int(&q, 11); int szFile = db_column_int(&q, 12); int gidx; char zTime[10]; int nParent = 0; int aParent[GR_MAX_RAIL]; db_bind_int(&qparent, ":fid", frid); db_bind_int(&qparent, ":mid", fmid); db_bind_int(&qparent, ":fnid", fnid); while( db_step(&qparent)==SQLITE_ROW && nParent<count(aParent) ){ aParent[nParent] = db_column_int(&qparent, 0); nParent++; } db_reset(&qparent); if( zBr==0 ) zBr = "trunk"; if( uBg ){ zBgClr = hash_color(zUser); }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){ zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr); } gidx = graph_add_row(pGraph, frid>0 ? frid : fpid+1000000000, nParent, aParent, zBr, zBgClr, zUuid, 0); if( strncmp(zDate, zPrevDate, 10) ){ sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); @ <tr><td> @ <div class="divider timelineDate">%s(zPrevDate)</div> @ </td><td></td><td></td></tr> } memcpy(zTime, &zDate[11], 5); zTime[5] = 0; if( frid==selRid ){ @ <tr class='timelineSelected'> }else{ @ <tr> } @ <td class="timelineTime">\ @ %z(href("%R/artifact/%!S",zUuid))%s(zTime)</a></td> @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div> @ </td> if( zBgClr && zBgClr[0] ){ @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'> }else{ @ <td class="timeline%s(zStyle)Cell"> } if( tmFlags & TIMELINE_COMPACT ){ @ <span class='timelineCompactComment' data-id='%d(frid)'> }else{ @ <span class='timeline%s(zStyle)Comment'> if( (tmFlags & TIMELINE_VERBOSE)!=0 && zUuid ){ hyperlink_to_uuid(zUuid); @ part of check-in \ hyperlink_to_uuid(zCkin); } } @ %W(zCom)</span> if( (tmFlags & TIMELINE_COMPACT)!=0 ){ @ <span class='timelineEllipsis' data-id='%d(frid)' \ @ id='ellipsis-%d(frid)'>...</span> @ <span class='clutter timelineCompactDetail' } if( tmFlags & TIMELINE_COLUMNAR ){ if( zBgClr && zBgClr[0] ){ @ <td class="timelineDetailCell" id='md%d(gidx)'> }else{ @ <td class="timelineDetailCell"> } } if( tmFlags & TIMELINE_COMPACT ){ cgi_printf("<span class='clutter' id='detail-%d'>",frid); } cgi_printf("<span class='timeline%sDetail'>", zStyle); if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("("); if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){ @ file: %z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a> if( fShowId ){ int srcId = delta_source_rid(frid); if( srcId>0 ){ @ id: %d(frid)←%d(srcId) }else{ @ id: %d(frid) } } } @ check-in: \ hyperlink_to_uuid(zCkin); if( fShowId ){ @ (%d(fmid)) } @ user: \ hyperlink_to_user(zUser, zDate, ","); @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>, if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ){ @ size: %d(szFile)) }else{ @ size: %d(szFile) } if( zUuid && origCheckin==0 ){ if( nParent==0 ){ @ <b>Added</b> }else if( pfnid ){ char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d", pfnid); @ <b>Renamed</b> from @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a> } } if( zUuid==0 ){ char *zNewName; zNewName = db_text(0, "SELECT name FROM filename WHERE fnid = " " (SELECT fnid FROM mlink" " WHERE mid=%d" " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))", fmid, zFilename); if( zNewName ){ @ <b>Renamed</b> to @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> fossil_free(zNewName); }else{ @ <b>Deleted</b> } } if( g.perm.Hyperlink && zUuid ){ const char *z = zFilename; @ <span id='links-%d(frid)'><span class='timelineExtraLinks'> @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin)) @ [annotate]</a> @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin)) @ [blame]</a> @ %z(href("%R/timeline?n=all&uf=%!S",zUuid))[check-ins using]</a> if( fpid>0 ){ @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zPUuid,zUuid))[diff]</a> } @ </span></span> } if( fDebug & FINFO_DEBUG_MLINK ){ int ii; char *zAncLink; @ <br />fid=%d(frid) pid=%d(fpid) mid=%d(fmid) if( nParent>0 ){ @ parents=%d(aParent[0]) for(ii=1; ii<nParent; ii++){ @ %d(aParent[ii]) } } zAncLink = href("%R/finfo?name=%T&ci=%!S&debug=1",zFilename,zCkin); @ %z(zAncLink)[ancestry]</a> } tag_private_status(frid); /* End timelineDetail */ if( tmFlags & TIMELINE_COMPACT ){ @ </span></span> }else{ @ </span> } @ </td></tr> } db_finalize(&q); db_finalize(&qparent); if( pGraph ){ graph_finish(pGraph, 1); if( pGraph->nErr ){ graph_free(pGraph); pGraph = 0; }else{ @ <tr class="timelineBottom"><td></td><td></td><td></td></tr> } } @ </table> timeline_output_graph_javascript(pGraph, TIMELINE_FILEDIFF, iTableId); style_footer(); } /* ** WEBPAGE: mlink ** URL: /mlink?name=FILENAME ** URL: /mlink?ci=NAME ** |
︙ | ︙ | |||
827 828 829 830 831 832 833 | void mlink_page(void){ const char *zFName = P("name"); const char *zCI = P("ci"); Stmt q; login_check_credentials(); if( !g.perm.Admin ){ login_needed(g.anon.Admin); return; } | < | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | void mlink_page(void){ const char *zFName = P("name"); const char *zCI = P("ci"); Stmt q; login_check_credentials(); if( !g.perm.Admin ){ login_needed(g.anon.Admin); return; } style_header("MLINK Table"); if( zFName==0 && zCI==0 ){ @ <span class='generalError'> @ Requires either a name= or ci= query parameter @ </span> }else if( zFName ){ int fnid = db_int(0,"SELECT fnid FROM filename WHERE name=%Q",zFName); |
︙ | ︙ | |||
927 928 929 930 931 932 933 | /* 5 */ " (SELECT uuid FROM blob WHERE rid=mlink.pmid)," /* 6 */ " mperm," /* 7 */ " isaux" " FROM mlink WHERE mid=%d ORDER BY 1", mid ); @ <h1>MLINK table for check-in %h(zCI)</h1> | | | | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | /* 5 */ " (SELECT uuid FROM blob WHERE rid=mlink.pmid)," /* 6 */ " mperm," /* 7 */ " isaux" " FROM mlink WHERE mid=%d ORDER BY 1", mid ); @ <h1>MLINK table for check-in %h(zCI)</h1> render_checkin_context(mid, 1); style_table_sorter(); @ <hr /> @ <div class='brlist'> @ <table class='sortable' data-column-types='ttxtttt' data-init-sort='1'> @ <thead><tr> @ <th>File</th> @ <th>Parent<br>Check-in</th> @ <th>Merge?</th> @ <th>New</th> |
︙ | ︙ | |||
983 984 985 986 987 988 989 | @ </tr> } db_finalize(&q); @ </tbody> @ </table> @ </div> } | | | 831 832 833 834 835 836 837 838 839 | @ </tr> } db_finalize(&q); @ </tbody> @ </table> @ </div> } style_footer(); } |
Changes to src/foci.c.
︙ | ︙ | |||
119 120 121 122 123 124 125 | ** ** (0) A full scan. Visit every manifest in the repo. (Slow) ** (1) checkinID=?. visit only the single manifest specified. ** (2) symName=? visit only the single manifest specified. */ static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; | | < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | ** ** (0) A full scan. Visit every manifest in the repo. (Slow) ** (1) checkinID=?. visit only the single manifest specified. ** (2) symName=? visit only the single manifest specified. */ static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; pIdxInfo->estimatedCost = 10000.0; for(i=0; i<pIdxInfo->nConstraint; i++){ if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ && (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID || pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME) ){ if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){ pIdxInfo->idxNum = 1; }else{ |
︙ | ︙ | |||
261 262 263 264 265 266 267 | fociColumn, /* xColumn - read data */ fociRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ | | | < < | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | fociColumn, /* xColumn - read data */ fociRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; sqlite3_create_module(db, "files_of_checkin", &foci_module, 0); return SQLITE_OK; } |
Changes to src/forum.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | /* ** Default to using Markdown markup */ #define DEFAULT_FORUM_MIMETYPE "text/x-markdown" #if INTERFACE /* | | | | > | | < < < < | < | | | | < | < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | > | | > | | | | | | | | > > < < < < < < | | | | | | | < < < < < < < < < | < < | | | | | | | < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | < < < < < < < | < < | | | < < | < < | | < < < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < | > < | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < | < < > | < < < < < < < < | < < | < | | < < < < < < < < < | | > > > > > > | < < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | < < < | < > | > | < < | < < < < < < < < < < | < < < | < < < > | < > > | > > > > > | < > > > > > | < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < | < | < < | | | < < < | < < < < < < < | < > > | | | < < < | | | | < < | | < | < | < < | < < < < < < < < < < < | < < < < | > | | | | > | | < < | < < < < < < < < < < < < < < < | > | | < < < < < < < | < < < < < | | < < < < < | < < | < < < < < < < < < | < < < < < | < < < < < < | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | < < < < < < | < < | < | < < < < < < < < < | < < < < < < < < < < < < < < < < < > > > > > > > > > > > > | < | | | < < < > > > > > > | < > > > > > > | < < < < < | > > > | > > | > > > > | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > < | < < < < < < < < | | < | | < < < < < < < < < < | | < < < < < < < < < < < < | < < | < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > | | < > > > | > > | | | | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | /* ** Default to using Markdown markup */ #define DEFAULT_FORUM_MIMETYPE "text/x-markdown" #if INTERFACE /* ** Each instance of the following object represents a single message - ** either the initial post, an edit to a post, a reply, or an edit to ** a reply. */ struct ForumEntry { int fpid; /* rid for this entry */ int fprev; /* zero if initial entry. non-zero if an edit */ int firt; /* This entry replies to firt */ int mfirt; /* Root in-reply-to */ char *zUuid; /* Artifact hash */ ForumEntry *pLeaf; /* Most recent edit for this entry */ ForumEntry *pEdit; /* This entry is an edit of pEditee */ ForumEntry *pNext; /* Next in chronological order */ ForumEntry *pPrev; /* Previous in chronological order */ ForumEntry *pDisplay; /* Next in display order */ int nIndent; /* Number of levels of indentation for this entry */ }; /* ** A single instance of the following tracks all entries for a thread. */ struct ForumThread { ForumEntry *pFirst; /* First entry in chronological order */ ForumEntry *pLast; /* Last entry in chronological order */ ForumEntry *pDisplay; /* Entries in display order */ ForumEntry *pTail; /* Last on the display list */ }; #endif /* INTERFACE */ /* ** Delete a complete ForumThread and all its entries. */ static void forumthread_delete(ForumThread *pThread){ ForumEntry *pEntry, *pNext; for(pEntry=pThread->pFirst; pEntry; pEntry = pNext){ pNext = pEntry->pNext; fossil_free(pEntry->zUuid); fossil_free(pEntry); } fossil_free(pThread); } #if 0 /* not used */ /* ** Search a ForumEntry list forwards looking for the entry with fpid */ static ForumEntry *forumentry_forward(ForumEntry *p, int fpid){ while( p && p->fpid!=fpid ) p = p->pNext; return p; } #endif /* ** Search backwards for a ForumEntry */ static ForumEntry *forumentry_backward(ForumEntry *p, int fpid){ while( p && p->fpid!=fpid ) p = p->pPrev; return p; } /* ** Add an entry to the display list */ static void forumentry_add_to_display(ForumThread *pThread, ForumEntry *p){ if( pThread->pDisplay==0 ){ pThread->pDisplay = p; }else{ pThread->pTail->pDisplay = p; } pThread->pTail = p; } /* ** Extend the display list for pThread by adding all entries that ** reference fpid. The first such entry will be no earlier then ** entry "p". */ static void forumthread_display_order( ForumThread *pThread, ForumEntry *p, int fpid, int nIndent ){ while( p ){ if( p->fprev==0 && p->mfirt==fpid ){ p->nIndent = nIndent; forumentry_add_to_display(pThread, p); forumthread_display_order(pThread, p->pNext, p->fpid, nIndent+1); } p = p->pNext; } } /* ** Construct a ForumThread object given the root record id. */ static ForumThread *forumthread_create(int froot, int computeHierarchy){ ForumThread *pThread; ForumEntry *pEntry; Stmt q; pThread = fossil_malloc( sizeof(*pThread) ); memset(pThread, 0, sizeof(*pThread)); db_prepare(&q, "SELECT fpid, firt, fprev, (SELECT uuid FROM blob WHERE rid=fpid)" " FROM forumpost" " WHERE froot=%d ORDER BY fmtime", froot ); while( db_step(&q)==SQLITE_ROW ){ pEntry = fossil_malloc( sizeof(*pEntry) ); memset(pEntry, 0, sizeof(*pEntry)); pEntry->fpid = db_column_int(&q, 0); pEntry->firt = db_column_int(&q, 1); pEntry->fprev = db_column_int(&q, 2); pEntry->zUuid = fossil_strdup(db_column_text(&q,3)); pEntry->mfirt = pEntry->firt; pEntry->pPrev = pThread->pLast; pEntry->pNext = 0; if( pThread->pLast==0 ){ pThread->pFirst = pEntry; }else{ pThread->pLast->pNext = pEntry; } pThread->pLast = pEntry; } db_finalize(&q); /* Establish which entries are the latest edit. After this loop ** completes, entries that have non-NULL pLeaf should not be ** displayed. */ for(pEntry=pThread->pFirst; pEntry; pEntry=pEntry->pNext){ if( pEntry->fprev ){ ForumEntry *pBase = 0, *p; p = forumentry_backward(pEntry->pPrev, pEntry->fprev); pEntry->pEdit = p; while( p ){ pBase = p; p->pLeaf = pEntry; p = pBase->pEdit; } for(p=pEntry->pNext; p; p=p->pNext){ if( p->mfirt==pEntry->fpid ) p->mfirt = pBase->fpid; } } } if( computeHierarchy ){ /* Compute the hierarchical display order */ pEntry = pThread->pFirst; pEntry->nIndent = 1; forumentry_add_to_display(pThread, pEntry); forumthread_display_order(pThread, pEntry, pEntry->fpid, 2); } /* Return the result */ return pThread; } /* ** COMMAND: test-forumthread ** ** Usage: %fossil test-forumthread THREADID ** ** Display a summary of all messages on a thread. */ void forumthread_cmd(void){ int fpid; int froot; const char *zName; ForumThread *pThread; ForumEntry *p; db_find_and_open_repository(0,0); verify_all_options(); if( g.argc!=3 ) usage("THREADID"); zName = g.argv[2]; fpid = symbolic_name_to_rid(zName, "f"); if( fpid<=0 ){ fossil_fatal("Unknown or ambiguous forum id: \"%s\"", zName); } froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid); if( froot==0 ){ fossil_fatal("Not a forum post: \"%s\"", zName); } fossil_print("fpid = %d\n", fpid); fossil_print("froot = %d\n", froot); pThread = forumthread_create(froot, 1); fossil_print("Chronological:\n"); /* 123456789 123456789 123456789 123456789 123456789 */ fossil_print(" fpid firt fprev mfirt pLeaf\n"); for(p=pThread->pFirst; p; p=p->pNext){ fossil_print("%9d %9d %9d %9d %9d\n", p->fpid, p->firt, p->fprev, p->mfirt, p->pLeaf ? p->pLeaf->fpid : 0); } fossil_print("\nDisplay\n"); for(p=pThread->pDisplay; p; p=p->pDisplay){ fossil_print("%*s", (p->nIndent-1)*3, ""); if( p->pLeaf ){ fossil_print("%d->%d\n", p->fpid, p->pLeaf->fpid); }else{ fossil_print("%d\n", p->fpid); } } forumthread_delete(pThread); } /* ** Render a forum post for display */ void forum_render( const char *zTitle, /* The title. Might be NULL for no title */ const char *zMimetype, /* Mimetype of the message */ const char *zContent, /* Content of the message */ const char *zClass /* Put in a <div> if not NULL */ ){ if( zClass ){ @ <div class='%s(zClass)'> } if( zTitle ){ if( zTitle[0] ){ @ <h1>%h(zTitle)</h1> }else{ @ <h1><i>Deleted</i></h1> } } if( zContent && zContent[0] ){ Blob x; blob_init(&x, 0, 0); blob_append(&x, zContent, -1); wiki_render_by_mimetype(&x, zMimetype); blob_reset(&x); }else{ @ <i>Deleted</i> } if( zClass ){ @ </div> } } /* ** Generate the buttons in the display that allow a forum supervisor to ** mark a user as trusted. Only do this if: ** ** (1) The poster is an individual, not a special user like "anonymous" ** (2) The current user has Forum Supervisor privilege */ static void generateTrustControls(Manifest *pPost){ if( !g.perm.AdminForum ) return; if( login_is_special(pPost->zUser) ) return; @ <br> @ <label><input type="checkbox" name="trust"> @ Trust user "%h(pPost->zUser)" @ so that future posts by "%h(pPost->zUser)" do not require moderation. @ </label> @ <input type="hidden" name="trustuser" value="%h(pPost->zUser)"> } /* ** Display all posts in a forum thread in chronological order */ static void forum_display_chronological(int froot, int target){ ForumThread *pThread = forumthread_create(froot, 0); ForumEntry *p; int notAnon = login_is_individual(); for(p=pThread->pFirst; p; p=p->pNext){ char *zDate; Manifest *pPost; int isPrivate; /* True for posts awaiting moderation */ int sameUser; /* True if author is also the reader */ pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); if( pPost==0 ) continue; if( p->fpid==target ){ @ <div id="forum%d(p->fpid)" class="forumTime forumSel"> }else if( p->pLeaf!=0 ){ @ <div id="forum%d(p->fpid)" class="forumTime forumObs"> }else{ @ <div id="forum%d(p->fpid)" class="forumTime"> } if( pPost->zThreadTitle ){ @ <h1>%h(pPost->zThreadTitle)</h1> } zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); @ <p>By %h(pPost->zUser) on %h(zDate) (%d(p->fpid)) fossil_free(zDate); if( p->pEdit ){ @ edit of %z(href("%R/forumpost/%S?t=c",p->pEdit->zUuid))%d(p->fprev)</a> } if( p->firt ){ ForumEntry *pIrt = p->pPrev; while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev; if( pIrt ){ @ reply to %z(href("%R/forumpost/%S?t=c",pIrt->zUuid))%d(p->firt)</a> } } if( p->pLeaf ){ @ updated by %z(href("%R/forumpost/%S?t=c",p->pLeaf->zUuid))\ @ %d(p->pLeaf->fpid)</a> } if( g.perm.Debug ){ @ <span class="debug">\ @ <a href="%R/artifact/%h(p->zUuid)">artifact</a></span> } if( p->fpid!=target ){ @ %z(href("%R/forumpost/%S?t=c",p->zUuid))[link]</a> } isPrivate = content_is_private(p->fpid); sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; if( isPrivate && !g.perm.ModForum && !sameUser ){ @ <p><span class="modpending">Awaiting Moderator Approval</span></p> }else{ forum_render(0, pPost->zMimetype, pPost->zWiki, 0); } if( g.perm.WrForum && p->pLeaf==0 ){ int sameUser = login_is_individual() && fossil_strcmp(pPost->zUser, g.zLogin)==0; @ <p><form action="%R/forumedit" method="POST"> @ <input type="hidden" name="fpid" value="%s(p->zUuid)"> if( !isPrivate ){ /* Reply and Edit are only available if the post has already ** been approved */ @ <input type="submit" name="reply" value="Reply"> if( g.perm.Admin || sameUser ){ @ <input type="submit" name="edit" value="Edit"> @ <input type="submit" name="nullout" value="Delete"> } }else if( g.perm.ModForum ){ /* Provide moderators with moderation buttons for posts that ** are pending moderation */ @ <input type="submit" name="approve" value="Approve"> @ <input type="submit" name="reject" value="Reject"> generateTrustControls(pPost); }else if( sameUser ){ /* A post that is pending moderation can be deleted by the ** person who originally submitted the post */ @ <input type="submit" name="reject" value="Delete"> } @ </form></p> } manifest_destroy(pPost); @ </div> } forumthread_delete(pThread); } /* ** Display all messages in a forumthread with indentation. */ static int forum_display_hierarchical(int froot, int target){ ForumThread *pThread; ForumEntry *p; Manifest *pPost, *pOPost; int fpid; const char *zUuid; char *zDate; const char *zSel; int notAnon = login_is_individual(); pThread = forumthread_create(froot, 1); for(p=pThread->pFirst; p; p=p->pNext){ if( p->fpid==target ){ while( p->pEdit ) p = p->pEdit; target = p->fpid; break; } } for(p=pThread->pDisplay; p; p=p->pDisplay){ int isPrivate; /* True for posts awaiting moderation */ int sameUser; /* True if reader is also the poster */ pOPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); if( p->pLeaf ){ fpid = p->pLeaf->fpid; zUuid = p->pLeaf->zUuid; pPost = manifest_get(fpid, CFTYPE_FORUM, 0); }else{ fpid = p->fpid; zUuid = p->zUuid; pPost = pOPost; } zSel = p->fpid==target ? " forumSel" : ""; if( p->nIndent==1 ){ @ <div id='forum%d(fpid)' class='forumHierRoot%s(zSel)'> }else{ @ <div id='forum%d(fpid)' class='forumHier%s(zSel)' \ @ style='margin-left: %d((p->nIndent-1)*3)ex;'> } pPost = manifest_get(fpid, CFTYPE_FORUM, 0); if( pPost==0 ) continue; if( pPost->zThreadTitle ){ @ <h1>%h(pPost->zThreadTitle)</h1> } zDate = db_text(0, "SELECT datetime(%.17g)", pOPost->rDate); @ <p>By %h(pOPost->zUser) on %h(zDate) fossil_free(zDate); if( g.perm.Debug ){ @ <span class="debug">\ @ <a href="%R/artifact/%h(p->zUuid)">(%d(p->fpid))</a></span> } if( p->pLeaf ){ zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); if( fossil_strcmp(pOPost->zUser,pPost->zUser)==0 ){ @ and edited on %h(zDate) }else{ @ as edited by %h(pPost->zUser) on %h(zDate) } fossil_free(zDate); if( g.perm.Debug ){ @ <span class="debug">\ @ <a href="%R/artifact/%h(p->pLeaf->zUuid)">(%d(fpid))</a></span> } manifest_destroy(pOPost); } if( fpid!=target ){ @ %z(href("%R/forumpost/%S",zUuid))[link]</a> } isPrivate = content_is_private(fpid); sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; if( isPrivate && !g.perm.ModForum && !sameUser ){ @ <p><span class="modpending">Awaiting Moderator Approval</span></p> }else{ forum_render(0, pPost->zMimetype, pPost->zWiki, 0); } if( g.perm.WrForum ){ @ <p><form action="%R/forumedit" method="POST"> @ <input type="hidden" name="fpid" value="%s(zUuid)"> if( !isPrivate ){ /* Reply and Edit are only available if the post has already ** been approved */ @ <input type="submit" name="reply" value="Reply"> if( g.perm.Admin || sameUser ){ @ <input type="submit" name="edit" value="Edit"> @ <input type="submit" name="nullout" value="Delete"> } }else if( g.perm.ModForum ){ /* Provide moderators with moderation buttons for posts that ** are pending moderation */ @ <input type="submit" name="approve" value="Approve"> @ <input type="submit" name="reject" value="Reject"> generateTrustControls(pPost); }else if( sameUser ){ /* A post that is pending moderation can be deleted by the ** person who originally submitted the post */ @ <input type="submit" name="reject" value="Delete"> } @ </form></p> } manifest_destroy(pPost); @ </div> } forumthread_delete(pThread); return target; } /* ** WEBPAGE: forumpost ** ** Show a single forum posting. The posting is shown in context with ** it's entire thread. The selected posting is enclosed within ** <div class='forumSel'>...</div>. Javascript is used to move the ** selected posting into view after the page loads. ** ** Query parameters: ** ** name=X REQUIRED. The hash of the post to display ** t=MODE Display mode. MODE is 'c' for chronological or ** 'h' for hierarchical, or 'a' for automatic. */ void forumpost_page(void){ forumthread_page(); } /* ** WEBPAGE: forumthread ** ** Show all forum messages associated with a particular message thread. ** The result is basically the same as /forumpost except that none of ** the postings in the thread are selected. ** ** Query parameters: ** ** name=X REQUIRED. The hash of any post of the thread. ** t=MODE Display mode. MODE is 'c' for chronological or ** 'h' for hierarchical, or 'a' for automatic. */ void forumthread_page(void){ int fpid; int froot; const char *zName = P("name"); const char *zMode = PD("t","a"); login_check_credentials(); if( !g.perm.RdForum ){ login_needed(g.anon.RdForum); return; } if( zName==0 ){ webpage_error("Missing \"name=\" query parameter"); } fpid = symbolic_name_to_rid(zName, "f"); if( fpid<=0 ){ webpage_error("Unknown or ambiguous forum id: \"%s\"", zName); } style_header("Forum"); froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid); if( froot==0 ){ webpage_error("Not a forum post: \"%s\"", zName); } if( fossil_strcmp(g.zPath,"forumthread")==0 ) fpid = 0; if( zMode[0]=='a' ){ if( cgi_from_mobile() ){ zMode = "c"; /* Default to chronological on mobile */ }else{ zMode = "h"; } } if( zMode[0]=='c' ){ style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName); forum_display_chronological(froot, fpid); }else{ style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName); forum_display_hierarchical(froot, fpid); } style_load_js("forum.js"); style_footer(); } /* ** Return true if a forum post should be moderated. */ static int forum_need_moderation(void){ if( P("domod") ) return 1; if( g.perm.WrTForum ) return 0; if( g.perm.ModForum ) return 0; return 1; } /* ** Add a new Forum Post artifact to the repository. ** ** Return true if a redirect occurs. */ static int forum_post( const char *zTitle, /* Title. NULL for replies */ int iInReplyTo, /* Post replying to. 0 for new threads */ int iEdit, /* Post being edited, or zero for a new post */ const char *zUser, /* Username. NULL means use login name */ const char *zMimetype, /* Mimetype of content. */ const char *zContent /* Content */ ){ char *zDate; char *zI; char *zG; int iBasis; Blob x, cksum, formatCheck, errMsg; Manifest *pPost; schema_forum(); if( iInReplyTo==0 && iEdit>0 ){ iBasis = iEdit; iInReplyTo = db_int(0, "SELECT firt FROM forumpost WHERE fpid=%d", iEdit); }else{ iBasis = iInReplyTo; } webpage_assert( (zTitle==0)+(iInReplyTo==0)==1 ); blob_init(&x, 0, 0); zDate = date_in_standard_format("now"); blob_appendf(&x, "D %s\n", zDate); fossil_free(zDate); zG = db_text(0, "SELECT uuid FROM blob, forumpost" " WHERE blob.rid==forumpost.froot" " AND forumpost.fpid=%d", iBasis); if( zG ){ blob_appendf(&x, "G %s\n", zG); fossil_free(zG); } |
︙ | ︙ | |||
1344 1345 1346 1347 1348 1349 1350 | if( login_is_nobody() ){ zUser = "anonymous"; }else{ zUser = login_name(); } } blob_appendf(&x, "U %F\n", zUser); | | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | if( login_is_nobody() ){ zUser = "anonymous"; }else{ zUser = login_name(); } } blob_appendf(&x, "U %F\n", zUser); blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent); md5sum_blob(&x, &cksum); blob_appendf(&x, "Z %b\n", &cksum); blob_reset(&cksum); /* Verify that the artifact we are creating is well-formed */ blob_init(&formatCheck, 0, 0); blob_init(&errMsg, 0, 0); |
︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 | @ <div class='debug'> @ This is the artifact that would have been generated: @ <pre>%h(blob_str(&x))</pre> @ </div> blob_reset(&x); return 0; }else{ | < < | < < < < < | | < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | @ <div class='debug'> @ This is the artifact that would have been generated: @ <pre>%h(blob_str(&x))</pre> @ </div> blob_reset(&x); return 0; }else{ int nrid = wiki_put(&x, 0, forum_need_moderation()); cgi_redirectf("%R/forumpost/%S", rid_to_uuid(nrid)); return 1; } } /* ** Paint the form elements for entering a Forum post */ static void forum_entry_widget( const char *zTitle, const char *zMimetype, const char *zContent ){ if( zTitle ){ @ Title: <input type="input" name="title" value="%h(zTitle)" size="50"><br> } @ Markup style: mimetype_option_menu(zMimetype); @ <br><textarea name="content" class="wikiedit" cols="80" \ @ rows="25" wrap="virtual">%h(zContent)</textarea><br> } /* ** WEBPAGE: forumnew ** WEBPAGE: forumedit ** ** Start a new thread on the forum or reply to an existing thread. ** But first prompt to see if the user would like to log in. */ void forum_page_init(void){ int isEdit; char *zGoto; login_check_credentials(); if( !g.perm.WrForum ){ login_needed(g.anon.WrForum); return; } if( sqlite3_strglob("*edit*", g.zPath)==0 ){ zGoto = mprintf("%R/forume2?fpid=%S",PD("fpid","")); isEdit = 1; }else{ zGoto = mprintf("%R/forume1"); isEdit = 0; } if( login_is_individual() ){ if( isEdit ){ forumedit_page(); }else{ forumnew_page(); } return; } style_header("%h As Anonymous?", isEdit ? "Reply" : "Post"); @ <p>You are not logged in. @ <p><table border="0" cellpadding="10"> @ <tr><td> @ <form action="%s(zGoto)" method="POST"> @ <input type="submit" value="Remain Anonymous"> @ </form> |
︙ | ︙ | |||
1490 1491 1492 1493 1494 1495 1496 | @ <form action="%R/login" method="POST"> @ <input type="hidden" name="g" value="%s(zGoto)"> @ <input type="hidden" name="noanon" value="1"> @ <input type="submit" value="Login"> @ </form> @ <td>Log into an existing account @ </table> | < | < < < < < < < < < < < < < < < < < < | | < | | < | | | | > > > > > > > > > < | | < < < < < < < < < | < < < < | < < < | < < < < | > | < < | < | < < < < > | | < | < | | < | | | | | | | < | < | < < < < < < < < < < < | | | | | | | < | | < | < > | < < < | < < < < < < < < < | < | < < < < < < < | < < < < < < | | < < < < < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < | < < < < < | < < < < < < < | < < < | < < < < < < < < < < | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 | @ <form action="%R/login" method="POST"> @ <input type="hidden" name="g" value="%s(zGoto)"> @ <input type="hidden" name="noanon" value="1"> @ <input type="submit" value="Login"> @ </form> @ <td>Log into an existing account @ </table> style_footer(); fossil_free(zGoto); } /* ** Write the "From: USER" line on the webpage. */ static void forum_from_line(void){ if( login_is_nobody() ){ @ From: anonymous<br> }else{ @ From: %h(login_name())<br> } } /* ** WEBPAGE: forume1 ** ** Start a new forum thread. */ void forumnew_page(void){ const char *zTitle = PDT("title",""); const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE); const char *zContent = PDT("content",""); login_check_credentials(); if( !g.perm.WrForum ){ login_needed(g.anon.WrForum); return; } if( P("submit") ){ if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return; } if( P("preview") ){ @ <h1>Preview:</h1> forum_render(zTitle, zMimetype, zContent, "forumEdit"); } style_header("New Forum Thread"); @ <form action="%R/forume1" method="POST"> @ <h1>New Thread:</h1> forum_from_line(); forum_entry_widget(zTitle, zMimetype, zContent); @ <input type="submit" name="preview" value="Preview"> if( P("preview") ){ @ <input type="submit" name="submit" value="Submit"> }else{ @ <input type="submit" name="submit" value="Submit" disabled> } if( g.perm.Debug ){ /* For the test-forumnew page add these extra debugging controls */ @ <div class="debug"> @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \ @ Dry run</label> @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \ @ Require moderator approval</label> @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \ @ Show query parameters</label> @ </div> } @ </form> style_footer(); } /* ** WEBPAGE: forume2 ** ** Edit an existing forum message. ** Query parameters: ** ** fpid=X Hash of the post to be editted. REQUIRED */ void forumedit_page(void){ int fpid; Manifest *pPost = 0; const char *zMimetype = 0; const char *zContent = 0; const char *zTitle = 0; int isCsrfSafe; int isDelete = 0; login_check_credentials(); if( !g.perm.WrForum ){ login_needed(g.anon.WrForum); return; } fpid = symbolic_name_to_rid(PD("fpid",""), "f"); if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){ webpage_error("Missing or invalid fpid query parameter"); } if( P("cancel") ){ cgi_redirectf("%R/forumpost/%S",P("fpid")); return; } isCsrfSafe = cgi_csrf_safe(1); if( g.perm.ModForum && isCsrfSafe ){ if( P("approve") ){ const char *zUserToTrust; moderation_approve(fpid); if( g.perm.AdminForum && PB("trust") && (zUserToTrust = P("trustuser"))!=0 ){ db_multi_exec("UPDATE user SET cap=cap||'4' " "WHERE login=%Q AND cap NOT GLOB '*4*'", zUserToTrust); } cgi_redirectf("%R/forumpost/%S",P("fpid")); return; } if( P("reject") ){ char *zParent = db_text(0, "SELECT uuid FROM forumpost, blob" " WHERE forumpost.fpid=%d AND blob.rid=forumpost.firt", fpid ); moderation_disapprove(fpid); if( zParent ){ cgi_redirectf("%R/forumpost/%S",zParent); }else{ cgi_redirectf("%R/forum"); } return; } } isDelete = P("nullout")!=0; if( P("submit") && isCsrfSafe ){ int done = 1; const char *zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE); const char *zContent = PDT("content",""); if( P("reply") ){ done = forum_post(0, fpid, 0, 0, zMimetype, zContent); }else if( P("edit") || isDelete ){ done = forum_post(P("title"), 0, fpid, 0, zMimetype, zContent); }else{ webpage_error("Missing 'reply' query parameter"); } if( done ) return; } if( isDelete ){ zMimetype = "text/x-fossil-wiki"; zContent = ""; if( pPost->zThreadTitle ) zTitle = ""; style_header("Delete %s", zTitle ? "Post" : "Reply"); @ <h1>Original Post:</h1> forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, "forumEdit"); @ <h1>Change Into:</h1> forum_render(zTitle, zMimetype, zContent,"forumEdit"); @ <form action="%R/forume2" method="POST"> @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> @ <input type="hidden" name="nullout" value="1"> @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> @ <input type="hidden" name="content" value="%h(zContent)"> if( zTitle ){ @ <input type="hidden" name="title" value="%h(zTitle)"> } }else if( P("edit") ){ /* Provide an edit to the fpid post */ zMimetype = P("mimetype"); zContent = PT("content"); zTitle = P("title"); if( zContent==0 ) zContent = fossil_strdup(pPost->zWiki); if( zMimetype==0 ) zMimetype = fossil_strdup(pPost->zMimetype); if( zTitle==0 && pPost->zThreadTitle!=0 ){ zTitle = fossil_strdup(pPost->zThreadTitle); } style_header("Edit %s", zTitle ? "Post" : "Reply"); @ <h1>Original Post:</h1> forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, "forumEdit"); if( P("preview") ){ @ <h1>Preview of Edited Post:</h1> forum_render(zTitle, zMimetype, zContent,"forumEdit"); } @ <h1>Revised Message:</h1> @ <form action="%R/forume2" method="POST"> @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> @ <input type="hidden" name="edit" value="1"> forum_from_line(); forum_entry_widget(zTitle, zMimetype, zContent); }else{ /* Reply */ zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE); zContent = PDT("content",""); style_header("Reply"); @ <h1>Replying To:</h1> forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit"); if( P("preview") ){ @ <h1>Preview:</h1> forum_render(0, zMimetype,zContent, "forumEdit"); } @ <h1>Enter Reply:</h1> @ <form action="%R/forume2" method="POST"> @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> @ <input type="hidden" name="reply" value="1"> forum_from_line(); forum_entry_widget(0, zMimetype, zContent); } if( !isDelete ){ @ <input type="submit" name="preview" value="Preview"> } @ <input type="submit" name="cancel" value="Cancel"> if( P("preview") || isDelete ){ @ <input type="submit" name="submit" value="Submit"> } if( g.perm.Debug ){ /* For the test-forumnew page add these extra debugging controls */ @ <div class="debug"> @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \ @ Dry run</label> @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \ @ Require moderator approval</label> @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \ @ Show query parameters</label> @ </div> } @ </form> style_footer(); } /* ** WEBPAGE: forum ** ** The main page for the forum feature. Show a list of recent forum ** threads. Also show a search box at the top if search is enabled, ** and a button for creating a new thread, if enabled. ** ** Query parameters: ** ** n=N The number of threads to show on each page ** x=X Skip the first X threads */ void forum_main_page(void){ Stmt q; int iLimit, iOfst, iCnt; int srchFlags; login_check_credentials(); srchFlags = search_restrict(SRCH_FORUM); if( !g.perm.RdForum ){ login_needed(g.anon.RdForum); return; } style_header("Forum"); if( g.perm.WrForum ){ style_submenu_element("New Thread","%R/forumnew"); } if( g.perm.ModForum && moderation_needed() ){ style_submenu_element("Moderation Requests", "%R/modreq"); } if( (srchFlags & SRCH_FORUM)!=0 ){ if( search_screen(SRCH_FORUM, 0) ){ style_submenu_element("Recent Threads","%R/forum"); style_footer(); return; } } iLimit = atoi(PD("n","25")); iOfst = atoi(PD("x","0")); iCnt = 0; if( db_table_exists("repository","forumpost") ){ db_prepare(&q, "WITH thread(age,duration,cnt,root,last) AS (" " SELECT" " julianday('now') - max(fmtime)," |
︙ | ︙ | |||
2030 2031 2032 2033 2034 2035 2036 | db_finalize(&q); } if( iCnt>0 ){ @ </table></div> }else{ @ <h1>No forum posts found</h1> } | | | 1071 1072 1073 1074 1075 1076 1077 1078 1079 | db_finalize(&q); } if( iCnt>0 ){ @ </table></div> }else{ @ <h1>No forum posts found</h1> } style_footer(); } |
Changes to src/forum.js.
︙ | ︙ | |||
12 13 14 15 16 17 18 | if(x[0]){ var w = window.innerHeight; var h = x[0].scrollHeight; var y = absoluteY(x[0]); if( w>h ) y = y + (h-w)/2; if( y>0 ) window.scrollTo(0, y); } | | | 12 13 14 15 16 17 18 19 | if(x[0]){ var w = window.innerHeight; var h = x[0].scrollHeight; var y = absoluteY(x[0]); if( w>h ) y = y + (h-w)/2; if( y>0 ) window.scrollTo(0, y); } }()) |
Deleted src/fossil.bootstrap.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.confirmer.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.copybutton.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.diff.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.dom.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.fetch.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.numbered-lines.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.brlist.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.chat.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.fileedit.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.forumpost.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.pikchrshow.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.pikchrshowasm.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.whistory.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.page.wikiedit.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.pikchr.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.popupwidget.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.storage.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.tabs.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/fossil.wikiedit-wysiwyg.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/fshell.c.
︙ | ︙ | |||
55 56 57 58 59 60 61 | int nArg; int mxArg = 0; int n, i; char **azArg = 0; int fDebug; pid_t childPid; char *zLine = 0; | < < < < < < | | | 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 | int nArg; int mxArg = 0; int n, i; char **azArg = 0; int fDebug; pid_t childPid; char *zLine = 0; fDebug = find_option("debug", 0, 0)!=0; db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); db_close(0); sqlite3_shutdown(); linenoiseSetMultiLine(1); while( (free(zLine), zLine = linenoise("fossil> ")) ){ /* Remember shell history within the current session */ linenoiseHistoryAdd(zLine); /* Parse the line of input */ n = (int)strlen(zLine); for(i=0, nArg=1; i<n; i++){ while( fossil_isspace(zLine[i]) ){ i++; } if( i>=n ) break; if( nArg>=mxArg ){ mxArg = nArg+10; azArg = fossil_realloc(azArg, sizeof(char*)*mxArg); if( nArg==1 ) azArg[0] = g.argv[0]; } if( zLine[i]=='"' || zLine[i]=='\'' ){ char cQuote = zLine[i]; i++; azArg[nArg++] = &zLine[i]; for(i++; i<n && zLine[i]!=cQuote; i++){} }else{ azArg[nArg++] = &zLine[i]; while( i<n && !isspace(zLine[i]) ){ i++; } } zLine[i] = 0; } /* If the --debug flag was used, display the parsed arguments */ if( fDebug ){ for(i=1; i<nArg; i++){ |
︙ | ︙ | |||
113 114 115 116 117 118 119 | printf("could not fork a child process to handle the command\n"); fflush(stdout); continue; } if( childPid==0 ){ /* This is the child process */ int main(int, char**); | | < | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | printf("could not fork a child process to handle the command\n"); fflush(stdout); continue; } if( childPid==0 ){ /* This is the child process */ int main(int, char**); main(nArg, azArg); exit(0); }else{ /* The parent process */ int status; waitpid(childPid, &status, 0); } } #endif } |
Changes to src/fusefs.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 | ** This module implements the userspace side of a Fuse Filesystem that ** contains all check-ins for a fossil repository. ** ** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS. ** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for ** the Fuse Filesystem, of course. */ #include "config.h" #include <stdio.h> #include <string.h> | > < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** This module implements the userspace side of a Fuse Filesystem that ** contains all check-ins for a fossil repository. ** ** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS. ** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for ** the Fuse Filesystem, of course. */ #ifdef FOSSIL_HAVE_FUSEFS #include "config.h" #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include "fusefs.h" |
︙ | ︙ | |||
281 282 283 284 285 286 287 | } static struct fuse_operations fusefs_methods = { .getattr = fusefs_getattr, .readdir = fusefs_readdir, .read = fusefs_read, }; | < | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | } static struct fuse_operations fusefs_methods = { .getattr = fusefs_getattr, .readdir = fusefs_readdir, .read = fusefs_read, }; /* ** COMMAND: fusefs ** ** Usage: %fossil fusefs [--debug] DIRECTORY ** ** This command uses the Fuse Filesystem (FuseFS) to mount a directory ** at DIRECTORY that contains the content of all check-ins in the ** repository. The names of files are DIRECTORY/checkins/VERSION/PATH ** where DIRECTORY is the root of the mount, VERSION is any valid |
︙ | ︙ | |||
313 314 315 316 317 318 319 | ** appropriate support libraries. ** ** After stopping the "fossil fusefs" command, it might also be necessary ** to run "fusermount -u DIRECTORY" to reset the FuseFS before using it ** again. */ void fusefs_cmd(void){ | < | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | ** appropriate support libraries. ** ** After stopping the "fossil fusefs" command, it might also be necessary ** to run "fusermount -u DIRECTORY" to reset the FuseFS before using it ** again. */ void fusefs_cmd(void){ char *zMountPoint; char *azNewArgv[5]; int doDebug = find_option("debug","d",0)!=0; db_find_and_open_repository(0,0); verify_all_options(); blob_init(&fusefs.content, 0, 0); |
︙ | ︙ | |||
335 336 337 338 339 340 341 | azNewArgv[2] = "-s"; azNewArgv[3] = zMountPoint; azNewArgv[4] = 0; g.localOpen = 0; /* Prevent tags like "current" and "prev" */ fuse_main(4, azNewArgv, &fusefs_methods, NULL); fusefs_reset(); fusefs_clear_path(); | < < < < > | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | azNewArgv[2] = "-s"; azNewArgv[3] = zMountPoint; azNewArgv[4] = 0; g.localOpen = 0; /* Prevent tags like "current" and "prev" */ fuse_main(4, azNewArgv, &fusefs_methods, NULL); fusefs_reset(); fusefs_clear_path(); } #endif /* FOSSIL_HAVE_FUSEFS */ /* ** Return version numbers for the FUSE header that was used at compile-time ** and/or the FUSE library that was loaded at runtime. */ const char *fusefs_lib_version(void){ #if defined(FOSSIL_HAVE_FUSEFS) && FUSE_MAJOR_VERSION>=3 |
︙ | ︙ |
Deleted src/fuzz.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/glob.c.
︙ | ︙ | |||
87 88 89 90 91 92 93 | struct Glob { int nPattern; /* Number of patterns */ char **azPattern; /* Array of pointers to patterns */ }; #endif /* INTERFACE */ /* | | | | | < | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | struct Glob { int nPattern; /* Number of patterns */ char **azPattern; /* Array of pointers to patterns */ }; #endif /* INTERFACE */ /* ** zPatternList is a comma-separated list of glob patterns. Parse up ** that list and use it to create a new Glob object. ** ** Elements of the glob list may be optionally enclosed in single our ** double-quotes. This allows a comma to be part of a glob pattern. ** ** Leading and trailing spaces on unquoted glob patterns are ignored. ** ** An empty or null pattern list results in a null glob, which will ** match nothing. */ Glob *glob_create(const char *zPatternList){ int nList; /* Size of zPatternList in bytes */ int i; /* Loop counters */ |
︙ | ︙ | |||
125 126 127 128 129 130 131 | delimiter = z[0]; z++; }else{ delimiter = ','; } p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) ); p->azPattern[p->nPattern++] = z; | | | > | < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | delimiter = z[0]; z++; }else{ delimiter = ','; } p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) ); p->azPattern[p->nPattern++] = z; /* Find the next delimter (or the end of the string). */ for(i=0; z[i] && z[i]!=delimiter; i++){ if( delimiter!=',' ) continue; /* If quoted, keep going. */ if( fossil_isspace(z[i]) ) break; /* If space, stop. */ } if( z[i]==0 ) break; z[i] = 0; z += i+1; } return p; } |
︙ | ︙ | |||
163 164 165 166 167 168 169 | void glob_free(Glob *pGlob){ if( pGlob ){ fossil_free(pGlob->azPattern); fossil_free(pGlob); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | void glob_free(Glob *pGlob){ if( pGlob ){ fossil_free(pGlob->azPattern); fossil_free(pGlob); } } /* ** COMMAND: test-glob ** ** Usage: %fossil test-glob PATTERN STRING... ** ** PATTERN is a comma- and whitespace-separated list of optionally ** quoted glob patterns. Show which of the STRINGs that follow match |
︙ | ︙ |
Changes to src/graph.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** This file contains code to compute a revision history graph. */ #include "config.h" #include "graph.h" #include <assert.h> | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | | < < < < < | | | < < < < < < < < < < < | 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 | ** ** This file contains code to compute a revision history graph. */ #include "config.h" #include "graph.h" #include <assert.h> #if INTERFACE #define GR_MAX_RAIL 40 /* Max number of "rails" to display */ /* The graph appears vertically beside a timeline. Each row in the ** timeline corresponds to a row in the graph. GraphRow.idx is 0 for ** the top-most row and increases moving down. Hence (in the absence of ** time skew) parents have a larger index than their children. ** ** The nParent field is -1 for entires that do not participate in the graph ** but which are included just so that we can capture their background color. */ struct GraphRow { int rid; /* The rid for the check-in */ i8 nParent; /* Number of parents. -1 for technote lines */ int *aParent; /* Array of parents. 0 element is primary .*/ char *zBranch; /* Branch name */ char *zBgClr; /* Background Color */ char zUuid[HNAME_MAX+1]; /* Check-in for file ID */ GraphRow *pNext; /* Next row down in the list of all rows */ GraphRow *pPrev; /* Previous row */ int idx; /* Row index. First is 1. 0 used for "none" */ int idxTop; /* Direct descendent highest up on the graph */ GraphRow *pChild; /* Child immediately above this node */ u8 isDup; /* True if this is duplicate of a prior entry */ u8 isLeaf; /* True if this is a leaf node */ u8 timeWarp; /* Child is earlier in time */ u8 bDescender; /* True if riser from bottom of graph to here. */ i8 iRail; /* Which rail this check-in appears on. 0-based.*/ i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */ u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */ int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */ int mergeUpto; /* Draw the mergeOut rail up to this level */ u64 mergeDown; /* Draw merge lines up from bottom of graph */ u64 railInUse; /* Mask of occupied rails at this row */ }; /* Context while building a graph */ struct GraphContext { int nErr; /* Number of errors encountered */ int mxRail; /* Number of rails required to render the graph */ GraphRow *pFirst; /* First row in the list */ GraphRow *pLast; /* Last row in the list */ int nBranch; /* Number of distinct branches */ char **azBranch; /* Names of the branches */ int nRow; /* Number of rows */ int nHash; /* Number of slots in apHash[] */ GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */ }; #endif /* The N-th bit */ #define BIT(N) (((u64)1)<<(N)) /* ** Malloc for zeroed space. Panic if unable to provide the ** requested space. */ void *safeMalloc(int nByte){ void *p = fossil_malloc(nByte); |
︙ | ︙ | |||
196 197 198 199 200 201 202 | p->apHash[h] = pRow; } } /* ** Look up the row with rid. */ | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | p->apHash[h] = pRow; } } /* ** Look up the row with rid. */ static GraphRow *hashFind(GraphContext *p, int rid){ int h = rid % p->nHash; while( p->apHash[h] && p->apHash[h]->rid!=rid ){ h++; if( h>=p->nHash ) h = 0; } return p->apHash[h]; } |
︙ | ︙ | |||
232 233 234 235 236 237 238 | } /* ** Add a new row to the graph context. Rows are added from top to bottom. */ int graph_add_row( GraphContext *p, /* The context to which the row is added */ | | < | | < < < < < | 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 | } /* ** Add a new row to the graph context. Rows are added from top to bottom. */ int graph_add_row( GraphContext *p, /* The context to which the row is added */ int rid, /* RID for the check-in */ int nParent, /* Number of parents */ int *aParent, /* Array of parents */ const char *zBranch, /* Branch for this check-in */ const char *zBgClr, /* Background color. NULL or "" for white. */ const char *zUuid, /* hash name of the object being graphed */ int isLeaf /* True if this row is a leaf */ ){ GraphRow *pRow; int nByte; static int nRow = 0; if( p->nErr ) return 0; nByte = sizeof(GraphRow); if( nParent>0 ) nByte += sizeof(pRow->aParent[0])*nParent; pRow = (GraphRow*)safeMalloc( nByte ); pRow->aParent = nParent>0 ? (int*)&pRow[1] : 0; pRow->rid = rid; pRow->nParent = nParent; pRow->zBranch = persistBranchName(p, zBranch); if( zUuid==0 ) zUuid = ""; sqlite3_snprintf(sizeof(pRow->zUuid), pRow->zUuid, "%s", zUuid); pRow->isLeaf = isLeaf; memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser)); if( zBgClr==0 ) zBgClr = ""; pRow->zBgClr = persistBranchName(p, zBgClr); |
︙ | ︙ | |||
283 284 285 286 287 288 289 | /* ** Return the index of a rail currently not in use for any row between ** top and bottom, inclusive. */ static int findFreeRail( GraphContext *p, /* The graph context */ int top, int btm, /* Span of rows for which the rail is needed */ | | < < < | < < | < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < | < | < | < > < < < < < < < < < < | | < < | < < | > < < < < < < < | < < < < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | /* ** Return the index of a rail currently not in use for any row between ** top and bottom, inclusive. */ static int findFreeRail( GraphContext *p, /* The graph context */ int top, int btm, /* Span of rows for which the rail is needed */ int iNearto /* Find rail nearest to this rail */ ){ GraphRow *pRow; int i; int iBest = 0; int iBestDist = 9999; u64 inUseMask = 0; for(pRow=p->pFirst; pRow && pRow->idx<top; pRow=pRow->pNext){} while( pRow && pRow->idx<=btm ){ inUseMask |= pRow->railInUse; pRow = pRow->pNext; } for(i=0; i<32; i++){ if( (inUseMask & BIT(i))==0 ){ int dist; if( iNearto<=0 ){ return i; } dist = i - iNearto; if( dist<0 ) dist = -dist; if( dist<iBestDist ){ iBestDist = dist; iBest = i; } } } if( iBestDist>1000 ) p->nErr++; if( iBest>p->mxRail ) p->mxRail = iBest; return iBest; } /* ** Assign all children of node pBottom to the same rail as pBottom. */ static void assignChildrenToRail(GraphRow *pBottom){ int iRail = pBottom->iRail; GraphRow *pCurrent; GraphRow *pPrior; u64 mask = ((u64)1)<<iRail; pBottom->railInUse |= mask; pPrior = pBottom; for(pCurrent=pBottom->pChild; pCurrent; pCurrent=pCurrent->pChild){ assert( pPrior->idx > pCurrent->idx ); assert( pCurrent->iRail<0 ); pCurrent->iRail = iRail; pCurrent->railInUse |= mask; pPrior->aiRiser[iRail] = pCurrent->idx; while( pPrior->idx > pCurrent->idx ){ pPrior->railInUse |= mask; pPrior = pPrior->pPrev; assert( pPrior!=0 ); } } } /* ** Create a merge-arrow riser going from pParent up to pChild. */ static void createMergeRiser( GraphContext *p, GraphRow *pParent, GraphRow *pChild ){ int u; u64 mask; GraphRow *pLoop; if( pParent->mergeOut<0 ){ u = pParent->aiRiser[pParent->iRail]; if( u>=0 && u<pChild->idx ){ /* The thick arrow up to the next primary child of pDesc goes ** further up than the thin merge arrow riser, so draw them both ** on the same rail. */ pParent->mergeOut = pParent->iRail; pParent->mergeUpto = pChild->idx; }else{ /* The thin merge arrow riser is taller than the thick primary ** child riser, so use separate rails. */ int iTarget = pParent->iRail; pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1, iTarget); pParent->mergeUpto = pChild->idx; mask = BIT(pParent->mergeOut); for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid; pLoop=pLoop->pNext){ pLoop->railInUse |= mask; } } } pChild->mergeIn[pParent->mergeOut] = 1; } /* ** Compute the maximum rail number. */ static void find_max_rail(GraphContext *p){ GraphRow *pRow; p->mxRail = 0; for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut; while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){ p->mxRail++; } } } /* ** Draw a riser from pRow to the top of the graph */ static void riser_to_top(GraphRow *pRow){ u64 mask = BIT(pRow->iRail); pRow->aiRiser[pRow->iRail] = 0; while( pRow ){ pRow->railInUse |= mask; pRow = pRow->pPrev; } } /* ** Compute the complete graph ** ** When primary or merge parents are off-screen, normally a line is drawn ** from the node down to the bottom of the graph. This line is called a ** "descender". But if the omitDescenders flag is true, then lines down ** to the bottom of the screen are omitted. */ void graph_finish(GraphContext *p, int omitDescenders){ GraphRow *pRow, *pDesc, *pDup, *pLoop, *pParent; int i, j; u64 mask; int hasDup = 0; /* True if one or more isDup entries */ const char *zTrunk; /* If mergeRiserFrom[X]==Y that means rail X holds a merge riser ** coming up from the bottom of the graph from off-screen check-in Y ** where Y is the RID. There is no riser on rail X if mergeRiserFrom[X]==0. */ int mergeRiserFrom[GR_MAX_RAIL]; if( p==0 || p->pFirst==0 || p->nErr ) return; p->nErr = 1; /* Assume an error until proven otherwise */ /* Initialize all rows */ p->nHash = p->nRow*2 + 1; p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); |
︙ | ︙ | |||
538 539 540 541 542 543 544 | ** ** Each node has one primary parent and zero or more "merge" parents. ** A merge parent is a prior check-in from which changes were merged into ** the current check-in. If a merge parent is not in the visible section ** of this graph, then no arrows will be drawn for it, so remove it from ** the aParent[] array. */ | | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | ** ** Each node has one primary parent and zero or more "merge" parents. ** A merge parent is a prior check-in from which changes were merged into ** the current check-in. If a merge parent is not in the visible section ** of this graph, then no arrows will be drawn for it, so remove it from ** the aParent[] array. */ if( omitDescenders ){ for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ for(i=1; i<pRow->nParent; i++){ if( hashFind(p, pRow->aParent[i])==0 ){ pRow->aParent[i] = pRow->aParent[--pRow->nParent]; i--; } } } } /* If the primary parent is in a different branch, but there are ** other parents in the same branch, reorder the parents to make ** the parent from the same branch the primary parent. */ for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ if( pRow->isDup ) continue; if( pRow->nParent<2 ) continue; /* Not a fork */ pParent = hashFind(p, pRow->aParent[0]); if( pParent==0 ) continue; /* Parent off-screen */ if( pParent->zBranch==pRow->zBranch ) continue; /* Same branch */ for(i=1; i<pRow->nParent; i++){ pParent = hashFind(p, pRow->aParent[i]); if( pParent && pParent->zBranch==pRow->zBranch ){ int t = pRow->aParent[0]; pRow->aParent[0] = pRow->aParent[i]; pRow->aParent[i] = t; break; } } } |
︙ | ︙ | |||
647 648 649 650 651 652 653 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ if( pRow->isDup ) continue; if( pRow->nParent<=0 ) continue; /* Root node */ pParent = hashFind(p, pRow->aParent[0]); if( pParent==0 ) continue; /* Parent off-screen */ if( pParent->zBranch!=pRow->zBranch ) continue; /* Different branch */ if( pParent->idx <= pRow->idx ){ | | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < > > > > > > | > > > < | | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ if( pRow->isDup ) continue; if( pRow->nParent<=0 ) continue; /* Root node */ pParent = hashFind(p, pRow->aParent[0]); if( pParent==0 ) continue; /* Parent off-screen */ if( pParent->zBranch!=pRow->zBranch ) continue; /* Different branch */ if( pParent->idx <= pRow->idx ){ pParent->timeWarp = 1; continue; /* Time-warp */ } if( pRow->idxTop < pParent->idxTop ){ pParent->pChild = pRow; pParent->idxTop = pRow->idxTop; } } /* Identify rows where the primary parent is off screen. Assign ** each to a rail and draw descenders to the bottom of the screen. ** ** Strive to put the "trunk" branch on far left. */ zTrunk = persistBranchName(p, "trunk"); for(i=0; i<2; i++){ for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ if( pRow->isDup ) continue; if( pRow->nParent<0 ) continue; if( i==0 ){ if( pRow->zBranch!=zTrunk ) continue; }else { if( pRow->iRail>=0 ) continue; } if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){ if( omitDescenders ){ pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx, 0); }else{ pRow->iRail = ++p->mxRail; } if( p->mxRail>=GR_MAX_RAIL ) return; mask = BIT(pRow->iRail); if( !omitDescenders ){ pRow->bDescender = pRow->nParent>0; for(pLoop=pRow; pLoop; pLoop=pLoop->pNext){ pLoop->railInUse |= mask; } } assignChildrenToRail(pRow); } } } /* Assign rails to all rows that are still unassigned. */ for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ int parentRid; if( pRow->iRail>=0 ){ if( pRow->pChild==0 && !pRow->timeWarp ){ if( !omitDescenders && count_nonbranch_children(pRow->rid)!=0 ){ riser_to_top(pRow); } } |
︙ | ︙ | |||
745 746 747 748 749 750 751 | if( p->mxRail>=GR_MAX_RAIL ) return; pRow->railInUse = BIT(pRow->iRail); continue; } if( pParent->idx>pRow->idx ){ /* Common case: Child occurs after parent and is above the ** parent in the timeline */ | | < | < < | | < < < < < < < < < | < < < < < < < < < | < < | < < < < < < | | < < < < < < < < < < < < < < | | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | if( p->mxRail>=GR_MAX_RAIL ) return; pRow->railInUse = BIT(pRow->iRail); continue; } if( pParent->idx>pRow->idx ){ /* Common case: Child occurs after parent and is above the ** parent in the timeline */ pRow->iRail = findFreeRail(p, 0, pParent->idx, pParent->iRail); if( p->mxRail>=GR_MAX_RAIL ) return; pParent->aiRiser[pRow->iRail] = pRow->idx; }else{ /* Timewarp case: Child occurs earlier in time than parent and ** appears below the parent in the timeline. */ int iDownRail = ++p->mxRail; if( iDownRail<1 ) iDownRail = ++p->mxRail; pRow->iRail = ++p->mxRail; if( p->mxRail>=GR_MAX_RAIL ) return; pRow->railInUse = BIT(pRow->iRail); pParent->aiRiser[iDownRail] = pRow->idx; mask = BIT(iDownRail); for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){ pLoop->railInUse |= mask; } } } mask = BIT(pRow->iRail); pRow->railInUse |= mask; if( pRow->pChild ){ assignChildrenToRail(pRow); }else if( !omitDescenders && count_nonbranch_children(pRow->rid)!=0 ){ if( !pRow->timeWarp ) riser_to_top(pRow); } if( pParent ){ for(pLoop=pParent->pPrev; pLoop && pLoop!=pRow; pLoop=pLoop->pPrev){ pLoop->railInUse |= mask; } } } /* ** Insert merge rails and merge arrows */ for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ for(i=1; i<pRow->nParent; i++){ int parentRid = pRow->aParent[i]; pDesc = hashFind(p, parentRid); if( pDesc==0 ){ /* Merge from a node that is off-screen */ int iMrail = -1; for(j=0; j<GR_MAX_RAIL; j++){ if( mergeRiserFrom[j]==parentRid ){ iMrail = j; break; } } if( iMrail==-1 ){ iMrail = findFreeRail(p, pRow->idx, p->nRow, 0); if( p->mxRail>=GR_MAX_RAIL ) return; mergeRiserFrom[iMrail] = parentRid; } mask = BIT(iMrail); pRow->mergeIn[iMrail] = 1; pRow->mergeDown |= mask; for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){ pLoop->railInUse |= mask; } }else{ /* Merge from an on-screen node */ createMergeRiser(p, pDesc, pRow); if( p->mxRail>=GR_MAX_RAIL ) return; } } } /* ** Insert merge rails from primaries to duplicates. */ if( hasDup ){ int dupRail; int mxRail; find_max_rail(p); mxRail = p->mxRail; dupRail = mxRail+1; if( p->mxRail>=GR_MAX_RAIL ) return; for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ if( !pRow->isDup ) continue; pRow->iRail = dupRail; pDesc = hashFind(p, pRow->rid); assert( pDesc!=0 && pDesc!=pRow ); createMergeRiser(p, pDesc, pRow); if( pDesc->mergeOut>mxRail ) mxRail = pDesc->mergeOut; } if( dupRail<=mxRail ){ dupRail = mxRail+1; for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ if( pRow->isDup ) pRow->iRail = dupRail; } } if( mxRail>=GR_MAX_RAIL ) return; } /* ** Find the maximum rail number. */ find_max_rail(p); p->nErr = 0; } |
Changes to src/graph.js.
1 2 | /* This module contains javascript needed to render timeline graphs in Fossil. ** | < < < < < < | | | | | | < | < < < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | 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 | /* This module contains javascript needed to render timeline graphs in Fossil. ** ** Prior to sourcing this script, there should be a separate ** <script type='application/json' id='timeline-data-NN'> for each graph, ** each containing JSON like this: ** ** { "iTableId": INTEGER, // Table sequence number (NN) ** "circleNodes": BOOLEAN, // True for circle nodes. False for squares ** "showArrowheads": BOOLEAN, // True for arrowheads. False to omit ** "iRailPitch": INTEGER, // Spacing between vertical lines (px) ** "colorGraph": BOOLEAN, // True to put color on graph lines ** "nomo": BOOLEAN, // True to join merge lines with rails ** "iTopRow": INTEGER, // Index of top-most row in the graph ** "omitDescenders": BOOLEAN, // Omit ancestor lines off bottom of screen ** "fileDiff": BOOLEAN, // True for file diff. False for check-in ** "scrollToSelect": BOOLEAN, // Scroll to selection on first render ** "nrail": INTEGER, // Number of vertical "rails" ** "baseUrl": TEXT, // Top-level URL ** "rowinfo": ROWINFO-ARRAY } ** ** The rowinfo field is an array of structures, one per entry in the timeline, ** where each structure has the following fields: ** ** id: The id of the <div> element for the row. This is an integer. ** to get an actual id, prepend "m" to the integer. The top node ** is iTopRow and numbers increase moving down the tx. ** bg: The background color for this row ** r: The "rail" that the node for this row sits on. The left-most ** rail is 0 and the number increases to the right. ** d: True if there is a "descender" - an arrow coming from the bottom ** of the page straight up to this node. ** mo: "merge-out". If non-negative, this is the rail position ** for the upward portion of a merge arrow. The merge arrow goes up ** to the row identified by mu:. If this value is negative then ** node has no merge children and no merge-out line is drawn. ** mu: The id of the row which is the top of the merge-out arrow. ** u: Draw a thick child-line out of the top of this node and up to ** the node with an id equal to this value. 0 if it is straight to ** the top of the page, -1 if there is no thick-line riser. ** f: 0x01: a leaf node. ** au: An array of integers that define thick-line risers for branches. ** The integers are in pairs. For each pair, the first integer is ** is the rail on which the riser should run and the second integer ** is the id of the node upto which the riser should run. ** mi: "merge-in". An array of integer rail positions from which ** merge arrows should be drawn into this node. If the value is ** negative, then the rail position is the absolute value of mi[] ** and a thin merge-arrow descender is drawn to the bottom of ** the screen. ** h: The artifact hash of the object being graphed */ var amendCssOnce = 1; // Only change the CSS one time function amendCss(circleNodes,showArrowheads){ if( !amendCssOnce ) return; var css = ""; if( circleNodes ){ css += ".tl-node, .tl-node:after { border-radius: 50%; }"; } if( !showArrowheads ){ css += ".tl-arrow.u { display: none; }"; } if( css!=="" ){ var style = document.createElement("style"); style.textContent = css; document.querySelector("head").appendChild(style); } amendCssOnce = 0; } function TimelineGraph(tx){ var topObj = document.getElementById("timelineTable"+tx.iTableId); amendCss(tx.circleNodes, tx.showArrowheads); var canvasDiv; var railPitch; var mergeOffset; var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine; function initGraph(){ var parent = topObj.rows[0].cells[1]; parent.style.verticalAlign = "top"; canvasDiv = document.createElement("div"); canvasDiv.className = "tl-canvas"; canvasDiv.style.position = "absolute"; parent.appendChild(canvasDiv); var elems = {}; var elemClasses = [ "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line", "arrow merge r", "line merge", "arrow warp", "line warp" ]; for( var i=0; i<elemClasses.length; i++ ){ var cls = elemClasses[i]; var elem = document.createElement("div"); elem.className = "tl-" + cls; if( cls.indexOf("line")==0 ) elem.className += " v"; canvasDiv.appendChild(elem); var k = cls.replace(/\s/g, "_"); var r = elem.getBoundingClientRect(); var w = Math.round(r.right - r.left); var h = Math.round(r.bottom - r.top); elems[k] = {w: w, h: h, cls: cls}; } node = elems.node; arrow = elems.arrow_u; arrowSmall = elems.arrow_u_sm; line = elems.line; mArrow = elems.arrow_merge_r; mLine = elems.line_merge; wArrow = elems.arrow_warp; wLine = elems.line_warp; var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1); if( window.innerWidth<400 ){ railPitch = minRailPitch; }else{ if( tx.iRailPitch>0 ){ railPitch = tx.iRailPitch; |
︙ | ︙ | |||
292 293 294 295 296 297 298 | if( h ) n.style.height = h+"px"; if( color ) n.style.backgroundColor = color; n.className = "tl-"+cls; canvasDiv.appendChild(n); return n; } function absoluteY(obj){ | | > | | | < | < < < < < | | | | < | < < < < < < < < < < < < < < < < < < | < < < < < < | > | < | < | < | < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < | < < | < < < < | < < < < < | < < < < < < < < < < < < < < < < < < | | < < < < < < | < | < < < < < < < | | | | | | | | | | | < | | | < | | < | < | < | | | < | | | < < | | | | | | < | < | | | | < < < < < < < < < < < < < < < < | < | < | | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | if( h ) n.style.height = h+"px"; if( color ) n.style.backgroundColor = color; n.className = "tl-"+cls; canvasDiv.appendChild(n); return n; } function absoluteY(obj){ var top = 0; if( obj.offsetParent ){ do{ top += obj.offsetTop; }while( obj = obj.offsetParent ); } return top; } function miLineY(p){ return p.y + node.h - mLine.w - 1; } function drawLine(elem,color,x0,y0,x1,y1){ var cls = elem.cls + " "; if( x1===null ){ x1 = x0+elem.w; cls += "v"; }else{ y1 = y0+elem.w; cls += "h"; } drawBox(cls,color,x0,y0,x1,y1); } function drawUpArrow(from,to,color){ var y = to.y + node.h; var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0); var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow; var x = to.x + (node.w-line.w)/2; var y0 = from.y + node.h/2; var y1 = Math.ceil(to.y + node.h + arw.h/2); drawLine(line,color,x,y0,null,y1); x = to.x + (node.w-arw.w)/2; var n = drawBox(arw.cls,null,x,y); if(color) n.style.borderBottomColor = color; } function drawMergeLine(x0,y0,x1,y1){ drawLine(mLine,null,x0,y0,x1,y1); } function drawMergeArrow(p,rail){ var x0 = rail*railPitch + node.w/2; if( rail in mergeLines ){ x0 += mergeLines[rail]; if( p.r<rail ) x0 += mLine.w; }else{ x0 += (p.r<rail ? -1 : 1)*line.w/2; } var x1 = mArrow.w ? mArrow.w/2 : -node.w/2; x1 = p.x + (p.r<rail ? node.w + Math.ceil(x1) : -x1); var y = miLineY(p); drawMergeLine(x0,y,x1,null); var x = p.x + (p.r<rail ? node.w : -mArrow.w); var cls = "arrow merge " + (p.r<rail ? "l" : "r"); drawBox(cls,null,x,y+(mLine.w-mArrow.h)/2); } function drawNode(p, btm){ if( p.bg ){ var e = document.getElementById("mc"+p.id); if(e) e.style.backgroundColor = p.bg; e = document.getElementById("md"+p.id); if(e) e.style.backgroundColor = p.bg; } if( p.r<0 ) return; if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg); var cls = node.cls; if( p.mi.length ) cls += " merge"; if( p.f&1 ) cls += " leaf"; var n = drawBox(cls,p.bg,p.x,p.y); n.id = "tln"+p.id; n.onclick = clickOnNode; n.style.zIndex = 10; if( !tx.omitDescenders ){ if( p.u==0 ) drawUpArrow(p,{x: p.x, y: -node.h},p.fg); if( p.d ) drawUpArrow({x: p.x, y: btm-node.h/2},p,p.fg); } if( p.mo>=0 ){ var x0 = p.x + node.w/2; var x1 = p.mo*railPitch + node.w/2; var u = tx.rowinfo[p.mu-tx.iTopRow]; var y1 = miLineY(u); if( p.u<0 || p.mo!=p.r ){ x1 += mergeLines[p.mo] = -mLine.w/2; var y0 = p.y+2; if( p.r!=p.mo ) drawMergeLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null); drawMergeLine(x1,y0+mLine.w,null,y1); }else if( mergeOffset ){ mergeLines[p.mo] = u.r<p.r ? -mergeOffset-mLine.w : mergeOffset; x1 += mergeLines[p.mo]; drawMergeLine(x1,p.y+node.h/2,null,y1); }else{ delete mergeLines[p.mo]; } } for( var i=0; i<p.au.length; i+=2 ){ var rail = p.au[i]; var x0 = p.x + node.w/2; var x1 = rail*railPitch + (node.w-line.w)/2; if( x0<x1 ){ x0 = Math.ceil(x0); x1 += line.w; } var y0 = p.y + (node.h-line.w)/2; var u = tx.rowinfo[p.au[i+1]-tx.iTopRow]; if( u.id<p.id ){ drawLine(line,u.fg,x0,y0,x1,null); drawUpArrow(p,u,u.fg); }else{ var y1 = u.y + (node.h-line.w)/2; drawLine(wLine,u.fg,x0,y0,x1,null); drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w); drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null); var x = u.x-wArrow.w; var y = u.y+(node.h-wArrow.h)/2; var n = drawBox(wArrow.cls,null,x,y); if( u.fg ) n.style.borderLeftColor = u.fg; } } for( var i=0; i<p.mi.length; i++ ){ var rail = p.mi[i]; if( rail<0 ){ rail = -rail; mergeLines[rail] = -mLine.w/2; var x = rail*railPitch + (node.w-mLine.w)/2; drawMergeLine(x,miLineY(p),null,btm); } drawMergeArrow(p,rail); } } var mergeLines; function renderGraph(){ mergeLines = {}; canvasDiv.innerHTML = ""; var canvasY = absoluteY(canvasDiv); for(var i=0; i<tx.rowinfo.length; i++ ){ var e = document.getElementById("m"+tx.rowinfo[i].id); tx.rowinfo[i].y = absoluteY(e) - canvasY; tx.rowinfo[i].x = tx.rowinfo[i].r*railPitch; } var tlBtm = document.querySelector(".timelineBottom"); if( tlBtm.offsetHeight<node.h ){ tlBtm.style.height = node.h + "px"; } var btm = absoluteY(tlBtm) - canvasY + tlBtm.offsetHeight; for( var i=tx.rowinfo.length-1; i>=0; i-- ){ drawNode(tx.rowinfo[i], btm); } } var selRow; function clickOnNode(){ var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow]; if( !selRow ){ selRow = p; this.className += " sel"; canvasDiv.className += " sel"; }else if( selRow==p ){ selRow = null; this.className = this.className.replace(" sel", ""); canvasDiv.className = canvasDiv.className.replace(" sel", ""); }else{ if( tx.fileDiff ){ location.href=tx.baseUrl + "/fdiff?v1="+selRow.h+"&v2="+p.h }else{ location.href=tx.baseUrl + "/vdiff?from="+selRow.h+"&to="+p.h } } } function changeDisplay(selector,value){ var x = document.getElementsByClassName(selector); var n = x.length; for(var i=0; i<n; i++) {x[i].style.display = value;} } |
︙ | ︙ | |||
786 787 788 789 790 791 792 | for(i=0; i<lx.length; i++){ var rx = lx[i]; if( rx.getAttribute('data-reordered') ) break; rx.setAttribute('data-reordered',1); rx.appendChild(rx.firstChild); rx.insertBefore(rx.childNodes[1],rx.firstChild); } | < < < < < < < | | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | for(i=0; i<lx.length; i++){ var rx = lx[i]; if( rx.getAttribute('data-reordered') ) break; rx.setAttribute('data-reordered',1); rx.appendChild(rx.firstChild); rx.insertBefore(rx.childNodes[1],rx.firstChild); } } } /* Look for all timeline-data-NN objects. Load each one and draw ** a graph for each one. */ (function(){ var i; for(i=0; 1; i++){ var dataObj = document.getElementById("timeline-data-"+i); if(!dataObj) break; var txJson = dataObj.textContent || dataObj.innerText; var tx = JSON.parse(txJson); TimelineGraph(tx); } }()) |
Changes to src/gzip.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** file. The GZIP format is described in RFC-1952. ** ** State information is stored in static variables, so this implementation ** can only be building up a single GZIP file at a time. */ #include "config.h" #include <assert.h> | > > > > | > | | 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 | ** file. The GZIP format is described in RFC-1952. ** ** State information is stored in static variables, so this implementation ** can only be building up a single GZIP file at a time. */ #include "config.h" #include <assert.h> #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #include "gzip.h" /* ** State information for the GZIP file under construction. */ struct gzip_state { int eState; /* 0: idle 1: header 2: compressing */ int iCRC; /* The checksum */ z_stream stream; /* The working compressor */ Blob out; /* Results stored here */ } gzip; /* ** Write a 32-bit integer as little-endian into the given buffer. */ |
︙ | ︙ |
Deleted src/hbmenu.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/hname.c.
︙ | ︙ | |||
214 215 216 217 218 219 220 | return HPOLICY_AUTO; } } /* ** Names of the hash policies. */ | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | return HPOLICY_AUTO; } } /* ** Names of the hash policies. */ static const char *azPolicy[] = { "sha1", "auto", "sha3", "sha3-only", "shun-sha1" }; /* Return the name of the current hash policy. */ const char *hpolicy_name(void){ return azPolicy[g.eHashPolicy]; |
︙ | ︙ |
Deleted src/hook.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/href.js.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** (with type='application/json' to avoid Content Security Policy issues) ** containing: ** ** {"delay":MILLISECONDS, "mouseover":BOOLEAN} ** ** The <script> must have an id='href-data'. DELAY is the number ** milliseconds delay prior to populating href= and action=. If the | | | < | < < > > | < < < < < | < < < > < < < < < < | < < < | | 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 | ** (with type='application/json' to avoid Content Security Policy issues) ** containing: ** ** {"delay":MILLISECONDS, "mouseover":BOOLEAN} ** ** The <script> must have an id='href-data'. DELAY is the number ** milliseconds delay prior to populating href= and action=. If the ** mouseover boolean is true, then the timer does not start until a ** mouse motion event occurs over top of the document. */ function setAllHrefs(){ var anchors = document.getElementsByTagName("a"); for(var i=0; i<anchors.length; i++){ var j = anchors[i]; if(j.hasAttribute("data-href")) j.href=j.getAttribute("data-href"); } var forms = document.getElementsByTagName("form"); for(var i=0; i<forms.length; i++){ var j = forms[i]; if(j.hasAttribute("data-action")) j.action=j.getAttribute("data-action"); } } function antiRobotDefense(){ var x = document.getElementById("href-data"); var jx = x.textContent || x.innerText; var g = JSON.parse(jx); var isOperaMini = Object.prototype.toString.call(window.operamini)==="[object OperaMini]"; if(g.mouseover && !isOperaMini){ document.getElementByTagName("body")[0].onmousemove=function(){ setTimeout(setAllHrefs, g.delay); } }else{ setTimeout(setAllHrefs, g.delay); } } antiRobotDefense() |
Changes to src/http.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | #define isatty(d) _isatty(d) #endif #ifndef fileno #define fileno(s) _fileno(s) #endif #endif | < < < < < < < < < < < < < < < < < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #define isatty(d) _isatty(d) #endif #ifndef fileno #define fileno(s) _fileno(s) #endif #endif /* Maximum number of HTTP Authorization attempts */ #define MAX_HTTP_AUTH 2 /* Keep track of HTTP Basic Authorization failures */ static int fSeenHttpAuth = 0; /* ** Construct the "login" card with the client credentials. ** ** login LOGIN NONCE SIGNATURE ** ** The LOGIN is the user id of the client. NONCE is the sha1 checksum ** of all payload that follows the login card. SIGNATURE is the sha1 |
︙ | ︙ | |||
93 94 95 96 97 98 99 | zPw = 0; }else{ /* Password failure while doing a sync from the command-line interface */ url_prompt_for_password(); zPw = g.url.passwd; } | | < | < < < < < < < < < < < < < > | < < < < < < < < | | < | < < < | | > > > > > < < < | | | | | | < < | 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 | zPw = 0; }else{ /* Password failure while doing a sync from the command-line interface */ url_prompt_for_password(); zPw = g.url.passwd; } /* The login card wants the SHA1 hash of the password, so convert the ** password to its SHA1 hash if it isn't already a SHA1 hash. */ /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */ if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0); blob_append(&pw, zPw, -1); sha1sum_blob(&pw, &sig); blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig); blob_reset(&pw); blob_reset(&sig); blob_reset(&nonce); } /* ** Construct an appropriate HTTP request header. Write the header ** into pHdr. This routine initializes the pHdr blob. pPayload is ** the complete payload (including the login card) already compressed. */ static void http_build_header(Blob *pPayload, Blob *pHdr){ int i; const char *zSep; blob_zero(pHdr); i = strlen(g.url.path); if( i>0 && g.url.path[i-1]=='/' ){ zSep = ""; }else{ zSep = "/"; } blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.url.path, zSep); if( g.url.proxyAuth ){ blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth); } if( g.zHttpAuth && g.zHttpAuth[0] ){ const char *zCredentials = g.zHttpAuth; char *zEncoded = encode64(zCredentials, -1); blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded); fossil_free(zEncoded); } blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname); blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent()); if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n"); if( g.fHttpTrace ){ blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); }else{ blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n"); } blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload)); } /* ** Use Fossil credentials for HTTP Basic Authorization prompt */ static int use_fossil_creds_for_httpauth_prompt(void){ Blob x; |
︙ | ︙ | |||
230 231 232 233 234 235 236 | } if( save_httpauth_prompt() ){ set_httpauth(zHttpAuth); } return zHttpAuth; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < > < < < < < < < < < < < < < < < < < < | | | | | | | | < | > < < < < < < < | < | < | | < > > | > | | < < | < < < < < < < < < < < < < < < < | < < < < | | | | | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | < | < < < < < < | | < < < | | < | | < < < < < < < | < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | } if( save_httpauth_prompt() ){ set_httpauth(zHttpAuth); } return zHttpAuth; } /* ** Sign the content in pSend, compress it, and send it to the server ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply ** in pRecv. pRecv is assumed to be uninitialized when ** this routine is called - this routine will initialize it. ** ** The server address is contain in the "g" global structure. The ** url_parse() routine should have been called prior to this routine ** in order to fill this structure appropriately. */ int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){ Blob login; /* The login card */ Blob payload; /* The complete payload including login card */ Blob hdr; /* The HTTP request header */ int closeConnection; /* True to close the connection when done */ int iLength; /* Expected length of the reply payload */ int iRecvLen; /* Received length of the reply payload */ int rc = 0; /* Result code */ int iHttpVersion; /* Which version of HTTP protocol server uses */ char *zLine; /* A single line of the reply header */ int i; /* Loop counter */ int isError = 0; /* True if the reply is an error message */ int isCompressed = 1; /* True if the reply is compressed */ if( transport_open(&g.url) ){ fossil_warning("%s", transport_errmsg(&g.url)); return 1; } /* Construct the login card and prepare the complete payload */ blob_zero(&login); if( useLogin ) http_build_login_card(pSend, &login); if( g.fHttpTrace ){ payload = login; blob_append(&payload, blob_buffer(pSend), blob_size(pSend)); }else{ blob_compress2(&login, pSend, &payload); blob_reset(&login); } /* Construct the HTTP request header */ http_build_header(&payload, &hdr); /* When tracing, write the transmitted HTTP message both to standard ** output and into a file. The file can then be used to drive the ** server-side like this: ** ** ./fossil test-http <http-request-1.txt */ if( g.fHttpTrace ){ static int traceCnt = 0; char *zOutFile; FILE *out; traceCnt++; zOutFile = mprintf("http-request-%d.txt", traceCnt); out = fopen(zOutFile, "wb"); if( out ){ fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out); fwrite(blob_buffer(&payload), 1, blob_size(&payload), out); fclose(out); } free(zOutFile); zOutFile = mprintf("http-reply-%d.txt", traceCnt); out = fopen(zOutFile, "wb"); transport_log(out); free(zOutFile); } /* ** Send the request to the server. */ transport_send(&g.url, &hdr); transport_send(&g.url, &payload); blob_reset(&hdr); blob_reset(&payload); transport_flip(&g.url); /* ** Read and interpret the server reply */ closeConnection = 1; iLength = -1; while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){ /* printf("[%s]\n", zLine); fflush(stdout); */ if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){ if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err; if( rc==401 ){ if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){ if( g.zHttpAuth ){ if( g.zHttpAuth ) free(g.zHttpAuth); } g.zHttpAuth = prompt_for_httpauth_creds(); transport_close(&g.url); return http_exchange(pSend, pReply, useLogin, maxRedirect); } } if( rc!=200 && rc!=301 && rc!=302 ){ int ii; for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} while( zLine[ii]==' ' ) ii++; fossil_warning("server says: %s", &zLine[ii]); goto write_err; } if( iHttpVersion==0 ){ closeConnection = 1; }else{ closeConnection = 0; } }else if( g.url.isSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){ if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err; if( rc!=200 && rc!=301 && rc!=302 ){ int ii; for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} while( zLine[ii]==' ' ) ii++; fossil_warning("server says: %s", &zLine[ii]); goto write_err; } closeConnection = 0; }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){ for(i=15; fossil_isspace(zLine[i]); i++){} iLength = atoi(&zLine[i]); }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ char c; for(i=11; fossil_isspace(zLine[i]); i++){} c = zLine[i]; if( c=='c' || c=='C' ){ closeConnection = 1; }else if( c=='k' || c=='K' ){ closeConnection = 0; } }else if( ( rc==301 || rc==302 ) && fossil_strnicmp(zLine, "location:", 9)==0 ){ int i, j; if ( --maxRedirect == 0){ fossil_warning("redirect limit exceeded"); goto write_err; } for(i=9; zLine[i] && zLine[i]==' '; i++){} if( zLine[i]==0 ){ fossil_warning("malformed redirect: %s", zLine); goto write_err; } j = strlen(zLine) - 1; while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ j -= 4; zLine[j] = 0; } fossil_print("redirect with status %d to %s\n", rc, &zLine[i]); url_parse(&zLine[i], 0); transport_close(&g.url); transport_global_shutdown(&g.url); fSeenHttpAuth = 0; if( g.zHttpAuth ) free(g.zHttpAuth); g.zHttpAuth = get_httpauth(); return http_exchange(pSend, pReply, useLogin, maxRedirect); }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){ if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){ isCompressed = 0; }else if( fossil_strnicmp(&zLine[14], "application/x-fossil-uncompressed", -1)==0 ){ isCompressed = 0; }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){ isError = 1; } } } if( iLength<0 ){ fossil_warning("server did not reply"); goto write_err; } if( rc!=200 ){ fossil_warning("\"location:\" missing from %d redirect reply", rc); goto write_err; } /* ** Extract the reply payload that follows the header */ blob_zero(pReply); blob_resize(pReply, iLength); iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength); if( iRecvLen != iLength ){ fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength); goto write_err; } blob_resize(pReply, iLength); if( isError ){ char *z; int i, j; z = blob_str(pReply); for(i=j=0; z[i]; i++, j++){ if( z[i]=='<' ){ while( z[i] && z[i]!='>' ) i++; |
︙ | ︙ | |||
753 754 755 756 757 758 759 | /* ** Jump to here if an error is seen. */ write_err: transport_close(&g.url); return 1; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 416 417 418 419 420 421 422 | /* ** Jump to here if an error is seen. */ write_err: transport_close(&g.url); return 1; } |
Changes to src/http_socket.c.
︙ | ︙ | |||
135 136 137 138 139 140 141 | } } /* ** Open a socket connection. The identify of the server is determined ** by pUrlData ** | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | } } /* ** Open a socket connection. The identify of the server is determined ** by pUrlData ** ** pUrlData->name Name of the server. Ex: www.fossil-scm.org ** pUrlData->port TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ int socket_open(UrlData *pUrlData){ int rc = 0; struct addrinfo *ai = 0; |
︙ | ︙ | |||
194 195 196 197 198 199 200 | return rc; } /* ** Send content out over the open socket connection. */ size_t socket_send(void *NotUsed, const void *pContent, size_t N){ | | | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | return rc; } /* ** Send content out over the open socket connection. */ size_t socket_send(void *NotUsed, const void *pContent, size_t N){ size_t sent; size_t total = 0; while( N>0 ){ sent = send(iSocket, pContent, N, 0); if( sent<=0 ) break; total += sent; N -= sent; pContent = (void*)&((char*)pContent)[sent]; } return total; } /* ** Receive content back from the open socket connection. |
︙ | ︙ | |||
230 231 232 233 234 235 236 | if( got<=0 ) break; total += (size_t)got; N -= (size_t)got; pContent = (void*)&((char*)pContent)[got]; } return total; } | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 | if( got<=0 ) break; total += (size_t)got; N -= (size_t)got; pContent = (void*)&((char*)pContent)[got]; } return total; } /* ** Attempt to resolve pUrlData->name to an IP address and setup g.zIpAddr ** so rcvfrom gets populated. For hostnames with more than one IP (or ** if overridden in ~/.ssh/config) the rcvfrom may not match the host ** to which we connect. */ void socket_ssh_resolve_addr(UrlData *pUrlData){ struct addrinfo *ai = 0; struct addrinfo hints; char zRemote[NI_MAXHOST]; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if( getaddrinfo(pUrlData->name, NULL, &hints, &ai)==0 && ai!=0 && getnameinfo(ai->ai_addr, ai->ai_addrlen, zRemote, sizeof(zRemote), 0, 0, NI_NUMERICHOST)==0 ){ g.zIpAddr = mprintf("%s (%s)", zRemote, pUrlData->name); } if( ai ) freeaddrinfo(ai); if( g.zIpAddr==0 ){ g.zIpAddr = mprintf("%s", pUrlData->name); } } |
Changes to src/http_ssl.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file manages low-level SSL communications. ** ** This file implements a singleton. A single SSL connection may be active | | < < < | < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file manages low-level SSL communications. ** ** This file implements a singleton. A single SSL connection may be active ** at a time. State information is stored in static variables. The identity ** of the server is held in global variables that are set by url_parse(). ** ** SSL support is abstracted out into this module because Fossil can ** be compiled without SSL support (which requires OpenSSL library) */ #include "config.h" #ifdef FOSSIL_ENABLE_SSL #include <openssl/bio.h> #include <openssl/ssl.h> #include <openssl/err.h> #include "http_ssl.h" #include <assert.h> #include <sys/types.h> /* ** There can only be a single OpenSSL IO connection open at a time. ** State information about that IO is stored in the following ** local variables: */ static int sslIsInit = 0; /* True after global initialization */ static BIO *iBio = 0; /* OpenSSL I/O abstraction */ static char *sslErrMsg = 0; /* Text of most recent OpenSSL error */ static SSL_CTX *sslCtx; /* SSL context */ static SSL *ssl; /* ** Clear the SSL error message */ static void ssl_clear_errmsg(void){ free(sslErrMsg); sslErrMsg = 0; |
︙ | ︙ | |||
201 202 203 204 205 206 207 208 | fossil_warning("The remote server requested a client certificate for " "authentication. Specify the pathname to a file containing the PEM " "encoded certificate and private key with the --ssl-identity option " "or the ssl-identity setting."); return 0; /* no cert available */ } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > < < < < < > < | < < < < < < < < < < | < < > > | < | < < < < > | > | < | | < < < < | | > > | | < < | | | < | 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 | fossil_warning("The remote server requested a client certificate for " "authentication. Specify the pathname to a file containing the PEM " "encoded certificate and private key with the --ssl-identity option " "or the ssl-identity setting."); return 0; /* no cert available */ } /* ** Call this routine once before any other use of the SSL interface. ** This routine does initial configuration of the SSL module. */ void ssl_global_init(void){ const char *zCaSetting = 0, *zCaFile = 0, *zCaDirectory = 0; const char *identityFile; if( sslIsInit==0 ){ SSL_library_init(); SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); sslCtx = SSL_CTX_new(SSLv23_client_method()); /* Disable SSLv2 and SSLv3 */ SSL_CTX_set_options(sslCtx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); /* Set up acceptable CA root certificates */ zCaSetting = db_get("ssl-ca-location", 0); if( zCaSetting==0 || zCaSetting[0]=='\0' ){ /* CA location not specified, use platform's default certificate store */ X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx)); }else{ /* User has specified a CA location, make sure it exists and use it */ switch( file_isdir(zCaSetting, ExtFILE) ){ case 0: { /* doesn't exist */ fossil_panic("ssl-ca-location is set to '%s', " "but is not a file or directory", zCaSetting); break; } case 1: { /* directory */ zCaDirectory = zCaSetting; break; } case 2: { /* file */ zCaFile = zCaSetting; break; } } if( SSL_CTX_load_verify_locations(sslCtx, zCaFile, zCaDirectory)==0 ){ fossil_panic("Failed to use CA root certificates from " "ssl-ca-location '%s'", zCaSetting); } } /* Load client SSL identity, preferring the filename specified on the ** command line */ if( g.zSSLIdentity!=0 ){ identityFile = g.zSSLIdentity; }else{ identityFile = db_get("ssl-identity", 0); } if( identityFile!=0 && identityFile[0]!='\0' ){ if( SSL_CTX_use_certificate_file(sslCtx,identityFile,SSL_FILETYPE_PEM)!=1 || SSL_CTX_use_PrivateKey_file(sslCtx,identityFile,SSL_FILETYPE_PEM)!=1 ){ fossil_panic("Could not load SSL identity from %s", identityFile); } } /* Register a callback to tell the user what to do when the server asks ** for a cert */ SSL_CTX_set_client_cert_cb(sslCtx, ssl_client_cert_callback); sslIsInit = 1; } } /* ** Call this routine to shutdown the SSL module prior to program exit. */ void ssl_global_shutdown(void){ if( sslIsInit ){ SSL_CTX_free(sslCtx); ssl_clear_errmsg(); sslIsInit = 0; } } /* ** Close the currently open SSL connection. If no connection is open, ** this routine is a no-op. */ void ssl_close(void){ if( iBio!=NULL ){ (void)BIO_reset(iBio); BIO_free_all(iBio); iBio = NULL; } } /* See RFC2817 for details */ static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){ int rc, httpVerMin; char *bbuf; Blob snd, reply; int done=0,end=0; blob_zero(&snd); blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname, pUrlData->proxyOrigPort); blob_appendf(&snd, "Host: %s:%d\r\n", pUrlData->hostname, pUrlData->proxyOrigPort); if( pUrlData->proxyAuth ){ blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth); } blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1); blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent()); blob_append(&snd, "\r\n", 2); BIO_write(bio, blob_buffer(&snd), blob_size(&snd)); |
︙ | ︙ | |||
403 404 405 406 407 408 409 | }while(!done); sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc); blob_reset(&reply); return rc; } /* | < < < < < < < < < < < | < < | < | | > | > | > > > > > > > > > > > | < | < < | < < < < < < < < < < | < | | | < < < < < < < | < > | < | < | < < | < > > > | < < | | | < < > > | | | < < < < < < < < < < < < < | | > > > | > > > > > > | | | | | > | < < | | | < | | > > > | < < | | | < < > < < < < < < < < < < | < < | < < | > | | > > > > | > > > > > > > | < < | | < < < < < < < < < | < < > < | < < | > > > > | | | | > | > | > > > > > > | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | }while(!done); sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc); blob_reset(&reply); return rc; } /* ** Open an SSL connection. The identify of the server is determined ** as follows: ** ** g.url.name Name of the server. Ex: www.fossil-scm.org ** pUrlData->port TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ int ssl_open(UrlData *pUrlData){ X509 *cert; int hasSavedCertificate = 0; int trusted = 0; unsigned long e; ssl_global_init(); /* Get certificate for current server from global config and * (if we have it in config) add it to certificate store. */ cert = ssl_get_certificate(pUrlData, &trusted); if ( cert!=NULL ){ X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert); X509_free(cert); hasSavedCertificate = 1; } if( pUrlData->useProxy ){ int rc; char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port); BIO *sBio = BIO_new_connect(connStr); free(connStr); if( BIO_do_connect(sBio)<=0 ){ ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)", pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); ssl_close(); return 1; } rc = establish_proxy_tunnel(pUrlData, sBio); if( rc<200||rc>299 ){ ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc); return 1; } pUrlData->path = pUrlData->proxyUrlPath; iBio = BIO_new_ssl(sslCtx, 1); BIO_push(iBio, sBio); }else{ iBio = BIO_new_ssl_connect(sslCtx); } if( iBio==NULL ) { ssl_set_errmsg("SSL: cannot open SSL (%s)", ERR_reason_error_string(ERR_get_error())); return 1; } BIO_get_ssl(iBio, &ssl); #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT) if( !SSL_set_tlsext_host_name(ssl, (pUrlData->useProxy?pUrlData->hostname:pUrlData->name)) ){ fossil_warning("WARNING: failed to set server name indication (SNI), " "continuing without it.\n"); } #endif SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if( !pUrlData->useProxy ){ char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port); BIO_set_conn_hostname(iBio, connStr); free(connStr); if( BIO_do_connect(iBio)<=0 ){ ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); ssl_close(); return 1; } } if( BIO_do_handshake(iBio)<=0 ) { ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)", pUrlData->useProxy?pUrlData->hostname:pUrlData->name, pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port, ERR_reason_error_string(ERR_get_error())); ssl_close(); return 1; } /* Check if certificate is valid */ cert = SSL_get_peer_certificate(ssl); if ( cert==NULL ){ ssl_set_errmsg("No SSL certificate was presented by the peer"); ssl_close(); return 1; } if( trusted<=0 && (e = SSL_get_verify_result(ssl)) != X509_V_OK ){ char *desc, *prompt; const char *warning = ""; Blob ans; char cReply; BIO *mem; unsigned char md[32]; unsigned int mdLength = 31; mem = BIO_new(BIO_s_mem()); X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE); BIO_puts(mem, "\n\nIssued By:\n\n"); X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE); BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n "); if(X509_digest(cert, EVP_sha1(), md, &mdLength)){ int j; for( j = 0; j < mdLength; ++j ) { BIO_printf(mem, " %02x", md[j]); } } BIO_write(mem, "", 1); /* nul-terminate mem buffer */ BIO_get_mem_data(mem, &desc); if( hasSavedCertificate ){ warning = "WARNING: Certificate doesn't match the " "saved certificate for this host!"; } prompt = mprintf("\nSSL verification failed: %s\n" "Certificate received: \n\n%s\n\n%s\n" "Either:\n" " * verify the certificate is correct using the " "SHA1 fingerprint above\n" " * use the global ssl-ca-location setting to specify your CA root\n" " certificates list\n\n" "If you are not expecting this message, answer no and " "contact your server\nadministrator.\n\n" "Accept certificate for host %s (a=always/y/N)? ", X509_verify_cert_error_string(e), desc, warning, pUrlData->useProxy?pUrlData->hostname:pUrlData->name); BIO_free(mem); prompt_user(prompt, &ans); free(prompt); cReply = blob_str(&ans)[0]; blob_reset(&ans); if( cReply!='y' && cReply!='Y' && cReply!='a' && cReply!='A') { X509_free(cert); ssl_set_errmsg("SSL certificate declined"); ssl_close(); return 1; } if( cReply=='a' || cReply=='A') { if ( trusted==0 ){ prompt_user("\nSave this certificate as fully trusted (a=always/N)? ", &ans); cReply = blob_str(&ans)[0]; trusted = ( cReply=='a' || cReply=='A' ); blob_reset(&ans); } ssl_save_certificate(pUrlData, cert, trusted); } } /* Set the Global.zIpAddr variable to the server we are talking to. ** This is used to populate the ipaddr column of the rcvfrom table, ** if any files are received from the server. */ { /* IPv4 only code */ const unsigned char *ip = (const unsigned char *) BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2); g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } X509_free(cert); return 0; } /* ** Save certificate to global config. */ void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){ BIO *mem; char *zCert, *zHost; mem = BIO_new(BIO_s_mem()); PEM_write_bio_X509(mem, cert); BIO_write(mem, "", 1); /* nul-terminate mem buffer */ BIO_get_mem_data(mem, &zCert); zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name); db_set(zHost, zCert, 1); free(zHost); zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name); db_set_int(zHost, trusted, 1); free(zHost); BIO_free(mem); } /* ** Get certificate for pUrlData->urlName from global config. ** Return NULL if no certificate found. */ X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){ char *zHost, *zCert; BIO *mem; X509 *cert; zHost = mprintf("cert:%s", pUrlData->useProxy ? pUrlData->hostname : pUrlData->name); zCert = db_get(zHost, NULL); free(zHost); if ( zCert==NULL ) return NULL; if ( pTrusted!=0 ){ zHost = mprintf("trusted:%s", pUrlData->useProxy ? pUrlData->hostname : pUrlData->name); *pTrusted = db_get_int(zHost, 0); free(zHost); } mem = BIO_new(BIO_s_mem()); BIO_puts(mem, zCert); cert = PEM_read_bio_X509(mem, NULL, 0, NULL); free(zCert); BIO_free(mem); return cert; } /* ** Send content out over the SSL connection. */ size_t ssl_send(void *NotUsed, void *pContent, size_t N){ size_t total = 0; while( N>0 ){ int sent = BIO_write(iBio, pContent, N); if( sent<=0 ){ if( BIO_should_retry(iBio) ){ continue; } break; } total += sent; N -= sent; pContent = (void*)&((char*)pContent)[sent]; } return total; } /* ** Receive content back from the SSL connection. */ size_t ssl_receive(void *NotUsed, void *pContent, size_t N){ size_t total = 0; while( N>0 ){ int got = BIO_read(iBio, pContent, N); if( got<=0 ){ if( BIO_should_retry(iBio) ){ continue; } break; } total += got; N -= got; pContent = (void*)&((char*)pContent)[got]; } return total; } #endif /* FOSSIL_ENABLE_SSL */ |
Changes to src/http_transport.c.
︙ | ︙ | |||
78 79 80 81 82 83 84 | /* ** Check zFossil to see if it is a reasonable "fossil" command to ** run on the server. Do not allow an attacker to substitute something ** like "/bin/rm". */ static int is_safe_fossil_command(const char *zFossil){ | | | | | | < < < < < < < < < > < | > | > > > > < | | < | < | < < < < < | | | | | | | | | | | | | < | > | > | | 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 | /* ** Check zFossil to see if it is a reasonable "fossil" command to ** run on the server. Do not allow an attacker to substitute something ** like "/bin/rm". */ static int is_safe_fossil_command(const char *zFossil){ static const char *azSafe[] = { "*/fossil", "*/echo" }; int i; for(i=0; i<sizeof(azSafe)/sizeof(azSafe[0]); i++){ if( sqlite3_strglob(azSafe[i], zFossil)==0 ) return 1; if( strcmp(azSafe[i]+2, zFossil)==0 ) return 1; } return 0; } /* ** Default SSH command */ #ifdef _WIN32 static const char zDefaultSshCmd[] = "plink -ssh -T"; #else static const char zDefaultSshCmd[] = "ssh -e none -T"; #endif /* ** SSH initialization of the transport layer */ int transport_ssh_open(UrlData *pUrlData){ /* For SSH we need to create and run SSH fossil http ** to talk to the remote machine. */ char *zSsh; /* The base SSH command */ Blob zCmd; /* The SSH command */ char *zHost; /* The host name to contact */ socket_ssh_resolve_addr(pUrlData); zSsh = db_get("ssh-command", zDefaultSshCmd); blob_init(&zCmd, zSsh, -1); if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){ #ifdef _WIN32 blob_appendf(&zCmd, " -P %d", pUrlData->port); #else blob_appendf(&zCmd, " -p %d", pUrlData->port); #endif } if( pUrlData->user && pUrlData->user[0] ){ zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name); blob_append_escaped_arg(&zCmd, zHost); fossil_free(zHost); }else{ blob_append_escaped_arg(&zCmd, pUrlData->name); } if( !is_safe_fossil_command(pUrlData->fossil) ){ fossil_panic("the ssh:// URL is asking to run an unsafe command [%s] on " "the server.", pUrlData->fossil); } blob_append_escaped_arg(&zCmd, pUrlData->fossil); blob_append(&zCmd, " test-http", 10); if( pUrlData->path && pUrlData->path[0] ){ blob_append_escaped_arg(&zCmd, pUrlData->path); }else{ fossil_panic("ssh:// URI does not specify a path to the repository"); } if( g.fSshTrace ){ fossil_print("%s\n", blob_str(&zCmd)); /* Show the whole SSH command */ } popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); if( sshPid==0 ){ socket_set_errmsg("cannot start ssh tunnel using [%b]", &zCmd); } blob_reset(&zCmd); return sshPid==0; } /* ** Open a connection to the server. The server is defined by the following ** variables: ** ** pUrlData->name Name of the server. Ex: www.fossil-scm.org ** pUrlData->port TCP/IP port. Ex: 80 ** pUrlData->isHttps Use TLS for the connection ** ** Return the number of errors. */ int transport_open(UrlData *pUrlData){ int rc = 0; if( transport.isOpen==0 ){ if( pUrlData->isSsh ){ rc = transport_ssh_open(pUrlData); if( rc==0 ) transport.isOpen = 1; }else if( pUrlData->isHttps ){ #ifdef FOSSIL_ENABLE_SSL rc = ssl_open(pUrlData); if( rc==0 ) transport.isOpen = 1; #else socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support"); rc = 1; #endif }else if( pUrlData->isFile ){ sqlite3_uint64 iRandId; sqlite3_randomness(sizeof(iRandId), &iRandId); transport.zOutFile = mprintf("%s-%llu-out.http", g.zRepositoryName, iRandId); transport.zInFile = mprintf("%s-%llu-in.http", g.zRepositoryName, iRandId); transport.pFile = fossil_fopen(transport.zOutFile, "wb"); if( transport.pFile==0 ){ fossil_panic("cannot output temporary file: %s", transport.zOutFile); } transport.isOpen = 1; }else{ rc = socket_open(pUrlData); if( rc==0 ) transport.isOpen = 1; } } |
︙ | ︙ | |||
219 220 221 222 223 224 225 | fclose(transport.pLog); transport.pLog = 0; } if( pUrlData->isSsh ){ transport_ssh_close(); }else if( pUrlData->isHttps ){ #ifdef FOSSIL_ENABLE_SSL | | | | | | | | | < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | fclose(transport.pLog); transport.pLog = 0; } if( pUrlData->isSsh ){ transport_ssh_close(); }else if( pUrlData->isHttps ){ #ifdef FOSSIL_ENABLE_SSL ssl_close(); #endif }else if( pUrlData->isFile ){ if( transport.pFile ){ fclose(transport.pFile); transport.pFile = 0; } file_delete(transport.zInFile); file_delete(transport.zOutFile); free(transport.zInFile); free(transport.zOutFile); }else{ socket_close(); } transport.isOpen = 0; } } /* ** Send content over the wire. */ void transport_send(UrlData *pUrlData, Blob *toSend){ char *z = blob_buffer(toSend); int n = blob_size(toSend); transport.nSent += n; if( pUrlData->isSsh ){ fwrite(z, 1, n, sshOut); fflush(sshOut); }else if( pUrlData->isHttps ){ #ifdef FOSSIL_ENABLE_SSL int sent; while( n>0 ){ sent = ssl_send(0, z, n); /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */ if( sent<=0 ) break; n -= sent; } #endif }else if( pUrlData->isFile ){ fwrite(z, 1, n, transport.pFile); }else{ int sent; while( n>0 ){ sent = socket_send(0, z, n); /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */ if( sent<=0 ) break; n -= sent; } } } /* ** This routine is called when the outbound message is complete and ** it is time to being receiving a reply. */ void transport_flip(UrlData *pUrlData){ if( pUrlData->isFile ){ char *zCmd; fclose(transport.pFile); zCmd = mprintf("\"%s\" http --in \"%s\" --out \"%s\" --ipaddr 127.0.0.1" " \"%s\" --localauth", g.nameOfExe, transport.zOutFile, transport.zInFile, pUrlData->name ); fossil_system(zCmd); free(zCmd); transport.pFile = fossil_fopen(transport.zInFile, "rb"); } } /* |
︙ | ︙ | |||
317 318 319 320 321 322 323 | /* ** Read N bytes of content directly from the wire and write into ** the buffer. */ static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){ int got; | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | /* ** Read N bytes of content directly from the wire and write into ** the buffer. */ static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){ int got; if( sshIn ){ int x; int wanted = N; got = 0; while( wanted>0 ){ x = read(sshIn, &zBuf[got], wanted); if( x<=0 ) break; got += x; |
︙ | ︙ |
Changes to src/import.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | #if INTERFACE /* ** A single file change record. */ struct ImportFile { char *zName; /* Name of a file */ | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #if INTERFACE /* ** A single file change record. */ struct ImportFile { char *zName; /* Name of a file */ char *zUuid; /* UUID of the file */ char *zPrior; /* Prior name if the name was changed */ char isFrom; /* True if obtained from the parent */ char isExe; /* True if executable */ char isLink; /* True if symlink */ }; #endif |
︙ | ︙ | |||
57 58 59 60 61 62 63 | char *zBranch; /* Name of a branch for a commit */ char *zPrevBranch; /* The branch of the previous check-in */ char *aData; /* Data content */ char *zMark; /* The current mark */ char *zDate; /* Date/time stamp */ char *zUser; /* User name */ char *zComment; /* Comment of a commit */ | | < | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | char *zBranch; /* Name of a branch for a commit */ char *zPrevBranch; /* The branch of the previous check-in */ char *aData; /* Data content */ char *zMark; /* The current mark */ char *zDate; /* Date/time stamp */ char *zUser; /* User name */ char *zComment; /* Comment of a commit */ char *zFrom; /* from value as a UUID */ char *zPrevCheckin; /* Name of the previous check-in */ char *zFromMark; /* The mark of the "from" field */ int nMerge; /* Number of merge values */ int nMergeAlloc; /* Number of slots in azMerge[] */ char **azMerge; /* Merge values */ int nFile; /* Number of aFile values */ int nFileAlloc; /* Number of slots in aFile[] */ ImportFile *aFile; /* Information about files in a commit */ int fromLoaded; /* True zFrom content loaded into aFile[] */ int tagCommit; /* True if the commit adds a tag */ } gg; /* ** Duplicate a string. */ |
︙ | ︙ | |||
142 143 144 145 146 147 148 | } /* ** Insert an artifact into the BLOB table if it isn't there already. ** If zMark is not zero, create a cross-reference from that mark back ** to the newly inserted artifact. ** | | | < | < | < | 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 | } /* ** Insert an artifact into the BLOB table if it isn't there already. ** If zMark is not zero, create a cross-reference from that mark back ** to the newly inserted artifact. ** ** If saveUuid is true, then pContent is a commit record. Record its ** UUID in gg.zPrevCheckin. */ static int fast_insert_content( Blob *pContent, /* Content to insert */ const char *zMark, /* Label using this mark, if not NULL */ int saveUuid, /* Save artifact hash in gg.zPrevCheckin */ int doParse /* Invoke manifest_crosslink() */ ){ Blob hash; Blob cmpr; int rid; hname_hash(pContent, 0, &hash); rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &hash); if( rid==0 ){ static Stmt ins; db_static_prepare(&ins, "INSERT INTO blob(uuid, size, content) VALUES(:uuid, :size, :content)" ); db_bind_text(&ins, ":uuid", blob_str(&hash)); db_bind_int(&ins, ":size", gg.nData); blob_compress(pContent, &cmpr); db_bind_blob(&ins, ":content", &cmpr); db_step(&ins); db_reset(&ins); |
︙ | ︙ | |||
189 190 191 192 193 194 195 | ); db_multi_exec( "INSERT OR IGNORE INTO xmark(tname, trid, tuuid)" "VALUES(%B,%d,%B)", &hash, rid, &hash ); } | | < < < < < < < < < < < < < < < < < < > > | > < | > | < | 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 | ); db_multi_exec( "INSERT OR IGNORE INTO xmark(tname, trid, tuuid)" "VALUES(%B,%d,%B)", &hash, rid, &hash ); } if( saveUuid ){ fossil_free(gg.zPrevCheckin); gg.zPrevCheckin = fossil_strdup(blob_str(&hash)); } blob_reset(&hash); return rid; } /* ** Use data accumulated in gg from a "blob" record to add a new file ** to the BLOB table. */ static void finish_blob(void){ Blob content; blob_init(&content, gg.aData, gg.nData); fast_insert_content(&content, gg.zMark, 0, 0); blob_reset(&content); import_reset(0); } /* ** Use data accumulated in gg from a "tag" record to add a new ** control artifact to the BLOB table. */ static void finish_tag(void){ Blob record, cksum; if( gg.zDate && gg.zTag && gg.zFrom && gg.zUser ){ blob_zero(&record); blob_appendf(&record, "D %s\n", gg.zDate); blob_appendf(&record, "T +sym-%F%F%F %s", gimport.zTagPre, gg.zTag, gimport.zTagSuf, gg.zFrom); if( gg.zComment ){ blob_appendf(&record, " %F", gg.zComment); } blob_appendf(&record, "\nU %F\n", gg.zUser); md5sum_blob(&record, &cksum); blob_appendf(&record, "Z %b\n", &cksum); fast_insert_content(&record, 0, 0, 1); blob_reset(&cksum); } import_reset(0); } /* ** Compare two ImportFile objects for sorting */ |
︙ | ︙ | |||
285 286 287 288 289 290 291 | Blob record, cksum; import_prior_files(); qsort(gg.aFile, gg.nFile, sizeof(gg.aFile[0]), mfile_cmp); blob_zero(&record); blob_appendf(&record, "C %F\n", gg.zComment); blob_appendf(&record, "D %s\n", gg.zDate); | < | < < | | | < < < < | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | Blob record, cksum; import_prior_files(); qsort(gg.aFile, gg.nFile, sizeof(gg.aFile[0]), mfile_cmp); blob_zero(&record); blob_appendf(&record, "C %F\n", gg.zComment); blob_appendf(&record, "D %s\n", gg.zDate); if( !g.fQuiet ) fossil_print("%.10s\r", gg.zDate); for(i=0; i<gg.nFile; i++){ const char *zUuid = gg.aFile[i].zUuid; if( zUuid==0 ) continue; blob_appendf(&record, "F %F %s", gg.aFile[i].zName, zUuid); if( gg.aFile[i].isExe ){ blob_append(&record, " x\n", 3); }else if( gg.aFile[i].isLink ){ blob_append(&record, " l\n", 3); }else{ blob_append(&record, "\n", 1); } } if( gg.zFrom ){ blob_appendf(&record, "P %s", gg.zFrom); for(i=0; i<gg.nMerge; i++){ blob_appendf(&record, " %s", gg.azMerge[i]); } blob_append(&record, "\n", 1); |
︙ | ︙ | |||
347 348 349 350 351 352 353 | free(zFromBranch); db_multi_exec("INSERT INTO xbranch(tname, brnm) VALUES(%Q,%Q)", gg.zMark, gg.zBranch); blob_appendf(&record, "U %F\n", gg.zUser); md5sum_blob(&record, &cksum); blob_appendf(&record, "Z %b\n", &cksum); | | < < > < | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | free(zFromBranch); db_multi_exec("INSERT INTO xbranch(tname, brnm) VALUES(%Q,%Q)", gg.zMark, gg.zBranch); blob_appendf(&record, "U %F\n", gg.zUser); md5sum_blob(&record, &cksum); blob_appendf(&record, "Z %b\n", &cksum); fast_insert_content(&record, gg.zMark, 1, 1); blob_reset(&cksum); /* The "git fast-export" command might output multiple "commit" lines ** that reference a tag using "refs/tags/TAGNAME". The tag should only ** be applied to the last commit that is output. The problem is we do not ** know at this time if the current commit is the last one to hold this ** tag or not. So make an entry in the XTAG table to record this tag ** but overwrite that entry if a later instance of the same tag appears. ** ** This behavior seems like a bug in git-fast-export, but it is easier ** to work around the problem than to fix git-fast-export. */ if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){ blob_appendf(&record, "D %s\n", gg.zDate); blob_appendf(&record, "T +sym-%F%F%F %s\n", gimport.zBranchPre, gg.zBranch, gimport.zBranchSuf, gg.zPrevCheckin); blob_appendf(&record, "U %F\n", gg.zUser); md5sum_blob(&record, &cksum); blob_appendf(&record, "Z %b\n", &cksum); db_multi_exec( "INSERT OR REPLACE INTO xtag(tname, tcontent)" " VALUES(%Q,%Q)", gg.zBranch, blob_str(&record) ); blob_reset(&record); blob_reset(&cksum); } fossil_free(gg.zPrevBranch); gg.zPrevBranch = gg.zBranch; gg.zBranch = 0; import_reset(0); } /* |
︙ | ︙ | |||
435 436 437 438 439 440 441 | }else{ *pzIn = &z[i]; } return z; } /* | | | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | }else{ *pzIn = &z[i]; } return z; } /* ** Convert a "mark" or "committish" into the UUID. */ static char *resolve_committish(const char *zCommittish){ char *zRes; zRes = db_text(0, "SELECT tuuid FROM xmark WHERE tname=%Q", zCommittish); return zRes; } |
︙ | ︙ | |||
544 545 546 547 548 549 550 | } zName[i] = 0; } static struct{ const char *zMasterName; /* Name of master branch */ | | < < < < < | 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | } zName[i] = 0; } static struct{ const char *zMasterName; /* Name of master branch */ int authorFlag; /* Use author as checkin committer */ } ggit; /* ** Read the git-fast-import format from pIn and insert the corresponding ** content into the database. */ static void git_fast_import(FILE *pIn){ |
︙ | ︙ | |||
599 600 601 602 603 604 605 | ** tag to the new commit. However, if there are multiple instances ** of pattern B with the same TAGNAME, then only put the tag on the ** last commit that holds that tag. ** ** None of the above is explained in the git-fast-export ** documentation. We had to figure it out via trial and error. */ | | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | ** tag to the new commit. However, if there are multiple instances ** of pattern B with the same TAGNAME, then only put the tag on the ** last commit that holds that tag. ** ** None of the above is explained in the git-fast-export ** documentation. We had to figure it out via trial and error. */ for(i=5; i<strlen(zRefName) && zRefName[i]!='/'; i++){} gg.tagCommit = strncmp(&zRefName[5], "tags", 4)==0; /* True for pattern B */ if( zRefName[i+1]!=0 ) zRefName += i+1; if( fossil_strcmp(zRefName, "master")==0 ) zRefName = ggit.zMasterName; gg.zBranch = fossil_strdup(zRefName); gg.fromLoaded = 0; }else if( strncmp(zLine, "tag ", 4)==0 ){ gg.xFinish(); |
︙ | ︙ | |||
638 639 640 641 642 643 644 | fossil_free(gg.aData); gg.aData = 0; gg.nData = atoi(&zLine[5]); if( gg.nData ){ int got; gg.aData = fossil_malloc( gg.nData+1 ); got = fread(gg.aData, 1, gg.nData, pIn); if( got!=gg.nData ){ | | | | | < < < < < < | < < | < < < < | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 | fossil_free(gg.aData); gg.aData = 0; gg.nData = atoi(&zLine[5]); if( gg.nData ){ int got; gg.aData = fossil_malloc( gg.nData+1 ); got = fread(gg.aData, 1, gg.nData, pIn); if( got!=gg.nData ){ fossil_panic("short read: got %d of %d bytes", got, gg.nData); } gg.aData[got] = '\0'; if( gg.zComment==0 && (gg.xFinish==finish_commit || gg.xFinish==finish_tag) ){ /* Strip trailing newline, it's appended to the comment. */ if( gg.aData[got-1] == '\n' ) gg.aData[got-1] = '\0'; gg.zComment = gg.aData; gg.aData = 0; gg.nData = 0; } } }else if( (!ggit.authorFlag && strncmp(zLine, "author ", 7)==0) || (ggit.authorFlag && strncmp(zLine, "committer ",10)==0 && gg.zUser!=NULL) ){ /* No-op */ }else if( strncmp(zLine, "mark ", 5)==0 ){ trim_newline(&zLine[5]); fossil_free(gg.zMark); gg.zMark = fossil_strdup(&zLine[5]); }else if( strncmp(zLine, "tagger ", 7)==0 || (ggit.authorFlag && strncmp(zLine, "author ", 7)==0) || strncmp(zLine, "committer ",10)==0 ){ sqlite3_int64 secSince1970; z = strchr(zLine, ' '); while( fossil_isspace(*z) ) z++; if( (zTo=strchr(z, '>'))==NULL ) goto malformed_line; *(++zTo) = '\0'; /* Lookup user by contact info. */ fossil_free(gg.zUser); gg.zUser = db_text(0, "SELECT login FROM user WHERE info=%Q", z); if( gg.zUser==NULL ){ /* If there is no user with this contact info, * then use the email address as the username. */ if ( (z=strchr(z, '<'))==NULL ) goto malformed_line; z++; *(zTo-1) = '\0'; gg.zUser = fossil_strdup(z); } secSince1970 = 0; for(zTo++; fossil_isdigit(*zTo); zTo++){ secSince1970 = secSince1970*10 + *zTo - '0'; } fossil_free(gg.zDate); gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970); gg.zDate[10] = 'T'; }else if( strncmp(zLine, "from ", 5)==0 ){ trim_newline(&zLine[5]); fossil_free(gg.zFromMark); gg.zFromMark = fossil_strdup(&zLine[5]); fossil_free(gg.zFrom); |
︙ | ︙ | |||
730 731 732 733 734 735 736 | dequote_git_filename(zName); i = 0; pFile = import_find_file(zName, &i, gg.nFile); if( pFile==0 ){ pFile = import_add_file(); pFile->zName = fossil_strdup(zName); } | | < < < < | < | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 | dequote_git_filename(zName); i = 0; pFile = import_find_file(zName, &i, gg.nFile); if( pFile==0 ){ pFile = import_add_file(); pFile->zName = fossil_strdup(zName); } pFile->isExe = (fossil_strcmp(zPerm, "100755")==0); pFile->isLink = (fossil_strcmp(zPerm, "120000")==0); fossil_free(pFile->zUuid); pFile->zUuid = resolve_committish(zUuid); pFile->isFrom = 0; }else if( strncmp(zLine, "D ", 2)==0 ){ import_prior_files(); z = &zLine[2]; zName = rest_of_line(&z); dequote_git_filename(zName); |
︙ | ︙ | |||
769 770 771 772 773 774 775 | i = 0; mx = gg.nFile; nFrom = strlen(zFrom); while( (pFile = import_find_file(zFrom, &i, mx))!=0 ){ if( pFile->isFrom==0 ) continue; pNew = import_add_file(); pFile = &gg.aFile[i-1]; | | | | | | | > | < < < < < < < < < < < < | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | i = 0; mx = gg.nFile; nFrom = strlen(zFrom); while( (pFile = import_find_file(zFrom, &i, mx))!=0 ){ if( pFile->isFrom==0 ) continue; pNew = import_add_file(); pFile = &gg.aFile[i-1]; if( strlen(pFile->zName)>nFrom ){ pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]); }else{ pNew->zName = fossil_strdup(pFile->zName); } pNew->isExe = pFile->isExe; pNew->isLink = pFile->isLink; pNew->zUuid = fossil_strdup(pFile->zUuid); pNew->isFrom = 0; } }else if( strncmp(zLine, "R ", 2)==0 ){ int nFrom; import_prior_files(); z = &zLine[2]; zFrom = next_token(&z); zTo = rest_of_line(&z); i = 0; nFrom = strlen(zFrom); while( (pFile = import_find_file(zFrom, &i, gg.nFile))!=0 ){ if( pFile->isFrom==0 ) continue; pNew = import_add_file(); pFile = &gg.aFile[i-1]; if( strlen(pFile->zName)>nFrom ){ pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]); }else{ pNew->zName = fossil_strdup(pFile->zName); } pNew->zPrior = pFile->zName; pNew->isExe = pFile->isExe; pNew->isLink = pFile->isLink; pNew->zUuid = pFile->zUuid; pNew->isFrom = 0; gg.nFile--; *pFile = *pNew; memset(pNew, 0, sizeof(*pNew)); } fossil_fatal("cannot handle R records, use --full-tree"); }else if( strncmp(zLine, "deleteall", 9)==0 ){ gg.fromLoaded = 1; }else if( strncmp(zLine, "N ", 2)==0 ){ /* No-op */ }else { goto malformed_line; } } gg.xFinish(); import_reset(1); return; |
︙ | ︙ | |||
852 853 854 855 856 857 858 | const char *zTrunk; /* Name of trunk folder in repo root */ int lenTrunk; /* String length of zTrunk */ const char *zBranches; /* Name of branches folder in repo root */ int lenBranches; /* String length of zBranches */ const char *zTags; /* Name of tags folder in repo root */ int lenTags; /* String length of zTags */ Bag newBranches; /* Branches that were created in this revision */ | | | 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 | const char *zTrunk; /* Name of trunk folder in repo root */ int lenTrunk; /* String length of zTrunk */ const char *zBranches; /* Name of branches folder in repo root */ int lenBranches; /* String length of zBranches */ const char *zTags; /* Name of tags folder in repo root */ int lenTags; /* String length of zTags */ Bag newBranches; /* Branches that were created in this revision */ int revFlag; /* Add svn-rev-nn tags on every checkin */ const char *zRevPre; /* Prepended to revision tag names */ const char *zRevSuf; /* Appended to revision tag names */ const char **azIgnTree; /* NULL-terminated list of dirs to ignore */ } gsvn; typedef struct { char *zKey; char *zVal; |
︙ | ︙ | |||
1015 1016 1017 1018 1019 1020 1021 | svn_read_props(pIn, rec); blob_zero(&rec->content); zLen = svn_find_header(*rec, "Text-content-length"); if( zLen ){ rec->contentFlag = 1; nLen = atoi(zLen); blob_read_from_channel(&rec->content, pIn, nLen); | | | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | svn_read_props(pIn, rec); blob_zero(&rec->content); zLen = svn_find_header(*rec, "Text-content-length"); if( zLen ){ rec->contentFlag = 1; nLen = atoi(zLen); blob_read_from_channel(&rec->content, pIn, nLen); if( blob_size(&rec->content)!=nLen ){ fossil_fatal("short read: got %d of %d bytes", blob_size(&rec->content), nLen ); } }else{ rec->contentFlag = 0; } |
︙ | ︙ | |||
1280 1281 1282 1283 1284 1285 1286 | char *zBranch = 0; int branchId = 0; if( gsvn.azIgnTree ){ const char **pzIgnTree; unsigned nPath = strlen(zPath); for( pzIgnTree = gsvn.azIgnTree; *pzIgnTree; ++pzIgnTree ){ const char *zIgn = *pzIgnTree; | | | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 | char *zBranch = 0; int branchId = 0; if( gsvn.azIgnTree ){ const char **pzIgnTree; unsigned nPath = strlen(zPath); for( pzIgnTree = gsvn.azIgnTree; *pzIgnTree; ++pzIgnTree ){ const char *zIgn = *pzIgnTree; int nIgn = strlen(zIgn); if( strncmp(zPath, zIgn, nIgn) == 0 && ( nPath == nIgn || (nPath > nIgn && zPath[nIgn] == '/')) ){ return 0; } } } *type = SVN_UNKNOWN; |
︙ | ︙ | |||
1406 1407 1408 1409 1410 1411 1412 | " AND tbranch=:branch" ); db_prepare(&addRev, "INSERT OR IGNORE INTO xrevisions (trev, tbranch) VALUES(:rev, :branch)" ); db_prepare(&cpyPath, "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" | | < | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 | " AND tbranch=:branch" ); db_prepare(&addRev, "INSERT OR IGNORE INTO xrevisions (trev, tbranch) VALUES(:rev, :branch)" ); db_prepare(&cpyPath, "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" " SELECT :path||:sep||substr(filename, length(:srcpath)+2), :branch, uuid, perm" " FROM xfoci" " WHERE checkinID=:rid" " AND filename>:srcpath||'/'" " AND filename<:srcpath||'0'" ); db_prepare(&cpyRoot, "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" |
︙ | ︙ | |||
1652 1653 1654 1655 1656 1657 1658 | db_finalize(&cpyPath); db_finalize(&cpyRoot); db_finalize(&revSrc); fossil_print(" Done!\n"); } /* | | < < | | | | | | | | < | < < < < < < < < < < < | 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 | db_finalize(&cpyPath); db_finalize(&cpyRoot); db_finalize(&revSrc); fossil_print(" Done!\n"); } /* ** COMMAND: import ** ** Usage: %fossil import ?--git? ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? ** or: %fossil import --svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? ** ** Read interchange format generated by another VCS and use it to ** construct a new Fossil repository named by the NEW-REPOSITORY ** argument. If no input file is supplied the interchange format ** data is read from standard input. ** ** The following formats are currently understood by this command ** ** --git Import from the git-fast-export file format (default) ** Options: ** --import-marks FILE Restore marks table from FILE ** --export-marks FILE Save marks table to FILE ** --rename-master NAME Renames the master branch to NAME ** --use-author Uses author as the committer ** ** --svn Import from the svnadmin-dump file format. The default ** behaviour (unless overridden by --flat) is to treat 3 ** folders in the SVN root as special, following the ** common layout of SVN repositories. These are (by ** default) trunk/, branches/ and tags/. The SVN --deltas ** format is supported but not required. ** Options: ** --trunk FOLDER Name of trunk folder ** --branches FOLDER Name of branches folder ** --tags FOLDER Name of tags folder ** --base PATH Path to project root in repository ** --flat The whole dump is a single branch ** --rev-tags Tag each revision, implied by -i ** --no-rev-tags Disables tagging effect of -i ** --rename-rev PAT Rev tag names, default "svn-rev-%" ** --ignore-tree DIR Ignores subtree rooted at DIR ** ** Common Options: ** -i|--incremental allow importing into an existing repository ** -f|--force overwrite repository if already exists ** -q|--quiet omit progress output ** --no-rebuild skip the "rebuilding metadata" step ** --no-vacuum skip the final VACUUM of the database file ** --rename-trunk NAME use NAME as name of imported trunk branch ** --rename-branch PAT rename all branch names using PAT pattern ** --rename-tag PAT rename all tag names using PAT pattern ** ** The --incremental option allows an existing repository to be extended ** with new content. The --rename-* options may be useful to avoid name ** conflicts when using the --incremental option. ** ** The argument to --rename-* contains one "%" character to be replaced ** with the original name. For example, "--rename-tag svn-%-tag" renames ** the tag called "release" to "svn-release-tag". ** ** --ignore-tree is useful for importing Subversion repositories which ** move branches to subdirectories of "branches/deleted" instead of ** deleting them. It can be supplied multiple times if necessary. ** ** See also: export */ void import_cmd(void){ char *zPassword; FILE *pIn; Stmt q; int forceFlag = find_option("force", "f", 0)!=0; int svnFlag = find_option("svn", 0, 0)!=0; int gitFlag = find_option("git", 0, 0)!=0; int omitRebuild = find_option("no-rebuild",0,0)!=0; int omitVacuum = find_option("no-vacuum",0,0)!=0; /* Options common to all input formats */ int incrFlag = find_option("incremental", "i", 0)!=0; /* Options for --svn only */ const char *zBase = ""; int flatFlag = 0; |
︙ | ︙ | |||
1803 1804 1805 1806 1807 1808 1809 | flatFlag = find_option("flat", 0, 0)!=0; gsvn.zTrunk = find_option("trunk", 0, 1); gsvn.zBranches = find_option("branches", 0, 1); gsvn.zTags = find_option("tags", 0, 1); gsvn.revFlag = find_option("rev-tags", 0, 0) || (incrFlag && !find_option("no-rev-tags", 0, 0)); }else if( gitFlag ){ | < < < < < < < < < < < < < < < < | < | 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 | flatFlag = find_option("flat", 0, 0)!=0; gsvn.zTrunk = find_option("trunk", 0, 1); gsvn.zBranches = find_option("branches", 0, 1); gsvn.zTags = find_option("tags", 0, 1); gsvn.revFlag = find_option("rev-tags", 0, 0) || (incrFlag && !find_option("no-rev-tags", 0, 0)); }else if( gitFlag ){ markfile_in = find_option("import-marks", 0, 1); markfile_out = find_option("export-marks", 0, 1); if( !(ggit.zMasterName = find_option("rename-master", 0, 1)) ){ ggit.zMasterName = "master"; } ggit.authorFlag = find_option("use-author", 0, 0)!=0; } verify_all_options(); if( g.argc!=3 && g.argc!=4 ){ usage("--git|--svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?"); } if( g.argc==4 ){ pIn = fossil_fopen(g.argv[3], "rb"); if( pIn==0 ) fossil_fatal("cannot open input file \"%s\"", g.argv[3]); }else{ pIn = stdin; fossil_binary_mode(pIn); } if( !incrFlag ){ if( forceFlag ) file_delete(g.argv[2]); db_create_repository(g.argv[2]); } db_open_repository(g.argv[2]); db_open_config(0, 0); db_begin_transaction(); if( !incrFlag ){ db_initial_setup(0, 0, 0); db_set("main-branch", gimport.zTrunkName, 0); } if( svnFlag ){ db_multi_exec( "CREATE TEMP TABLE xrevisions(" " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," " UNIQUE(tbranch, trev)" ");" |
︙ | ︙ | |||
1914 1915 1916 1917 1918 1919 1920 | Bag blobs, vers; bag_init(&blobs); bag_init(&vers); /* The following temp-tables are used to hold information needed for ** the import. ** ** The XMARK table provides a mapping from fast-import "marks" and symbols | | < | | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 | Bag blobs, vers; bag_init(&blobs); bag_init(&vers); /* The following temp-tables are used to hold information needed for ** the import. ** ** The XMARK table provides a mapping from fast-import "marks" and symbols ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). ** Given any valid fast-import symbol, the corresponding fossil rid and ** uuid can found by searching against the xmark.tname field. ** ** The XBRANCH table maps commit marks and symbols into the branch those ** commits belong to. If xbranch.tname is a fast-import symbol for a ** check-in then xbranch.brnm is the branch that check-in is part of. ** ** The XTAG table records information about tags that need to be applied ** to various branches after the import finishes. The xtag.tcontent field |
︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 | if( import_marks(f, &blobs, NULL, NULL)<0 ){ fossil_fatal("error importing marks from file: %s", markfile_in); } fclose(f); } manifest_crosslink_begin(); | < < < < < < < < < < < < < < < < < < < < < | | 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 | if( import_marks(f, &blobs, NULL, NULL)<0 ){ fossil_fatal("error importing marks from file: %s", markfile_in); } fclose(f); } manifest_crosslink_begin(); git_fast_import(pIn); db_prepare(&q, "SELECT tcontent FROM xtag"); while( db_step(&q)==SQLITE_ROW ){ Blob record; db_ephemeral_blob(&q, 0, &record); fast_insert_content(&record, 0, 0, 1); import_reset(0); } db_finalize(&q); if( markfile_out ){ int rid; Stmt q_marks; FILE *f; |
︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 | db_end_transaction(0); fossil_print(" \r"); if( omitRebuild ){ omitVacuum = 1; }else{ db_begin_transaction(); fossil_print("Rebuilding repository meta-data...\n"); | | < | 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 | db_end_transaction(0); fossil_print(" \r"); if( omitRebuild ){ omitVacuum = 1; }else{ db_begin_transaction(); fossil_print("Rebuilding repository meta-data...\n"); rebuild_db(0, 1, !incrFlag); verify_cancel(); db_end_transaction(0); } if( !omitVacuum ){ fossil_print("Vacuuming..."); fflush(stdout); db_multi_exec("VACUUM"); } fossil_print(" ok\n"); if( !incrFlag ){ fossil_print("project-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); } } |
Changes to src/info.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | return zTags; } /* ** Print common information about a particular record. ** | | | | | 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 | return zTags; } /* ** Print common information about a particular record. ** ** * The UUID ** * The record ID ** * mtime and ctime ** * who signed it ** */ void show_common_info( int rid, /* The rid for the check-in to display info for */ const char *zUuidName, /* Name of the UUID */ int showComment, /* True to show the check-in comment */ int showFamily /* True to show parents and children */ ){ Stmt q; char *zComment = 0; char *zTags; char *zDate; char *zUuid; zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); if( zUuid ){ zDate = db_text(0, "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", rid ); /* 01234567890123 */ fossil_print("%-13s %.40s %s\n", zUuidName, zUuid, zDate ? zDate : ""); free(zDate); if( showComment ){ zComment = db_text(0, "SELECT coalesce(ecomment,comment) || " " ' (user: ' || coalesce(euser,user,'?') || ')' " " FROM event WHERE objid=%d", rid |
︙ | ︙ | |||
115 116 117 118 119 120 121 | zTags = info_tags_of_checkin(rid, 0); if( zTags && zTags[0] ){ fossil_print("tags: %s\n", zTags); } free(zTags); if( zComment ){ fossil_print("comment: "); | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | zTags = info_tags_of_checkin(rid, 0); if( zTags && zTags[0] ){ fossil_print("tags: %s\n", zTags); } free(zTags); if( zComment ){ fossil_print("comment: "); comment_print(zComment, 0, 14, -1, g.comFmtFlags); free(zComment); } } /* ** Print information about the URLs used to access a repository and ** checkouts in a repository. |
︙ | ︙ | |||
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | const char *zParentCode; zParentCode = db_get("parent-project-code",0); if( zParentCode ){ fossil_print("derived-from: %s %s\n", zParentCode, db_get("parent-project-name","")); } } /* ** COMMAND: info ** ** Usage: %fossil info ?VERSION | REPOSITORY_FILENAME? ?OPTIONS? ** ** With no arguments, provide information about the current tree. ** If an argument is specified, provide information about the object ** in the repository of the current tree that the argument refers ** to. Or if the argument is the name of a repository, show ** information about that repository. ** ** If the argument is a repository name, then the --verbose option shows | > | | | > | | < | | | | < < < < | < < | | | | | | | < < < < < < < < < < < < < < < | | | < < < < < < | | > > > < > | > > > > > > > > > > > > > > > > > > > > > > > | > > > | | > > > > > > > > > | | < < < < < < < < < < > > > > > > > > > | < | > > > > | < > > > > > > > > > > | < < < < < < | > | > | < < > | | > > | > > > < < > < | > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | const char *zParentCode; zParentCode = db_get("parent-project-code",0); if( zParentCode ){ fossil_print("derived-from: %s %s\n", zParentCode, db_get("parent-project-name","")); } } /* ** COMMAND: info ** ** Usage: %fossil info ?VERSION | REPOSITORY_FILENAME? ?OPTIONS? ** ** With no arguments, provide information about the current tree. ** If an argument is specified, provide information about the object ** in the repository of the current tree that the argument refers ** to. Or if the argument is the name of a repository, show ** information about that repository. ** ** If the argument is a repository name, then the --verbose option shows ** known the check-out locations for that repository and all URLs used ** to access the repository. The --verbose is (currently) a no-op if ** the argument is the name of a object within the repository. ** ** Use the "finfo" command to get information about a specific ** file in a checkout. ** ** Options: ** ** -R|--repository FILE Extract info from repository FILE ** -v|--verbose Show extra information about repositories ** ** See also: annotate, artifact, finfo, timeline */ void info_cmd(void){ i64 fsize; int verboseFlag = find_option("verbose","v",0)!=0; if( !verboseFlag ){ verboseFlag = find_option("detail","l",0)!=0; /* deprecated */ } if( g.argc==3 && (fsize = file_size(g.argv[2], ExtFILE))>0 && (fsize&0x1ff)==0 ){ db_open_config(0, 0); db_open_repository(g.argv[2]); db_record_repository_filename(g.argv[2]); fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>")); fossil_print("project-code: %s\n", db_get("project-code", "<none>")); showParentProject(); extraRepoInfo(); return; } db_find_and_open_repository(0,0); verify_all_options(); if( g.argc==2 ){ int vid; /* 012345678901234 */ db_record_repository_filename(0); fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>")); if( g.localOpen ){ fossil_print("repository: %s\n", db_repository_filename()); fossil_print("local-root: %s\n", g.zLocalRoot); } if( verboseFlag ) extraRepoInfo(); if( g.zConfigDbName ){ fossil_print("config-db: %s\n", g.zConfigDbName); } fossil_print("project-code: %s\n", db_get("project-code", "")); showParentProject(); vid = g.localOpen ? db_lget_int("checkout", 0) : 0; if( vid ){ show_common_info(vid, "checkout:", 1, 1); } fossil_print("check-ins: %d\n", db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/")); }else{ int rid; rid = name_to_rid(g.argv[2]); if( rid==0 ){ fossil_fatal("no such object: %s", g.argv[2]); } show_common_info(rid, "uuid:", 1, 1); } } /* ** Show the context graph (immediate parents and children) for ** check-in rid. */ void render_checkin_context(int rid, int parentsOnly){ Blob sql; Stmt q; blob_zero(&sql); blob_append(&sql, timeline_query_for_www(), -1); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "DELETE FROM ok;" "INSERT INTO ok VALUES(%d);" "INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;", rid, rid ); if( !parentsOnly ){ db_multi_exec( "INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;", rid ); } blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC"); db_prepare(&q, "%s", blob_sql_text(&sql)); www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL, 0, 0, rid, 0); db_finalize(&q); } /* ** Show a graph all wiki, tickets, and check-ins that refer to object zUuid. ** ** If zLabel is not NULL and the graph is not empty, then output zLabel as ** a prefix to the graph. */ void render_backlink_graph(const char *zUuid, const char *zLabel){ Blob sql; Stmt q; char *zGlob; zGlob = mprintf("%.5s*", zUuid); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "DELETE FROM ok;" "INSERT OR IGNORE INTO ok" " SELECT srcid FROM backlink" " WHERE target GLOB %Q" " AND %Q GLOB (target || '*');", zGlob, zUuid ); if( !db_exists("SELECT 1 FROM ok") ) return; if( zLabel ) cgi_printf("%s", zLabel); blob_zero(&sql); blob_append(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC"); db_prepare(&q, "%s", blob_sql_text(&sql)); www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL, 0, 0, 0, 0); db_finalize(&q); } /* ** WEBPAGE: test-backlinks ** ** Show a timeline of all check-ins and other events that have entries ** in the backlink table. This is used for testing the rendering ** of the "References" section of the /info page. */ void backlink_timeline_page(void){ Blob sql; Stmt q; login_check_credentials(); if( !g.perm.Read || !g.perm.RdTkt || !g.perm.RdWiki ){ login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); return; } style_header("Backlink Timeline (Internal Testing Use)"); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "DELETE FROM ok;" "INSERT OR IGNORE INTO ok" " SELECT blob.rid FROM backlink, blob" " WHERE blob.uuid BETWEEN backlink.target AND (backlink.target||'x')" ); blob_zero(&sql); blob_append(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC"); db_prepare(&q, "%s", blob_sql_text(&sql)); www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL, 0, 0, 0, 0); db_finalize(&q); style_footer(); } /* ** Append the difference between artifacts to the output */ static void append_diff( const char *zFrom, /* Diff from this artifact */ const char *zTo, /* ... to this artifact */ u64 diffFlags, /* Diff formatting flags */ ReCompiled *pRe /* Only show change matching this regex */ ){ int fromid; int toid; Blob from, to, out; if( zFrom ){ fromid = uuid_to_rid(zFrom, 0); content_get(fromid, &from); }else{ blob_zero(&from); } if( zTo ){ toid = uuid_to_rid(zTo, 0); content_get(toid, &to); }else{ blob_zero(&to); } blob_zero(&out); if( diffFlags & DIFF_SIDEBYSIDE ){ text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG); @ %s(blob_str(&out)) }else{ text_diff(&from, &to, &out, pRe, diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG); @ <pre class="udiff"> @ %s(blob_str(&out)) @ </pre> } blob_reset(&from); blob_reset(&to); blob_reset(&out); } /* ** Write a line of web-page output that shows changes that have occurred ** to a file between two check-ins. */ static void append_file_change_line( const char *zName, /* Name of the file that has changed */ const char *zOld, /* blob.uuid before change. NULL for added files */ const char *zNew, /* blob.uuid after change. NULL for deletes */ const char *zOldName, /* Prior name. NULL if no name change. */ u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */ ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */ int mperm /* executable or symlink permission for zNew */ ){ @ <p> if( !g.perm.Hyperlink ){ if( zNew==0 ){ @ Deleted %h(zName). }else if( zOld==0 ){ |
︙ | ︙ | |||
389 390 391 392 393 394 395 | @ %h(zName) became a symlink. }else{ @ %h(zName) became a regular file. } }else{ @ Changes to %h(zName). } | | | < < < < < < < < < | < | | < | < | < | < | | | | | | | | | | | | | > > > | > | > > | > | < < > | < > < | | < < < | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 | @ %h(zName) became a symlink. }else{ @ %h(zName) became a regular file. } }else{ @ Changes to %h(zName). } if( diffFlags ){ append_diff(zOld, zNew, diffFlags, pRe); } }else{ if( zOld && zNew ){ if( fossil_strcmp(zOld, zNew)!=0 ){ @ Modified %z(href("%R/finfo?name=%T&m=%!S",zName,zNew))%h(zName)</a> @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a> @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>. }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){ @ Name change @ from %z(href("%R/finfo?name=%T&m=%!S",zOldName,zOld))%h(zOldName)</a> @ to %z(href("%R/finfo?name=%T&m=%!S",zName,zNew))%h(zName)</a>. }else{ @ %z(href("%R/finfo?name=%T&m=%!S",zName,zNew))%h(zName)</a> became if( mperm==PERM_EXE ){ @ executable with contents }else if( mperm==PERM_LNK ){ @ a symlink with target }else{ @ a regular file with contents } @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>. } }else if( zOld ){ @ Deleted %z(href("%R/finfo?name=%T&m=%!S",zName,zOld))%h(zName)</a> @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>. }else{ @ Added %z(href("%R/finfo?name=%T&m=%!S",zName,zNew))%h(zName)</a> @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>. } if( diffFlags ){ append_diff(zOld, zNew, diffFlags, pRe); }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ @ @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a> } } @ </p> } /* ** Generate javascript to enhance HTML diffs. */ void append_diff_javascript(int sideBySide){ if( !sideBySide ) return; style_load_one_js_file("sbsdiff.js"); } /* ** Construct an appropriate diffFlag for text_diff() based on query ** parameters and the to boolean arguments. */ u64 construct_diff_flags(int diffType){ u64 diffFlags = 0; /* Zero means do not show any diff */ if( diffType>0 ){ int x; if( diffType==2 ){ diffFlags = DIFF_SIDEBYSIDE; /* "dw" query parameter determines width of each column */ x = atoi(PD("dw","80"))*(DIFF_CONTEXT_MASK+1); if( x<0 || x>DIFF_WIDTH_MASK ) x = DIFF_WIDTH_MASK; diffFlags += x; } if( P("w") ){ diffFlags |= DIFF_IGNORE_ALLWS; } /* "dc" query parameter determines lines of context */ x = atoi(PD("dc","7")); if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK; diffFlags += x; /* The "noopt" parameter disables diff optimization */ if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; diffFlags |= DIFF_STRIP_EOLCR; } return diffFlags; } /* ** WEBPAGE: ci_tags ** URL: /ci_tags?name=ARTIFACTID ** ** Show all tags and properties for a given check-in. ** ** This information used to be part of the main /ci page, but it is of ** marginal usefulness. Better to factor it out into a sub-screen. */ void ci_tags_page(void){ const char *zHash; int rid; Stmt q; int cnt = 0; Blob sql; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } rid = name_to_rid_www("name"); if( rid==0 ){ style_header("Check-in Information Error"); @ No such object: %h(g.argv[2]) style_footer(); return; } zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); style_header("Tags and Properties"); @ <h1>Tags and Properties for Check-In \ @ %z(href("%R/ci/%!S",zHash))%S(zHash)</a></h1> db_prepare(&q, "SELECT tag.tagid, tagname, " " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," " value, datetime(tagxref.mtime,toLocal()), tagtype," " (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)" " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
︙ | ︙ | |||
542 543 544 545 546 547 548 | @ <span class="infoTag">%h(zTagname)=%h(zValue)</span> }else { @ <span class="infoTag">%h(zTagname)</span> } if( tagtype==2 ){ if( zOrigUuid && zOrigUuid[0] ){ @ inherited from | | | | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | @ <span class="infoTag">%h(zTagname)=%h(zValue)</span> }else { @ <span class="infoTag">%h(zTagname)</span> } if( tagtype==2 ){ if( zOrigUuid && zOrigUuid[0] ){ @ inherited from hyperlink_to_uuid(zOrigUuid); }else{ @ propagates to descendants } } if( zSrcUuid && zSrcUuid[0] ){ if( tagtype==0 ){ @ by }else{ @ added by } hyperlink_to_uuid(zSrcUuid); @ on hyperlink_to_date(zDate,0); } @ </li> } db_finalize(&q); if( cnt ){ |
︙ | ︙ | |||
578 579 580 581 582 583 584 | " WHERE tagxref.rid=%d;" "INSERT OR IGNORE INTO ok " " SELECT tagxref.origid" " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" " WHERE tagxref.rid=%d;", rid, rid, rid ); | < < | | | | | | | | | > > | | | < < < | | < | > | < < < < < | < | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | " WHERE tagxref.rid=%d;" "INSERT OR IGNORE INTO ok " " SELECT tagxref.origid" " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" " WHERE tagxref.rid=%d;", rid, rid, rid ); db_multi_exec( "SELECT tag.tagid, tagname, " " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," " value, datetime(tagxref.mtime,toLocal()), tagtype," " (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)" " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" " WHERE tagxref.rid=%d" " ORDER BY tagname /*sort*/", rid, rid, rid ); blob_zero(&sql); blob_append(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC"); db_prepare(&q, "%s", blob_sql_text(&sql)); www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL, 0, 0, rid, 0); db_finalize(&q); style_footer(); } /* ** WEBPAGE: vinfo ** WEBPAGE: ci ** URL: /ci?name=ARTIFACTID ** URL: /vinfo?name=ARTIFACTID ** ** Display information about a particular check-in. ** ** We also jump here from /info if the name is a check-in ** ** If the /ci and /vinfo pages used to differ in their default ** diff settings, but now diff settings persist with a cookie and ** so /ci and /vinfo behave the same. */ void ci_page(void){ Stmt q1, q2, q3; int rid; int isLeaf; int diffType; /* 0: no diff, 1: unified, 2: side-by-side */ u64 diffFlags; /* Flag parameter for text_diff() */ const char *zName; /* Name of the check-in to be displayed */ const char *zUuid; /* UUID of zName */ const char *zParent; /* UUID of the parent check-in (if any) */ const char *zRe; /* regex parameter */ ReCompiled *pRe = 0; /* regex */ const char *zW; /* URL param for ignoring whitespace */ const char *zPage = "vinfo"; /* Page that shows diffs */ const char *zPageHide = "ci"; /* Page that hides diffs */ login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } zName = P("name"); rid = name_to_rid_www("name"); if( rid==0 ){ style_header("Check-in Information Error"); @ No such object: %h(g.argv[2]) style_footer(); return; } zRe = P("regex"); if( zRe ) re_compile(&pRe, zRe, 0); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zParent = db_text(0, "SELECT uuid FROM plink, blob" " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", rid ); isLeaf = !db_exists("SELECT 1 FROM plink WHERE pid=%d", rid); db_prepare(&q1, "SELECT uuid, datetime(mtime,toLocal()), user, comment," " datetime(omtime,toLocal()), mtime" " FROM blob, event" " WHERE blob.rid=%d" " AND event.objid=%d", rid, rid ); cookie_link_parameter("diff","diff","2"); diffType = atoi(PD("diff","2")); if( db_step(&q1)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q1, 0); int nUuid = db_column_bytes(&q1, 0); char *zEUser, *zEComment; const char *zUser; const char *zOrigUser; const char *zComment; const char *zDate; const char *zOrigDate; style_header("Check-in [%S]", zUuid); login_anonymous_available(); zEUser = db_text(0, "SELECT value FROM tagxref" " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_USER, rid); zEComment = db_text(0, "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d", TAG_COMMENT, rid); zOrigUser = db_column_text(&q1, 2); zUser = zEUser ? zEUser : zOrigUser; zComment = db_column_text(&q1, 3); zDate = db_column_text(&q1,1); zOrigDate = db_column_text(&q1, 4); if( zOrigDate==0 ) zOrigDate = zDate; @ <div class="section">Overview</div> @ <table class="label-value"> @ <tr><th>Comment:</th><td class="infoComment">\ @ %!W(zEComment?zEComment:zComment)</td></tr> /* The Download: line */ if( g.perm.Zip ){ char *zPJ = db_get("short-project-name", 0); |
︙ | ︙ | |||
738 739 740 741 742 743 744 | } db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag " " WHERE rid=%d AND tagtype>0 " " AND tag.tagid=tagxref.tagid " " AND +tag.tagname GLOB 'sym-*'", rid); while( db_step(&q2)==SQLITE_ROW ){ const char *zTagName = db_column_text(&q2, 0); | < < < | < < < < < < < < < < < < < < < < < < < < < | < | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | < | | | < | < | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | } db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag " " WHERE rid=%d AND tagtype>0 " " AND tag.tagid=tagxref.tagid " " AND +tag.tagname GLOB 'sym-*'", rid); while( db_step(&q2)==SQLITE_ROW ){ const char *zTagName = db_column_text(&q2, 0); @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a> } db_finalize(&q2); @ </td></tr> @ <tr><th>Files:</th> @ <td> @ %z(href("%R/tree?ci=%!S",zUuid))files</a> @ | %z(href("%R/fileage?name=%!S",zUuid))file ages</a> @ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders</a> @ </td> @ </tr> @ <tr><th>%s(hname_alg(nUuid)):</th><td>%s(zUuid) if( g.perm.Setup ){ @ (Record ID: %d(rid)) } @ </td></tr> @ <tr><th>User & Date:</th><td> hyperlink_to_user(zUser,zDate," on "); hyperlink_to_date(zDate, "</td></tr>"); if( zEComment ){ @ <tr><th>Original Comment:</th> @ <td class="infoComment">%!W(zComment)</td></tr> } if( fossil_strcmp(zDate, zOrigDate)!=0 || fossil_strcmp(zOrigUser, zUser)!=0 ){ @ <tr><th>Original User & Date:</th><td> hyperlink_to_user(zOrigUser,zOrigDate," on "); hyperlink_to_date(zOrigDate, "</td></tr>"); } if( g.perm.Admin ){ db_prepare(&q2, "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)" " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)" " WHERE blob.rid=%d", rid ); if( db_step(&q2)==SQLITE_ROW ){ const char *zIpAddr = db_column_text(&q2, 0); const char *zUser = db_column_text(&q2, 1); const char *zDate = db_column_text(&q2, 2); if( zUser==0 || zUser[0]==0 ) zUser = "unknown"; @ <tr><th>Received From:</th> @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr> } db_finalize(&q2); } if( g.perm.Hyperlink ){ @ <tr><th>Other Links:</th> @ <td> @ %z(href("%R/artifact/%!S",zUuid))manifest</a> @ | %z(href("%R/ci_tags/%!S",zUuid))tags</a> if( g.perm.Admin ){ @ | %z(href("%R/mlink?ci=%!S",zUuid))mlink table</a> } if( g.anon.Write ){ @ | %z(href("%R/ci_edit?r=%!S",zUuid))edit</a> } @ </td> @ </tr> } @ </table> }else{ style_header("Check-in Information"); login_anonymous_available(); } db_finalize(&q1); render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n"); @ <div class="section">Context</div> render_checkin_context(rid, 0); @ <div class="section">Changes</div> @ <div class="sectionmenu"> diffFlags = construct_diff_flags(diffType); zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; if( diffType!=0 ){ @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\ @ Hide Diffs</a> } if( diffType!=1 ){ @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\ @ Unified Diffs</a> |
︙ | ︙ | |||
921 922 923 924 925 926 927 | if( zParent ){ @ %z(chref("button","%R/vpatch?from=%!S&to=%!S",zParent,zUuid)) @ Patch</a> } if( g.perm.Admin ){ @ %z(chref("button","%R/mlink?ci=%!S",zUuid))MLink Table</a> } | | | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | if( zParent ){ @ %z(chref("button","%R/vpatch?from=%!S&to=%!S",zParent,zUuid)) @ Patch</a> } if( g.perm.Admin ){ @ %z(chref("button","%R/mlink?ci=%!S",zUuid))MLink Table</a> } @</div> if( pRe ){ @ <p><b>Only differences that match regular expression "%h(zRe)" @ are shown.</b></p> } db_prepare(&q3, "SELECT name," " mperm," |
︙ | ︙ | |||
945 946 947 948 949 950 951 | ); while( db_step(&q3)==SQLITE_ROW ){ const char *zName = db_column_text(&q3,0); int mperm = db_column_int(&q3, 1); const char *zOld = db_column_text(&q3,2); const char *zNew = db_column_text(&q3,3); const char *zOldName = db_column_text(&q3, 4); | | < < | > | | < < < | | < | | | | | < < | < < < < < < < | | < < | | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 | ); while( db_step(&q3)==SQLITE_ROW ){ const char *zName = db_column_text(&q3,0); int mperm = db_column_int(&q3, 1); const char *zOld = db_column_text(&q3,2); const char *zNew = db_column_text(&q3,3); const char *zOldName = db_column_text(&q3, 4); append_file_change_line(zName, zOld, zNew, zOldName, diffFlags,pRe,mperm); } db_finalize(&q3); append_diff_javascript(diffType==2); cookie_render(); style_footer(); } /* ** WEBPAGE: winfo ** URL: /winfo?name=UUID ** ** Display information about a wiki page. */ void winfo_page(void){ int rid; Manifest *pWiki; char *zUuid; char *zDate; Blob wiki; int modPending; const char *zModAction; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } rid = name_to_rid_www("name"); if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){ style_header("Wiki Page Information Error"); @ No such object: %h(P("name")) style_footer(); return; } if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){ if( strcmp(zModAction,"delete")==0 ){ moderation_disapprove(rid); /* ** Next, check if the wiki page still exists; if not, we cannot ** redirect to it. */ if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){ cgi_redirectf("%R/wiki?name=%T", pWiki->zWikiTitle); /*NOTREACHED*/ }else{ cgi_redirectf("%R/modreq"); /*NOTREACHED*/ } } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } style_header("Update of \"%h\"", pWiki->zWikiTitle); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); style_submenu_element("Raw", "artifact/%s", zUuid); style_submenu_element("History", "whistory?name=%t", pWiki->zWikiTitle); style_submenu_element("Page", "wiki?name=%t", pWiki->zWikiTitle); login_anonymous_available(); @ <div class="section">Overview</div> @ <p><table class="label-value"> @ <tr><th>Artifact ID:</th> @ <td>%z(href("%R/artifact/%!S",zUuid))%s(zUuid)</a> if( g.perm.Setup ){ @ (%d(rid)) } modPending = moderation_pending_www(rid); @ </td></tr> @ <tr><th>Page Name:</th><td>%h(pWiki->zWikiTitle)</td></tr> @ <tr><th>Date:</th><td> hyperlink_to_date(zDate, "</td></tr>"); @ <tr><th>Original User:</th><td> hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>"); if( pWiki->zMimetype ){ @ <tr><th>Mimetype:</th><td>%h(pWiki->zMimetype)</td></tr> } if( pWiki->nParent>0 ){ int i; @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td> for(i=0; i<pWiki->nParent; i++){ char *zParent = pWiki->azParent[i]; @ %z(href("info/%!S",zParent))%s(zParent)</a> } @ </td></tr> } @ </table> if( g.perm.ModWiki && modPending ){ @ <div class="section">Moderation</div> @ <blockquote> @ <form method="POST" action="%R/winfo/%s(zUuid)"> @ <label><input type="radio" name="modaction" value="delete"> @ Delete this change</label><br /> @ <label><input type="radio" name="modaction" value="approve"> @ Approve this change</label><br /> @ <input type="submit" value="Submit"> @ </form> @ </blockquote> } @ <div class="section">Content</div> blob_init(&wiki, pWiki->zWiki, -1); wiki_render_by_mimetype(&wiki, pWiki->zMimetype); blob_reset(&wiki); manifest_destroy(pWiki); style_footer(); } /* ** Find an check-in based on query parameter zParam and parse its ** manifest. Return the number of errors. */ static Manifest *vdiff_parse_manifest(const char *zParam, int *pRid){ |
︙ | ︙ | |||
1094 1095 1096 1097 1098 1099 1100 | if( !is_a_version(rid) ){ webpage_error("Artifact %s is not a check-in.", P(zParam)); return 0; } return manifest_get(rid, CFTYPE_MANIFEST, 0); } | < | 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 | if( !is_a_version(rid) ){ webpage_error("Artifact %s is not a check-in.", P(zParam)); return 0; } return manifest_get(rid, CFTYPE_MANIFEST, 0); } /* ** Output a description of a check-in */ static void checkin_description(int rid){ Stmt q; db_prepare(&q, "SELECT datetime(mtime), coalesce(euser,user)," |
︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 | const char *zUuid = db_column_text(&q, 3); const char *zTagList = db_column_text(&q, 4); Blob comment; int wikiFlags = WIKI_INLINE|WIKI_NOBADLINKS; if( db_get_boolean("timeline-block-markup", 0)==0 ){ wikiFlags |= WIKI_NOBLOCK; } | | | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 | const char *zUuid = db_column_text(&q, 3); const char *zTagList = db_column_text(&q, 4); Blob comment; int wikiFlags = WIKI_INLINE|WIKI_NOBADLINKS; if( db_get_boolean("timeline-block-markup", 0)==0 ){ wikiFlags |= WIKI_NOBLOCK; } hyperlink_to_uuid(zUuid); blob_zero(&comment); db_column_blob(&q, 2, &comment); wiki_convert(&comment, 0, wikiFlags); blob_reset(&comment); @ (user: hyperlink_to_user(zUser,zDate,","); if( zTagList && zTagList[0] && g.perm.Hyperlink ){ |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | } @ date: hyperlink_to_date(zDate, ")"); tag_private_status(rid); } db_finalize(&q); } | < | < > | | < < < < < | < | > | < < < | < < < < < < < < < < < < < < < < < < < < < < | | < < | < < < < < | | < < < < < | < | > > | > > > | > > > < | < > > | > | < < < < | < < < < < < < < < < < < < < < < < | | < < < > | > | < < | | | | | | | | | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | } @ date: hyperlink_to_date(zDate, ")"); tag_private_status(rid); } db_finalize(&q); } /* ** WEBPAGE: vdiff ** URL: /vdiff?from=TAG&to=TAG ** ** Show the difference between two check-ins identified by the from= and ** to= query parameters. ** ** Query parameters: ** ** from=TAG Left side of the comparison ** to=TAG Right side of the comparison ** branch=TAG Show all changes on a particular branch ** diff=INTEGER 0: none, 1: unified, 2: side-by-side ** glob=STRING only diff files matching this glob ** dc=N show N lines of context around each diff ** w=BOOLEAN ignore whitespace when computing diffs ** nohdr omit the description at the top of the page ** ** ** Show all differences between two check-ins. */ void vdiff_page(void){ int ridFrom, ridTo; int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */ u64 diffFlags = 0; Manifest *pFrom, *pTo; ManifestFile *pFileFrom, *pFileTo; const char *zBranch; const char *zFrom; const char *zTo; const char *zRe; const char *zW; const char *zGlob; ReCompiled *pRe = 0; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } login_anonymous_available(); cookie_link_parameter("diff","diff","2"); diffType = atoi(PD("diff","2")); cookie_render(); zRe = P("regex"); if( zRe ) re_compile(&pRe, zRe, 0); zBranch = P("branch"); if( zBranch && zBranch[0] ){ cgi_replace_parameter("from", mprintf("root:%s", zBranch)); cgi_replace_parameter("to", zBranch); } pTo = vdiff_parse_manifest("to", &ridTo); if( pTo==0 ) return; pFrom = vdiff_parse_manifest("from", &ridFrom); if( pFrom==0 ) return; zGlob = P("glob"); zFrom = P("from"); zTo = P("to"); if(zGlob && !*zGlob){ zGlob = NULL; } diffFlags = construct_diff_flags(diffType); zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo); if( diffType!=0 ){ style_submenu_element("Hide Diff", "%R/vdiff?from=%T&to=%T&diff=0%s%T%s", zFrom, zTo, zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW); } if( diffType!=2 ){ style_submenu_element("Side-by-Side Diff", "%R/vdiff?from=%T&to=%T&diff=2%s%T%s", zFrom, zTo, zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW); } if( diffType!=1 ) { style_submenu_element("Unified Diff", "%R/vdiff?from=%T&to=%T&diff=1%s%T%s", zFrom, zTo, zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW); } style_submenu_element("Invert", "%R/vdiff?from=%T&to=%T&%s%T%s", zTo, zFrom, zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW); if( zGlob ){ style_submenu_element("Clear glob", "%R/vdiff?from=%T&to=%T&%s", zFrom, zTo, zW); }else{ style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW); } if( diffType!=0 ){ style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); } style_header("Check-in Differences"); if( P("nohdr")==0 ){ @ <h2>Difference From:</h2><blockquote> checkin_description(ridFrom); @ </blockquote><h2>To:</h2><blockquote> checkin_description(ridTo); @ </blockquote> if( pRe ){ @ <p><b>Only differences that match regular expression "%h(zRe)" @ are shown.</b></p> } if( zGlob ){ @ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p> } @<hr /><p> } manifest_file_rewind(pFrom); pFileFrom = manifest_file_next(pFrom, 0); manifest_file_rewind(pTo); pFileTo = manifest_file_next(pTo, 0); while( pFileFrom || pFileTo ){ int cmp; if( pFileFrom==0 ){ cmp = +1; }else if( pFileTo==0 ){ cmp = -1; }else{ cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); } if( cmp<0 ){ if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){ append_file_change_line(pFileFrom->zName, pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0); } pFileFrom = manifest_file_next(pFrom, 0); }else if( cmp>0 ){ if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){ append_file_change_line(pFileTo->zName, 0, pFileTo->zUuid, 0, diffFlags, pRe, manifest_file_mperm(pFileTo)); } pFileTo = manifest_file_next(pTo, 0); }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ pFileFrom = manifest_file_next(pFrom, 0); pFileTo = manifest_file_next(pTo, 0); }else{ if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0 || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){ append_file_change_line(pFileFrom->zName, pFileFrom->zUuid, pFileTo->zUuid, 0, diffFlags, pRe, manifest_file_mperm(pFileTo)); } pFileFrom = manifest_file_next(pFrom, 0); pFileTo = manifest_file_next(pTo, 0); } } manifest_destroy(pFrom); manifest_destroy(pTo); append_diff_javascript(diffType==2); style_footer(); } #if INTERFACE /* ** Possible return values from object_description() */ #define OBJTYPE_CHECKIN 0x0001 |
︙ | ︙ | |||
1386 1387 1388 1389 1390 1391 1392 | #define OBJTYPE_EXE 0x0100 #define OBJTYPE_FORUM 0x0200 /* ** Possible flags for the second parameter to ** object_description() */ | | < > > > > > > > > > > > > | < | < | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | #define OBJTYPE_EXE 0x0100 #define OBJTYPE_FORUM 0x0200 /* ** Possible flags for the second parameter to ** object_description() */ #define OBJDESC_DETAIL 0x0001 /* more detail */ #endif /* ** Write a description of an object to the www reply. ** ** If the object is a file then mention: ** ** * It's artifact ID ** * All its filenames ** * The check-in it was part of, with times and users ** ** If the object is a manifest, then mention: ** ** * It's artifact ID ** * date of check-in ** * Comment & user */ int object_description( int rid, /* The artifact ID */ u32 objdescFlags, /* Flags to control display */ Blob *pDownloadName /* Fill with an appropriate download name */ ){ Stmt q; int cnt = 0; int nWiki = 0; int objType = 0; char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); int showDetail = (objdescFlags & OBJDESC_DETAIL)!=0; char *prevName = 0; db_prepare(&q, "SELECT filename.name, datetime(event.mtime,toLocal())," " coalesce(event.ecomment,event.comment)," " coalesce(event.euser,event.user)," " b.uuid, mlink.mperm," " coalesce((SELECT value FROM tagxref" |
︙ | ︙ | |||
1436 1437 1438 1439 1440 1441 1442 | const char *zCom = db_column_text(&q, 2); const char *zUser = db_column_text(&q, 3); const char *zVers = db_column_text(&q, 4); int mPerm = db_column_int(&q, 5); const char *zBr = db_column_text(&q, 6); int szFile = db_column_int(&q,7); int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0; | < < < < | < | < | | | < < < | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 | const char *zCom = db_column_text(&q, 2); const char *zUser = db_column_text(&q, 3); const char *zVers = db_column_text(&q, 4); int mPerm = db_column_int(&q, 5); const char *zBr = db_column_text(&q, 6); int szFile = db_column_int(&q,7); int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0; if( sameFilename && !showDetail ){ if( cnt==1 ){ @ %z(href("%R/whatis/%!S",zUuid))[more...]</a> } cnt++; continue; } if( !sameFilename ){ if( prevName && showDetail ) { @ </ul> } if( mPerm==PERM_LNK ){ @ <li>Symbolic link objType |= OBJTYPE_SYMLINK; }else if( mPerm==PERM_EXE ){ @ <li>Executable file objType |= OBJTYPE_EXE; }else{ @ <li>File } objType |= OBJTYPE_CONTENT; @ %z(href("%R/finfo?name=%T&m=%!S",zName,zUuid))%h(zName)</a> tag_private_status(rid); if( showDetail ){ @ <ul> } prevName = fossil_strdup(zName); } if( showDetail ){ @ <li> hyperlink_to_date(zDate,""); @ — part of check-in hyperlink_to_uuid(zVers); }else{ @ — part of check-in hyperlink_to_uuid(zVers); @ at hyperlink_to_date(zDate,""); } if( zBr && zBr[0] ){ @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a> } @ — %!W(zCom) (user: hyperlink_to_user(zUser,zDate,","); @ size: %d(szFile)) if( g.perm.Hyperlink ){ @ %z(href("%R/annotate?filename=%T&checkin=%!S",zName,zVers)) @ [annotate]</a> @ %z(href("%R/blame?filename=%T&checkin=%!S",zName,zVers)) @ [blame]</a> @ %z(href("%R/timeline?n=all&uf=%!S",zUuid))[check-ins using]</a> } cnt++; if( pDownloadName && blob_size(pDownloadName)==0 ){ blob_append(pDownloadName, zName, -1); } } if( prevName && showDetail ){ |
︙ | ︙ | |||
1580 1581 1582 1583 1584 1585 1586 | }else if( zType[0]=='f' ){ objType |= OBJTYPE_FORUM; @ Forum post }else{ @ Tag referencing } if( zType[0]!='e' || eventTagId == 0){ | | | 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | }else if( zType[0]=='f' ){ objType |= OBJTYPE_FORUM; @ Forum post }else{ @ Tag referencing } if( zType[0]!='e' || eventTagId == 0){ hyperlink_to_uuid(zUuid); } @ - %!W(zCom) by hyperlink_to_user(zUser,zDate," on"); hyperlink_to_date(zDate, "."); if( pDownloadName && blob_size(pDownloadName)==0 ){ blob_appendf(pDownloadName, "%S.txt", zUuid); } |
︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 | /* const char *zSrc = db_column_text(&q, 4); */ if( cnt>0 ){ @ Also attachment "%h(zFilename)" to }else{ @ Attachment "%h(zFilename)" to } objType |= OBJTYPE_ATTACHMENT; | | | 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 | /* const char *zSrc = db_column_text(&q, 4); */ if( cnt>0 ){ @ Also attachment "%h(zFilename)" to }else{ @ Attachment "%h(zFilename)" to } objType |= OBJTYPE_ATTACHMENT; if( fossil_is_uuid(zTarget) ){ if ( db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){ if( g.perm.Hyperlink && g.anon.RdTkt ){ @ ticket [%z(href("%R/tktview?name=%!S",zTarget))%S(zTarget)</a>] }else{ @ ticket [%S(zTarget)] |
︙ | ︙ | |||
1668 1669 1670 1671 1672 1673 1674 | blob_appendf(pDownloadName, "%S.txt", zUuid); } tag_private_status(rid); } return objType; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 | blob_appendf(pDownloadName, "%S.txt", zUuid); } tag_private_status(rid); } return objType; } /* ** WEBPAGE: fdiff ** URL: fdiff?v1=UUID&v2=UUID ** ** Two arguments, v1 and v2, identify the artifacts to be diffed. ** Show diff side by side unless sbs is 0. Generate plain text if ** "patch" is present, otherwise generate "pretty" HTML. ** ** Alternative URL: fdiff?from=filename1&to=filename2&ci=checkin ** |
︙ | ︙ | |||
1741 1742 1743 1744 1745 1746 1747 1748 1749 | int v1, v2; int isPatch = P("patch")!=0; int diffType; /* 0: none, 1: unified, 2: side-by-side */ char *zV1; char *zV2; const char *zRe; ReCompiled *pRe = 0; u32 objdescFlags = 0; int verbose = PB("verbose"); | > < | | > | | | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | int v1, v2; int isPatch = P("patch")!=0; int diffType; /* 0: none, 1: unified, 2: side-by-side */ char *zV1; char *zV2; const char *zRe; ReCompiled *pRe = 0; u64 diffFlags; u32 objdescFlags = 0; int verbose = PB("verbose"); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } cookie_link_parameter("diff","diff","2"); diffType = atoi(PD("diff","2")); cookie_render(); if( P("from") && P("to") ){ v1 = artifact_from_ci_and_filename(0, "from"); v2 = artifact_from_ci_and_filename(0, "to"); }else{ Stmt q; v1 = name_to_rid_www("v1"); v2 = name_to_rid_www("v2"); /* If the two file versions being compared both have the same ** filename, then offer an "Annotate" link that constructs an |
︙ | ︙ | |||
1787 1788 1789 1790 1791 1792 1793 | "%R/annotate?origin=%s&checkin=%s&filename=%T", zOrig, zCkin, zFN); } db_finalize(&q); } if( v1==0 || v2==0 ) fossil_redirect_home(); zRe = P("regex"); | < < | < | | < < | | < | | | | < < < < < > > < < | | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | | | < | < < | | < < < < < | 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 | "%R/annotate?origin=%s&checkin=%s&filename=%T", zOrig, zCkin, zFN); } db_finalize(&q); } if( v1==0 || v2==0 ) fossil_redirect_home(); zRe = P("regex"); if( zRe ) re_compile(&pRe, zRe, 0); if( verbose ) objdescFlags |= OBJDESC_DETAIL; if( isPatch ){ Blob c1, c2, *pOut; pOut = cgi_output_blob(); cgi_set_content_type("text/plain"); diffFlags = 4; content_get(v1, &c1); content_get(v2, &c2); text_diff(&c1, &c2, pOut, pRe, diffFlags); blob_reset(&c1); blob_reset(&c2); return; } zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); diffFlags = construct_diff_flags(diffType) | DIFF_HTML; style_header("Diff"); style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); if( diffType==2 ){ style_submenu_element("Unified Diff", "%R/fdiff?v1=%T&v2=%T&diff=1", P("v1"), P("v2")); }else{ style_submenu_element("Side-by-side Diff", "%R/fdiff?v1=%T&v2=%T&diff=2", P("v1"), P("v2")); } style_submenu_checkbox("verbose", "Verbose", 0, 0); style_submenu_element("Patch", "%R/fdiff?v1=%T&v2=%T&patch", P("v1"), P("v2")); if( P("smhdr")!=0 ){ @ <h2>Differences From Artifact @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2> }else{ @ <h2>Differences From @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2> object_description(v1, objdescFlags, 0); @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2> object_description(v2, objdescFlags, 0); } if( pRe ){ @ <b>Only differences that match regular expression "%h(zRe)" @ are shown.</b> } @ <hr /> append_diff(zV1, zV2, diffFlags, pRe); append_diff_javascript(diffType); style_footer(); } /* ** WEBPAGE: raw ** URL: /raw?name=ARTIFACTID&m=TYPE ** URL: /raw?ci=BRANCH&filename=NAME ** ** Return the uninterpreted content of an artifact. Used primarily ** to view artifacts that are images. */ void rawartifact_page(void){ int rid = 0; char *zUuid; const char *zMime; Blob content; if( P("ci") && P("filename") ){ rid = artifact_from_ci_and_filename(0, 0); } if( rid==0 ){ rid = name_to_rid_www("name"); } login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( rid==0 ) fossil_redirect_home(); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); if( fossil_strcmp(P("name"), zUuid)==0 && login_is_nobody() ){ g.isConst = 1; } free(zUuid); zMime = P("m"); if( zMime==0 ){ char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename" " WHERE mlink.fid=%d" " AND filename.fnid=mlink.fnid", rid); if( !zFName ){ /* Look also at the attachment table */ zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob" " WHERE blob.rid=%d" " AND attachment.src=blob.uuid", rid); } if( zFName ) zMime = mimetype_from_name(zFName); if( zMime==0 ) zMime = "application/x-fossil-artifact"; } content_get(rid, &content); cgi_set_content_type(zMime); cgi_set_content(&content); } /* ** Render a hex dump of a file. */ static void hexdump(Blob *pBlob){ |
︙ | ︙ | |||
2074 2075 2076 2077 2078 2079 2080 | }else{ zLine[k+1] = ' '; zLine[k+2] = ' '; } } zLine[53] = ' '; zLine[54] = ' '; | < | > | | < < < < < < < < < < < < < < < < < < | | | | | 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 | }else{ zLine[k+1] = ' '; zLine[k+2] = ' '; } } zLine[53] = ' '; zLine[54] = ' '; for(j=0; j<16; j++){ k = j+55; if( i+j<n ){ unsigned char c = x[i+j]; if( c>=0x20 && c<=0x7e ){ zLine[k] = c; }else{ zLine[k] = '.'; } }else{ zLine[k] = 0; } } zLine[71] = 0; @ %h(zLine) } } /* ** WEBPAGE: hexdump ** URL: /hexdump?name=ARTIFACTID ** |
︙ | ︙ | |||
2132 2133 2134 2135 2136 2137 2138 | char *zUuid; u32 objdescFlags = 0; rid = name_to_rid_www("name"); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( rid==0 ) fossil_redirect_home(); | < | > | < < < | | | | | | < < < < < < < | | | < | | | | | | > > | > > | < < < < | | | > > > > > > | | | < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | < | | | < | | | < < < < < | | < < > | < < < > | < | < < < > | < < | < < > > | < < < | < < | | | < | | < < < > | | < | < < < < < < < | | | > | > | > | < < < < < | < < < < < | | | | | < < > | < | | | < < < < < < < < < < | | < < < < < | < < < | < | < | < < < < | < < < < < < | < | < < | < | | | | < < < < < | | | < | | < < < < > > | < | < < | > | < < < < | | | | | | | | | | | < < < < < < < < < < < < < < < < < > > > < < > > > > > | > > | | | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | | | | < | < < < | | < | > | < < < < < < < < < < < < < < < < < | < < > | | > | > > | < < | < < < < < < < < < < < < > > > | < < | | < < < < | < < | < < < | < < < | < | | | < < < < < < | < < < < < | | < < < < < | | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 | char *zUuid; u32 objdescFlags = 0; rid = name_to_rid_www("name"); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( rid==0 ) fossil_redirect_home(); if( g.perm.Admin ){ const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){ style_submenu_element("Unshun", "%s/shun?accept=%s&sub=1#delshun", g.zTop, zUuid); }else{ style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } style_header("Hex Artifact Content"); zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid); if( g.perm.Setup ){ @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> }else{ @ <h2>Artifact %s(zUuid):</h2> } blob_zero(&downloadName); if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL; object_description(rid, objdescFlags, &downloadName); style_submenu_element("Download", "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); @ <hr /> content_get(rid, &content); @ <blockquote><pre> hexdump(&content); @ </pre></blockquote> style_footer(); } /* ** Look for "ci" and "filename" query parameters. If found, try to ** use them to extract the record ID of an artifact for the file. ** ** Also look for "fn" as an alias for "filename". If either "filename" ** or "fn" is present but "ci" is missing, use "tip" as a default value ** for "ci". ** ** If zNameParam is not NULL, this use that parameter as the filename ** rather than "fn" or "filename". ** ** If pUrl is not NULL, then record the "ci" and "filename" values in ** pUrl. ** ** At least one of pUrl or zNameParam must be NULL. */ int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){ const char *zFilename; const char *zCI; int cirid; Manifest *pManifest; ManifestFile *pFile; if( zNameParam ){ zFilename = P(zNameParam); }else{ zFilename = P("filename"); if( zFilename==0 ){ zFilename = P("fn"); } } if( zFilename==0 ) return 0; zCI = P("ci"); cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci"); if( cirid<=0 ) return 0; pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0); if( pManifest==0 ) return 0; manifest_file_rewind(pManifest); while( (pFile = manifest_file_next(pManifest,0))!=0 ){ if( fossil_strcmp(zFilename, pFile->zName)==0 ){ int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid); manifest_destroy(pManifest); if( pUrl ){ assert( zNameParam==0 ); url_add_parameter(pUrl, "fn", zFilename); if( zCI ) url_add_parameter(pUrl, "ci", zCI); } return rid; } } manifest_destroy(pManifest); return 0; } /* ** The "z" argument is a string that contains the text of a source code ** file. This routine appends that text to the HTTP reply with line numbering. ** ** zLn is the ?ln= parameter for the HTTP query. If there is an argument, ** then highlight that line number and scroll to it once the page loads. ** If there are two line numbers, highlight the range of lines. ** Multiple ranges can be highlighed by adding additional line numbers ** separated by a non-digit character (also not one of [-,.]). */ void output_text_with_line_numbers( const char *z, const char *zLn ){ int iStart, iEnd; /* Start and end of region to highlight */ int n = 0; /* Current line number */ int i = 0; /* Loop index */ int iTop = 0; /* Scroll so that this line is on top of screen. */ Stmt q; iStart = iEnd = atoi(zLn); db_multi_exec( "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)"); if( iStart>0 ){ do{ while( fossil_isdigit(zLn[i]) ) i++; if( zLn[i]==',' || zLn[i]=='-' || zLn[i]=='.' ){ i++; while( zLn[i]=='.' ){ i++; } iEnd = atoi(&zLn[i]); while( fossil_isdigit(zLn[i]) ) i++; } while( fossil_isdigit(zLn[i]) ) i++; if( iEnd<iStart ) iEnd = iStart; db_multi_exec( "INSERT OR REPLACE INTO lnos VALUES(%d,%d)", iStart, iEnd ); iStart = iEnd = atoi(&zLn[i++]); }while( zLn[i] && iStart && iEnd ); } db_prepare(&q, "SELECT min(iStart), max(iEnd) FROM lnos"); if( db_step(&q)==SQLITE_ROW ){ iStart = db_column_int(&q, 0); iEnd = db_column_int(&q, 1); iTop = iStart - 15 + (iEnd-iStart)/4; if( iTop>iStart - 2 ) iTop = iStart-2; } db_finalize(&q); @ <pre> while( z[0] ){ n++; db_prepare(&q, "SELECT min(iStart), max(iEnd) FROM lnos" " WHERE iStart <= %d AND iEnd >= %d", n, n); if( db_step(&q)==SQLITE_ROW ){ iStart = db_column_int(&q, 0); iEnd = db_column_int(&q, 1); } db_finalize(&q); for(i=0; z[i] && z[i]!='\n'; i++){} if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1); if( n==iStart ){ cgi_append_content("<div class=\"selectedText\">",-1); } cgi_printf("%6d ", n); if( i>0 ){ char *zHtml = htmlize(z, i); cgi_append_content(zHtml, -1); fossil_free(zHtml); } if( n==iTop ) cgi_append_content("</span>", -1); if( n==iEnd ) cgi_append_content("</div>", -1); else cgi_append_content("\n", 1); z += i; if( z[0]=='\n' ) z++; } if( n<iEnd ) cgi_printf("</div>"); @ </pre> if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){ style_load_one_js_file("scroll.js"); } } /* ** WEBPAGE: artifact ** WEBPAGE: file ** WEBPAGE: whatis ** ** Typical usage: ** ** /artifact/HASH ** /whatis/HASH ** /file/NAME ** ** Additional query parameters: ** ** ln - show line numbers ** ln=N - highlight line number N ** ln=M-N - highlight lines M through N inclusive ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive) ** verbose - show more detail in the description ** download - redirect to the download (artifact page only) ** name=SHA1HASH - Provide the SHA1HASH as a query parameter ** filename=NAME - Show information for content file NAME ** fn=NAME - "fn" is shorthand for "filename" ** ci=VERSION - The specific check-in to use for "filename=". ** ** The /artifact page show the complete content of a file ** identified by HASH as preformatted text. The ** /whatis page shows only a description of the file. The /file ** page shows the most recent version of the file or directory ** called NAME, or a list of the top-level directory if NAME is ** omitted. */ void artifact_page(void){ int rid = 0; Blob content; const char *zMime; Blob downloadName; int renderAsWiki = 0; int renderAsHtml = 0; int objType; int asText; const char *zUuid; u32 objdescFlags = 0; int descOnly = fossil_strcmp(g.zPath,"whatis")==0; int isFile = fossil_strcmp(g.zPath,"file")==0; const char *zLn = P("ln"); const char *zName = P("name"); HQuery url; url_initialize(&url, g.zPath); rid = artifact_from_ci_and_filename(&url, 0); if( rid==0 ){ url_add_parameter(&url, "name", zName); if( isFile ){ /* Do a top-level directory listing in /file mode if no argument ** specified */ if( zName==0 || zName[0]==0 ){ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip"); page_tree(); return; } /* Look for a single file with the given name */ rid = db_int(0, "SELECT fid FROM filename, mlink, event" " WHERE name=%Q" " AND mlink.fnid=filename.fnid" " AND event.objid=mlink.mid" " ORDER BY event.mtime DESC LIMIT 1", zName ); /* If no file called NAME exists, instead look for a directory ** with that name, and do a directory listing */ if( rid==0 ){ int nName = (int)strlen(zName); if( nName && zName[nName-1]=='/' ) nName--; if( db_exists( "SELECT 1 FROM filename" " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';", nName, zName, nName+1, nName, zName ) ){ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip"); page_tree(); return; } } /* If no file or directory called NAME: issue an error */ if( rid==0 ){ style_header("No such file"); @ File '%h(zName)' does not exist in this repository. style_footer(); return; } }else{ rid = name_to_rid_www("name"); } } login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( rid==0 ){ style_header("No such artifact"); @ Artifact '%h(zName)' does not exist in this repository. style_footer(); return; } if( descOnly || P("verbose")!=0 ){ url_add_parameter(&url, "verbose", "1"); objdescFlags |= OBJDESC_DETAIL; } zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); if( isFile ){ @ <h2>Latest version of file '%h(zName)':</h2> style_submenu_element("Artifact", "%R/artifact/%S", zUuid); }else if( g.perm.Setup ){ @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> }else{ @ <h2>Artifact %s(zUuid):</h2> } blob_zero(&downloadName); objType = object_description(rid, objdescFlags, &downloadName); if( !descOnly && P("download")!=0 ){ cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName), db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid)); /*NOTREACHED*/ } if( g.perm.Admin ){ const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){ style_submenu_element("Unshun", "%s/shun?accept=%s&sub=1#accshun", g.zTop, zUuid); }else{ style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } style_header("%s", isFile ? "File Content" : descOnly ? "Artifact Description" : "Artifact Content"); if( g.perm.Admin ){ Stmt q; db_prepare(&q, "SELECT coalesce(user.login,rcvfrom.uid)," " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr" " FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid" " WHERE blob.rid=%d" " AND rcvfrom.rcvid=blob.rcvid;", rid); while( db_step(&q)==SQLITE_ROW ){ const char *zUser = db_column_text(&q,0); const char *zDate = db_column_text(&q,1); const char *zIp = db_column_text(&q,2); @ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p> } db_finalize(&q); } style_submenu_element("Download", "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid); if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid); } asText = P("txt")!=0; zMime = mimetype_from_name(blob_str(&downloadName)); if( zMime ){ if( fossil_strcmp(zMime, "text/html")==0 ){ if( asText ){ style_submenu_element("Html", "%s", url_render(&url, "txt", 0, 0, 0)); }else{ renderAsHtml = 1; style_submenu_element("Text", "%s", url_render(&url, "txt", "1", 0, 0)); } }else if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 || fossil_strcmp(zMime, "text/x-markdown")==0 ){ if( asText ){ style_submenu_element("Wiki", "%s", url_render(&url, "txt", 0, 0, 0)); }else{ renderAsWiki = 1; style_submenu_element("Text", "%s", url_render(&url, "txt", "1", 0, 0)); } } } if( (objType & (OBJTYPE_WIKI|OBJTYPE_TICKET))!=0 ){ style_submenu_element("Parsed", "%R/info/%s", zUuid); } if( descOnly ){ style_submenu_element("Content", "%R/artifact/%s", zUuid); }else{ if( zLn==0 || atoi(zLn)==0 ){ style_submenu_checkbox("ln", "Line Numbers", 0, 0); } @ <hr /> content_get(rid, &content); if( renderAsWiki ){ wiki_render_by_mimetype(&content, zMime); }else if( renderAsHtml ){ @ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)" @ width="100%%" frameborder="0" marginwidth="0" marginheight="0" @ sandbox="allow-same-origin" @ onload="this.height=this.contentDocument.documentElement.scrollHeight;"> @ </iframe> }else{ style_submenu_element("Hex", "%s/hexdump?name=%s", g.zTop, zUuid); blob_to_utf8_no_bom(&content, 0); zMime = mimetype_from_content(&content); @ <blockquote> if( zMime==0 ){ const char *z; z = blob_str(&content); if( zLn ){ output_text_with_line_numbers(z, zLn); }else{ @ <pre> @ %h(z) @ </pre> } }else if( strncmp(zMime, "image/", 6)==0 ){ @ <i>(file is %d(blob_size(&content)) bytes of image data)</i><br /> @ <img src="%R/raw/%s(zUuid)?m=%s(zMime)" /> style_submenu_element("Image", "%R/raw/%s?m=%s", zUuid, zMime); }else{ @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> } @ </blockquote> } } style_footer(); } /* ** WEBPAGE: tinfo ** URL: /tinfo?name=ARTIFACTID ** ** Show the details of a ticket change control artifact. |
︙ | ︙ | |||
2771 2772 2773 2774 2775 2776 2777 | int modPending; const char *zModAction; char *zTktTitle; login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; } rid = name_to_rid_www("name"); if( rid==0 ){ fossil_redirect_home(); } | < | > | | | | < | | | | | | | | | | < < < < | | < < < < < > > > > > | 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 | int modPending; const char *zModAction; char *zTktTitle; login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; } rid = name_to_rid_www("name"); if( rid==0 ){ fossil_redirect_home(); } zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); if( g.perm.Admin ){ if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){ style_submenu_element("Unshun", "%s/shun?accept=%s&sub=1#accshun", g.zTop, zUuid); }else{ style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } pTktChng = manifest_get(rid, CFTYPE_TICKET, 0); if( pTktChng==0 ) fossil_redirect_home(); zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate); sqlite3_snprintf(sizeof(zTktName), zTktName, "%s", pTktChng->zTicketUuid); if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){ if( strcmp(zModAction,"delete")==0 ){ moderation_disapprove(rid); /* ** Next, check if the ticket still exists; if not, we cannot ** redirect to it. */ if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zTktName) ){ cgi_redirectf("%R/tktview/%s", zTktName); /*NOTREACHED*/ }else{ cgi_redirectf("%R/modreq"); /*NOTREACHED*/ } } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } zTktTitle = db_table_has_column("repository", "ticket", "title" ) ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName) : 0; style_header("Ticket Change Details"); style_submenu_element("Raw", "%R/artifact/%s", zUuid); style_submenu_element("History", "%R/tkthistory/%s", zTktName); style_submenu_element("Page", "%R/tktview/%t", zTktName); style_submenu_element("Timeline", "%R/tkttimeline/%t", zTktName); if( P("plaintext") ){ style_submenu_element("Formatted", "%R/info/%s", zUuid); }else{ style_submenu_element("Plaintext", "%R/info/%s?plaintext", zUuid); } @ <div class="section">Overview</div> @ <p><table class="label-value"> @ <tr><th>Artifact ID:</th> @ <td>%z(href("%R/artifact/%!S",zUuid))%s(zUuid)</a> if( g.perm.Setup ){ @ (%d(rid)) } modPending = moderation_pending_www(rid); @ <tr><th>Ticket:</th> @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a> if( zTktTitle ){ @<br />%h(zTktTitle) } @</td></tr> @ <tr><th>User & Date:</th><td> hyperlink_to_user(pTktChng->zUser, zDate, " on "); hyperlink_to_date(zDate, "</td></tr>"); @ </table> free(zDate); free(zTktTitle); if( g.perm.ModTkt && modPending ){ @ <div class="section">Moderation</div> @ <blockquote> @ <form method="POST" action="%R/tinfo/%s(zUuid)"> @ <label><input type="radio" name="modaction" value="delete"> @ Delete this change</label><br /> @ <label><input type="radio" name="modaction" value="approve"> @ Approve this change</label><br /> @ <input type="submit" value="Submit"> @ </form> @ </blockquote> } @ <div class="section">Changes</div> @ <p> ticket_output_change_artifact(pTktChng, 0); manifest_destroy(pTktChng); style_footer(); } /* ** WEBPAGE: info ** URL: info/ARTIFACTID ** ** The argument is a artifact ID which might be a check-in or a file or ** a ticket changes or a wiki edit or something else. ** ** Figure out what the artifact ID is and display it appropriately. */ void info_page(void){ const char *zName; Blob uuid; int rid; int rc; int nLen; zName = P("name"); if( zName==0 ) fossil_redirect_home(); nLen = strlen(zName); blob_set(&uuid, zName); if( name_collisions(zName) ){ cgi_set_parameter("src","info"); ambiguous_page(); return; } rc = name_to_uuid(&uuid, -1, "*"); if( rc==1 ){ if( validate16(zName, nLen) ){ if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ tktview_page(); return; } if( db_exists("SELECT 1 FROM tag" " WHERE tagname GLOB 'event-%q*'", zName) ){ event_page(); return; } } style_header("No Such Object"); @ <p>No such object: %h(zName)</p> if( nLen<4 ){ @ <p>Object name should be no less than 4 characters. Ten or more @ characters are recommended.</p> } style_footer(); return; }else if( rc==2 ){ cgi_set_parameter("src","info"); ambiguous_page(); return; } zName = blob_str(&uuid); rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName); if( rid==0 ){ style_header("Broken Link"); @ <p>No such object: %h(zName)</p> style_footer(); return; } if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ ci_page(); }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){ winfo_page(); }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){ tinfo_page(); }else if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){ ci_page(); }else if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){ ci_page(); }else if( db_exists("SELECT 1 FROM attachment WHERE attachid=%d", rid) ){ ainfo_page(); }else if( db_table_exists("repository","forumpost") && db_exists("SELECT 1 FROM forumpost WHERE fpid=%d", rid) ){ forumthread_page(); }else { artifact_page(); } } /* |
︙ | ︙ | |||
3069 3070 3071 3072 3073 3074 3075 | change_sym_tag(zNewBranch,"*"); } /* ** The apply_newtags method is called after all newtags have been added ** and the control artifact is completed and then written to the DB. */ | | < < < < < < < < < | < < < < < < | | | | < < > | | | 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 | change_sym_tag(zNewBranch,"*"); } /* ** The apply_newtags method is called after all newtags have been added ** and the control artifact is completed and then written to the DB. */ static void apply_newtags(Blob *ctrl, int rid, const char *zUuid){ Stmt q; int nChng = 0; db_prepare(&q, "SELECT tag, prefix, value FROM newtags" " ORDER BY prefix || tag"); while( db_step(&q)==SQLITE_ROW ){ const char *zTag = db_column_text(&q, 0); const char *zPrefix = db_column_text(&q, 1); const char *zValue = db_column_text(&q, 2); nChng++; if( zValue ){ blob_appendf(ctrl, "T %s%F %s %F\n", zPrefix, zTag, zUuid, zValue); }else{ blob_appendf(ctrl, "T %s%F %s\n", zPrefix, zTag, zUuid); } } db_finalize(&q); if( nChng>0 ){ int nrid; Blob cksum; blob_appendf(ctrl, "U %F\n", login_name()); md5sum_blob(ctrl, &cksum); blob_appendf(ctrl, "Z %b\n", &cksum); db_begin_transaction(); g.markPrivate = content_is_private(rid); nrid = content_put(ctrl); manifest_crosslink(nrid, ctrl, MC_PERMIT_HOOKS); assert( blob_is_reset(ctrl) ); db_end_transaction(0); } } /* ** This method checks that the date can be parsed. ** Returns 1 if datetime() can validate, 0 otherwise. */ int is_datetime(const char* zDate){ return db_int(0, "SELECT datetime(%Q) NOT NULL", zDate); } /* ** WEBPAGE: ci_edit ** ** Edit a check-in. (Check-ins are immutable and do not really change. ** This page really creates supplemental tags that affect the display ** of the check-in.) ** ** Query parmeters: ** ** rid=INTEGER Record ID of the check-in to edit (REQUIRED) ** ** POST parameters after pressing "Perview", "Cancel", or "Apply": ** ** c=TEXT New check-in comment ** u=TEXT New user name ** newclr Apply a background color ** clr=TEXT New background color (only if newclr) ** pclr Propagate new background color (only if newclr) ** dt=TEXT New check-in date/time (ISO8610 format) |
︙ | ︙ | |||
3218 3219 3220 3221 3222 3223 3224 | zNewColorFlag = P("newclr") ? " checked" : ""; zNewTagFlag = P("newtag") ? " checked" : ""; zNewTag = PDT("tagname",""); zNewBrFlag = P("newbr") ? " checked" : ""; zNewBranch = PDT("brname",""); zCloseFlag = P("close") ? " checked" : ""; zHideFlag = P("hide") ? " checked" : ""; | | > | 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 | zNewColorFlag = P("newclr") ? " checked" : ""; zNewTagFlag = P("newtag") ? " checked" : ""; zNewTag = PDT("tagname",""); zNewBrFlag = P("newbr") ? " checked" : ""; zNewBranch = PDT("brname",""); zCloseFlag = P("close") ? " checked" : ""; zHideFlag = P("hide") ? " checked" : ""; if( P("apply") && cgi_csrf_safe(1) ){ Blob ctrl; char *zNow; login_verify_csrf_secret(); blob_zero(&ctrl); zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); blob_appendf(&ctrl, "D %s\n", zNow); init_newtags(); if( zNewColorFlag[0] && zNewColor[0] && (fPropagateColor!=fNewPropagateColor |
︙ | ︙ | |||
3253 3254 3255 3256 3257 3258 3259 | if( P(zLabel) ) cancel_special(zTag); } db_finalize(&q); if( zHideFlag[0] ) hide_branch(); if( zCloseFlag[0] ) close_leaf(rid); if( zNewTagFlag[0] && zNewTag[0] ) add_tag(zNewTag); if( zNewBrFlag[0] && zNewBranch[0] ) change_branch(rid,zNewBranch); | | | 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 | if( P(zLabel) ) cancel_special(zTag); } db_finalize(&q); if( zHideFlag[0] ) hide_branch(); if( zCloseFlag[0] ) close_leaf(rid); if( zNewTagFlag[0] && zNewTag[0] ) add_tag(zNewTag); if( zNewBrFlag[0] && zNewBranch[0] ) change_branch(rid,zNewBranch); apply_newtags(&ctrl, rid, zUuid); cgi_redirectf("%R/ci/%S", zUuid); } blob_zero(&comment); blob_append(&comment, zNewComment, -1); zUuid[10] = 0; style_header("Edit Check-in [%s]", zUuid); if( P("preview") ){ |
︙ | ︙ | |||
3298 3299 3300 3301 3302 3303 3304 | @ %s(blob_str(&suffix)) @ </td></tr></table> if( zChngTime ){ @ <p>The timestamp on the tag used to make the changes above @ will be overridden as: %s(date_in_standard_format(zChngTime))</p> } @ </blockquote> | | > | | | | | | | < < < < < | | > | 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 | @ %s(blob_str(&suffix)) @ </td></tr></table> if( zChngTime ){ @ <p>The timestamp on the tag used to make the changes above @ will be overridden as: %s(date_in_standard_format(zChngTime))</p> } @ </blockquote> @ <hr /> blob_reset(&suffix); } @ <p>Make changes to attributes of check-in @ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p> form_begin(0, "%R/ci_edit"); login_insert_csrf_secret(); @ <div><input type="hidden" name="r" value="%s(zUuid)" /> @ <table border="0" cellspacing="10"> @ <tr><th align="right" valign="top">User:</th> @ <td valign="top"> @ <input type="text" name="u" size="20" value="%h(zNewUser)" /> @ </td></tr> @ <tr><th align="right" valign="top">Comment:</th> @ <td valign="top"> @ <textarea name="c" rows="10" cols="80">%h(zNewComment)</textarea> @ </td></tr> @ <tr><th align="right" valign="top">Check-in Time:</th> @ <td valign="top"> @ <input type="text" name="dt" size="20" value="%h(zNewDate)" /> @ </td></tr> if( zChngTime ){ @ <tr><th align="right" valign="top">Timestamp of this change:</th> @ <td valign="top"> @ <input type="text" name="chngtime" size="20" value="%h(zChngTime)" /> @ </td></tr> } @ <tr><th align="right" valign="top">Background Color:</th> @ <td valign="top"> @ <div><label><input type='checkbox' name='newclr'%s(zNewColorFlag) /> @ Change background color: \ @ <input type='color' name='clr'\ @ value='%s(zNewColor[0]?zNewColor:"#808080")'></label></div> @ <div><label> if( fNewPropagateColor ){ @ <input type="checkbox" name="pclr" checked="checked" /> }else{ @ <input type="checkbox" name="pclr" /> } @ Propagate color to descendants</label></div> @ </td></tr> @ <tr><th align="right" valign="top">Tags:</th> @ <td valign="top"> @ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) /> @ Add the following new tag name to this check-in:</label> @ <input type="text" size='15' name="tagname" value="%h(zNewTag)" \ @ id='tagname' /> zBranchName = db_text(0, "SELECT value FROM tagxref, tag" " WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid" " AND tagxref.tagid=%d", rid, TAG_BRANCH); db_prepare(&q, "SELECT tag.tagid, tagname, tagxref.value FROM tagxref, tag" " WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid" " ORDER BY CASE WHEN tagname GLOB 'sym-*' THEN substr(tagname,5)" |
︙ | ︙ | |||
3381 3382 3383 3384 3385 3386 3387 | }else if( tagid==TAG_HIDDEN ){ fHasHidden = 1; }else if( !isSpecialTag && zTagName && fossil_strcmp(&zTagName[4], zBranchName)==0){ continue; } sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid); | | | | | | | | | | | | | | | | | 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 | }else if( tagid==TAG_HIDDEN ){ fHasHidden = 1; }else if( !isSpecialTag && zTagName && fossil_strcmp(&zTagName[4], zBranchName)==0){ continue; } sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid); @ <br /><label> if( P(zLabel) ){ @ <input type="checkbox" name="c%d(tagid)" checked="checked" /> }else{ @ <input type="checkbox" name="c%d(tagid)" /> } if( isSpecialTag ){ @ Cancel special tag <b>%h(zTagName)</b></label> }else{ @ Cancel tag <b>%h(&zTagName[4])</b></label> } } db_finalize(&q); @ </td></tr> if( !zBranchName ){ zBranchName = db_get("main-branch", "trunk"); } if( !zNewBranch || !zNewBranch[0]){ zNewBranch = zBranchName; } @ <tr><th align="right" valign="top">Branching:</th> @ <td valign="top"> @ <label><input id="newbr" type="checkbox" name="newbr" \ @ data-branch='%h(zBranchName)'%s(zNewBrFlag) /> @ Make this check-in the start of a new branch named:</label> @ <input id="brname" type="text" style="width:15;" name="brname" \ @ value="%h(zNewBranch)" /></td></tr> if( !fHasHidden ){ @ <tr><th align="right" valign="top">Branch Hiding:</th> @ <td valign="top"> @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> @ Hide branch @ <span style="font-weight:bold" id="hbranch">%h(zBranchName)</span> @ from the timeline starting from this check-in</label> @ </td></tr> } if( !fHasClosed ){ if( is_a_leaf(rid) ){ @ <tr><th align="right" valign="top">Leaf Closure:</th> @ <td valign="top"> @ <label><input type="checkbox" name="close"%s(zCloseFlag) /> @ Mark this leaf as "closed" so that it no longer appears on the @ "leaves" page and is no longer labeled as a "<b>Leaf</b>"</label> @ </td></tr> }else if( zBranchName ){ @ <tr><th align="right" valign="top">Branch Closure:</th> @ <td valign="top"> @ <label><input type="checkbox" name="close"%s(zCloseFlag) /> @ Mark branch @ <span style="font-weight:bold" id="cbranch">%h(zBranchName)</span> @ as "closed".</label> @ </td></tr> } } if( zBranchName ) fossil_free(zBranchName); @ <tr><td colspan="2"> @ <input type="submit" name="cancel" value="Cancel" /> @ <input type="submit" name="preview" value="Preview" /> if( P("preview") ){ @ <input type="submit" name="apply" value="Apply Changes" /> } @ </td></tr> @ </table> @ </div></form> style_load_one_js_file("ci_edit.js"); style_footer(); } /* ** Prepare an ammended commit comment. Let the user modify it using the ** editor specified in the global_config table or either ** the VISUAL or EDITOR environment variable. ** |
︙ | ︙ | |||
3488 3489 3490 3491 3492 3493 3494 | blob_append(&prompt, zUuid, -1); } blob_append(&prompt, ".\n# Lines beginning with a # are ignored.\n", -1); prompt_for_user_comment(pComment, &prompt); blob_reset(&prompt); } | | | | > | < < < | 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 | blob_append(&prompt, zUuid, -1); } blob_append(&prompt, ".\n# Lines beginning with a # are ignored.\n", -1); prompt_for_user_comment(pComment, &prompt); blob_reset(&prompt); } #define AMEND_USAGE_STMT "UUID OPTION ?OPTION ...?" /* ** COMMAND: amend ** ** Usage: %fossil amend UUID OPTION ?OPTION ...? ** ** Amend the tags on check-in UUID to change how it displays in the timeline. ** ** Options: ** ** --author USER Make USER the author for check-in ** -m|--comment COMMENT Make COMMENT the check-in comment ** -M|--message-file FILE Read the amended comment from FILE ** -e|--edit-comment Launch editor to revise comment ** --date DATETIME Make DATETIME the check-in time ** --bgcolor COLOR Apply COLOR to this check-in ** --branchcolor COLOR Apply and propagate COLOR to the branch ** --tag TAG Add new TAG to this check-in ** --cancel TAG Cancel TAG from this check-in ** --branch NAME Make this check-in the start of branch NAME ** --hide Hide branch starting from this check-in ** --close Mark this "leaf" as closed ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. */ |
︙ | ︙ | |||
3541 3542 3543 3544 3545 3546 3547 | int fClose; /* True if leaf should be closed */ int fHide; /* True if branch should be hidden */ int fPropagateColor; /* True if color propagates before amend */ int fNewPropagateColor = 0; /* True if color propagates after amend */ int fHasHidden = 0; /* True if hidden tag already set */ int fHasClosed = 0; /* True if closed tag already set */ int fEditComment; /* True if editor to be used for comment */ | < < > < | < < | | 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 | int fClose; /* True if leaf should be closed */ int fHide; /* True if branch should be hidden */ int fPropagateColor; /* True if color propagates before amend */ int fNewPropagateColor = 0; /* True if color propagates after amend */ int fHasHidden = 0; /* True if hidden tag already set */ int fHasClosed = 0; /* True if closed tag already set */ int fEditComment; /* True if editor to be used for comment */ const char *zChngTime; /* The change time on the control artifact */ const char *zUuid; Blob ctrl; Blob comment; char *zNow; int nTags, nCancels; int i; Stmt q; if( g.argc==3 ) usage(AMEND_USAGE_STMT); fEditComment = find_option("edit-comment","e",0)!=0; zNewComment = find_option("comment","m",1); zComFile = find_option("message-file","M",1); zNewBranch = find_option("branch",0,1); zNewColor = find_option("bgcolor",0,1); zNewBrColor = find_option("branchcolor",0,1); if( zNewBrColor ){ zNewColor = zNewBrColor; fNewPropagateColor = 1; } zNewDate = find_option("date",0,1); zNewUser = find_option("author",0,1); pzNewTags = find_repeatable_option("tag",0,&nTags); pzCancelTags = find_repeatable_option("cancel",0,&nCancels); fClose = find_option("close",0,0)!=0; fHide = find_option("hide",0,0)!=0; zChngTime = find_option("chngtime",0,1); db_find_and_open_repository(0,0); user_select(); verify_all_options(); if( g.argc<3 || g.argc>=4 ) usage(AMEND_USAGE_STMT); rid = name_to_typed_rid(g.argv[2], "ci"); if( rid==0 && !is_a_version(rid) ) fossil_fatal("no such check-in"); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); if( zUuid==0 ) fossil_fatal("Unable to find UUID"); zComment = db_text(0, "SELECT coalesce(ecomment,comment)" " FROM event WHERE objid=%d", rid); zUser = db_text(0, "SELECT coalesce(euser,user)" " FROM event WHERE objid=%d", rid); zDate = db_text(0, "SELECT datetime(mtime)" " FROM event WHERE objid=%d", rid); zColor = db_text("", "SELECT bgcolor" |
︙ | ︙ | |||
3667 3668 3669 3670 3671 3672 3673 | cancel_tag(rid,pzCancelTags[i]); } fossil_free((void *)pzCancelTags); } if( fHide && !fHasHidden ) hide_branch(); if( fClose && !fHasClosed ) close_leaf(rid); if( zNewBranch && zNewBranch[0] ) change_branch(rid,zNewBranch); | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 | cancel_tag(rid,pzCancelTags[i]); } fossil_free((void *)pzCancelTags); } if( fHide && !fHasHidden ) hide_branch(); if( fClose && !fHasClosed ) close_leaf(rid); if( zNewBranch && zNewBranch[0] ) change_branch(rid,zNewBranch); apply_newtags(&ctrl, rid, zUuid); show_common_info(rid, "uuid:", 1, 0); } |
Deleted src/interwiki.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/json.c.
1 2 | #ifdef FOSSIL_ENABLE_JSON /* | | | | > | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < | 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 | #ifdef FOSSIL_ENABLE_JSON /* ** Copyright (c) 2011 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Code for the JSON API. ** ** For notes regarding the public JSON interface, please see: ** ** https://docs.google.com/document/d/1fXViveNhDbiXgCuE7QDXQOKeFzf2qNUkBEgiUvoqFN4/view ** ** ** Notes for hackers... ** ** Here's how command/page dispatching works: json_page_top() (in HTTP mode) or ** json_cmd_top() (in CLI mode) catch the "json" path/command. Those functions then ** dispatch to a JSON-mode-specific command/page handler with the type fossil_json_f(). ** See the API docs for that typedef (below) for the semantics of the callbacks. ** ** */ #include "VERSION.h" #include "config.h" #include "json.h" #include <assert.h> #include <time.h> #if INTERFACE #include "json_detail.h" /* workaround for apparent enum limitation in makeheaders */ #endif const FossilJsonKeys_ FossilJsonKeys = { "anonymousSeed" /*anonymousSeed*/, "authToken" /*authToken*/, "COMMAND_PATH" /*commandPath*/, "mtime" /*mtime*/, "payload" /* payload */, "requestId" /*requestId*/, "resultCode" /*resultCode*/, "resultText" /*resultText*/, "timestamp" /*timestamp*/ }; /* ** Returns true (non-0) if fossil appears to be running in JSON mode. */ int fossil_has_json(){ return g.json.isJsonMode && (g.isHTTP || g.json.post.o); } /* ** Placeholder /json/XXX page impl for NYI (Not Yet Implemented) |
︙ | ︙ | |||
154 155 156 157 158 159 160 | C(STMT_PREP,"Statement preparation failed"); C(STMT_BIND,"Statement parameter binding failed"); C(STMT_EXEC,"Statement execution/stepping failed"); C(DB_LOCKED,"Database is locked"); C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt"); C(DB_NOT_FOUND,"Fossil repository db file could not be found."); C(DB_NOT_VALID, "Fossil repository db file is not valid."); | | > > > > > > > > > > > | < > | | 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 | C(STMT_PREP,"Statement preparation failed"); C(STMT_BIND,"Statement parameter binding failed"); C(STMT_EXEC,"Statement execution/stepping failed"); C(DB_LOCKED,"Database is locked"); C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt"); C(DB_NOT_FOUND,"Fossil repository db file could not be found."); C(DB_NOT_VALID, "Fossil repository db file is not valid."); C(DB_NEEDS_CHECKOUT, "Command requires a local checkout."); #undef C default: return "Unknown Error"; } } /* ** Implements the cson_data_dest_f() interface and outputs the data to ** a fossil Blob object. pState must be-a initialized (Blob*), to ** which n bytes of src will be appended. **/ int cson_data_dest_Blob(void * pState, void const * src, unsigned int n){ Blob * b = (Blob*)pState; blob_append( b, (char const *)src, (int)n ) /* will die on OOM */; return 0; } /* ** Implements the cson_data_source_f() interface and reads input from ** a fossil Blob object. pState must be-a (Blob*) populated with JSON ** data. */ int cson_data_src_Blob(void * pState, void * dest, unsigned int * n){ Blob * b = (Blob*)pState; *n = blob_read( b, dest, *n ); return 0; } /* ** Convenience wrapper around cson_output() which appends the output ** to pDest. pOpt may be NULL, in which case g.json.outOpt will be used. */ int cson_output_Blob( cson_value const * pVal, Blob * pDest, cson_output_opt const * pOpt ){ return cson_output( pVal, cson_data_dest_Blob, pDest, pOpt ? pOpt : &g.json.outOpt ); } /* ** Convenience wrapper around cson_parse() which reads its input ** from pSrc. pSrc is rewound before parsing. ** ** pInfo may be NULL. If it is not NULL then it will contain details ** about the parse state when this function returns. ** ** On success a new JSON Object or Array is returned (owned by the ** caller). On error NULL is returned. */ cson_value * cson_parse_Blob( Blob * pSrc, cson_parse_info * pInfo ){ cson_value * root = NULL; blob_rewind( pSrc ); cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo ); return root; } /* ** Implements the cson_data_dest_f() interface and outputs the data to ** cgi_append_content(). pState is ignored. **/ |
︙ | ︙ | |||
289 290 291 292 293 294 295 | cson_value * v; char * zStr; va_list vargs; va_start(vargs,fmt); zStr = vmprintf(fmt,vargs); va_end(vargs); v = cson_value_new_string(zStr, strlen(zStr)); | | | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | cson_value * v; char * zStr; va_list vargs; va_start(vargs,fmt); zStr = vmprintf(fmt,vargs); va_end(vargs); v = cson_value_new_string(zStr, strlen(zStr)); free(zStr); return v; } cson_value * json_new_int( i64 v ){ return cson_value_new_integer((cson_int_t)v); } /* ** Gets a POST/POST.payload/GET/COOKIE/ENV value. The returned memory ** is owned by the g.json object (one of its sub-objects). Returns ** NULL if no match is found. ** ** ENV means the system environment (getenv()). ** ** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV. ** ** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE, ** ENV, but the amalgamation of the GET/POST vars makes it difficult ** for me to do that. Since fossil only uses one cookie, cookie ** precedence isn't a real/high-priority problem. */ cson_value * json_getenv( char const * zKey ){ cson_value * rc; rc = g.json.reqPayload.o ? cson_object_get( g.json.reqPayload.o, zKey ) : NULL; |
︙ | ︙ | |||
559 560 561 562 563 564 565 | } /* ** Guesses a RESPONSE Content-Type value based (primarily) on the ** HTTP_ACCEPT header. ** ** It will try to figure out if the client can support | | | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | } /* ** Guesses a RESPONSE Content-Type value based (primarily) on the ** HTTP_ACCEPT header. ** ** It will try to figure out if the client can support ** application/json or application/javascript, and will fall back to ** text/plain if it cannot figure out anything more specific. ** ** Returned memory is static and immutable, but if the environment ** changes after calling this then subsequent calls to this function ** might return different (also static/immutable) values. */ char const * json_guess_content_type(){ char const * cset; char doUtf8; cset = PD("HTTP_ACCEPT_CHARSET",NULL); doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset))) ? 1 : 0; if( g.json.jsonp ){ return doUtf8 ? "application/javascript; charset=utf-8" : "application/javascript"; }else{ /* Content-type If the browser does not sent an ACCEPT for application/json then we fall back to text/plain. */ |
︙ | ︙ | |||
602 603 604 605 606 607 608 | }else{ return "text/plain"; } } } } | < < < < < < < < < < < < < < < < | < < < < < < < < | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | }else{ return "text/plain"; } } } } /* ** Sends pResponse to the output stream as the response object. This ** function does no validation of pResponse except to assert() that it ** is not NULL. The caller is responsible for ensuring that it meets ** API response envelope conventions. ** ** In CLI mode pResponse is sent to stdout immediately. In HTTP ** mode pResponse replaces any current CGI content but cgi_reply() ** is not called to flush the output. ** ** If g.json.jsonp is not NULL then the content type is set to ** application/javascript and the output is wrapped in a jsonp ** wrapper. */ void json_send_response( cson_value const * pResponse ){ assert( NULL != pResponse ); if( g.isHTTP ){ cgi_reset_content(); if( g.json.jsonp ){ cgi_printf("%s(",g.json.jsonp); } cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt ); if( g.json.jsonp ){ cgi_append_content(")",1); } }else{/*CLI mode*/ |
︙ | ︙ | |||
679 680 681 682 683 684 685 | ** ** Must be called once before login_check_credentials() is called or ** we will not be able to replace fossil's internal idea of the auth ** info in time (and future changes to that state may cause unexpected ** results). ** ** The result of this call are cached for future calls. | < < < < < < | | < < < | | | | | | | < | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | ** ** Must be called once before login_check_credentials() is called or ** we will not be able to replace fossil's internal idea of the auth ** info in time (and future changes to that state may cause unexpected ** results). ** ** The result of this call are cached for future calls. */ cson_value * json_auth_token(){ assert(g.json.gc.a && "json_main_bootstrap() was not called!"); if( !g.json.authToken ){ /* Try to get an authorization token from GET parameter, POSTed JSON, or fossil cookie (in that order). */ g.json.authToken = json_getenv(FossilJsonKeys.authToken); if(g.json.authToken && cson_value_is_string(g.json.authToken) && !PD(login_cookie_name(),NULL)){ /* tell fossil to use this login info. FIXME?: because the JSON bits don't carry around login_cookie_name(), there is(?) a potential(?) login hijacking window here. We may need to change the JSON auth token to be in the form: login_cookie_name()=... Then again, the hardened cookie value helps ensure that only a proper key/value match is valid. */ cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) ); }else if( g.isHTTP ){ /* try fossil's conventional cookie. */ /* Reminder: chicken/egg scenario regarding db access in CLI mode because login_cookie_name() needs the db. CLI mode does not use any authentication, so we don't need to support it here. */ |
︙ | ︙ | |||
742 743 744 745 746 747 748 | */ cson_value * json_req_payload_get(char const *pKey){ return g.json.reqPayload.o ? cson_object_get(g.json.reqPayload.o,pKey) : NULL; } | < < < < < < < < < < < < | < < < | < < | < | | < | > | > | > | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | */ cson_value * json_req_payload_get(char const *pKey){ return g.json.reqPayload.o ? cson_object_get(g.json.reqPayload.o,pKey) : NULL; } /* ** Initializes some JSON bits which need to be initialized relatively ** early on. It should only be called from cgi_init() or ** json_cmd_top() (early on in those functions). ** ** Initializes g.json.gc and g.json.param. This code does not (and ** must not) rely on any of the fossil environment having been set ** up. e.g. it must not use cgi_parameter() and friends because this ** must be called before those data are initialized. */ void json_main_bootstrap(){ cson_value * v; assert( (NULL == g.json.gc.v) && "json_main_bootstrap() was called twice!" ); g.json.timerId = fossil_timer_start(); /* g.json.gc is our "garbage collector" - where we put JSON values which need a long lifetime but don't have a logical parent to put them in. */ v = cson_value_new_array(); g.json.gc.v = v; assert(0 != g.json.gc.v); g.json.gc.a = cson_value_get_array(v); assert(0 != g.json.gc.a); cson_value_add_reference(v) /* Needed to allow us to include this value in other JSON containers without transferring ownership to those containers. All other persistent g.json.XXX.v values get appended to g.json.gc.a, and therefore already have a live reference for this purpose. */ ; /* g.json.param holds the JSONized counterpart of fossil's cgi_parameter_xxx() family of data. We store them as JSON, as opposed to using fossil's data directly, because we can retain full type information for data this way (as opposed to it always |
︙ | ︙ | |||
834 835 836 837 838 839 840 | ** for consistency with how json_err() works. */ void json_warn( int code, char const * fmt, ... ){ cson_object * obj = NULL; assert( (code>FSL_JSON_W_START) && (code<FSL_JSON_W_END) && "Invalid warning code."); | | | | 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | ** for consistency with how json_err() works. */ void json_warn( int code, char const * fmt, ... ){ cson_object * obj = NULL; assert( (code>FSL_JSON_W_START) && (code<FSL_JSON_W_END) && "Invalid warning code."); assert(g.json.gc.a && "json_main_bootstrap() was not called!"); if(!g.json.warnings){ g.json.warnings = cson_new_array(); assert((NULL != g.json.warnings) && "Alloc error."); json_gc_add("$WARNINGS",cson_array_value(g.json.warnings)); } obj = cson_new_object(); cson_array_append(g.json.warnings, cson_object_value(obj)); cson_object_set(obj,"code",cson_value_new_integer(code)); if(fmt && *fmt){ /* FIXME: treat NULL fmt as standard warning message for the code, but we don't have those yet. */ va_list vargs; char * msg; va_start(vargs,fmt); msg = vmprintf(fmt,vargs); va_end(vargs); cson_object_set(obj,"text", cson_value_new_string(msg,strlen(msg))); free(msg); } } /* ** Splits zStr (which must not be NULL) into tokens separated by the ** given separator character. If doDeHttp is true then each element ** will be passed through dehttpize(), otherwise they are used |
︙ | ︙ | |||
906 907 908 909 910 911 912 | assert( head != p ); zPart = (char*)fossil_malloc(len+1); memcpy(zPart, head, len); zPart[len] = 0; if(doDeHttp){ dehttpize(zPart); } | < | | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 | assert( head != p ); zPart = (char*)fossil_malloc(len+1); memcpy(zPart, head, len); zPart[len] = 0; if(doDeHttp){ dehttpize(zPart); } if( *zPart ){ /* should only fail if someone manages to url-encoded a NUL byte */ part = cson_value_new_string(zPart, strlen(zPart)); if( 0 != cson_array_append( target, part ) ){ cson_value_free(part); rc = -rc; break; } }else{ |
︙ | ︙ | |||
982 983 984 985 986 987 988 | ** tested this) die with an error if an auth cookie is malformed. ** ** This must be called by the top-level JSON command dispatching code ** before they do any work. ** ** This must only be called once, or an assertion may be triggered. */ | | | | | < | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | ** tested this) die with an error if an auth cookie is malformed. ** ** This must be called by the top-level JSON command dispatching code ** before they do any work. ** ** This must only be called once, or an assertion may be triggered. */ static void json_mode_bootstrap(){ static char once = 0 /* guard against multiple runs */; char const * zPath = P("PATH_INFO"); assert(g.json.gc.a && "json_main_bootstrap() was not called!"); assert( (0==once) && "json_mode_bootstrap() called too many times!"); if( once ){ return; }else{ once = 1; } g.json.isJsonMode = 1; g.json.resultCode = 0; g.json.cmd.offset = -1; g.json.jsonp = PD("jsonp",NULL) /* FIXME: do some sanity checking on g.json.jsonp and ignore it if it is not halfway reasonable. */ ; |
︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 | /* Simulate JSON POST data via input file. Pedantic reminder: error handling does not honor user-supplied g.json.outOpt because outOpt cannot (generically) be configured until after POST-reading is finished. */ FILE * inFile = NULL; char const * jfile = find_option("json-input",NULL,1); | < | > | | < < > | | 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 | /* Simulate JSON POST data via input file. Pedantic reminder: error handling does not honor user-supplied g.json.outOpt because outOpt cannot (generically) be configured until after POST-reading is finished. */ FILE * inFile = NULL; char const * jfile = find_option("json-input",NULL,1); if(!jfile || !*jfile){ break; } inFile = (0==strcmp("-",jfile)) ? stdin : fossil_fopen(jfile,"rb"); if(!inFile){ g.json.resultCode = FSL_JSON_E_FILE_OPEN_FAILED; fossil_panic("Could not open JSON file [%s].",jfile) /* Does not return. */ ; } cgi_parse_POST_JSON(inFile, 0); if( stdin != inFile ){ fclose(inFile); } break; } /* g.json.reqPayload exists only to simplify some of our access to the request payload. We currently only use this in the context of Object payloads, not Arrays, strings, etc. */ g.json.reqPayload.v = cson_object_get( g.json.post.o, FossilJsonKeys.payload ); if( g.json.reqPayload.v ){ g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v ) /* g.json.reqPayload.o may legally be NULL, which means only that g.json.reqPayload.v is-not-a Object. */; } |
︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | } if(!g.json.jsonp){ g.json.jsonp = json_find_option_cstr("jsonp",NULL,NULL); } if(!g.isHTTP){ | | | 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | } if(!g.json.jsonp){ g.json.jsonp = json_find_option_cstr("jsonp",NULL,NULL); } if(!g.isHTTP){ g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/; } {/* set up JSON output formatting options. */ int indent = -1; indent = json_find_option_int("indent",NULL,"I",-1); g.json.outOpt.indentation = (0>indent) ? (g.isHTTP ? 0 : 1) |
︙ | ︙ | |||
1168 1169 1170 1171 1172 1173 1174 | ** ** Note that CLI options are not included in the command path. Use ** find_option() to get those. ** */ char const * json_command_arg(unsigned short ndx){ cson_array * ar = g.json.cmd.a; | | | | < | > | < | < | 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 | ** ** Note that CLI options are not included in the command path. Use ** find_option() to get those. ** */ char const * json_command_arg(unsigned short ndx){ cson_array * ar = g.json.cmd.a; assert((NULL!=ar) && "Internal error. Was json_mode_bootstrap() called?"); assert((g.argc>1) && "Internal error - we never should have gotten this far."); if( g.json.cmd.offset < 0 ){ /* first-time setup. */ short i = 0; #define NEXT cson_string_cstr( \ cson_value_get_string( \ cson_array_get(ar,i) \ )) char const * tok = NEXT; while( tok ){ if( !g.isHTTP/*workaround for "abbreviated name" in CLI mode*/ ? (0==strcmp(g.argv[1],tok)) : (0==strncmp("json",tok,4)) ){ g.json.cmd.offset = i; break; } ++i; tok = NEXT; } } #undef NEXT if(g.json.cmd.offset < 0){ return NULL; }else{ ndx = g.json.cmd.offset + ndx; return cson_string_cstr(cson_value_get_string(cson_array_get( ar, g.json.cmd.offset + ndx ))); } } /* Returns the C-string form of json_auth_token(), or NULL ** if json_auth_token() returns NULL. */ char const * json_auth_token_cstr(){ return cson_value_get_cstr( json_auth_token() ); } /* ** Returns the JsonPageDef with the given name, or NULL if no match is ** found. ** ** head must be a pointer to an array of JsonPageDefs in which the ** last entry has a NULL name. */ JsonPageDef const * json_handler_for_name( char const * name, JsonPageDef const * head ){ JsonPageDef const * pageDef = head; assert( head != NULL ); if(name && *name) for( ; pageDef->name; ++pageDef ){ if( 0 == strcmp(name, pageDef->name) ){ return pageDef; } } |
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 | */ static cson_value * json_response_command_path(){ if(!g.json.cmd.a){ return NULL; }else{ cson_value * rc = NULL; Blob path = empty_blob; | | < | < | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 | */ static cson_value * json_response_command_path(){ if(!g.json.cmd.a){ return NULL; }else{ cson_value * rc = NULL; Blob path = empty_blob; unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/ unsigned int i = 1; for( ; i < aLen; ++i ){ char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i))); if(!part){ #if 1 fossil_warning("Iterating further than expected in %s.", __FILE__); #endif break; } |
︙ | ︙ | |||
1336 1337 1338 1339 1340 1341 1342 | */ cson_value * json_g_to_json(){ cson_object * o = NULL; cson_object * pay = NULL; pay = o = cson_new_object(); #define INT(OBJ,K) cson_object_set(o, #K, json_new_int(OBJ.K)) | | < | 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | */ cson_value * json_g_to_json(){ cson_object * o = NULL; cson_object * pay = NULL; pay = o = cson_new_object(); #define INT(OBJ,K) cson_object_set(o, #K, json_new_int(OBJ.K)) #define CSTR(OBJ,K) cson_object_set(o, #K, OBJ.K ? json_new_string(OBJ.K) : cson_value_null()) #define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null()) VAL(capabilities, json_cap_value()); INT(g, argc); INT(g, isConst); CSTR(g, zConfigDbName); INT(g, repositoryOpen); INT(g, localOpen); |
︙ | ︙ | |||
1457 1458 1459 1460 1461 1462 1463 | cson_object * o = NULL; int rc; resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode); o = cson_new_object(); v = cson_object_value(o); if( ! o ) return NULL; #define SET(K) if(!tmp) goto cleanup; \ | < | > | < | | > | 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 | cson_object * o = NULL; int rc; resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode); o = cson_new_object(); v = cson_object_value(o); if( ! o ) return NULL; #define SET(K) if(!tmp) goto cleanup; \ rc = cson_object_set( o, K, tmp ); \ if(rc) do{\ cson_value_free(tmp); \ tmp = NULL; \ goto cleanup; \ }while(0) tmp = json_new_string(MANIFEST_UUID); SET("fossil"); tmp = json_new_timestamp(-1); SET(FossilJsonKeys.timestamp); |
︙ | ︙ | |||
1492 1493 1494 1495 1496 1497 1498 | } if(g.json.cmd.commandStr){ tmp = json_new_string(g.json.cmd.commandStr); }else{ tmp = json_response_command_path(); } | < < < | | < > < | < > | 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 | } if(g.json.cmd.commandStr){ tmp = json_new_string(g.json.cmd.commandStr); }else{ tmp = json_response_command_path(); } SET("command"); tmp = json_getenv(FossilJsonKeys.requestId); if( tmp ) cson_object_set( o, FossilJsonKeys.requestId, tmp ); if(0){/* these are only intended for my own testing...*/ if(g.json.cmd.v){ tmp = g.json.cmd.v; SET("$commandPath"); } if(g.json.param.v){ tmp = g.json.param.v; SET("$params"); } if(0){/*Only for debugging, add some info to the response.*/ tmp = cson_value_new_integer( g.json.cmd.offset ); cson_object_set( o, "cmd.offset", tmp ); cson_object_set( o, "isCGI", cson_value_new_bool( g.isHTTP ) ); } } if(fossil_timer_is_active(g.json.timerId)){ /* This is, philosophically speaking, not quite the right place for ending the timer, but this is the one function which all of the JSON exit paths use (and they call it after processing, just before they end). */ sqlite3_uint64 span = fossil_timer_stop(g.json.timerId); /* I'm actually seeing sub-uSec runtimes in some tests, but a time of 0 is "just kinda wrong". */ cson_object_set(o,"procTimeUs", cson_value_new_integer((cson_int_t)span)); span /= 1000/*for milliseconds */; cson_object_set(o,"procTimeMs", cson_value_new_integer((cson_int_t)span)); assert(!fossil_timer_is_active(g.json.timerId)); g.json.timerId = -1; } if(g.json.warnings){ tmp = cson_array_value(g.json.warnings); SET("warnings"); } /* Only add the payload to SUCCESS responses. Else delete it. */ if( NULL != payload ){ if( resultCode ){ cson_value_free(payload); payload = NULL; }else{ tmp = payload; SET(FossilJsonKeys.payload); } } if(json_find_option_bool("debugFossilG","json-debug-g",NULL,0) &&(g.perm.Admin||g.perm.Setup)){ tmp = json_g_to_json(); SET("g"); } #undef SET goto ok; cleanup: |
︙ | ︙ | |||
1592 1593 1594 1595 1596 1597 1598 | ** is NULL then json_err_cstr(code) is used. */ void json_err( int code, char const * msg, int alsoOutput ){ int rc = code ? code : (g.json.resultCode ? g.json.resultCode : FSL_JSON_E_UNKNOWN); cson_value * resp = NULL; | < | < | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | ** is NULL then json_err_cstr(code) is used. */ void json_err( int code, char const * msg, int alsoOutput ){ int rc = code ? code : (g.json.resultCode ? g.json.resultCode : FSL_JSON_E_UNKNOWN); cson_value * resp = NULL; rc = json_dumbdown_rc(rc); if( rc && !msg ){ msg = g.zErrMsg; if(!msg){ msg = json_err_cstr(rc); } } resp = json_create_response(rc, msg, NULL); if(!resp){ /* about the only error case here is out-of-memory. DO NOT call fossil_panic() here because that calls this function. */ fprintf(stderr, "%s: Fatal error: could not allocate " "response object.\n", g.argv[0]); fossil_exit(1); } if( g.isHTTP ){ if(alsoOutput){ |
︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 | ** Sets g.json.resultCode and g.zErrMsg, but does not report the error ** via json_err(). Returns the code passed to it. ** ** code must be in the inclusive range 1000..9999. */ int json_set_err( int code, char const * fmt, ... ){ assert( (code>=1000) && (code<=9999) ); | | | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 | ** Sets g.json.resultCode and g.zErrMsg, but does not report the error ** via json_err(). Returns the code passed to it. ** ** code must be in the inclusive range 1000..9999. */ int json_set_err( int code, char const * fmt, ... ){ assert( (code>=1000) && (code<=9999) ); free(g.zErrMsg); g.json.resultCode = code; if(!fmt || !*fmt){ g.zErrMsg = mprintf("%s", json_err_cstr(code)); }else{ va_list vargs; char * msg; va_start(vargs,fmt); |
︙ | ︙ | |||
1786 1787 1788 1789 1790 1791 1792 | cson_value * json_tags_for_checkin_rid(int rid, int propagatingOnly){ cson_value * v = NULL; char * tags = info_tags_of_checkin(rid, propagatingOnly); if(tags){ if(*tags){ v = json_string_split2(tags,',',0); } | | | 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 | cson_value * json_tags_for_checkin_rid(int rid, int propagatingOnly){ cson_value * v = NULL; char * tags = info_tags_of_checkin(rid, propagatingOnly); if(tags){ if(*tags){ v = json_string_split2(tags,',',0); } free(tags); } return v; } /* ** Returns a "new" value representing the boolean value of zVal ** (false if zVal is NULL). Note that cson does not really allocate |
︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 | : cson_value_false(); } /* ** Impl of /json/resultCodes ** */ | | | | | | < | 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 | : cson_value_false(); } /* ** Impl of /json/resultCodes ** */ cson_value * json_page_resultCodes(){ cson_array * list = cson_new_array(); cson_object * obj = NULL; cson_string * kRC; cson_string * kSymbol; cson_string * kNumber; cson_string * kDesc; cson_array_reserve( list, 35 ); kRC = cson_new_string("resultCode",10); kSymbol = cson_new_string("cSymbol",7); kNumber = cson_new_string("number",6); kDesc = cson_new_string("description",11); #define C(K) obj = cson_new_object(); \ cson_object_set_s(obj, kRC, json_new_string(json_rc_cstr(FSL_JSON_E_##K)) ); \ cson_object_set_s(obj, kSymbol, json_new_string("FSL_JSON_E_"#K) ); \ cson_object_set_s(obj, kNumber, cson_value_new_integer(FSL_JSON_E_##K) ); \ cson_object_set_s(obj, kDesc, json_new_string(json_err_cstr(FSL_JSON_E_##K))); \ cson_array_append( list, cson_object_value(obj) ); obj = NULL; C(GENERIC); C(INVALID_REQUEST); C(UNKNOWN_COMMAND); C(UNKNOWN); C(TIMEOUT); |
︙ | ︙ | |||
1876 1877 1878 1879 1880 1881 1882 | /* ** /json/version implementation. ** ** Returns the payload object (owned by the caller). */ | | | 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | /* ** /json/version implementation. ** ** Returns the payload object (owned by the caller). */ cson_value * json_page_version(){ cson_value * jval = NULL; cson_object * jobj = NULL; jval = cson_value_new_object(); jobj = cson_value_get_object(jval); #define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X))) FSET(MANIFEST_UUID,"manifestUuid"); FSET(MANIFEST_VERSION,"manifestVersion"); |
︙ | ︙ | |||
1930 1931 1932 1933 1934 1935 1936 | ** ** Returned object contains details about the "capabilities" of the ** current user (what he may/may not do). ** ** This is primarily intended for debuggering, but may have ** a use in client code. (?) */ | | | 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 | ** ** Returned object contains details about the "capabilities" of the ** current user (what he may/may not do). ** ** This is primarily intended for debuggering, but may have ** a use in client code. (?) */ cson_value * json_page_cap(){ cson_value * payload = cson_value_new_object(); cson_value * sub = cson_value_new_object(); Stmt q; cson_object * obj = cson_value_get_object(payload); db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", g.userUid); if( db_step(&q)==SQLITE_ROW ){ /* reminder: we don't use g.zLogin because it's 0 for the guest |
︙ | ︙ | |||
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 | db_finalize(&q); cson_object_set( obj, "permissionFlags", sub ); obj = cson_value_get_object(sub); #define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X)) ADD(Setup,"setup"); ADD(Admin,"admin"); ADD(Password,"password"); ADD(Query,"query"); /* don't think this one is actually used */ ADD(Write,"checkin"); ADD(Read,"checkout"); ADD(Hyperlink,"history"); ADD(Clone,"clone"); ADD(RdWiki,"readWiki"); | > | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 | db_finalize(&q); cson_object_set( obj, "permissionFlags", sub ); obj = cson_value_get_object(sub); #define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X)) ADD(Setup,"setup"); ADD(Admin,"admin"); ADD(Delete,"delete"); ADD(Password,"password"); ADD(Query,"query"); /* don't think this one is actually used */ ADD(Write,"checkin"); ADD(Read,"checkout"); ADD(Hyperlink,"history"); ADD(Clone,"clone"); ADD(RdWiki,"readWiki"); |
︙ | ︙ | |||
1988 1989 1990 1991 1992 1993 1994 | ADD(WrForum,"writeForum"); ADD(WrTForum,"writeTrustedForum"); ADD(ModForum,"moderateForum"); ADD(AdminForum,"adminForum"); ADD(EmailAlert,"emailAlert"); ADD(Announce,"announce"); ADD(Debug,"debug"); | < | | < | | | | 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 | ADD(WrForum,"writeForum"); ADD(WrTForum,"writeTrustedForum"); ADD(ModForum,"moderateForum"); ADD(AdminForum,"adminForum"); ADD(EmailAlert,"emailAlert"); ADD(Announce,"announce"); ADD(Debug,"debug"); #undef ADD return payload; } /* ** Implementation of the /json/stat page/command. ** */ cson_value * json_page_stat(){ i64 t, fsize; int n, m; int full; enum { BufLen = 1000 }; char zBuf[BufLen]; cson_value * jv = NULL; cson_object * jo = NULL; cson_value * jv2 = NULL; cson_object * jo2 = NULL; char * zTmp = NULL; if( !g.perm.Read ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'o' permissions."); return NULL; } full = json_find_option_bool("full",NULL,"f", json_find_option_bool("verbose",NULL,"v",0)); #define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf))); jv = cson_value_new_object(); jo = cson_value_get_object(jv); zTmp = db_get("project-name",NULL); cson_object_set(jo, "projectName", json_new_string(zTmp)); free(zTmp); zTmp = db_get("project-description",NULL); cson_object_set(jo, "projectDescription", json_new_string(zTmp)); free(zTmp); zTmp = NULL; fsize = file_size(g.zRepositoryName, ExtFILE); cson_object_set(jo, "repositorySize", cson_value_new_integer((cson_int_t)fsize)); if(full){ n = db_int(0, "SELECT count(*) FROM blob"); m = db_int(0, "SELECT count(*) FROM delta"); cson_object_set(jo, "blobCount", cson_value_new_integer((cson_int_t)n)); cson_object_set(jo, "deltaCount", cson_value_new_integer((cson_int_t)m)); |
︙ | ︙ | |||
2078 2079 2080 2081 2082 2083 2084 | }/*full*/ n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" " + 0.99"); cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n)); cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425)); sqlite3_snprintf(BufLen, zBuf, db_get("project-code","")); SETBUF(jo, "projectCode"); | | < | | | < | < | < | | < | < | 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 | }/*full*/ n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" " + 0.99"); cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n)); cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425)); sqlite3_snprintf(BufLen, zBuf, db_get("project-code","")); SETBUF(jo, "projectCode"); cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME))); jv2 = cson_value_new_object(); jo2 = cson_value_get_object(jv2); cson_object_set(jo, "sqlite", jv2); sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)", sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion()); SETBUF(jo2, "version"); cson_object_set(jo2, "pageCount", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.page_count"))); cson_object_set(jo2, "pageSize", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.page_size"))); cson_object_set(jo2, "freeList", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.freelist_count"))); sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA repository.encoding")); SETBUF(jo2, "encoding"); sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA repository.journal_mode")); cson_object_set(jo2, "journalMode", *zBuf ? cson_value_new_string(zBuf, strlen(zBuf)) : cson_value_null()); return jv; #undef SETBUF } |
︙ | ︙ | |||
2184 2185 2186 2187 2188 2189 2190 | } } /* ** Impl of /json/rebuild. Requires admin privileges. */ | | | | | | | | | | | | | | | | | | | < < | 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 | } } /* ** Impl of /json/rebuild. Requires admin privileges. */ static cson_value * json_page_rebuild(){ if( !g.perm.Admin ){ json_set_err(FSL_JSON_E_DENIED,"Requires 'a' privileges."); return NULL; }else{ /* Reminder: the db_xxx() ops "should" fail via the fossil core error handlers, which will cause a JSON error and exit(). i.e. we don't handle the errors here. TODO: confirm that all these db routine fail gracefully in JSON mode. On large repos (e.g. fossil's) this operation is likely to take longer than the client timeout, which will cause it to fail (but it's sqlite3, so it'll fail gracefully). */ db_close(1); db_open_repository(g.zRepositoryName); db_begin_transaction(); rebuild_db(0, 0, 0); db_end_transaction(0); return NULL; } } /* ** Impl of /json/g. Requires admin/setup rights. */ static cson_value * json_page_g(){ if(!g.perm.Admin || !g.perm.Setup){ json_set_err(FSL_JSON_E_DENIED, "Requires 'a' or 's' privileges."); return NULL; } return json_g_to_json(); } /* Impl in json_login.c. */ cson_value * json_page_anon_password(); /* Impl in json_artifact.c. */ cson_value * json_page_artifact(); /* Impl in json_branch.c. */ cson_value * json_page_branch(); /* Impl in json_diff.c. */ cson_value * json_page_diff(); /* Impl in json_dir.c. */ cson_value * json_page_dir(); /* Impl in json_login.c. */ cson_value * json_page_login(); /* Impl in json_login.c. */ cson_value * json_page_logout(); /* Impl in json_query.c. */ cson_value * json_page_query(); /* Impl in json_report.c. */ cson_value * json_page_report(); /* Impl in json_tag.c. */ cson_value * json_page_tag(); /* Impl in json_user.c. */ cson_value * json_page_user(); /* Impl in json_config.c. */ cson_value * json_page_config(); /* Impl in json_finfo.c. */ cson_value * json_page_finfo(); /* Impl in json_status.c. */ cson_value * json_page_status(); /* ** Mapping of names to JSON pages/commands. Each name is a subpath of ** /json (in CGI mode) or a subcommand of the json command in CLI mode */ static const JsonPageDef JsonPageDefs[] = { /* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */ {"anonymousPassword", json_page_anon_password, 0}, {"artifact", json_page_artifact, 0}, {"branch", json_page_branch,0}, {"cap", json_page_cap, 0}, {"config", json_page_config, 0 }, {"diff", json_page_diff, 0}, {"dir", json_page_dir, 0}, {"finfo", json_page_finfo, 0}, {"g", json_page_g, 0}, {"HAI",json_page_version,0}, {"login",json_page_login,0}, {"logout",json_page_logout,0}, {"query",json_page_query,0}, {"rebuild",json_page_rebuild,0}, {"report", json_page_report, 0}, {"resultCodes", json_page_resultCodes,0}, {"stat",json_page_stat,0}, {"status", json_page_status, 0}, {"tag", json_page_tag,0}, /*{"ticket", json_page_nyi,0},*/ {"timeline", json_page_timeline,0}, {"user",json_page_user,0}, {"version",json_page_version,0}, |
︙ | ︙ | |||
2331 2332 2333 2334 2335 2336 2337 | ** ** Pages under /json/... must be entered into JsonPageDefs. ** This function dispatches them, and is the HTTP equivalent of ** json_cmd_top(). */ void json_page_top(void){ char const * zCommand; | | | | 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 | ** ** Pages under /json/... must be entered into JsonPageDefs. ** This function dispatches them, and is the HTTP equivalent of ** json_cmd_top(). */ void json_page_top(void){ char const * zCommand; assert(g.json.gc.a && "json_main_bootstrap() was not called!"); json_mode_bootstrap(); zCommand = json_command_arg(1); if(!zCommand || !*zCommand){ json_dispatch_missing_args_err( JsonPageDefs, "No command (sub-path) specified." " Try one of: "); return; } |
︙ | ︙ | |||
2403 2404 2405 2406 2407 2408 2409 | and they all default to false. We enable them here because (A) fossil doesn't use them in local mode but (B) having them set gives us one less difference in the CLI/CGI/Server-mode JSON handling. */ ; | | | | 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 | and they all default to false. We enable them here because (A) fossil doesn't use them in local mode but (B) having them set gives us one less difference in the CLI/CGI/Server-mode JSON handling. */ ; json_main_bootstrap(); json_mode_bootstrap(); if( 2 > cson_array_length_get(g.json.cmd.a) ){ goto usage; } #if 0 json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing."); json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again."); #endif |
︙ | ︙ |
Changes to src/json_artifact.c.
︙ | ︙ | |||
209 210 211 212 213 214 215 | } /* ** Sub-impl of /json/artifact for check-ins. */ static cson_value * json_artifact_ci( cson_object * zParent, int rid ){ if(!g.perm.Read){ | | < | < | | < | | 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 256 257 258 259 260 261 262 263 264 265 266 | } /* ** Sub-impl of /json/artifact for check-ins. */ static cson_value * json_artifact_ci( cson_object * zParent, int rid ){ if(!g.perm.Read){ json_set_err( FSL_JSON_E_DENIED, "Viewing check-ins requires 'o' privileges." ); return NULL; }else{ cson_value * artV = json_artifact_for_ci(rid, 1); cson_object * art = cson_value_get_object(artV); if(art){ cson_object_merge( zParent, art, CSON_MERGE_REPLACE ); cson_free_object(art); } return cson_object_value(zParent); } } /* ** Internal mapping of /json/artifact/FOO commands/callbacks. */ static ArtifactDispatchEntry ArtifactDispatchList[] = { {"checkin", json_artifact_ci}, {"file", json_artifact_file}, {"tag", NULL}, {"ticket", json_artifact_ticket}, {"wiki", json_artifact_wiki}, /* Final entry MUST have a NULL name. */ {NULL,NULL} }; /* ** Internal helper which returns: ** ** If the "format" (CLI: -f) flag is set function returns the same as ** json_wiki_get_content_format_flag(), else it returns true (non-0) ** if either the includeContent (HTTP) or -content|-c boolean flags ** (CLI) are set. */ static int json_artifact_get_content_format_flag(){ enum { MagicValue = -9 }; int contentFormat = json_wiki_get_content_format_flag(MagicValue); if(MagicValue == contentFormat){ contentFormat = json_find_option_bool("includeContent","content","c",0) /* deprecated */ ? -1 : 0; } return contentFormat; } extern int json_wiki_get_content_format_flag( int defaultValue ) /* json_wiki.c */; cson_value * json_artifact_wiki(cson_object * zParent, int rid){ if( ! g.perm.RdWiki ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'j' privileges."); return NULL; }else{ |
︙ | ︙ | |||
380 381 382 383 384 385 386 | ); /* TODO: add a "state" flag for the file in each check-in, e.g. "modified", "new", "deleted". */ checkin_arr = cson_new_array(); cson_object_set(pay, "checkins", cson_array_value(checkin_arr)); while( (SQLITE_ROW==db_step(&q) ) ){ | | < | | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | ); /* TODO: add a "state" flag for the file in each check-in, e.g. "modified", "new", "deleted". */ checkin_arr = cson_new_array(); cson_object_set(pay, "checkins", cson_array_value(checkin_arr)); while( (SQLITE_ROW==db_step(&q) ) ){ cson_object * row = cson_value_get_object(cson_sqlite3_row_to_object(q.pStmt)); /* FIXME: move this isNew/isDel stuff into an SQL CASE statement. */ char const isNew = cson_value_get_bool(cson_object_get(row,"isNew")); char const isDel = cson_value_get_bool(cson_object_get(row,"isDel")); cson_object_set(row, "isNew", NULL); cson_object_set(row, "isDel", NULL); cson_object_set(row, "state", json_new_string(json_artifact_status_to_string(isNew, isDel))); cson_array_append( checkin_arr, cson_object_value(row) ); } db_finalize(&q); return cson_object_value(pay); } /* ** Impl of /json/artifact. This basically just determines the type of ** an artifact and forwards the real work to another function. */ cson_value * json_page_artifact(){ cson_object * pay = NULL; char const * zName = NULL; char const * zType = NULL; char const * zUuid = NULL; cson_value * entry = NULL; Blob uuid = empty_blob; int rc; |
︙ | ︙ | |||
479 480 481 482 483 484 485 | if(0!=fossil_strcmp(dispatcher->name, zType)){ continue; }else{ entry = (*dispatcher->func)(pay, rid); break; } } | < < < < < < < < | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | if(0!=fossil_strcmp(dispatcher->name, zType)){ continue; }else{ entry = (*dispatcher->func)(pay, rid); break; } } if(!g.json.resultCode){ assert( NULL != entry ); assert( NULL != zType ); cson_object_set( pay, "type", json_new_string(zType) ); cson_object_set( pay, "uuid", json_new_string(zUuid) ); /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/ /*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/ |
︙ | ︙ |
Changes to src/json_branch.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "json_branch.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | | 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 | #include "json_branch.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_branch_list(); static cson_value * json_branch_create(); /* ** Mapping of /json/branch/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_Branch[] = { {"create", json_branch_create, 0}, {"list", json_branch_list, 0}, {"new", json_branch_create, -1/* for compat with non-JSON branch command.*/}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implements the /json/branch family of pages/commands. Far from ** complete. ** */ cson_value * json_page_branch(){ return json_page_dispatch_helper(&JsonPageDefs_Branch[0]); } /* ** Impl for /json/branch/list ** ** ** CLI mode options: ** ** --range X | -r X, where X is one of (open,closed,all) ** (only the first letter is significant, default=open). ** -a (same as --range a) ** -c (same as --range c) ** ** HTTP mode options: ** ** "range" GET/POST.payload parameter. FIXME: currently we also use ** POST, but really want to restrict this to POST.payload. */ static cson_value * json_branch_list(){ cson_value * payV; cson_object * pay; cson_value * listV; cson_array * list; char const * range = NULL; int branchListFlags = BRL_OPEN_ONLY; char * sawConversionError = NULL; Stmt q = empty_Stmt; if( !g.perm.Read ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'o' permissions."); return NULL; } payV = cson_value_new_object(); pay = cson_value_get_object(payV); listV = cson_value_new_array(); list = cson_value_get_array(listV); if(fossil_has_json()){ range = json_getenv_cstr("range"); } range = json_find_option_cstr("range",NULL,"r"); if((!range||!*range) && !g.isHTTP){ range = find_option("all","a",0); if(range && *range){ range = "a"; |
︙ | ︙ | |||
126 127 128 129 130 131 132 | : 0; if(zCurrent){ cson_object_set(pay,"current",json_new_string(zCurrent)); } } | | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | : 0; if(zCurrent){ cson_object_set(pay,"current",json_new_string(zCurrent)); } } branch_prepare_list_query(&q, branchListFlags); cson_object_set(pay,"branches",listV); while((SQLITE_ROW==db_step(&q))){ cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0); if(v){ cson_array_append(list,v); }else if(!sawConversionError){ sawConversionError = mprintf("Column-to-json failed @ %s:%d", |
︙ | ︙ | |||
152 153 154 155 156 157 158 | /* ** Parameters for the create-branch operation. */ typedef struct BranchCreateOptions{ char const * zName; char const * zBasis; char const * zColor; | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | /* ** Parameters for the create-branch operation. */ typedef struct BranchCreateOptions{ char const * zName; char const * zBasis; char const * zColor; char isPrivate; /** Might be set to an error string by json_branch_new(). */ char const * rcErrMsg; } BranchCreateOptions; |
︙ | ︙ | |||
195 196 197 198 199 200 201 | char *zUuid; /* Artifact ID of origin */ Stmt q; /* Generic query */ char *zDate; /* Date that branch was created */ char *zComment; /* Check-in comment for the new branch */ Blob branch; /* manifest for the new branch */ Manifest *pParent; /* Parsed parent manifest */ Blob mcksum; /* Self-checksum on the manifest */ | < < < < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | char *zUuid; /* Artifact ID of origin */ Stmt q; /* Generic query */ char *zDate; /* Date that branch was created */ char *zComment; /* Check-in comment for the new branch */ Blob branch; /* manifest for the new branch */ Manifest *pParent; /* Parsed parent manifest */ Blob mcksum; /* Self-checksum on the manifest */ /* fossil branch new name */ if( zBranch==0 || zBranch[0]==0 ){ zOpt->rcErrMsg = "Branch name may not be null/empty."; return FSL_JSON_E_INVALID_ARGS; } if( db_exists( "SELECT 1 FROM tagxref" |
︙ | ︙ | |||
263 264 265 266 267 268 269 | blob_appendf(&branch, "R %s\n", pParent->zRepoCksum); } manifest_destroy(pParent); /* Add the symbolic branch name and the "branch" tag to identify ** this as a new branch */ if( content_is_private(rootid) ) zOpt->isPrivate = 1; | | > > > | | > > > > | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | blob_appendf(&branch, "R %s\n", pParent->zRepoCksum); } manifest_destroy(pParent); /* Add the symbolic branch name and the "branch" tag to identify ** this as a new branch */ if( content_is_private(rootid) ) zOpt->isPrivate = 1; if( zOpt->isPrivate && zColor==0 ) zColor = "#fec084"; if( zColor!=0 ){ blob_appendf(&branch, "T *bgcolor * %F\n", zColor); } blob_appendf(&branch, "T *branch * %F\n", zBranch); blob_appendf(&branch, "T *sym-%F *\n", zBranch); if( zOpt->isPrivate ){ blob_appendf(&branch, "T +private *\n"); } /* Cancel all other symbolic tags */ db_prepare(&q, "SELECT tagname FROM tagxref, tag" " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid" " AND tagtype>0 AND tagname GLOB 'sym-*'" " ORDER BY tagname", rootid); while( db_step(&q)==SQLITE_ROW ){ const char *zTag = db_column_text(&q, 0); blob_appendf(&branch, "T -%F *\n", zTag); } db_finalize(&q); blob_appendf(&branch, "U %F\n", g.zLogin); md5sum_blob(&branch, &mcksum); blob_appendf(&branch, "Z %b\n", &mcksum); brid = content_put(&branch); if( brid==0 ){ fossil_panic("Problem committing manifest: %s", g.zErrMsg); } db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid); if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){ fossil_panic("%s", g.zErrMsg); } assert( blob_is_reset(&branch) ); content_deltify(rootid, &brid, 1, 0); if( zNewRid ){ *zNewRid = brid; } /* Commit */ db_end_transaction(0); #if 0 /* Do an autosync push, if requested */ /* arugable for JSON mode? */ if( !g.isHTTP && !isPrivate ) autosync(SYNC_PUSH); #endif return 0; } /* ** Impl of /json/branch/create. */ static cson_value * json_branch_create(){ cson_value * payV = NULL; cson_object * pay = NULL; int rc = 0; BranchCreateOptions opt; char * zUuid = NULL; int rid = 0; if( !g.perm.Write ){ |
︙ | ︙ | |||
333 334 335 336 337 338 339 | } if(!opt.zName){ opt.zName = json_command_arg(g.json.dispatchDepth+1); } if(!opt.zName){ | | < | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | } if(!opt.zName){ opt.zName = json_command_arg(g.json.dispatchDepth+1); } if(!opt.zName){ json_set_err(FSL_JSON_E_MISSING_ARGS, "'name' parameter was not specified." ); return NULL; } opt.zColor = json_find_option_cstr("bgColor","bgcolor",NULL); opt.zBasis = json_find_option_cstr("basis",NULL,NULL); if(!opt.zBasis && !g.isHTTP){ opt.zBasis = json_command_arg(g.json.dispatchDepth+2); |
︙ | ︙ |
Changes to src/json_config.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_config.h" #if INTERFACE #include "json_detail.h" #endif | | | < < < < < < < < < < < < | < < < < < < < < < < > | 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 | #include "config.h" #include "json_config.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_config_get(); static cson_value * json_config_save(); /* ** Mapping of /json/config/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_Config[] = { {"get", json_config_get, 0}, {"save", json_config_save, 0}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implements the /json/config family of pages/commands. ** */ cson_value * json_page_config(){ return json_page_dispatch_helper(&JsonPageDefs_Config[0]); } /* ** JSON-internal mapping of config options to config groups. This is ** mostly a copy of the config options in configure.c, but that data ** is private and cannot be re-used directly here. */ static const struct JsonConfigProperty { char const * name; int groupMask; } JsonConfigProperties[] = { { "css", CONFIGSET_CSS }, { "header", CONFIGSET_SKIN }, { "footer", CONFIGSET_SKIN }, { "details", CONFIGSET_SKIN }, { "logo-mimetype", CONFIGSET_SKIN }, { "logo-image", CONFIGSET_SKIN }, { "background-mimetype", CONFIGSET_SKIN }, { "background-image", CONFIGSET_SKIN }, { "timeline-block-markup", CONFIGSET_SKIN }, { "timeline-max-comment", CONFIGSET_SKIN }, { "timeline-plaintext", CONFIGSET_SKIN }, { "adunit", CONFIGSET_SKIN }, { "adunit-omit-if-admin", CONFIGSET_SKIN }, { "adunit-omit-if-user", CONFIGSET_SKIN }, { "project-name", CONFIGSET_PROJ }, { "short-project-name", CONFIGSET_PROJ }, { "project-description", CONFIGSET_PROJ }, { "index-page", CONFIGSET_PROJ }, { "manifest", CONFIGSET_PROJ }, { "binary-glob", CONFIGSET_PROJ }, { "clean-glob", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "keep-glob", CONFIGSET_PROJ }, { "crlf-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "allow-symlinks", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, { "ticket-change", CONFIGSET_TKT }, { "ticket-newpage", CONFIGSET_TKT }, { "ticket-viewpage", CONFIGSET_TKT }, |
︙ | ︙ | |||
123 124 125 126 127 128 129 | }; /* ** Impl of /json/config/get. Requires setup rights. ** */ | | | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | }; /* ** Impl of /json/config/get. Requires setup rights. ** */ static cson_value * json_config_get(){ cson_object * pay = NULL; Stmt q = empty_Stmt; Blob sql = empty_blob; char const * zName = NULL; int confMask = 0; char optSkinBackups = 0; unsigned int i; |
︙ | ︙ | |||
199 200 201 202 203 204 205 | } /* ** Impl of /json/config/save. ** ** TODOs: */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 178 179 180 181 182 183 184 185 186 187 188 189 | } /* ** Impl of /json/config/save. ** ** TODOs: */ static cson_value * json_config_save(){ json_set_err(FSL_JSON_E_NYI, NULL); return NULL; } #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/json_detail.h.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** */ | < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** */ #include "cson_amalgamation.h" /** FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest "significant" change to the JSON API (a change in an interface or new functionality). It is sent as part of the /json/version request. We could arguably add it to each response or even add a version number to each response type, allowing very fine (too |
︙ | ︙ | |||
53 54 55 56 57 58 59 | ** value. ** ** Maintenance reminder: when entries are added to this list, update ** the code in json_page_resultCodes() and json_err_cstr() (both in ** json.c)! ** */ | < | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | ** value. ** ** Maintenance reminder: when entries are added to this list, update ** the code in json_page_resultCodes() and json_err_cstr() (both in ** json.c)! ** */ enum FossilJsonCodes { FSL_JSON_W_START = 0, FSL_JSON_W_UNKNOWN /*+1*/, FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/, FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/, FSL_JSON_W_STRING_TO_ARRAY_FAILED /*+4*/, FSL_JSON_W_TAG_NOT_FOUND /*+5*/, |
︙ | ︙ | |||
147 148 149 150 151 152 153 | ** It is imperative that NO callback functions EVER output ANYTHING to ** stdout, as that will effectively corrupt any JSON output, and ** almost certainly will corrupt any HTTP response headers. Output ** sent to stderr ends up in my apache log, so that might be useful ** for debugging in some cases, but no such code should be left ** enabled for non-debugging builds. */ | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** It is imperative that NO callback functions EVER output ANYTHING to ** stdout, as that will effectively corrupt any JSON output, and ** almost certainly will corrupt any HTTP response headers. Output ** sent to stderr ends up in my apache log, so that might be useful ** for debugging in some cases, but no such code should be left ** enabled for non-debugging builds. */ typedef cson_value * (*fossil_json_f)(); /* ** Holds name-to-function mappings for JSON page/command dispatching. ** ** Internally we model page dispatching lists as arrays of these ** objects, where the final entry in the array has a NULL name value ** to act as the end-of-list sentinel. |
︙ | ︙ | |||
258 259 260 261 262 263 264 | ** b) We are running in JSON CLI mode, but no POST data has been fed ** in. ** ** Whether or not we need to take args from CLI or POST data makes a ** difference in argument/parameter handling in many JSON routines, ** and thus this distinction. */ | | < | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | ** b) We are running in JSON CLI mode, but no POST data has been fed ** in. ** ** Whether or not we need to take args from CLI or POST data makes a ** difference in argument/parameter handling in many JSON routines, ** and thus this distinction. */ int fossil_has_json(); enum json_get_changed_files_flags { json_get_changed_files_ELIDE_PARENT = 1 << 0 }; #endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/ #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/json_diff.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | */ cson_value * json_generate_diff(const char *zFrom, const char *zTo, int nContext, char fSbs, char fHtml){ int fromid; int toid; int outLen; | < > | < | | 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 | */ cson_value * json_generate_diff(const char *zFrom, const char *zTo, int nContext, char fSbs, char fHtml){ int fromid; int toid; int outLen; Blob from = empty_blob, to = empty_blob, out = empty_blob; cson_value * rc = NULL; int flags = (DIFF_CONTEXT_MASK & nContext) | (fSbs ? DIFF_SIDEBYSIDE : 0) | (fHtml ? DIFF_HTML : 0); fromid = name_to_typed_rid(zFrom, "*"); if(fromid<=0){ json_set_err(FSL_JSON_E_UNRESOLVED_UUID, "Could not resolve 'from' ID."); return NULL; } toid = name_to_typed_rid(zTo, "*"); if(toid<=0){ json_set_err(FSL_JSON_E_UNRESOLVED_UUID, "Could not resolve 'to' ID."); return NULL; } content_get(fromid, &from); content_get(toid, &to); blob_zero(&out); text_diff(&from, &to, &out, 0, flags); blob_reset(&from); blob_reset(&to); outLen = blob_size(&out); if(outLen>=0){ rc = cson_value_new_string(blob_buffer(&out), (unsigned int)blob_size(&out)); } |
︙ | ︙ | |||
81 82 83 84 85 86 87 | ** v1=1st version to diff ** v2=2nd version to diff ** ** Can come from GET, POST.payload, CLI -v1/-v2 or as positional ** parameters following the command name (in HTTP and CLI modes). ** */ | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | ** v1=1st version to diff ** v2=2nd version to diff ** ** Can come from GET, POST.payload, CLI -v1/-v2 or as positional ** parameters following the command name (in HTTP and CLI modes). ** */ cson_value * json_page_diff(){ cson_object * pay = NULL; cson_value * v = NULL; char const * zFrom; char const * zTo; int nContext = 0; char doSBS; char doHtml; |
︙ | ︙ |
Changes to src/json_dir.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_dir.h" #if INTERFACE #include "json_detail.h" #endif | | | | | 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 | #include "config.h" #include "json_dir.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_page_dir_list(); /* ** Mapping of /json/wiki/XXX commands/paths to callbacks. */ #if 0 /* TODO: Not used? */ static const JsonPageDef JsonPageDefs_Dir[] = { /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; #endif #if 0 /* TODO: Not used? */ static char const * json_dir_path_extra(){ static char const * zP = NULL; if( !zP ){ zP = g.zExtra; while(zP && *zP && ('/'==*zP)){ ++zP; } } return zP; } #endif /* ** Impl of /json/dir. 98% of it was taken directly ** from browse.c::page_dir() */ static cson_value * json_page_dir_list(){ cson_object * zPayload = NULL; /* return value */ cson_array * zEntries = NULL; /* accumulated list of entries. */ cson_object * zEntry = NULL; /* a single dir/file entry. */ cson_array * keyStore = NULL; /* garbage collector for shared strings. */ cson_string * zKeyName = NULL; cson_string * zKeySize = NULL; cson_string * zKeyIsDir = NULL; |
︙ | ︙ | |||
279 280 281 282 283 284 285 | return cson_object_value(zPayload); } /* ** Implements the /json/dir family of pages/commands. ** */ | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | return cson_object_value(zPayload); } /* ** Implements the /json/dir family of pages/commands. ** */ cson_value * json_page_dir(){ #if 1 return json_page_dir_list(); #else return json_page_dispatch_helper(&JsonPageDefs_Dir[0]); #endif } #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/json_finfo.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | #include "json_detail.h" #endif /* ** Implements the /json/finfo page/command. ** */ | | | < | | | | | 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 | #include "json_detail.h" #endif /* ** Implements the /json/finfo page/command. ** */ cson_value * json_page_finfo(){ cson_object * pay = NULL; cson_array * checkins = NULL; char const * zFilename = NULL; Blob sql = empty_blob; Stmt q = empty_Stmt; char const * zAfter = NULL; char const * zBefore = NULL; int limit = -1; int currentRow = 0; char const * zCheckin = NULL; char sort = -1; if(!g.perm.Read){ json_set_err(FSL_JSON_E_DENIED,"Requires 'o' privileges."); return NULL; } json_warn( FSL_JSON_W_UNKNOWN, "Achtung: the output of the finfo command is up for change."); /* For the "name" argument we have to jump through some hoops to make sure that we don't get the fossil-internally-assigned "name" option. */ zFilename = json_find_option_cstr2("name",NULL,NULL, g.json.dispatchDepth+1); if(!zFilename || !*zFilename){ json_set_err(FSL_JSON_E_MISSING_ARGS, "Missing 'name' parameter."); return NULL; } if(0==db_int(0,"SELECT 1 FROM filename WHERE name=%Q",zFilename)){ json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND, "File entry not found."); return NULL; } zBefore = json_find_option_cstr("before",NULL,"b"); zAfter = json_find_option_cstr("after",NULL,"a"); limit = json_find_option_int("limit",NULL,"n", -1); zCheckin = json_find_option_cstr("checkin",NULL,"ci"); blob_append_sql(&sql, /*0*/ "SELECT b.uuid," /*1*/ " ci.uuid," /*2*/ " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */ /*3*/ " cast(strftime('%%s',event.mtime) AS INTEGER)," /*4*/ " coalesce(event.euser, event.user)," /*5*/ " coalesce(event.ecomment, event.comment)," /*6*/ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ /*7*/ " event.bgcolor," /*8*/ " b.size," /*9*/ " (mlink.pid==0) AS isNew," |
︙ | ︙ | |||
87 88 89 90 91 92 93 | ); if( zCheckin && *zCheckin ){ char * zU = NULL; int rc = name_to_uuid2( zCheckin, "ci", &zU ); /*printf("zCheckin=[%s], zU=[%s]", zCheckin, zU);*/ if(rc<=0){ | | < | | < | < | < | | | 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 | ); if( zCheckin && *zCheckin ){ char * zU = NULL; int rc = name_to_uuid2( zCheckin, "ci", &zU ); /*printf("zCheckin=[%s], zU=[%s]", zCheckin, zU);*/ if(rc<=0){ json_set_err((rc<0) ? FSL_JSON_E_AMBIGUOUS_UUID : FSL_JSON_E_RESOURCE_NOT_FOUND, "Check-in UUID %s.", (rc<0) ? "is ambiguous" : "not found"); blob_reset(&sql); return NULL; } blob_append_sql(&sql, " AND ci.uuid='%q'", zU); free(zU); }else{ if( zAfter && *zAfter ){ blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zAfter); sort = 1; }else if( zBefore && *zBefore ){ blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zBefore); } } blob_append_sql(&sql," ORDER BY event.mtime %s /*sort*/", (sort>0?"ASC":"DESC")); /*printf("SQL=\n%s\n",blob_str(&sql));*/ db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); pay = cson_new_object(); cson_object_set(pay, "name", json_new_string(zFilename)); if( limit > 0 ){ cson_object_set(pay, "limit", json_new_int(limit)); } checkins = cson_new_array(); cson_object_set(pay, "checkins", cson_array_value(checkins)); while( db_step(&q)==SQLITE_ROW ){ cson_object * row = cson_new_object(); int const isNew = db_column_int(&q,9); int const isDel = db_column_int(&q,10); cson_array_append( checkins, cson_object_value(row) ); cson_object_set(row, "checkin", json_new_string( db_column_text(&q,1) )); cson_object_set(row, "uuid", json_new_string( db_column_text(&q,2) )); /*cson_object_set(row, "parentArtifact", json_new_string( db_column_text(&q,6) ));*/ cson_object_set(row, "timestamp", json_new_int( db_column_int64(&q,3) )); cson_object_set(row, "user", json_new_string( db_column_text(&q,4) )); cson_object_set(row, "comment", json_new_string( db_column_text(&q,5) )); /*cson_object_set(row, "bgColor", json_new_string( db_column_text(&q,7) ));*/ cson_object_set(row, "size", json_new_int( db_column_int64(&q,8) )); cson_object_set(row, "state", json_new_string(json_artifact_status_to_string(isNew,isDel))); if( (0 < limit) && (++currentRow >= limit) ){ break; } } db_finalize(&q); return pay ? cson_object_value(pay) : NULL; } #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/json_login.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | #endif /* ** Implementation of the /json/login page. ** */ | | > | < | | > | | | 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 | #endif /* ** Implementation of the /json/login page. ** */ cson_value * json_page_login(){ char preciseErrors = /* if true, "complete" JSON error codes are used, else they are "dumbed down" to a generic login error code. */ #if 1 g.json.errorDetailParanoia ? 0 : 1 #else 0 #endif ; /* FIXME: we want to check the GET/POST args in this order: - GET: name, n, password, p - POST: name, password but a bug in cgi_parameter() is breaking that, causing PD() to return the last element of the PATH_INFO instead. Summary: If we check for P("name") first, then P("n"), then ONLY a GET param of "name" will match ("n" is not recognized). If we reverse the order of the checks then both forms work. Strangely enough, the "p"/"password" check is not affected by this. */ char const * name = cson_value_get_cstr(json_req_payload_get("name")); char const * pw = NULL; char const * anonSeed = NULL; cson_value * payload = NULL; int uid = 0; /* reminder to self: Fossil internally (for the sake of /wiki) interprets paths in the form /foo/bar/baz such that P("name") == |
︙ | ︙ | |||
143 144 145 146 147 148 149 | : FSL_JSON_E_LOGIN_FAILED; return NULL; }else{ char * cookie = NULL; cson_object * po; char * cap = NULL; if(anonSeed){ | | | | < | < | 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 | : FSL_JSON_E_LOGIN_FAILED; return NULL; }else{ char * cookie = NULL; cson_object * po; char * cap = NULL; if(anonSeed){ login_set_anon_cookie(NULL, &cookie); }else{ login_set_user_cookie(name, uid, &cookie); } payload = cson_value_new_object(); po = cson_value_get_object(payload); cson_object_set(po, "authToken", json_new_string(cookie)); free(cookie); cson_object_set(po, "name", json_new_string(name)); cap = db_text(NULL, "SELECT cap FROM user WHERE login=%Q", name); cson_object_set(po, "capabilities", cap ? json_new_string(cap) : cson_value_null() ); free(cap); cson_object_set(po, "loginCookieName", json_new_string( login_cookie_name() ) ); /* TODO: add loginExpiryTime to the payload. To do this properly we "should" add an ([unsigned] int *) to login_set_user_cookie() and login_set_anon_cookie(), to which the expiry time is assigned. (Remember that JSON doesn't do unsigned int.) For non-anonymous users we could also simply query the |
︙ | ︙ | |||
181 182 183 184 185 186 187 | } } /* ** Impl of /json/logout. ** */ | | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | } } /* ** Impl of /json/logout. ** */ cson_value * json_page_logout(){ cson_value const *token = g.json.authToken; /* Remember that json_mode_bootstrap() replaces the login cookie with the JSON auth token if the request contains it. If the request is missing the auth token then this will fetch fossil's original cookie. Either way, it's what we want :). We require the auth token to avoid someone maliciously trying to log someone else out (not 100% sure if that would be possible, given fossil's hardened cookie, but |
︙ | ︙ | |||
207 208 209 210 211 212 213 | } return json_page_whoami(); } /* ** Implementation of the /json/anonymousPassword page. */ | | | | | 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 | } return json_page_whoami(); } /* ** Implementation of the /json/anonymousPassword page. */ cson_value * json_page_anon_password(){ cson_value * v = cson_value_new_object(); cson_object * o = cson_value_get_object(v); unsigned const int seed = captcha_seed(); char const * zCaptcha = captcha_decode(seed); cson_object_set(o, "seed", cson_value_new_integer( (cson_int_t)seed ) ); cson_object_set(o, "password", cson_value_new_string( zCaptcha, strlen(zCaptcha) ) ); return v; } /* ** Implements the /json/whoami page/command. */ cson_value * json_page_whoami(){ cson_value * payload = NULL; cson_object * obj = NULL; Stmt q; if(!g.json.authToken){ /* assume we just logged out. */ db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'"); } else{ db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", g.userUid); } |
︙ | ︙ |
Changes to src/json_query.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | ** ** format=string 'a' means each row is an Array of values, 'o' ** (default) creates each row as an Object. ** ** TODO: in CLI mode (only) use -S FILENAME to read the sql ** from a file. */ | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ** ** format=string 'a' means each row is an Array of values, 'o' ** (default) creates each row as an Object. ** ** TODO: in CLI mode (only) use -S FILENAME to read the sql ** from a file. */ cson_value * json_page_query(){ char const * zSql = NULL; cson_value * payV; char const * zFmt; Stmt q = empty_Stmt; int check; if(!g.perm.Admin && !g.perm.Setup){ json_set_err(FSL_JSON_E_DENIED, |
︙ | ︙ |
Changes to src/json_report.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "json_report.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | 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 | #include "json_report.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_report_create(); static cson_value * json_report_get(); static cson_value * json_report_list(); static cson_value * json_report_run(); static cson_value * json_report_save(); /* ** Mapping of /json/report/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_Report[] = { {"create", json_report_create, 0}, {"get", json_report_get, 0}, {"list", json_report_list, 0}, {"run", json_report_run, 0}, {"save", json_report_save, 0}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implementation of the /json/report page. ** ** */ cson_value * json_page_report(){ if(!g.perm.RdTkt && !g.perm.NewTkt ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'r' or 'n' permissions."); return NULL; } return json_page_dispatch_helper(JsonPageDefs_Report); } |
︙ | ︙ | |||
75 76 77 78 79 80 81 | if(arg && fossil_isdigit(*arg)) { nReport = atoi(arg); } } return nReport; } | | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | if(arg && fossil_isdigit(*arg)) { nReport = atoi(arg); } } return nReport; } static cson_value * json_report_create(){ json_set_err(FSL_JSON_E_NYI, NULL); return NULL; } static cson_value * json_report_get(){ int nReport; Stmt q = empty_Stmt; cson_value * pay = NULL; if(!g.perm.TktFmt){ json_set_err(FSL_JSON_E_DENIED, "Requires 't' privileges."); |
︙ | ︙ | |||
120 121 122 123 124 125 126 | db_finalize(&q); return pay; } /* ** Impl of /json/report/list. */ | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | db_finalize(&q); return pay; } /* ** Impl of /json/report/list. */ static cson_value * json_report_list(){ Blob sql = empty_blob; cson_value * pay = NULL; if(!g.perm.RdTkt){ json_set_err(FSL_JSON_E_DENIED, "Requires 'r' privileges."); return NULL; } |
︙ | ︙ | |||
156 157 158 159 160 161 162 | ** report=int (CLI: -report # or -r #) is the report number to run. ** ** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands. ** ** format=a|o Specifies result format: a=each row is an arry, o=each ** row is an object. Default=o. */ | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | ** report=int (CLI: -report # or -r #) is the report number to run. ** ** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands. ** ** format=a|o Specifies result format: a=each row is an arry, o=each ** row is an object. Default=o. */ static cson_value * json_report_run(){ int nReport; Stmt q = empty_Stmt; cson_object * pay = NULL; cson_array * tktList = NULL; char const * zFmt; char * zTitle = NULL; Blob sql = empty_blob; |
︙ | ︙ | |||
253 254 255 256 257 258 259 | pay = NULL; end: return pay ? cson_object_value(pay) : NULL; } | | | 253 254 255 256 257 258 259 260 261 262 263 | pay = NULL; end: return pay ? cson_object_value(pay) : NULL; } static cson_value * json_report_save(){ return NULL; } #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/json_status.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 | cson_object_set(oPay, "localRoot", json_new_string(g.zLocalRoot)); vid = db_lget_int("checkout", 0); if(!vid){ json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" ); return 0; } | < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | cson_object_set(oPay, "localRoot", json_new_string(g.zLocalRoot)); vid = db_lget_int("checkout", 0); if(!vid){ json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" ); return 0; } /* TODO: dupe show_common_info() state */ tmpO = cson_new_object(); cson_object_set(oPay, "checkout", cson_object_value(tmpO)); zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); cson_object_set(tmpO, "uuid", json_new_string(zTmp) ); free(zTmp); |
︙ | ︙ | |||
92 93 94 95 96 97 98 | #endif /* Now get the list of non-pristine files... */ aFiles = cson_new_array(); cson_object_set( oPay, "files", cson_array_value( aFiles ) ); db_prepare(&q, | | < < > > | 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 | #endif /* Now get the list of non-pristine files... */ aFiles = cson_new_array(); cson_object_set( oPay, "files", cson_array_value( aFiles ) ); db_prepare(&q, "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)" " FROM vfile " " WHERE is_selected(id)" " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1" ); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); int isDeleted = db_column_int(&q, 1); int isChnged = db_column_int(&q,2); int isNew = db_column_int(&q,3)==0; int isRenamed = db_column_int(&q,4); cson_object * oFile; char const * zStatus = "???"; char * zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); if( isDeleted ){ zStatus = "deleted"; }else if( isNew ){ zStatus = "new" /* maintenance reminder: MUST come BEFORE the isChnged checks. */; }else if( isRenamed ){ zStatus = "renamed"; }else if( !file_isfile_or_link(zFullName) ){ if( file_access(zFullName, F_OK)==0 ){ zStatus = "notAFile"; ++nErr; }else{ zStatus = "missing"; ++nErr; |
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 | }else if( 1==isChnged ){ if( file_contains_merge_marker(zFullName) ){ zStatus = "conflict"; }else{ zStatus = "edited"; } } oFile = cson_new_object(); cson_array_append( aFiles, cson_object_value(oFile) ); | > < < < < < < < < < < < < < | < > | | | 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 | }else if( 1==isChnged ){ if( file_contains_merge_marker(zFullName) ){ zStatus = "conflict"; }else{ zStatus = "edited"; } } oFile = cson_new_object(); cson_array_append( aFiles, cson_object_value(oFile) ); /* optimization potential: move these keys into cson_strings to take advantage of refcounting. */ cson_object_set( oFile, "name", json_new_string( zPathname ) ); cson_object_set( oFile, "status", json_new_string( zStatus ) ); free(zFullName); } cson_object_set( oPay, "errorCount", json_new_int( nErr ) ); db_finalize(&q); #if 0 /* TODO: add "merged with" status. First need (A) to decide on a structure and (B) to set up some tests for the multi-merge case.*/ db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid" " WHERE id<=0"); while( db_step(&q)==SQLITE_ROW ){ const char *zLabel = "MERGED_WITH"; switch( db_column_int(&q, 1) ){ case -1: zLabel = "CHERRYPICK "; break; case -2: zLabel = "BACKOUT "; break; case -4: zLabel = "INTEGRATE "; break; } blob_append(report, zPrefix, nPrefix); blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0)); } db_finalize(&q); if( nErr ){ fossil_panic("aborting due to prior errors"); } #endif return cson_object_value( oPay ); } #endif /* FOSSIL_ENABLE_JSON */ |
Changes to src/json_tag.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "json_tag.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | 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 | #include "json_tag.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_tag_add(); static cson_value * json_tag_cancel(); static cson_value * json_tag_find(); static cson_value * json_tag_list(); /* ** Mapping of /json/tag/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_Tag[] = { {"add", json_tag_add, 0}, {"cancel", json_tag_cancel, 0}, {"find", json_tag_find, 0}, {"list", json_tag_list, 0}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implements the /json/tag family of pages/commands. ** */ cson_value * json_page_tag(){ return json_page_dispatch_helper(&JsonPageDefs_Tag[0]); } /* ** Impl of /json/tag/add. */ static cson_value * json_tag_add(){ cson_value * payV = NULL; cson_object * pay = NULL; char const * zName = NULL; char const * zCheckin = NULL; char fRaw = 0; char fPropagate = 0; char const * zValue = NULL; |
︙ | ︙ | |||
115 116 117 118 119 120 121 | cson_object_set(pay, "raw", cson_value_new_bool(fRaw)); { Blob uu = empty_blob; int rc; blob_append(&uu, zName, -1); rc = name_to_uuid(&uu, 9, "*"); if(0!=rc){ | | < | | 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 | cson_object_set(pay, "raw", cson_value_new_bool(fRaw)); { Blob uu = empty_blob; int rc; blob_append(&uu, zName, -1); rc = name_to_uuid(&uu, 9, "*"); if(0!=rc){ json_set_err(FSL_JSON_E_UNKNOWN,"Could not convert name back to UUID!"); blob_reset(&uu); goto error; } cson_object_set(pay, "appliedTo", json_new_string(blob_buffer(&uu))); blob_reset(&uu); } goto ok; error: assert( 0 != g.json.resultCode ); cson_value_free(payV); payV = NULL; ok: return payV; } /* ** Impl of /json/tag/cancel. */ static cson_value * json_tag_cancel(){ char const * zName = NULL; char const * zCheckin = NULL; char fRaw = 0; const char *zPrefix = NULL; if( !g.perm.Write ){ json_set_err(FSL_JSON_E_DENIED, |
︙ | ︙ | |||
187 188 189 190 191 192 193 | return NULL; } /* ** Impl of /json/tag/find. */ | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | return NULL; } /* ** Impl of /json/tag/find. */ static cson_value * json_tag_find(){ cson_value * payV = NULL; cson_object * pay = NULL; cson_value * listV = NULL; cson_array * list = NULL; char const * zName = NULL; char const * zType = NULL; char const * zType2 = NULL; |
︙ | ︙ | |||
322 323 324 325 326 327 328 | /* ** Impl for /json/tag/list ** ** TODOs: ** ** Add -type TYPE (ci, w, e, t) */ | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | /* ** Impl for /json/tag/list ** ** TODOs: ** ** Add -type TYPE (ci, w, e, t) */ static cson_value * json_tag_list(){ cson_value * payV = NULL; cson_object * pay = NULL; cson_value const * tagsVal = NULL; char const * zCheckin = NULL; char fRaw = 0; char fTicket = 0; Stmt q = empty_Stmt; |
︙ | ︙ |
Changes to src/json_timeline.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "config.h" #include "json_timeline.h" #if INTERFACE #include "json_detail.h" #endif | | | | < | | | 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 | #include "config.h" #include "json_timeline.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_timeline_branch(); static cson_value * json_timeline_ci(); static cson_value * json_timeline_ticket(); /* ** Mapping of /json/timeline/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_Timeline[] = { /* the short forms are only enabled in CLI mode, to avoid that we end up with HTTP clients using 3 different names for the same requests. */ {"branch", json_timeline_branch, 0}, {"checkin", json_timeline_ci, 0}, {"event", json_timeline_event, 0}, {"ticket", json_timeline_ticket, 0}, {"wiki", json_timeline_wiki, 0}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implements the /json/timeline family of pages/commands. Far from ** complete. ** */ cson_value * json_page_timeline(){ #if 0 /* The original timeline code does not require 'h' access, but it arguably should. For JSON mode i think one could argue that History permissions are required. */ if(! g.perm.Hyperlink && !g.perm.Read ){ json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access."); |
︙ | ︙ | |||
141 142 143 144 145 146 147 | ** ** If payload is not NULL then on success its "tag" or "branch" ** property is set to the tag/branch name found in the request. ** ** Only one of "tag" or "branch" modes will work at a time, and if ** both are specified, which one takes precedence is unspecified. */ | | | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | ** ** If payload is not NULL then on success its "tag" or "branch" ** property is set to the tag/branch name found in the request. ** ** Only one of "tag" or "branch" modes will work at a time, and if ** both are specified, which one takes precedence is unspecified. */ static char json_timeline_add_tag_branch_clause(Blob *pSql, cson_object * pPayload){ char const * zTag = NULL; char const * zBranch = NULL; char const * zMiOnly = NULL; char const * zUnhide = NULL; int tagid = 0; if(! g.perm.Read ){ return 0; |
︙ | ︙ | |||
167 168 169 170 171 172 173 | zUnhide = json_find_option_cstr("unhide",NULL,NULL); tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTag); if(tagid<=0){ return -1; } if(pPayload){ | | < | < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | zUnhide = json_find_option_cstr("unhide",NULL,NULL); tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTag); if(tagid<=0){ return -1; } if(pPayload){ cson_object_set( pPayload, zBranch ? "branch" : "tag", json_new_string(zTag) ); } blob_appendf(pSql, " AND (" " EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); if(!zUnhide){ blob_appendf(pSql, " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=blob.rid" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", TAG_HIDDEN); } if(zBranch){ /* from "r" flag code in page_timeline().*/ blob_appendf(pSql, " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid" |
︙ | ︙ | |||
220 221 222 223 224 225 226 | ** of the "after" ("a") or "before" ("b") environment parameters. ** This function gives "after" precedence over "before", and only ** applies one of them. ** ** Returns -1 if it adds a "before" clause, 1 if it adds ** an "after" clause, and 0 if adds only an order-by clause. */ | | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | ** of the "after" ("a") or "before" ("b") environment parameters. ** This function gives "after" precedence over "before", and only ** applies one of them. ** ** Returns -1 if it adds a "before" clause, 1 if it adds ** an "after" clause, and 0 if adds only an order-by clause. */ static char json_timeline_add_time_clause(Blob *pSql){ char const * zAfter = NULL; char const * zBefore = NULL; int rc = 0; zAfter = json_find_option_cstr("after",NULL,"a"); zBefore = zAfter ? NULL : json_find_option_cstr("before",NULL,"b"); if(zAfter&&*zAfter){ |
︙ | ︙ | |||
352 353 354 355 356 357 358 | cson_object_set(row, "uuid", json_new_string(db_column_text(&q,3))); if(!isNew && (flags & json_get_changed_files_ELIDE_PARENT)){ cson_object_set(row, "parent", json_new_string(db_column_text(&q,4))); } cson_object_set(row, "size", json_new_int(db_column_int(&q,5))); cson_object_set(row, "state", | | | < | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | cson_object_set(row, "uuid", json_new_string(db_column_text(&q,3))); if(!isNew && (flags & json_get_changed_files_ELIDE_PARENT)){ cson_object_set(row, "parent", json_new_string(db_column_text(&q,4))); } cson_object_set(row, "size", json_new_int(db_column_int(&q,5))); cson_object_set(row, "state", json_new_string(json_artifact_status_to_string(isNew,isDel))); zDownload = mprintf("/raw/%s?name=%s", /* reminder: g.zBaseURL is of course not set for CLI mode. */ db_column_text(&q,2), db_column_text(&q,3)); cson_object_set(row, "downloadPath", json_new_string(zDownload)); free(zDownload); } db_finalize(&q); return rowsV; } static cson_value * json_timeline_branch(){ cson_value * pay = NULL; Blob sql = empty_blob; Stmt q = empty_Stmt; int limit = 0; if(!g.perm.Read){ json_set_err(FSL_JSON_E_DENIED, "Requires 'o' permissions."); |
︙ | ︙ | |||
446 447 448 449 450 451 452 | /* ** Implementation of /json/timeline/ci. ** ** Still a few TODOs (like figuring out how to structure ** inheritance info). */ | | | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | /* ** Implementation of /json/timeline/ci. ** ** Still a few TODOs (like figuring out how to structure ** inheritance info). */ static cson_value * json_timeline_ci(){ cson_value * payV = NULL; cson_object * pay = NULL; cson_value * tmp = NULL; cson_value * listV = NULL; cson_array * list = NULL; int check = 0; char verboseFlag; |
︙ | ︙ | |||
506 507 508 509 510 511 512 | int const rid = db_column_int(&q,0); cson_value * rowV = json_artifact_for_ci(rid, verboseFlag); cson_object * row = cson_value_get_object(rowV); if(!row){ if( !warnRowToJsonFailed ){ warnRowToJsonFailed = 1; json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, | | | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | int const rid = db_column_int(&q,0); cson_value * rowV = json_artifact_for_ci(rid, verboseFlag); cson_object * row = cson_value_get_object(rowV); if(!row){ if( !warnRowToJsonFailed ){ warnRowToJsonFailed = 1; json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, "Could not convert at least one timeline result row to JSON." ); } continue; } cson_array_append(list, rowV); } #undef SET goto ok; error: assert( 0 != g.json.resultCode ); cson_value_free(payV); payV = NULL; ok: db_finalize(&q); return payV; } /* ** Implementation of /json/timeline/event. ** */ cson_value * json_timeline_event(){ /* This code is 95% the same as json_timeline_ci(), by the way. */ cson_value * payV = NULL; cson_object * pay = NULL; cson_array * list = NULL; int check = 0; Stmt q = empty_Stmt; Blob sql = empty_blob; |
︙ | ︙ | |||
549 550 551 552 553 554 555 | if(check){ json_set_err(check, "Query initialization failed."); goto error; } #if 0 /* only for testing! */ | | < | < < | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | if(check){ json_set_err(check, "Query initialization failed."); goto error; } #if 0 /* only for testing! */ cson_object_set(pay, "timelineSql", cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)))); #endif db_multi_exec("%s", blob_buffer(&sql) /*safe-for-%s*/); blob_reset(&sql); db_prepare(&q, "SELECT" /* For events, the name is generally more useful than the uuid, but the uuid is unambiguous and can be used with commands like 'artifact'. */ " substr((SELECT tagname FROM tag AS tn WHERE tn.tagid=json_timeline.tagId AND tagname LIKE 'event-%%'),7) AS name," " uuid as uuid," " mtime AS timestamp," " comment AS comment, " " user AS user," " eventType AS eventType" " FROM json_timeline" " ORDER BY rowid"); |
︙ | ︙ | |||
586 587 588 589 590 591 592 | return payV; } /* ** Implementation of /json/timeline/wiki. ** */ | | | < | < | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | return payV; } /* ** Implementation of /json/timeline/wiki. ** */ cson_value * json_timeline_wiki(){ /* This code is 95% the same as json_timeline_ci(), by the way. */ cson_value * payV = NULL; cson_object * pay = NULL; cson_array * list = NULL; int check = 0; Stmt q = empty_Stmt; Blob sql = empty_blob; if( !g.perm.RdWiki && !g.perm.Read ){ json_set_err( FSL_JSON_E_DENIED, "Wiki timeline requires 'o' or 'j' access."); return NULL; } payV = cson_value_new_object(); pay = cson_value_get_object(payV); check = json_timeline_setup_sql( "w", &sql, pay ); if(check){ json_set_err(check, "Query initialization failed."); goto error; } #if 0 /* only for testing! */ cson_object_set(pay, "timelineSql", cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)))); #endif db_multi_exec("%s", blob_buffer(&sql) /*safe-for-%s*/); blob_reset(&sql); db_prepare(&q, "SELECT" " uuid AS uuid," " mtime AS timestamp," #if 0 |
︙ | ︙ | |||
649 650 651 652 653 654 655 | return payV; } /* ** Implementation of /json/timeline/ticket. ** */ | | | < | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 | return payV; } /* ** Implementation of /json/timeline/ticket. ** */ static cson_value * json_timeline_ticket(){ /* This code is 95% the same as json_timeline_ci(), by the way. */ cson_value * payV = NULL; cson_object * pay = NULL; cson_value * tmp = NULL; cson_value * listV = NULL; cson_array * list = NULL; int check = 0; Stmt q = empty_Stmt; Blob sql = empty_blob; if( !g.perm.RdTkt && !g.perm.Read ){ json_set_err(FSL_JSON_E_DENIED, "Ticket timeline requires 'o' or 'r' access."); return NULL; } payV = cson_value_new_object(); pay = cson_value_get_object(payV); check = json_timeline_setup_sql( "t", &sql, pay ); if(check){ json_set_err(check, "Query initialization failed."); |
︙ | ︙ | |||
733 734 735 736 737 738 739 | } rowV = cson_sqlite3_row_to_object(q.pStmt); row = cson_value_get_object(rowV); if(!row){ manifest_destroy(pMan); json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, | | | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | } rowV = cson_sqlite3_row_to_object(q.pStmt); row = cson_value_get_object(rowV); if(!row){ manifest_destroy(pMan); json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, "Could not convert at least one timeline result row to JSON." ); continue; } /* FIXME: certainly there's a more efficient way for use to get the ticket UUIDs? */ cson_object_set(row,"ticketUuid",json_new_string(pMan->zTicketUuid)); manifest_destroy(pMan); |
︙ | ︙ |
Changes to src/json_user.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_user.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | 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 | #include "config.h" #include "json_user.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_user_get(); static cson_value * json_user_list(); static cson_value * json_user_save(); /* ** Mapping of /json/user/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_User[] = { {"save", json_user_save, 0}, {"get", json_user_get, 0}, {"list", json_user_list, 0}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implements the /json/user family of pages/commands. ** */ cson_value * json_page_user(){ return json_page_dispatch_helper(&JsonPageDefs_User[0]); } /* ** Impl of /json/user/list. Requires admin/setup rights. */ static cson_value * json_user_list(){ cson_value * payV = NULL; Stmt q; if(!g.perm.Admin && !g.perm.Setup){ json_set_err(FSL_JSON_E_DENIED, "Requires 'a' or 's' privileges."); return NULL; } |
︙ | ︙ | |||
120 121 122 123 124 125 126 | return u; } /* ** Impl of /json/user/get. Requires admin or setup rights. */ | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | return u; } /* ** Impl of /json/user/get. Requires admin or setup rights. */ static cson_value * json_user_get(){ cson_value * payV = NULL; char const * pUser = NULL; if(!g.perm.Admin && !g.perm.Setup){ json_set_err(FSL_JSON_E_DENIED, "Requires 'a' or 's' privileges."); return NULL; } |
︙ | ︙ | |||
168 169 170 171 172 173 174 | ** Requires either Admin, Setup, or Password access. Non-admin/setup ** users can only change their own information. Non-setup users may ** not modify the 's' permission. Admin users without setup ** permissions may not edit any other user who has the 's' permission. ** */ int json_user_update_from_json( cson_object * pUser ){ | | < > > > > > > > | 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 | ** Requires either Admin, Setup, or Password access. Non-admin/setup ** users can only change their own information. Non-setup users may ** not modify the 's' permission. Admin users without setup ** permissions may not edit any other user who has the 's' permission. ** */ int json_user_update_from_json( cson_object * pUser ){ #define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) )) char const * zName = CSTR("name"); char const * zNameNew = zName; char * zNameFree = NULL; char const * zInfo = CSTR("info"); char const * zCap = CSTR("capabilities"); char const * zPW = CSTR("password"); cson_value const * forceLogout = cson_object_get(pUser, "forceLogout"); int gotFields = 0; #undef CSTR cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") ); char const tgtHasSetup = zCap && (NULL!=strchr(zCap, 's')); char tgtHadSetup = 0; Blob sql = empty_blob; Stmt q = empty_Stmt; #if 0 if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){ return json_set_err( FSL_JSON_E_DENIED, "Password change requires 'a', 's', " "or 'p' permissions."); } #endif if(uid<=0 && (!zName||!*zName)){ return json_set_err(FSL_JSON_E_MISSING_ARGS, "One of 'uid' or 'name' is required."); }else if(uid>0){ zNameFree = db_text(NULL, "SELECT login FROM user WHERE uid=%d",uid); if(!zNameFree){ return json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND, |
︙ | ︙ | |||
211 212 213 214 215 216 217 | goto error; }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, "User %s already exists.", zName); goto error; }else{ Stmt ins = empty_Stmt; | < < | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | goto error; }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, "User %s already exists.", zName); goto error; }else{ Stmt ins = empty_Stmt; db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName); db_step( &ins ); db_finalize(&ins); uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); assert(uid>0); zNameNew = zName; cson_object_set( pUser, "uid", cson_value_new_integer(uid) ); } }else{ uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); |
︙ | ︙ | |||
346 347 348 349 350 351 352 | #else /* need name for login group support :/ */ blob_append_sql(&sql, " WHERE login=%Q", zName); #endif #if 0 puts(blob_str(&sql)); cson_output_FILE( cson_object_value(pUser), stdout, NULL ); #endif | < < < < | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | #else /* need name for login group support :/ */ blob_append_sql(&sql, " WHERE login=%Q", zName); #endif #if 0 puts(blob_str(&sql)); cson_output_FILE( cson_object_value(pUser), stdout, NULL ); #endif db_prepare(&q, "%s", blob_sql_text(&sql)); db_exec(&q); db_finalize(&q); #if TRY_LOGIN_GROUP if( zPW || cson_value_get_bool(forceLogout) ){ Blob groupSql = empty_blob; char * zErr = NULL; blob_append_sql(&groupSql, "INSERT INTO user(login)" " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);", zName, zName ); blob_append(&groupSql, blob_str(&sql), blob_size(&sql)); login_group_sql(blob_str(&groupSql), NULL, NULL, &zErr); blob_reset(&groupSql); if( zErr ){ json_set_err( FSL_JSON_E_UNKNOWN, "Repo-group update at least partially failed: %s", zErr); free(zErr); goto error; |
︙ | ︙ | |||
392 393 394 395 396 397 398 | return g.json.resultCode; } /* ** Impl of /json/user/save. */ | | | | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | return g.json.resultCode; } /* ** Impl of /json/user/save. */ static cson_value * json_user_save(){ /* try to get user info from GET/CLI args and construct a JSON form of it... */ cson_object * u = cson_new_object(); char const * str = NULL; char b = -1; int i = -1; int uid = -1; cson_value * payload = NULL; /* String properties... */ #define PROP(LK,SK) str = json_find_option_cstr(LK,NULL,SK); \ if(str){ cson_object_set(u, LK, json_new_string(str)); } (void)0 PROP("name","n"); PROP("password","p"); PROP("info","i"); PROP("capabilities","c"); #undef PROP /* Boolean properties... */ #define PROP(LK,DFLT) b = json_find_option_bool(LK,NULL,NULL,DFLT); \ if(DFLT!=b){ cson_object_set(u, LK, cson_value_new_bool(b)); } (void)0 PROP("forceLogout",-1); #undef PROP #define PROP(LK,DFLT) i = json_find_option_int(LK,NULL,NULL,DFLT); \ if(DFLT != i){ cson_object_set(u, LK, cson_value_new_integer(i)); } (void)0 PROP("uid",-99); #undef PROP |
︙ | ︙ |
Changes to src/json_wiki.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "json_wiki.h" #if INTERFACE #include "json_detail.h" #endif | | | | | | | | | 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 | #include "config.h" #include "json_wiki.h" #if INTERFACE #include "json_detail.h" #endif static cson_value * json_wiki_create(); static cson_value * json_wiki_get(); static cson_value * json_wiki_list(); static cson_value * json_wiki_preview(); static cson_value * json_wiki_save(); static cson_value * json_wiki_diff(); /* ** Mapping of /json/wiki/XXX commands/paths to callbacks. */ static const JsonPageDef JsonPageDefs_Wiki[] = { {"create", json_wiki_create, 0}, {"diff", json_wiki_diff, 0}, {"get", json_wiki_get, 0}, {"list", json_wiki_list, 0}, {"preview", json_wiki_preview, 0}, {"save", json_wiki_save, 0}, {"timeline", json_timeline_wiki,0}, /* Last entry MUST have a NULL name. */ {NULL,NULL,0} }; /* ** Implements the /json/wiki family of pages/commands. ** */ cson_value * json_page_wiki(){ return json_page_dispatch_helper(JsonPageDefs_Wiki); } /* ** Returns the UUID for the given wiki blob RID, or NULL if not ** found. The returned string is allocated via db_text() and must be ** free()d by the caller. |
︙ | ︙ | |||
161 162 163 164 165 166 167 | } /* ** Searches for the latest version of a wiki page with the given ** name. If found it behaves like json_get_wiki_page_by_rid(theRid, ** contentFormat), else it returns NULL. */ | | < | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | } /* ** Searches for the latest version of a wiki page with the given ** name. If found it behaves like json_get_wiki_page_by_rid(theRid, ** contentFormat), else it returns NULL. */ cson_value * json_get_wiki_page_by_name(char const * zPageName, int contentFormat){ int rid; rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x, blob b" " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q' " " AND b.rid=x.rid" " ORDER BY x.mtime DESC LIMIT 1", zPageName |
︙ | ︙ | |||
243 244 245 246 247 248 249 | } } /* ** Implementation of /json/wiki/get. ** */ | | | > | < < < < < < < < < | < | | < < < | < < < < < < < < | < | < | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | } } /* ** Implementation of /json/wiki/get. ** */ static cson_value * json_wiki_get(){ char const * zPageName; char const * zSymName = NULL; int contentFormat = -1; if( !g.perm.RdWiki && !g.perm.Read ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'o' or 'j' access."); return NULL; } zPageName = json_find_option_cstr2("name",NULL,"n",g.json.dispatchDepth+1); zSymName = json_find_option_cstr("uuid",NULL,"u"); if((!zPageName||!*zPageName) && (!zSymName || !*zSymName)){ json_set_err(FSL_JSON_E_MISSING_ARGS, "At least one of the 'name' or 'uuid' arguments must be provided."); return NULL; } /* TODO: see if we have a page named zPageName. If not, try to resolve zPageName as a UUID. */ contentFormat = json_wiki_get_content_format_flag(contentFormat); return json_wiki_get_by_name_or_symname( zPageName, zSymName, contentFormat ); } /* ** Implementation of /json/wiki/preview. ** */ static cson_value * json_wiki_preview(){ char const * zContent = NULL; cson_value * pay = NULL; Blob contentOrig = empty_blob; Blob contentHtml = empty_blob; if( !g.perm.WrWiki ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'k' access."); return NULL; } zContent = cson_string_cstr(cson_value_get_string(g.json.reqPayload.v)); if(!zContent) { json_set_err(FSL_JSON_E_MISSING_ARGS, "The 'payload' property must be a string containing the wiki code to preview."); return NULL; } blob_append( &contentOrig, zContent, (int)cson_string_length_bytes(cson_value_get_string(g.json.reqPayload.v)) ); wiki_convert( &contentOrig, &contentHtml, 0 ); blob_reset( &contentOrig ); pay = cson_value_new_string( blob_str(&contentHtml), (unsigned int)blob_size(&contentHtml)); blob_reset( &contentHtml ); return pay; } /* ** Internal impl of /wiki/save and /wiki/create. If createMode is 0 |
︙ | ︙ | |||
346 347 348 349 350 351 352 | char allowCreateIfNotExists){ Blob content = empty_blob; /* wiki page content */ cson_value * nameV; /* wiki page name */ char const * zPageName; /* cstr form of page name */ cson_value * contentV; /* passed-in content */ cson_value * emptyContent = NULL; /* placeholder for empty content. */ cson_value * payV = NULL; /* payload/return value */ | | < | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | char allowCreateIfNotExists){ Blob content = empty_blob; /* wiki page content */ cson_value * nameV; /* wiki page name */ char const * zPageName; /* cstr form of page name */ cson_value * contentV; /* passed-in content */ cson_value * emptyContent = NULL; /* placeholder for empty content. */ cson_value * payV = NULL; /* payload/return value */ cson_string const * jstr = NULL; /* temp for cson_value-to-cson_string conversions. */ char const * zMimeType = 0; unsigned int contentLen = 0; int rid; if( (createMode && !g.perm.NewWiki) || (!createMode && !g.perm.WrWiki)){ json_set_err(FSL_JSON_E_DENIED, "Requires '%c' permissions.", |
︙ | ︙ | |||
450 451 452 453 454 455 456 | return payV; } /* ** Implementation of /json/wiki/create. */ | | | | | < | < < | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | return payV; } /* ** Implementation of /json/wiki/create. */ static cson_value * json_wiki_create(){ return json_wiki_create_or_save(1,0); } /* ** Implementation of /json/wiki/save. */ static cson_value * json_wiki_save(){ char const createIfNotExists = json_getenv_bool("createIfNotExists",0); return json_wiki_create_or_save(0,createIfNotExists); } /* ** Implementation of /json/wiki/list. */ static cson_value * json_wiki_list(){ cson_value * listV = NULL; cson_array * list = NULL; char const * zGlob = NULL; Stmt q = empty_Stmt; Blob sql = empty_blob; char const verbose = json_find_option_bool("verbose",NULL,"v",0); char fInvert = json_find_option_bool("invert",NULL,"i",0);; if( !g.perm.RdWiki && !g.perm.Read ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'j' or 'o' permissions."); return NULL; } blob_append(&sql,"SELECT" " substr(tagname,6) as name" " FROM tag WHERE tagname GLOB 'wiki-*'", -1); zGlob = json_find_option_cstr("glob",NULL,"g"); if(zGlob && *zGlob){ blob_append_sql(&sql," AND name %s GLOB %Q", fInvert ? "NOT" : "", zGlob); }else{ zGlob = json_find_option_cstr("like",NULL,"l"); |
︙ | ︙ | |||
532 533 534 535 536 537 538 | cson_value_free(listV); listV = NULL; end: db_finalize(&q); return listV; } | | | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | cson_value_free(listV); listV = NULL; end: db_finalize(&q); return listV; } static cson_value * json_wiki_diff(){ char const * zV1 = NULL; char const * zV2 = NULL; cson_object * pay = NULL; int argPos = g.json.dispatchDepth; int r1 = 0, r2 = 0; Manifest * pW1 = NULL, *pW2 = NULL; Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; char const * zErrTag = NULL; u64 diffFlags; char * zUuid = NULL; if( !g.perm.Hyperlink ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions."); return NULL; } |
︙ | ︙ | |||
589 590 591 592 593 594 595 | goto manifest; } blob_init(&w1, pW1->zWiki, -1); blob_zero(&w2); blob_init(&w2, pW2->zWiki, -1); blob_zero(&d); | | | | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | goto manifest; } blob_init(&w1, pW1->zWiki, -1); blob_zero(&w2); blob_init(&w2, pW2->zWiki, -1); blob_zero(&d); diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR; text_diff(&w1, &w2, &d, 0, diffFlags); blob_reset(&w1); blob_reset(&w2); pay = cson_new_object(); zUuid = json_wiki_get_uuid_for_rid( pW1->rid ); cson_object_set(pay, "v1", json_new_string(zUuid) ); |
︙ | ︙ |
Changes to src/leaf.c.
︙ | ︙ | |||
151 152 153 154 155 156 157 | " WHERE tx.rid=%s" " AND tx.tagid=%d" " AND tx.tagtype>0)", zVar, TAG_CLOSED ); } | < < < < < < < < < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | " WHERE tx.rid=%s" " AND tx.tagid=%d" " AND tx.tagtype>0)", zVar, TAG_CLOSED ); } /* ** Schedule a leaf check for "rid" and its parents. */ void leaf_eventually_check(int rid){ static Stmt parentsOf; db_static_prepare(&parentsOf, |
︙ | ︙ |
Added src/linenoise.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 | /* linenoise.c -- guerrilla line editing library against the idea that a * line editing lib needs to be 20,000 lines of C code. * * You can find the latest source code at: * * http://github.com/antirez/linenoise * * Does a number of crazy assumptions that happen to be true in 99.9999% of * the 2010 UNIX computers around. * * ------------------------------------------------------------------------ * * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER 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. * * ------------------------------------------------------------------------ * * References: * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html * * Todo list: * - Filter bogus Ctrl+<char> combinations. * - Win32 support * * Bloat: * - History search like Ctrl+r in readline? * * List of escape sequences used by this program, we do everything just * with three sequences. In order to be so cheap we may have some * flickering effect with some slow terminal, but the lesser sequences * the more compatible. * * EL (Erase Line) * Sequence: ESC [ n K * Effect: if n is 0 or missing, clear from cursor to end of line * Effect: if n is 1, clear from beginning of line to cursor * Effect: if n is 2, clear entire line * * CUF (CUrsor Forward) * Sequence: ESC [ n C * Effect: moves cursor forward n chars * * CUB (CUrsor Backward) * Sequence: ESC [ n D * Effect: moves cursor backward n chars * * The following is used to get the terminal width if getting * the width with the TIOCGWINSZ ioctl fails * * DSR (Device Status Report) * Sequence: ESC [ 6 n * Effect: reports the current cusor position as ESC [ n ; m R * where n is the row and m is the column * * When multi line mode is enabled, we also use an additional escape * sequence. However multi line editing is disabled by default. * * CUU (Cursor Up) * Sequence: ESC [ n A * Effect: moves cursor up of n chars. * * CUD (Cursor Down) * Sequence: ESC [ n B * Effect: moves cursor down of n chars. * * When linenoiseClearScreen() is called, two additional escape sequences * are used in order to clear the screen and position the cursor at home * position. * * CUP (Cursor position) * Sequence: ESC [ H * Effect: moves the cursor to upper left corner * * ED (Erase display) * Sequence: ESC [ 2 J * Effect: clear the whole screen * */ #include <termios.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> #include <unistd.h> #include "linenoise.h" #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_MAX_LINE 4096 static char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; static linenoiseCompletionCallback *completionCallback = NULL; static linenoiseHintsCallback *hintsCallback = NULL; static linenoiseFreeHintsCallback *freeHintsCallback = NULL; static struct termios orig_termios; /* In order to restore at exit.*/ static int rawmode = 0; /* For atexit() function to check if restore is needed*/ static int mlmode = 0; /* Multi line mode. Default is single line. */ static int atexit_registered = 0; /* Register atexit just 1 time. */ static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; static int history_len = 0; static char **history = NULL; /* The linenoiseState structure represents the state during line editing. * We pass this state to functions implementing specific editing * functionalities. */ struct linenoiseState { int ifd; /* Terminal stdin file descriptor. */ int ofd; /* Terminal stdout file descriptor. */ char *buf; /* Edited line buffer. */ size_t buflen; /* Edited line buffer size. */ const char *prompt; /* Prompt to display. */ size_t plen; /* Prompt length. */ size_t pos; /* Current cursor position. */ size_t oldpos; /* Previous refresh cursor position. */ size_t len; /* Current edited line length. */ size_t cols; /* Number of columns in terminal. */ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ int history_index; /* The history index we are currently editing. */ }; enum KEY_ACTION{ KEY_NULL = 0, /* NULL */ CTRL_A = 1, /* Ctrl+a */ CTRL_B = 2, /* Ctrl-b */ CTRL_C = 3, /* Ctrl-c */ CTRL_D = 4, /* Ctrl-d */ CTRL_E = 5, /* Ctrl-e */ CTRL_F = 6, /* Ctrl-f */ CTRL_H = 8, /* Ctrl-h */ TAB = 9, /* Tab */ CTRL_K = 11, /* Ctrl+k */ CTRL_L = 12, /* Ctrl+l */ ENTER = 13, /* Enter */ CTRL_N = 14, /* Ctrl-n */ CTRL_P = 16, /* Ctrl-p */ CTRL_T = 20, /* Ctrl-t */ CTRL_U = 21, /* Ctrl+u */ CTRL_W = 23, /* Ctrl+w */ ESC = 27, /* Escape */ BACKSPACE = 127 /* Backspace */ }; static void linenoiseAtExit(void); int linenoiseHistoryAdd(const char *line); static void refreshLine(struct linenoiseState *l); /* Debugging macro. */ #if 0 FILE *lndebug_fp = NULL; #define lndebug(...) \ do { \ if (lndebug_fp == NULL) { \ lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ fprintf(lndebug_fp, \ "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ (int)l->maxrows,old_rows); \ } \ fprintf(lndebug_fp, ", " __VA_ARGS__); \ fflush(lndebug_fp); \ } while (0) #else #define lndebug(fmt, ...) #endif /* ======================= Low level terminal handling ====================== */ /* Set if to use or not the multi line mode. */ void linenoiseSetMultiLine(int ml) { mlmode = ml; } /* Return true if the terminal name is in the list of terminals we know are * not able to understand basic escape sequences. */ static int isUnsupportedTerm(void) { char *term = getenv("TERM"); int j; if (term == NULL) return 0; for (j = 0; unsupported_term[j]; j++) if (!strcasecmp(term,unsupported_term[j])) return 1; return 0; } /* Raw mode: 1960 magic shit. */ static int enableRawMode(int fd) { struct termios raw; if (!isatty(STDIN_FILENO)) goto fatal; if (!atexit_registered) { atexit(linenoiseAtExit); atexit_registered = 1; } if (tcgetattr(fd,&orig_termios) == -1) goto fatal; raw = orig_termios; /* modify the original mode */ /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* output modes - disable post processing */ raw.c_oflag &= ~(OPOST); /* control modes - set 8 bit chars */ raw.c_cflag |= (CS8); /* local modes - choing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); /* control chars - set return condition: min number of bytes and timer. * We want read to return every single byte, without timeout. */ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ /* put terminal in raw mode after flushing */ if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal; rawmode = 1; return 0; fatal: errno = ENOTTY; return -1; } static void disableRawMode(int fd) { /* Don't even check the return value as it's too late. */ if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1) rawmode = 0; } /* Use the ESC [6n escape sequence to query the horizontal cursor position * and return it. On error -1 is returned, on success the position of the * cursor. */ static int getCursorPosition(int ifd, int ofd) { char buf[32]; int cols, rows; unsigned int i = 0; /* Report cursor location */ if (write(ofd, "\x1b[6n", 4) != 4) return -1; /* Read the response: ESC [ rows ; cols R */ while (i < sizeof(buf)-1) { if (read(ifd,buf+i,1) != 1) break; if (buf[i] == 'R') break; i++; } buf[i] = '\0'; /* Parse it. */ if (buf[0] != ESC || buf[1] != '[') return -1; if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1; return cols; } /* Try to get the number of columns in the current terminal, or assume 80 * if it fails. */ static int getColumns(int ifd, int ofd) { struct winsize ws; if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { /* ioctl() failed. Try to query the terminal itself. */ int start, cols; /* Get the initial position so we can restore it later. */ start = getCursorPosition(ifd,ofd); if (start == -1) goto failed; /* Go to right margin and get position. */ if (write(ofd,"\x1b[999C",6) != 6) goto failed; cols = getCursorPosition(ifd,ofd); if (cols == -1) goto failed; /* Restore position. */ if (cols > start) { char seq[32]; snprintf(seq,32,"\x1b[%dD",cols-start); if (write(ofd,seq,strlen(seq)) == -1) { /* Can't recover... */ } } return cols; } else { return ws.ws_col; } failed: return 80; } /* Clear the screen. Used to handle ctrl+l */ void linenoiseClearScreen(void) { if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) { /* nothing to do, just to avoid warning. */ } } /* Beep, used for completion when there is nothing to complete or when all * the choices were already shown. */ static void linenoiseBeep(void) { fprintf(stderr, "\x7"); fflush(stderr); } /* ============================== Completion ================================ */ /* Free a list of completion option populated by linenoiseAddCompletion(). */ static void freeCompletions(linenoiseCompletions *lc) { size_t i; for (i = 0; i < lc->len; i++) free(lc->cvec[i]); if (lc->cvec != NULL) free(lc->cvec); } /* This is an helper function for linenoiseEdit() and is called when the * user types the <tab> key in order to complete the string currently in the * input. * * The state of the editing is encapsulated into the pointed linenoiseState * structure as described in the structure definition. */ static int completeLine(struct linenoiseState *ls) { linenoiseCompletions lc = { 0, NULL }; int nread, nwritten; char c = 0; completionCallback(ls->buf,&lc); if (lc.len == 0) { linenoiseBeep(); } else { size_t stop = 0, i = 0; while(!stop) { /* Show completion or original buffer */ if (i < lc.len) { struct linenoiseState saved = *ls; ls->len = ls->pos = strlen(lc.cvec[i]); ls->buf = lc.cvec[i]; refreshLine(ls); ls->len = saved.len; ls->pos = saved.pos; ls->buf = saved.buf; } else { refreshLine(ls); } nread = read(ls->ifd,&c,1); if (nread <= 0) { freeCompletions(&lc); return -1; } switch(c) { case 9: /* tab */ i = (i+1) % (lc.len+1); if (i == lc.len) linenoiseBeep(); break; case 27: /* escape */ /* Re-show original buffer */ if (i < lc.len) refreshLine(ls); stop = 1; break; default: /* Update buffer and return */ if (i < lc.len) { nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]); ls->len = ls->pos = nwritten; } stop = 1; break; } } } freeCompletions(&lc); return c; /* Return last read character */ } /* Register a callback function to be called for tab-completion. */ void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { completionCallback = fn; } /* Register a hits function to be called to show hits to the user at the * right of the prompt. */ void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) { hintsCallback = fn; } /* Register a function to free the hints returned by the hints callback * registered with linenoiseSetHintsCallback(). */ void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) { freeHintsCallback = fn; } /* This function is used by the callback function registered by the user * in order to add completion options given the input string when the * user typed <tab>. See the example.c source code for a very easy to * understand example. */ void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { size_t len = strlen(str); char *copy, **cvec; copy = malloc(len+1); if (copy == NULL) return; memcpy(copy,str,len+1); cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); if (cvec == NULL) { free(copy); return; } lc->cvec = cvec; lc->cvec[lc->len++] = copy; } /* =========================== Line editing ================================= */ /* We define a very simple "append buffer" structure, that is an heap * allocated string where we can append to. This is useful in order to * write all the escape sequences in a buffer and flush them to the standard * output in a single call, to avoid flickering effects. */ struct abuf { char *b; int len; }; static void abInit(struct abuf *ab) { ab->b = NULL; ab->len = 0; } static void abAppend(struct abuf *ab, const char *s, int len) { char *new = realloc(ab->b,ab->len+len); if (new == NULL) return; memcpy(new+ab->len,s,len); ab->b = new; ab->len += len; } static void abFree(struct abuf *ab) { free(ab->b); } /* Helper of refreshSingleLine() and refreshMultiLine() to show hints * to the right of the prompt. */ void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { char seq[64]; if (hintsCallback && plen+l->len < l->cols) { int color = -1, bold = 0; char *hint = hintsCallback(l->buf,&color,&bold); if (hint) { int hintlen = strlen(hint); int hintmaxlen = l->cols-(plen+l->len); if (hintlen > hintmaxlen) hintlen = hintmaxlen; if (bold == 1 && color == -1) color = 37; if (color != -1 || bold != 0) snprintf(seq,64,"\033[%d;%d;49m",bold,color); abAppend(ab,seq,strlen(seq)); abAppend(ab,hint,hintlen); if (color != -1 || bold != 0) abAppend(ab,"\033[0m",4); /* Call the function to free the hint returned. */ if (freeHintsCallback) freeHintsCallback(hint); } } } /* Single line low level line refresh. * * Rewrite the currently edited line accordingly to the buffer content, * cursor position, and number of columns of the terminal. */ static void refreshSingleLine(struct linenoiseState *l) { char seq[64]; size_t plen = strlen(l->prompt); int fd = l->ofd; char *buf = l->buf; size_t len = l->len; size_t pos = l->pos; struct abuf ab; while((plen+pos) >= l->cols) { buf++; len--; pos--; } while (plen+len > l->cols) { len--; } abInit(&ab); /* Cursor to left edge */ snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); /* Write the prompt and the current buffer content */ abAppend(&ab,l->prompt,strlen(l->prompt)); abAppend(&ab,buf,len); /* Show hits if any. */ refreshShowHints(&ab,l,plen); /* Erase to right */ snprintf(seq,64,"\x1b[0K"); abAppend(&ab,seq,strlen(seq)); /* Move cursor to original position. */ snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); abAppend(&ab,seq,strlen(seq)); if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ abFree(&ab); } /* Multi line low level line refresh. * * Rewrite the currently edited line accordingly to the buffer content, * cursor position, and number of columns of the terminal. */ static void refreshMultiLine(struct linenoiseState *l) { char seq[64]; int plen = strlen(l->prompt); int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */ int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */ int rpos2; /* rpos after refresh. */ int col; /* colum position, zero-based. */ int old_rows = l->maxrows; int fd = l->ofd, j; struct abuf ab; /* Update maxrows if needed. */ if (rows > (int)l->maxrows) l->maxrows = rows; /* First step: clear all the lines used before. To do so start by * going to the last row. */ abInit(&ab); if (old_rows-rpos > 0) { /* lndebug("go down %d", old_rows-rpos); */ snprintf(seq,64,"\x1b[%dB", old_rows-rpos); abAppend(&ab,seq,strlen(seq)); } /* Now for every row clear it, go up. */ for (j = 0; j < old_rows-1; j++) { /* lndebug("clear+up"); */ snprintf(seq,64,"\r\x1b[0K\x1b[1A"); abAppend(&ab,seq,strlen(seq)); } /* Clean the top line. */ /* lndebug("clear"); */ snprintf(seq,64,"\r\x1b[0K"); abAppend(&ab,seq,strlen(seq)); /* Write the prompt and the current buffer content */ abAppend(&ab,l->prompt,strlen(l->prompt)); abAppend(&ab,l->buf,l->len); /* Show hits if any. */ refreshShowHints(&ab,l,plen); /* If we are at the very end of the screen with our prompt, we need to * emit a newline and move the prompt to the first column. */ if (l->pos && l->pos == l->len && (l->pos+plen) % l->cols == 0) { /* lndebug("<newline>"); */ abAppend(&ab,"\n",1); snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); rows++; if (rows > (int)l->maxrows) l->maxrows = rows; } /* Move cursor to right position. */ rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */ /* lndebug("rpos2 %d", rpos2); */ /* Go up till we reach the expected positon. */ if (rows-rpos2 > 0) { /* lndebug("go-up %d", rows-rpos2); */ snprintf(seq,64,"\x1b[%dA", rows-rpos2); abAppend(&ab,seq,strlen(seq)); } /* Set column. */ col = (plen+(int)l->pos) % (int)l->cols; /* lndebug("set col %d", 1+col); */ if (col) snprintf(seq,64,"\r\x1b[%dC", col); else snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); /* lndebug("\n"); */ l->oldpos = l->pos; if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ abFree(&ab); } /* Calls the two low level functions refreshSingleLine() or * refreshMultiLine() according to the selected mode. */ static void refreshLine(struct linenoiseState *l) { if (mlmode) refreshMultiLine(l); else refreshSingleLine(l); } /* Insert the character 'c' at cursor current position. * * On error writing to the terminal -1 is returned, otherwise 0. */ int linenoiseEditInsert(struct linenoiseState *l, char c) { if (l->len < l->buflen) { if (l->len == l->pos) { l->buf[l->pos] = c; l->pos++; l->len++; l->buf[l->len] = '\0'; if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) { /* Avoid a full update of the line in the * trivial case. */ if (write(l->ofd,&c,1) == -1) return -1; } else { refreshLine(l); } } else { memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos); l->buf[l->pos] = c; l->len++; l->pos++; l->buf[l->len] = '\0'; refreshLine(l); } } return 0; } /* Move cursor on the left. */ void linenoiseEditMoveLeft(struct linenoiseState *l) { if (l->pos > 0) { l->pos--; refreshLine(l); } } /* Move cursor on the right. */ void linenoiseEditMoveRight(struct linenoiseState *l) { if (l->pos != l->len) { l->pos++; refreshLine(l); } } /* Move cursor to the start of the line. */ void linenoiseEditMoveHome(struct linenoiseState *l) { if (l->pos != 0) { l->pos = 0; refreshLine(l); } } /* Move cursor to the end of the line. */ void linenoiseEditMoveEnd(struct linenoiseState *l) { if (l->pos != l->len) { l->pos = l->len; refreshLine(l); } } /* Substitute the currently edited line with the next or previous history * entry as specified by 'dir'. */ #define LINENOISE_HISTORY_NEXT 0 #define LINENOISE_HISTORY_PREV 1 void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { if (history_len > 1) { /* Update the current history entry before to * overwrite it with the next one. */ free(history[history_len - 1 - l->history_index]); history[history_len - 1 - l->history_index] = strdup(l->buf); /* Show the new entry */ l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; if (l->history_index < 0) { l->history_index = 0; return; } else if (l->history_index >= history_len) { l->history_index = history_len-1; return; } strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen); l->buf[l->buflen-1] = '\0'; l->len = l->pos = strlen(l->buf); refreshLine(l); } } /* Delete the character at the right of the cursor without altering the cursor * position. Basically this is what happens with the "Delete" keyboard key. */ void linenoiseEditDelete(struct linenoiseState *l) { if (l->len > 0 && l->pos < l->len) { memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1); l->len--; l->buf[l->len] = '\0'; refreshLine(l); } } /* Backspace implementation. */ void linenoiseEditBackspace(struct linenoiseState *l) { if (l->pos > 0 && l->len > 0) { memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos); l->pos--; l->len--; l->buf[l->len] = '\0'; refreshLine(l); } } /* Delete the previosu word, maintaining the cursor at the start of the * current word. */ void linenoiseEditDeletePrevWord(struct linenoiseState *l) { size_t old_pos = l->pos; size_t diff; while (l->pos > 0 && l->buf[l->pos-1] == ' ') l->pos--; while (l->pos > 0 && l->buf[l->pos-1] != ' ') l->pos--; diff = old_pos - l->pos; memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1); l->len -= diff; refreshLine(l); } /* This function is the core of the line editing capability of linenoise. * It expects 'fd' to be already in "raw mode" so that every key pressed * will be returned ASAP to read(). * * The resulting string is put into 'buf' when the user type enter, or * when ctrl+d is typed. * * The function returns the length of the current buffer. */ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) { struct linenoiseState l; /* Populate the linenoise state that we pass to functions implementing * specific editing functionalities. */ l.ifd = stdin_fd; l.ofd = stdout_fd; l.buf = buf; l.buflen = buflen; l.prompt = prompt; l.plen = strlen(prompt); l.oldpos = l.pos = 0; l.len = 0; l.cols = getColumns(stdin_fd, stdout_fd); l.maxrows = 0; l.history_index = 0; /* Buffer starts empty. */ l.buf[0] = '\0'; l.buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); if (write(l.ofd,prompt,l.plen) == -1) return -1; while(1) { char c; int nread; char seq[3]; nread = read(l.ifd,&c,1); if (nread <= 0) return l.len; /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ if (c == 9 && completionCallback != NULL) { c = completeLine(&l); /* Return on errors */ if (c < 0) return l.len; /* Read next character when 0 */ if (c == 0) continue; } switch(c) { case ENTER: /* enter */ history_len--; free(history[history_len]); if (mlmode) linenoiseEditMoveEnd(&l); if (hintsCallback) { /* Force a refresh without hints to leave the previous * line as the user typed it after a newline. */ linenoiseHintsCallback *hc = hintsCallback; hintsCallback = NULL; refreshLine(&l); hintsCallback = hc; } return (int)l.len; case CTRL_C: /* ctrl-c */ errno = EAGAIN; return -1; case BACKSPACE: /* backspace */ case 8: /* ctrl-h */ linenoiseEditBackspace(&l); break; case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the line is empty, act as end-of-file. */ if (l.len > 0) { linenoiseEditDelete(&l); } else { history_len--; free(history[history_len]); return -1; } break; case CTRL_T: /* ctrl-t, swaps current character with previous. */ if (l.pos > 0 && l.pos < l.len) { int aux = buf[l.pos-1]; buf[l.pos-1] = buf[l.pos]; buf[l.pos] = aux; if (l.pos != l.len-1) l.pos++; refreshLine(&l); } break; case CTRL_B: /* ctrl-b */ linenoiseEditMoveLeft(&l); break; case CTRL_F: /* ctrl-f */ linenoiseEditMoveRight(&l); break; case CTRL_P: /* ctrl-p */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case CTRL_N: /* ctrl-n */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; case ESC: /* escape sequence */ /* Read the next two bytes representing the escape sequence. * Use two calls to handle slow terminals returning the two * chars at different times. */ if (read(l.ifd,seq,1) == -1) break; if (read(l.ifd,seq+1,1) == -1) break; /* ESC [ sequences. */ if (seq[0] == '[') { if (seq[1] >= '0' && seq[1] <= '9') { /* Extended escape, read additional byte. */ if (read(l.ifd,seq+2,1) == -1) break; if (seq[2] == '~') { switch(seq[1]) { case '3': /* Delete key. */ linenoiseEditDelete(&l); break; } } } else { switch(seq[1]) { case 'A': /* Up */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case 'B': /* Down */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; case 'C': /* Right */ linenoiseEditMoveRight(&l); break; case 'D': /* Left */ linenoiseEditMoveLeft(&l); break; case 'H': /* Home */ linenoiseEditMoveHome(&l); break; case 'F': /* End*/ linenoiseEditMoveEnd(&l); break; } } } /* ESC O sequences. */ else if (seq[0] == 'O') { switch(seq[1]) { case 'H': /* Home */ linenoiseEditMoveHome(&l); break; case 'F': /* End*/ linenoiseEditMoveEnd(&l); break; } } break; default: if (linenoiseEditInsert(&l,c)) return -1; break; case CTRL_U: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; l.pos = l.len = 0; refreshLine(&l); break; case CTRL_K: /* Ctrl+k, delete from current to end of line. */ buf[l.pos] = '\0'; l.len = l.pos; refreshLine(&l); break; case CTRL_A: /* Ctrl+a, go to the start of the line */ linenoiseEditMoveHome(&l); break; case CTRL_E: /* ctrl+e, go to the end of the line */ linenoiseEditMoveEnd(&l); break; case CTRL_L: /* ctrl+l, clear screen */ linenoiseClearScreen(); refreshLine(&l); break; case CTRL_W: /* ctrl+w, delete previous word */ linenoiseEditDeletePrevWord(&l); break; } } return l.len; } /* This special mode is used by linenoise in order to print scan codes * on screen for debugging / development purposes. It is implemented * by the linenoise_example program using the --keycodes option. */ void linenoisePrintKeyCodes(void) { char quit[4]; printf("Linenoise key codes debugging mode.\n" "Press keys to see scan codes. Type 'quit' at any time to exit.\n"); if (enableRawMode(STDIN_FILENO) == -1) return; memset(quit,' ',4); while(1) { char c; int nread; nread = read(STDIN_FILENO,&c,1); if (nread <= 0) continue; memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ if (memcmp(quit,"quit",sizeof(quit)) == 0) break; printf("'%c' %02x (%d) (type quit to exit)\n", isprint(c) ? c : '?', (int)c, (int)c); printf("\r"); /* Go left edge manually, we are in raw mode. */ fflush(stdout); } disableRawMode(STDIN_FILENO); } /* This function calls the line editing function linenoiseEdit() using * the STDIN file descriptor set in raw mode. */ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { int count; if (buflen == 0) { errno = EINVAL; return -1; } if (enableRawMode(STDIN_FILENO) == -1) return -1; count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); disableRawMode(STDIN_FILENO); printf("\n"); return count; } /* This function is called when linenoise() is called with the standard * input file descriptor not attached to a TTY. So for example when the * program using linenoise is called in pipe or with a file redirected * to its standard input. In this case, we want to be able to return the * line regardless of its length (by default we are limited to 4k). */ static char *linenoiseNoTTY(void) { char *line = NULL; size_t len = 0, maxlen = 0; while(1) { if (len == maxlen) { if (maxlen == 0) maxlen = 16; maxlen *= 2; char *oldval = line; line = realloc(line,maxlen); if (line == NULL) { if (oldval) free(oldval); return NULL; } } int c = fgetc(stdin); if (c == EOF || c == '\n') { if (c == EOF && len == 0) { free(line); return NULL; } else { line[len] = '\0'; return line; } } else { line[len] = c; len++; } } } /* The high level function that is the main API of the linenoise library. * This function checks if the terminal has basic capabilities, just checking * for a blacklist of stupid terminals, and later either calls the line * editing function or uses dummy fgets() so that you will be able to type * something even in the most desperate of the conditions. */ char *linenoise(const char *prompt) { char buf[LINENOISE_MAX_LINE]; int count; if (!isatty(STDIN_FILENO)) { /* Not a tty: read from file / pipe. In this mode we don't want any * limit to the line size, so we call a function to handle that. */ return linenoiseNoTTY(); } else if (isUnsupportedTerm()) { size_t len; printf("%s",prompt); fflush(stdout); if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; len = strlen(buf); while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) { len--; buf[len] = '\0'; } return strdup(buf); } else { count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); if (count == -1) return NULL; return strdup(buf); } } /* This is just a wrapper the user may want to call in order to make sure * the linenoise returned buffer is freed with the same allocator it was * created with. Useful when the main program is using an alternative * allocator. */ void linenoiseFree(void *ptr) { free(ptr); } /* ================================ History ================================= */ /* Free the history, but does not reset it. Only used when we have to * exit() to avoid memory leaks are reported by valgrind & co. */ static void freeHistory(void) { if (history) { int j; for (j = 0; j < history_len; j++) free(history[j]); free(history); } } /* At exit we'll try to fix the terminal to the initial conditions. */ static void linenoiseAtExit(void) { disableRawMode(STDIN_FILENO); freeHistory(); } /* This is the API call to add a new entry in the linenoise history. * It uses a fixed array of char pointers that are shifted (memmoved) * when the history max length is reached in order to remove the older * entry and make room for the new one, so it is not exactly suitable for huge * histories, but will work well for a few hundred of entries. * * Using a circular buffer is smarter, but a bit more complex to handle. */ int linenoiseHistoryAdd(const char *line) { char *linecopy; if (history_max_len == 0) return 0; /* Initialization on first call. */ if (history == NULL) { history = malloc(sizeof(char*)*history_max_len); if (history == NULL) return 0; memset(history,0,(sizeof(char*)*history_max_len)); } /* Don't add duplicated lines. */ if (history_len && !strcmp(history[history_len-1], line)) return 0; /* Add an heap allocated copy of the line in the history. * If we reached the max length, remove the older line. */ linecopy = strdup(line); if (!linecopy) return 0; if (history_len == history_max_len) { free(history[0]); memmove(history,history+1,sizeof(char*)*(history_max_len-1)); history_len--; } history[history_len] = linecopy; history_len++; return 1; } /* Set the maximum length for the history. This function can be called even * if there is already some history, the function will make sure to retain * just the latest 'len' elements if the new history length value is smaller * than the amount of items already inside the history. */ int linenoiseHistorySetMaxLen(int len) { char **new; if (len < 1) return 0; if (history) { int tocopy = history_len; new = malloc(sizeof(char*)*len); if (new == NULL) return 0; /* If we can't copy everything, free the elements we'll not use. */ if (len < tocopy) { int j; for (j = 0; j < tocopy-len; j++) free(history[j]); tocopy = len; } memset(new,0,sizeof(char*)*len); memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy); free(history); history = new; } history_max_len = len; if (history_len > history_max_len) history_len = history_max_len; return 1; } /* Save the history in the specified file. On success 0 is returned * otherwise -1 is returned. */ int linenoiseHistorySave(const char *filename) { mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO); FILE *fp; int j; fp = fopen(filename,"w"); umask(old_umask); if (fp == NULL) return -1; chmod(filename,S_IRUSR|S_IWUSR); for (j = 0; j < history_len; j++) fprintf(fp,"%s\n",history[j]); fclose(fp); return 0; } /* Load the history from the specified file. If the file does not exist * zero is returned and no operation is performed. * * If the file exists and the operation succeeded 0 is returned, otherwise * on error -1 is returned. */ int linenoiseHistoryLoad(const char *filename) { FILE *fp = fopen(filename,"r"); char buf[LINENOISE_MAX_LINE]; if (fp == NULL) return -1; while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) { char *p; p = strchr(buf,'\r'); if (!p) p = strchr(buf,'\n'); if (p) *p = '\0'; linenoiseHistoryAdd(buf); } fclose(fp); return 0; } |
Added src/linenoise.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* linenoise.h -- VERSION 1.0 * * Guerrilla line editing library against the idea that a line editing lib * needs to be 20,000 lines of C code. * * See linenoise.c for more information. * * ------------------------------------------------------------------------ * * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com> * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LINENOISE_H #define __LINENOISE_H #ifdef __cplusplus extern "C" { #endif typedef struct linenoiseCompletions { size_t len; char **cvec; } linenoiseCompletions; typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); typedef void(linenoiseFreeHintsCallback)(void *); void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); void linenoiseSetHintsCallback(linenoiseHintsCallback *); void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); void linenoiseAddCompletion(linenoiseCompletions *, const char *); char *linenoise(const char *prompt); void linenoiseFree(void *ptr); int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySave(const char *filename); int linenoiseHistoryLoad(const char *filename); void linenoiseClearScreen(void); void linenoiseSetMultiLine(int ml); void linenoisePrintKeyCodes(void); #ifdef __cplusplus } #endif #endif /* __LINENOISE_H */ |
Changes to src/loadctrl.c.
︙ | ︙ | |||
43 44 45 46 47 48 49 | ** Print the load average on the host machine. */ void loadavg_test_cmd(void){ fossil_print("load-average: %f\n", load_average()); } /* | | | < | < < < < < < < < < | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | ** Print the load average on the host machine. */ void loadavg_test_cmd(void){ fossil_print("load-average: %f\n", load_average()); } /* ** Abort the current operation of the load average of the host computer ** is too high. */ void load_control(void){ double mxLoad = atof(db_get("max-loadavg", "0")); if( mxLoad<=0.0 || mxLoad>=load_average() ) return; style_header("Server Overload"); @ <h2>The server load is currently too high. @ Please try again later.</h2> @ <p>Current load average: %f(load_average()).<br /> @ Load average limit: %f(mxLoad)</p> style_footer(); cgi_set_status(503,"Server Overload"); cgi_reply(); exit(0); } |
Changes to src/login.c.
︙ | ︙ | |||
47 48 49 50 51 52 53 | # include <windows.h> /* for Sleep */ # if defined(__MINGW32__) || defined(_MSC_VER) # define sleep Sleep /* windows does not have sleep, but Sleep */ # endif #endif #include <time.h> | < < < < < < < < < < < < < < < | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # include <windows.h> /* for Sleep */ # if defined(__MINGW32__) || defined(_MSC_VER) # define sleep Sleep /* windows does not have sleep, but Sleep */ # endif #endif #include <time.h> /* ** Return the login-group name. Or return 0 if this repository is ** not a member of a login-group. */ const char *login_group_name(void){ static const char *zGroup = 0; |
︙ | ︙ | |||
118 119 120 121 122 123 124 | /* ** Redirect to the page specified by the "g" query parameter. ** Or if there is no "g" query parameter, redirect to the homepage. */ static void redirect_to_g(void){ const char *zGoto = P("g"); if( zGoto ){ | | > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Redirect to the page specified by the "g" query parameter. ** Or if there is no "g" query parameter, redirect to the homepage. */ static void redirect_to_g(void){ const char *zGoto = P("g"); if( zGoto ){ cgi_redirect(zGoto); }else{ fossil_redirect_home(); } } /* ** The IP address of the client is stored as part of login cookies. ** But some clients are behind firewalls that shift the IP address ** with each HTTP request. To allow such (broken) clients to log in, ** extract just a prefix of the IP address. */ static char *ipPrefix(const char *zIP){ int i, j; static int ip_prefix_terms = -1; if( ip_prefix_terms<0 ){ ip_prefix_terms = db_get_int("ip-prefix-terms",2); } if( ip_prefix_terms==0 ) return mprintf("0"); for(i=j=0; zIP[i]; i++){ if( zIP[i]=='.' ){ j++; if( j==ip_prefix_terms ) break; } } return mprintf("%.*s", i, zIP); } /* ** Return an abbreviated project code. The abbreviation is the first ** 16 characters of the project code. ** ** Memory is obtained from malloc. */ |
︙ | ︙ | |||
157 158 159 160 161 162 163 | if( zUsername==0 ) return 0; else if( zPassword==0 ) return 0; else if( zCS==0 ) return 0; else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0; zPw = captcha_decode((unsigned int)atoi(zCS)); if( fossil_stricmp(zPw, zPassword)!=0 ) return 0; uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'" | | < < | | | | | | | | < < < | | | | | | | < < < < < | 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 | if( zUsername==0 ) return 0; else if( zPassword==0 ) return 0; else if( zCS==0 ) return 0; else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0; zPw = captcha_decode((unsigned int)atoi(zCS)); if( fossil_stricmp(zPw, zPassword)!=0 ) return 0; uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'" " AND length(pw)>0 AND length(cap)>0"); return uid; } /* ** Make sure the accesslog table exists. Create it if it does not */ void create_accesslog_table(void){ db_multi_exec( "CREATE TABLE IF NOT EXISTS repository.accesslog(" " uname TEXT," " ipaddr TEXT," " success BOOLEAN," " mtime TIMESTAMP" ");" ); } /* ** Make a record of a login attempt, if login record keeping is enabled. */ static void record_login_attempt( const char *zUsername, /* Name of user logging in */ const char *zIpAddr, /* IP address from which they logged in */ int bSuccess /* True if the attempt was a success */ ){ if( !db_get_boolean("access-log", 0) ) return; create_accesslog_table(); db_multi_exec( "INSERT INTO accesslog(uname,ipaddr,success,mtime)" "VALUES(%Q,%Q,%d,julianday('now'));", zUsername, zIpAddr, bSuccess ); } /* ** Searches for the user ID matching the given name and password. ** On success it returns a positive value. On error it returns 0. ** On serious (DB-level) error it will probably exit. ** |
︙ | ︙ | |||
223 224 225 226 227 228 229 | ** form of the user's password. */ int login_search_uid(const char **pzUsername, const char *zPasswd){ char *zSha1Pw = sha1_shared_secret(zPasswd, *pzUsername, 0); int uid = db_int(0, "SELECT uid FROM user" " WHERE login=%Q" | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ** form of the user's password. */ int login_search_uid(const char **pzUsername, const char *zPasswd){ char *zSha1Pw = sha1_shared_secret(zPasswd, *pzUsername, 0); int uid = db_int(0, "SELECT uid FROM user" " WHERE login=%Q" " AND length(cap)>0 AND length(pw)>0" " AND login NOT IN ('anonymous','nobody','developer','reader')" " AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))" " AND (info NOT LIKE '%%expires 20%%'" " OR substr(info,instr(lower(info),'expires')+8,10)>datetime('now'))", *pzUsername, zSha1Pw, zPasswd ); |
︙ | ︙ | |||
252 253 254 255 256 257 258 | const char *zLogin = db_column_text(&q,0); if( (uid = login_search_uid(&zLogin, zPasswd) ) != 0 ){ *pzUsername = fossil_strdup(zLogin); break; } } db_finalize(&q); | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | const char *zLogin = db_column_text(&q,0); if( (uid = login_search_uid(&zLogin, zPasswd) ) != 0 ){ *pzUsername = fossil_strdup(zLogin); break; } } db_finalize(&q); } free(zSha1Pw); return uid; } /* ** Generates a login cookie value for a non-anonymous user. ** |
︙ | ︙ | |||
284 285 286 287 288 289 290 | ** ** This function also updates the user.cookie, user.ipaddr, ** and user.cexpire fields for the given user. ** ** If zDest is not NULL then the generated cookie is copied to ** *zDdest and ownership is transfered to the caller (who should ** eventually pass it to free()). | < < < < < < | < | | > > | | < | | | | > | | > > > > < < | < | > > > > | | | > < < > > > > > > > > > > > > > > > > > > | > | | | | > < < < | | < < < < < < < < < < < < < < < < < < < < < | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | ** ** This function also updates the user.cookie, user.ipaddr, ** and user.cexpire fields for the given user. ** ** If zDest is not NULL then the generated cookie is copied to ** *zDdest and ownership is transfered to the caller (who should ** eventually pass it to free()). */ void login_set_user_cookie( const char *zUsername, /* User's name */ int uid, /* User's ID */ char **zDest /* Optional: store generated cookie value. */ ){ const char *zCookieName = login_cookie_name(); const char *zExpire = db_get("cookie-expire","8766"); int expires = atoi(zExpire)*3600; char *zHash; char *zCookie; const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */ char *zRemoteAddr = ipPrefix(zIpAddr); /* Abbreviated IP address */ assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data."); zHash = db_text(0, "SELECT cookie FROM user" " WHERE uid=%d" " AND ipaddr=%Q" " AND cexpire>julianday('now')" " AND length(cookie)>30", uid, zRemoteAddr); if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))"); zCookie = login_gen_user_cookie_value(zUsername, zHash); cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires); record_login_attempt(zUsername, zIpAddr, 1); db_multi_exec( "UPDATE user SET cookie=%Q, ipaddr=%Q, " " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", zHash, zRemoteAddr, expires, uid ); free(zRemoteAddr); free(zHash); if( zDest ){ *zDest = zCookie; }else{ free(zCookie); } } /* Sets a cookie for an anonymous user login, which looks like this: ** ** HASH/TIME/anonymous ** ** Where HASH is the sha1sum of TIME/IPADDR/SECRET, in which IPADDR ** is the abbreviated IP address and SECRET is captcha-secret. ** ** If either zIpAddr or zRemoteAddr are NULL then REMOTE_ADDR ** is used. ** ** If zCookieDest is not NULL then the generated cookie is assigned to ** *zCookieDest and the caller must eventually free() it. */ void login_set_anon_cookie(const char *zIpAddr, char **zCookieDest ){ const char *zNow; /* Current time (julian day number) */ char *zCookie; /* The login cookie */ const char *zCookieName; /* Name of the login cookie */ Blob b; /* Blob used during cookie construction */ char *zRemoteAddr; /* Abbreviated IP address */ if(!zIpAddr){ zIpAddr = PD("REMOTE_ADDR","nil"); } zRemoteAddr = ipPrefix(zIpAddr); zCookieName = login_cookie_name(); zNow = db_text("0", "SELECT julianday('now')"); assert( zCookieName && zRemoteAddr && zIpAddr && zNow ); blob_init(&b, zNow, -1); blob_appendf(&b, "/%s/%s", zRemoteAddr, db_get("captcha-secret","")); sha1sum_blob(&b, &b); zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow); blob_reset(&b); cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), 6*3600); if( zCookieDest ){ *zCookieDest = zCookie; }else{ free(zCookie); } } /* ** "Unsets" the login cookie (insofar as cookies can be unset) and ** clears the current user's (g.userUid) login information from the ** user table. Sets: user.cookie, user.ipaddr, user.cexpire. ** ** We could/should arguably clear out g.userUid and g.perm here, but ** we don't currently do not. ** ** This is a no-op if g.userUid is 0. */ void login_clear_login_data(){ if(!g.userUid){ return; }else{ const char *cookie = login_cookie_name(); /* To logout, change the cookie value to an empty string */ cgi_set_cookie(cookie, "", login_cookie_path(), -86400); db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, " " cexpire=0 WHERE uid=%d" " AND login NOT IN ('anonymous','nobody'," " 'developer','reader')", g.userUid); cgi_replace_parameter(cookie, NULL); cgi_replace_parameter("anon", NULL); } } /* ** Return true if the prefix of zStr matches zPattern. Return false if ** they are different. ** ** A lowercase character in zPattern will match either upper or lower ** case in zStr. But an uppercase in zPattern will only match an ** uppercase in zStr. */ static int prefix_match(const char *zPattern, const char *zStr){ int i; char c; for(i=0; (c = zPattern[i])!=0; i++){ if( zStr[i]!=c && fossil_tolower(zStr[i])!=c ) return 0; } return 1; } /* ** Look at the HTTP_USER_AGENT parameter and try to determine if the user agent ** is a manually operated browser or a bot. When in doubt, assume a bot. ** Return true if we believe the agent is a real person. */ static int isHuman(const char *zAgent){ int i; if( zAgent==0 ) return 0; /* If no UserAgent, then probably a bot */ for(i=0; zAgent[i]; i++){ if( prefix_match("bot", zAgent+i) ) return 0; if( prefix_match("spider", zAgent+i) ) return 0; if( prefix_match("crawl", zAgent+i) ) return 0; /* If a URI appears in the User-Agent, it is probably a bot */ if( strncmp("http", zAgent+i,4)==0 ) return 0; } if( strncmp(zAgent, "Mozilla/", 8)==0 ){ if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */ /* 2016-05-30: A pernicious spider that likes to walk Fossil timelines has ** been detected on the SQLite website. The spider changes its user-agent ** string frequently, but it always seems to include the following text: */ if( sqlite3_strglob("*Safari/537.36Mozilla/5.0*", zAgent)==0 ) return 0; if( sqlite3_strglob("*Firefox/[1-9]*", zAgent)==0 ) return 1; if( sqlite3_strglob("*Chrome/[1-9]*", zAgent)==0 ) return 1; if( sqlite3_strglob("*(compatible;?MSIE?[1789]*", zAgent)==0 ) return 1; if( sqlite3_strglob("*Trident/[1-9]*;?rv:[1-9]*", zAgent)==0 ) return 1; /* IE11+ */ if( sqlite3_strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent)==0 ) return 1; return 0; } if( strncmp(zAgent, "Opera/", 6)==0 ) return 1; if( strncmp(zAgent, "Safari/", 7)==0 ) return 1; if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1; if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1; return 0; } /* ** COMMAND: test-ishuman ** ** Read lines of text from standard input. Interpret each line of text ** as a User-Agent string from an HTTP header. Label each line as HUMAN ** or ROBOT. */ |
︙ | ︙ | |||
507 508 509 510 511 512 513 | if( zReferer==0 ) return 0; zPattern = mprintf("%s/login*", g.zBaseURL); rc = sqlite3_strglob(zPattern, zReferer)==0; fossil_free(zPattern); return rc; } | < < < < < < < < < | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | if( zReferer==0 ) return 0; zPattern = mprintf("%s/login*", g.zBaseURL); rc = sqlite3_strglob(zPattern, zReferer)==0; fossil_free(zPattern); return rc; } /* ** Return TRUE if self-registration is available. If the zNeeded ** argument is not NULL, then only return true if self-registration is ** available and any of the capabilities named in zNeeded are available ** to self-registered users. */ int login_self_register_available(const char *zNeeded){ CapabilityString *pCap; int rc; if( !db_get_boolean("self-register",0) ) return 0; if( zNeeded==0 ) return 1; pCap = capability_add(0, db_get("default-perms","")); capability_expand(pCap); rc = capability_has_any(pCap, zNeeded); capability_free(pCap); return rc; } /* |
︙ | ︙ | |||
560 561 562 563 564 565 566 | const char *zAnonPw = 0; const char *zGoto = P("g"); int anonFlag; /* Login as "anonymous" would be useful */ char *zErrMsg = ""; int uid; /* User id logged in user */ char *zSha1Pw; const char *zIpAddr; /* IP address of requestor */ | > | | < | > > > > > > > > > > > > > > > | | < < | > > > > < < > | < | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | const char *zAnonPw = 0; const char *zGoto = P("g"); int anonFlag; /* Login as "anonymous" would be useful */ char *zErrMsg = ""; int uid; /* User id logged in user */ char *zSha1Pw; const char *zIpAddr; /* IP address of requestor */ const char *zReferer; int noAnon = P("noanon")!=0; login_check_credentials(); if( login_wants_https_redirect() ){ const char *zQS = P("QUERY_STRING"); if( P("redir")!=0 ){ style_header("Insecure Connection"); @ <h1>Unable To Establish An Encrypted Connection</h1> @ <p>This website requires that login credentials be sent over @ an encrypted connection. The current connection is not encrypted @ across the entire route between your browser and the server. @ An attempt was made to redirect to %h(g.zHttpsURL) but @ the connection is still insecure even after the redirect.</p> @ <p>This is probably some kind of configuration problem. Please @ contact your sysadmin.</p> @ <p>Sorry it did not work out.</p> style_footer(); return; } if( zQS==0 ){ zQS = "?redir=1"; }else if( zQS[0]!=0 ){ zQS = mprintf("?%s&redir=1", zQS); } cgi_redirectf("%s%T%s", g.zHttpsURL, P("PATH_INFO"), zQS); return; } sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); zUsername = P("u"); zPasswd = P("p"); anonFlag = g.zLogin==0 && PB("anon"); /* Handle log-out requests */ if( P("out") ){ login_clear_login_data(); redirect_to_g(); return; } /* Redirect for create-new-account requests */ if( P("self") ){ cgi_redirectf("%R/register"); return; } /* Deal with password-change requests */ if( g.perm.Password && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ /* If there is not a "real" login, we cannot change any password. */ if( g.zLogin ){ /* The user requests a password change */ zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); if( db_int(1, "SELECT 0 FROM user" " WHERE uid=%d" |
︙ | ︙ | |||
623 624 625 626 627 628 629 | @ Your password is unchanged. @ </span></p> ; }else{ char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); char *zChngPw; char *zErr; | < < < < < < < < > < | < < < < < < < < > < < < < < < | < | < < | > > | < > | > | < | < < > > | > > > | | | > > < < < | < < < < < | | > < < < < < < < < | < < < < < < > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | < < < < | < < | < < < < < < < < < < | < < < < < < < < < < | < | < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | | | | > > | | > | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 | @ Your password is unchanged. @ </span></p> ; }else{ char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); char *zChngPw; char *zErr; db_multi_exec( "UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid ); fossil_free(zNewPw); zChngPw = mprintf( "UPDATE user" " SET pw=shared_secret(%Q,%Q," " (SELECT value FROM config WHERE name='project-code'))" " WHERE login=%Q", zNew1, g.zLogin, g.zLogin ); if( login_group_sql(zChngPw, "<p>", "</p>\n", &zErr) ){ zErrMsg = mprintf("<span class=\"loginError\">%s</span>", zErr); fossil_free(zErr); }else{ redirect_to_g(); return; } } }else{ zErrMsg = @ <p><span class="loginError"> @ The password cannot be changed for this type of login. @ The password is unchanged. @ </span></p> ; } } zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */ zReferer = P("HTTP_REFERER"); uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs")); if( uid>0 ){ login_set_anon_cookie(zIpAddr, NULL); record_login_attempt("anonymous", zIpAddr, 1); redirect_to_g(); } if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ /* Attempting to log in as a user other than anonymous. */ uid = login_search_uid(&zUsername, zPasswd); if( uid<=0 ){ sleep(1); zErrMsg = @ <p><span class="loginError"> @ You entered an unknown user or an incorrect password. @ </span></p> ; record_login_attempt(zUsername, zIpAddr, 0); }else{ /* Non-anonymous login is successful. Set a cookie of the form: ** ** HASH/PROJECT/LOGIN ** ** where HASH is a random hex number, PROJECT is either project ** code prefix, and LOGIN is the user name. */ login_set_user_cookie(zUsername, uid, NULL); redirect_to_g(); } } style_header("Login/Logout"); style_adunit_config(ADUNIT_OFF); @ %s(zErrMsg) if( zGoto && !noAnon ){ char *zAbbrev = fossil_strdup(zGoto); int i; for(i=0; zAbbrev[i] && zAbbrev[i]!='?'; i++){} zAbbrev[i] = 0; if( g.zLogin ){ @ <p>Use a different login with greater privilege than <b>%h(g.zLogin)</b> @ to access <b>%h(zAbbrev)</b>. }else if( anonFlag ){ @ <p>Login as <b>anonymous</b> or any named user @ to access page <b>%h(zAbbrev)</b>. }else{ @ <p>Login as a named user to access page <b>%h(zAbbrev)</b>. } } if( g.sslNotAvailable==0 && strncmp(g.zBaseURL,"https:",6)!=0 && db_get_boolean("https-login",0) ){ form_begin(0, "https:%s/login", g.zBaseURL+5); }else{ form_begin(0, "%R/login"); } if( zGoto ){ @ <input type="hidden" name="g" value="%h(zGoto)" /> }else if( zReferer && strncmp(g.zBaseURL, zReferer, strlen(g.zBaseURL))==0 ){ @ <input type="hidden" name="g" value="%h(zReferer)" /> } if( anonFlag ){ @ <input type="hidden" name="anon" value="1" /> } if( g.zLogin ){ @ <p>Currently logged in as <b>%h(g.zLogin)</b>. @ <input type="submit" name="out" value="Logout"></p> }else{ @ <table class="login_out"> @ <tr> @ <td class="form_label">User ID:</td> if( anonFlag ){ @ <td><input type="text" id="u" name="u" value="anonymous" size="30"></td> }else{ @ <td><input type="text" id="u" name="u" value="" size="30" /></td> } @ </tr> @ <tr> @ <td class="form_label">Password:</td> @ <td><input type="password" id="p" name="p" value="" size="30" /></td> @ </tr> if( P("HTTPS")==0 ){ @ <tr><td class="form_label">Warning:</td> @ <td><span class='securityWarning'> @ Your password will be sent in the clear over an @ unencrypted connection. if( g.sslNotAvailable ){ @ No encrypted connection is available on this server. }else{ @ Consider logging in at @ <a href='%s(g.zHttpsURL)'>%h(g.zHttpsURL)</a> instead. } @ </span></td></tr> } if( g.zLogin==0 && (anonFlag || zGoto==0) ){ zAnonPw = db_text(0, "SELECT pw FROM user" " WHERE login='anonymous'" " AND cap!=''"); } @ <tr> @ <td></td> @ <td><input type="submit" name="in" value="Login"></td> @ </tr> if( !noAnon && login_self_register_available(0) ){ @ <tr> @ <td></td> @ <td><input type="submit" name="self" value="Create A New Account"> @ </tr> } @ </table> if( zAnonPw && !noAnon ){ unsigned int uSeed = captcha_seed(); const char *zDecoded = captcha_decode(uSeed); int bAutoCaptcha = db_get_boolean("auto-captcha", 0); char *zCaptcha = captcha_render(zDecoded); @ <p><input type="hidden" name="cs" value="%u(uSeed)" /> @ Visitors may enter <b>anonymous</b> as the user-ID with @ the 8-character hexadecimal password shown below:</p> @ <div class="captcha"><table class="captcha"><tr><td>\ @ <pre class="captcha"> @ %h(zCaptcha) @ </pre></td></tr></table> if( bAutoCaptcha ) { @ <input type="button" value="Fill out captcha" id='autofillButton' \ @ data-af='%s(zDecoded)' /> style_load_one_js_file("login.js"); } @ </div> free(zCaptcha); } @ </form> } if( login_is_individual() ){ if( g.perm.EmailAlert && alert_enabled() ){ @ <hr> @ <p>Configure <a href="%R/alerts">Email Alerts</a> @ for user <b>%h(g.zLogin)</b></p> } if( g.perm.Password ){ @ <hr> @ <p>Change Password for user <b>%h(g.zLogin)</b>:</p> form_begin(0, "%R/login"); @ <table> @ <tr><td class="form_label">Old Password:</td> @ <td><input type="password" name="p" size="30" /></td></tr> @ <tr><td class="form_label">New Password:</td> @ <td><input type="password" name="n1" size="30" /></td></tr> @ <tr><td class="form_label">Repeat New Password:</td> @ <td><input type="password" name="n2" size="30" /></td></tr> @ <tr><td></td> @ <td><input type="submit" value="Change Password" /></td></tr> @ </table> @ </form> } } style_footer(); } /* ** Attempt to find login credentials for user zLogin on a peer repository ** with project code zCode. Transfer those credentials to the local ** repository. ** ** Return true if a transfer was made and false if not. */ static int login_transfer_credentials( const char *zLogin, /* Login we are looking for */ const char *zCode, /* Project code of peer repository */ const char *zHash, /* HASH from login cookie HASH/CODE/LOGIN */ const char *zRemoteAddr /* Request comes from here */ ){ sqlite3 *pOther = 0; /* The other repository */ sqlite3_stmt *pStmt; /* Query against the other repository */ char *zSQL; /* SQL of the query against other repo */ char *zOtherRepo; /* Filename of the other repository */ int rc; /* Result code from SQLite library functions */ int nXfer = 0; /* Number of credentials transferred */ |
︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 | sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0); sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); sqlite3_busy_timeout(pOther, 5000); zSQL = mprintf( "SELECT cexpire FROM user" " WHERE login=%Q" | > | | | < | | < | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0); sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); sqlite3_busy_timeout(pOther, 5000); zSQL = mprintf( "SELECT cexpire FROM user" " WHERE login=%Q" " AND ipaddr=%Q" " AND length(cap)>0" " AND length(pw)>0" " AND cexpire>julianday('now')" " AND constant_time_cmp(cookie,%Q)=0", zLogin, zRemoteAddr, zHash ); pStmt = 0; rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ db_multi_exec( "UPDATE user SET cookie=%Q, ipaddr=%Q, cexpire=%.17g" " WHERE login=%Q", zHash, zRemoteAddr, sqlite3_column_double(pStmt, 0), zLogin ); nXfer++; } sqlite3_finalize(pStmt); } sqlite3_close(pOther); fossil_free(zOtherRepo); return nXfer; |
︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 | if( fossil_strcmp(zLogin, "nobody")==0 ) return 1; if( fossil_strcmp(zLogin, "developer")==0 ) return 1; if( fossil_strcmp(zLogin, "reader")==0 ) return 1; return 0; } /* | | | | > | > > | | | > > > > > > > > > > > > > > > > | | | < < | 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 | if( fossil_strcmp(zLogin, "nobody")==0 ) return 1; if( fossil_strcmp(zLogin, "developer")==0 ) return 1; if( fossil_strcmp(zLogin, "reader")==0 ) return 1; return 0; } /* ** Lookup the uid for a non-built-in user with zLogin and zCookie and ** zRemoteAddr. Return 0 if not found. ** ** Note that this only searches for logged-in entries with matching ** zCookie (db: user.cookie) and zRemoteAddr (db: user.ipaddr) ** entries. */ static int login_find_user( const char *zLogin, /* User name */ const char *zCookie, /* Login cookie value */ const char *zRemoteAddr /* Abbreviated IP address for valid login */ ){ int uid; if( login_is_special(zLogin) ) return 0; uid = db_int(0, "SELECT uid FROM user" " WHERE login=%Q" " AND ipaddr=%Q" " AND cexpire>julianday('now')" " AND length(cap)>0" " AND length(pw)>0" " AND constant_time_cmp(cookie,%Q)=0", zLogin, zRemoteAddr, zCookie ); return uid; } /* ** Return true if it is appropriate to redirect login requests to HTTPS. ** ** Redirect to https is appropriate if all of the above are true: ** (1) The redirect-to-https flag is set ** (2) The current connection is http, not https or ssh ** (3) The sslNotAvailable flag is clear */ int login_wants_https_redirect(void){ if( g.sslNotAvailable ) return 0; if( db_get_boolean("redirect-to-https",0)==0 ) return 0; if( P("HTTPS")!=0 ) return 0; return 1; } /* ** Attempt to use Basic Authentication to establish the user. Return the ** (non-zero) uid if successful. Return 0 if it does not work. */ static int logic_basic_authentication(const char *zIpAddr){ const char *zAuth = PD("HTTP_AUTHORIZATION", 0); int i; int uid = 0; int nDecode = 0; char *zDecode = 0; const char *zUsername = 0; const char *zPasswd = 0; if( zAuth==0 ) return 0; /* Fail: No Authentication: header */ while( fossil_isspace(zAuth[0]) ) zAuth++; /* Skip leading whitespace */ if( strncmp(zAuth, "Basic ", 6)!=0 ) return 0; /* Fail: Not Basic Authentication */ /* Parse out the username and password, separated by a ":" */ zAuth += 6; while( fossil_isspace(zAuth[0]) ) zAuth++; zDecode = decode64(zAuth, &nDecode); for(i=0; zDecode[i] && zDecode[i]!=':'; i++){} |
︙ | ︙ | |||
1258 1259 1260 1261 1262 1263 1264 | ** variables appropriately. ** ** g.userUid Database USER.UID value. Might be -1 for "nobody" ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" ** g.perm Permissions granted to this user ** g.anon Permissions that would be available to anonymous ** g.isHuman True if the user is human, not a spider or robot | < > > | < | | < < < | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | ** variables appropriately. ** ** g.userUid Database USER.UID value. Might be -1 for "nobody" ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" ** g.perm Permissions granted to this user ** g.anon Permissions that would be available to anonymous ** g.isHuman True if the user is human, not a spider or robot ** */ void login_check_credentials(void){ int uid = 0; /* User id */ const char *zCookie; /* Text of the login cookie */ const char *zIpAddr; /* Raw IP address of the requestor */ char *zRemoteAddr; /* Abbreviated IP address of the requestor */ const char *zCap = 0; /* Capability string */ const char *zPublicPages = 0; /* GLOB patterns of public pages */ const char *zLogin = 0; /* Login user for credentials */ /* Only run this check once. */ if( g.userUid!=0 ) return; sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); /* If the HTTP connection is coming over 127.0.0.1 and if ** local login is disabled and if we are using HTTP and not HTTPS, ** then there is no need to check user credentials. ** ** This feature allows the "fossil ui" command to give the user ** full access rights without having to log in. */ zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil")); if( ( cgi_is_loopback(zIpAddr) || (g.fSshClient & CGI_SSH_CLIENT)!=0 ) && g.useLocalauth && db_get_int("localauth",0)==0 && P("HTTPS")==0 ){ if( g.localOpen ) zLogin = db_lget("default-user",0); if( zLogin!=0 ){ uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin); }else{ uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); } g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid); zCap = "sx"; g.noPswd = 1; g.isHuman = 1; sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost"); } /* Check the login cookie to see if it matches a known valid user. */ if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){ /* Parse the cookie value up into HASH/ARG/USER */ char *zHash = fossil_strdup(zCookie); |
︙ | ︙ | |||
1328 1329 1330 1331 1332 1333 1334 | } } } if( zUser==0 ){ /* Invalid cookie */ }else if( fossil_strcmp(zUser, "anonymous")==0 ){ /* Cookies of the form "HASH/TIME/anonymous". The TIME must not be | | | > | | | | | | < | | < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < | 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 | } } } if( zUser==0 ){ /* Invalid cookie */ }else if( fossil_strcmp(zUser, "anonymous")==0 ){ /* Cookies of the form "HASH/TIME/anonymous". The TIME must not be ** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH. ** SECRET is the "captcha-secret" value in the repository. */ double rTime = atof(zArg); Blob b; blob_zero(&b); blob_appendf(&b, "%s/%s/%s", zArg, zRemoteAddr, db_get("captcha-secret","")); sha1sum_blob(&b, &b); if( fossil_strcmp(zHash, blob_str(&b))==0 ){ uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'" " AND length(cap)>0" " AND length(pw)>0" " AND %.17g+0.25>julianday('now')", rTime ); } blob_reset(&b); }else{ /* Cookies of the form "HASH/CODE/USER". Search first in the ** local user table, then the user table for project CODE if we ** are part of a login-group. */ uid = login_find_user(zUser, zHash, zRemoteAddr); if( uid==0 && login_transfer_credentials(zUser,zArg,zHash,zRemoteAddr) ){ uid = login_find_user(zUser, zHash, zRemoteAddr); if( uid ) record_login_attempt(zUser, zIpAddr, 1); } } sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash); } /* If no user found and the REMOTE_USER environment variable is set, ** then accept the value of REMOTE_USER as the user. */ if( uid==0 ){ const char *zRemoteUser = P("REMOTE_USER"); if( zRemoteUser && db_get_boolean("remote_user_ok",0) ){ uid = db_int(0, "SELECT uid FROM user WHERE login=%Q" " AND length(cap)>0 AND length(pw)>0", zRemoteUser); } } /* If the request didn't provide a login cookie or the login cookie didn't ** match a known valid user, check the HTTP "Authorization" header and ** see if those credentials are valid for a known user. */ if( uid==0 && db_get_boolean("http_authentication_ok",0) ){ uid = logic_basic_authentication(zIpAddr); } /* If no user found yet, try to log in as "nobody" */ if( uid==0 ){ uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); if( uid==0 ){ /* If there is no user "nobody", then make one up - with no privileges */ uid = -1; zCap = ""; } sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "none"); } /* At this point, we know that uid!=0. Find the privileges associated ** with user uid. */ assert( uid!=0 ); if( zCap==0 ){ Stmt s; |
︙ | ︙ | |||
1467 1468 1469 1470 1471 1472 1473 | ** who do not have the "h" permission as long as their UserAgent string ** makes it appear that they are human. Check to see if auto-hyperlink is ** enabled for this repository and make appropriate adjustments to the ** permission flags if it is. This should be done before the permissions ** are (potentially) copied to the anonymous permission set; otherwise, ** those will be out-of-sync. */ | > | > | | < | < | < | 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | ** who do not have the "h" permission as long as their UserAgent string ** makes it appear that they are human. Check to see if auto-hyperlink is ** enabled for this repository and make appropriate adjustments to the ** permission flags if it is. This should be done before the permissions ** are (potentially) copied to the anonymous permission set; otherwise, ** those will be out-of-sync. */ if( zCap[0] && !g.perm.Hyperlink && g.isHuman && db_get_boolean("auto-hyperlink",1) ){ g.perm.Hyperlink = 1; g.javascriptHyperlink = 1; } /* ** At this point, the capabilities for the logged in user are not going ** to be modified anymore; therefore, we can copy them over to the ones ** for the anonymous user. ** |
︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 | */ zPublicPages = db_get("public-pages",0); if( zPublicPages!=0 ){ Glob *pGlob = glob_create(zPublicPages); const char *zUri = PD("REQUEST_URI",""); zUri += (int)strlen(g.zTop); if( glob_match(pGlob, zUri) ){ | | < | 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | */ zPublicPages = db_get("public-pages",0); if( zPublicPages!=0 ){ Glob *pGlob = glob_create(zPublicPages); const char *zUri = PD("REQUEST_URI",""); zUri += (int)strlen(g.zTop); if( glob_match(pGlob, zUri) ){ login_set_capabilities(db_get("default-perms","u"), 0); } glob_free(pGlob); } } /* ** Memory of settings */ static int login_anon_once = 1; |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | switch( zCap[i] ){ case 's': p->Setup = 1; /* Fall thru into Admin */ case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip = p->RdWiki = p->WrWiki = p->NewWiki = p->ApndWiki = p->Hyperlink = p->Clone = p->NewTkt = p->Password = p->RdAddr = p->TktFmt = p->Attach = p->ApndTkt = | | | | > > | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 | switch( zCap[i] ){ case 's': p->Setup = 1; /* Fall thru into Admin */ case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip = p->RdWiki = p->WrWiki = p->NewWiki = p->ApndWiki = p->Hyperlink = p->Clone = p->NewTkt = p->Password = p->RdAddr = p->TktFmt = p->Attach = p->ApndTkt = p->ModWiki = p->ModTkt = p->Delete = p->RdForum = p->WrForum = p->ModForum = p->WrTForum = p->AdminForum = p->EmailAlert = p->Announce = p->Debug = p->WrUnver = p->Private = 1; /* Fall thru into Read/Write */ case 'i': p->Read = p->Write = 1; break; case 'o': p->Read = 1; break; case 'z': p->Zip = 1; break; case 'd': p->Delete = 1; break; case 'h': p->Hyperlink = 1; break; case 'g': p->Clone = 1; break; case 'p': p->Password = 1; break; case 'j': p->RdWiki = 1; break; case 'k': p->WrWiki = p->RdWiki = p->ApndWiki =1; break; case 'm': p->ApndWiki = 1; break; |
︙ | ︙ | |||
1601 1602 1603 1604 1605 1606 1607 | case '5': p->ModForum = 1; case '4': p->WrTForum = 1; case '3': p->WrForum = 1; case '2': p->RdForum = 1; break; case '7': p->EmailAlert = 1; break; case 'A': p->Announce = 1; break; | < | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | case '5': p->ModForum = 1; case '4': p->WrTForum = 1; case '3': p->WrForum = 1; case '2': p->RdForum = 1; break; case '7': p->EmailAlert = 1; break; case 'A': p->Announce = 1; break; case 'D': p->Debug = 1; break; /* The "u" privilege recursively ** inherits all privileges of the user named "reader" */ case 'u': { if( p->XReader==0 ){ const char *zUser; |
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 | login_anon_once = 1; } /* ** If the current login lacks any of the capabilities listed in ** the input, then return 0. If all capabilities are present, then ** return 1. | < < < | | 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | login_anon_once = 1; } /* ** If the current login lacks any of the capabilities listed in ** the input, then return 0. If all capabilities are present, then ** return 1. */ int login_has_capability(const char *zCap, int nCap, u32 flgs){ int i; int rc = 1; FossilUserPerms *p = (flgs & LOGIN_ANON) ? &g.anon : &g.perm; if( nCap<0 ) nCap = strlen(zCap); for(i=0; i<nCap && rc && zCap[i]; i++){ switch( zCap[i] ){ case 'a': rc = p->Admin; break; case 'b': rc = p->Attach; break; case 'c': rc = p->ApndTkt; break; case 'd': rc = p->Delete; break; case 'e': rc = p->RdAddr; break; case 'f': rc = p->NewWiki; break; case 'g': rc = p->Clone; break; case 'h': rc = p->Hyperlink; break; case 'i': rc = p->Write; break; case 'j': rc = p->RdWiki; break; case 'k': rc = p->WrWiki; break; |
︙ | ︙ | |||
1688 1689 1690 1691 1692 1693 1694 | case '2': rc = p->RdForum; break; case '3': rc = p->WrForum; break; case '4': rc = p->WrTForum; break; case '5': rc = p->ModForum; break; case '6': rc = p->AdminForum;break; case '7': rc = p->EmailAlert;break; case 'A': rc = p->Announce; break; | < < < < < | 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 | case '2': rc = p->RdForum; break; case '3': rc = p->WrForum; break; case '4': rc = p->WrTForum; break; case '5': rc = p->ModForum; break; case '6': rc = p->AdminForum;break; case '7': rc = p->EmailAlert;break; case 'A': rc = p->Announce; break; case 'D': rc = p->Debug; break; default: rc = 0; break; } } return rc; } /* |
︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 1773 | json_err( FSL_JSON_E_DENIED, NULL, 1 ); fossil_exit(0); /* NOTREACHED */ assert(0); }else #endif /* FOSSIL_ENABLE_JSON */ { const char *zQS = P("QUERY_STRING"); | > < < | | | > | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < > > > | | < < < < < < < < < | | | | | | < < | < < > < < < < | < < < < < < | < | | | | | | < < < < < < < | < < < | | | | > > > > > > > > > | | < < < < < < < < | < < | > < < < | | | | < | | | | < > > > > | > | < < < | < < | | | < | | < | | < | | < < < < < < | | | < | < < < < < < | < | | | < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 | json_err( FSL_JSON_E_DENIED, NULL, 1 ); fossil_exit(0); /* NOTREACHED */ assert(0); }else #endif /* FOSSIL_ENABLE_JSON */ { const char *zUrl = PD("REQUEST_URI", "index"); const char *zQS = P("QUERY_STRING"); Blob redir; blob_init(&redir, 0, 0); if( login_wants_https_redirect() && !g.sslNotAvailable ){ blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zUrl); }else{ blob_appendf(&redir, "%R/login?g=%T", zUrl); } if( anonOk ) blob_append(&redir, "&anon", 5); if( zQS && zQS[0] ){ blob_appendf(&redir, "&%s", zQS); } cgi_redirect(blob_str(&redir)); /* NOTREACHED */ assert(0); } } /* ** Call this routine if the user lacks g.perm.Hyperlink permission. If ** the anonymous user has Hyperlink permission, then paint a mesage ** to inform the user that much more information is available by ** logging in as anonymous. */ void login_anonymous_available(void){ if( !g.perm.Hyperlink && g.anon.Hyperlink ){ const char *zUrl = PD("REQUEST_URI", "index"); @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br /> @ Use <a href="%R/login?anon=1&g=%T(zUrl)">anonymous login</a> @ to enable hyperlinks.</p> } } /* ** While rendering a form, call this routine to add the Anti-CSRF token ** as a hidden element of the form. */ void login_insert_csrf_secret(void){ @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)" /> } /* ** Before using the results of a form, first call this routine to verify ** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token ** is missing or is incorrect, that indicates a cross-site scripting attack. ** If the event of an attack is detected, an error message is generated and ** all further processing is aborted. */ void login_verify_csrf_secret(void){ if( g.okCsrf ) return; if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){ g.okCsrf = 1; return; } fossil_fatal("Cross-site request forgery attempt"); } /* ** WEBPAGE: register ** ** Page to allow users to self-register. The "self-register" setting ** must be enabled for this page to operate. */ void register_page(void){ const char *zUserID, *zPasswd, *zConfirm, *zEAddr; const char *zDName; unsigned int uSeed; const char *zDecoded; char *zCaptcha; int iErrLine = -1; const char *zErr = 0; char *zPerms; /* Permissions for the default user */ int canDoAlerts = 0; /* True if receiving email alerts is possible */ int doAlerts = 0; /* True if subscription is wanted too */ if( !db_get_boolean("self-register", 0) ){ style_header("Registration not possible"); @ <p>This project does not allow user self-registration. Please contact the @ project administrator to obtain an account.</p> style_footer(); return; } zPerms = db_get("default-perms","u"); /* Prompt the user for email alerts if this repository is configured for ** email alerts and if the default permissions include "7" */ canDoAlerts = alert_tables_exist() && db_int(0, "SELECT fullcap(%Q) GLOB '*7*'", zPerms ); doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0; zUserID = PDT("u",""); zPasswd = PDT("p",""); zConfirm = PDT("cp",""); zEAddr = PDT("ea",""); zDName = PDT("dn",""); /* Verify user imputs */ if( P("new")==0 || !cgi_csrf_safe(1) ){ /* This is not a valid form submission. Fall through into ** the form display */ }else if( !captcha_is_correct(1) ){ iErrLine = 6; zErr = "Incorrect CAPTCHA"; }else if( strlen(zUserID)<3 ){ iErrLine = 1; zErr = "User ID too short. Must be at least 3 characters."; }else if( sqlite3_strglob("*[^-a-zA-Z0-9_.]*",zUserID)==0 ){ iErrLine = 1; zErr = "User ID may not contain spaces or special characters."; }else if( zDName[0]==0 ){ iErrLine = 2; zErr = "Required"; }else if( zEAddr[0]==0 ){ iErrLine = 3; zErr = "Required"; }else if( email_copy_addr(zEAddr,0)==0 ){ iErrLine = 3; zErr = "Not a valid email address"; }else if( strlen(zPasswd)<6 ){ iErrLine = 4; zErr = "Password must be at least 6 characters long"; }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){ iErrLine = 5; zErr = "Passwords do not match"; }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zUserID) ){ iErrLine = 1; zErr = "This User ID is already taken. Choose something different."; }else if( /* If the email is found anywhere in USER.INFO... */ db_exists("SELECT 1 FROM user WHERE info LIKE '%%%q%%'", zEAddr) || /* Or if the email is a verify subscriber email with an associated ** user... */ db_exists( "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL" " AND sverified",zEAddr) ){ iErrLine = 3; zErr = "This email address is already claimed by another user"; }else{ /* If all of the tests above have passed, that means that the submitted ** form contains valid data and we can proceed to create the new login */ Blob sql; int uid; char *zPass = sha1_shared_secret(zPasswd, zUserID, 0); blob_init(&sql, 0, 0); blob_append_sql(&sql, "INSERT INTO user(login,pw,cap,info,mtime)\n" "VALUES(%Q,%Q,%Q," "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())", zUserID, zPass, zPerms, zDName, zEAddr, g.zIpAddr); fossil_free(zPass); db_multi_exec("%s", blob_sql_text(&sql)); uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID); login_set_user_cookie(zUserID, uid, NULL); if( doAlerts ){ /* Also make the new user a subscriber. */ Blob hdr, body; AlertSender *pSender; sqlite3_int64 id; /* New subscriber Id */ const char *zCode; /* New subscriber code (in hex) */ const char *zGoto = P("g"); int nsub = 0; char ssub[20]; ssub[nsub++] = 'a'; if( g.perm.Read ) ssub[nsub++] = 'c'; if( g.perm.RdForum ) ssub[nsub++] = 'f'; if( g.perm.RdTkt ) ssub[nsub++] = 't'; if( g.perm.RdWiki ) ssub[nsub++] = 'w'; ssub[nsub] = 0; /* Also add the user to the subscriber table. */ db_multi_exec( "INSERT INTO subscriber(semail,suname," " sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)" " VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)" " ON CONFLICT(semail) DO UPDATE" " SET suname=excluded.suname", /* semail */ zEAddr, /* suname */ zUserID, /* sverified */ 0, /* sdigest */ 0, /* ssub */ ssub, /* smip */ g.zIpAddr ); id = db_last_insert_rowid(); if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q" " AND sverified", zEAddr) ){ /* This the case where the user was formerly a verified subscriber ** and here they have also registered as a user as well. It is ** not necessary to repeat the verfication step */ redirect_to_g(); } zCode = db_text(0, "SELECT hex(subscriberCode) FROM subscriber WHERE subscriberId=%lld", id); /* A verification email */ pSender = alert_sender_new(0,0); blob_init(&hdr,0,0); blob_init(&body,0,0); blob_appendf(&hdr, "To: <%s>\n", zEAddr); blob_appendf(&hdr, "Subject: Subscription verification\n"); alert_append_confirmation_message(&body, zCode); alert_send(pSender, &hdr, &body, 0); style_header("Email Verification"); if( pSender->zErr ){ @ <h1>Internal Error</h1> @ <p>The following internal error was encountered while trying @ to send the confirmation email: @ <blockquote><pre> @ %h(pSender->zErr) @ </pre></blockquote> }else{ @ <p>An email has been sent to "%h(zEAddr)". That email contains a @ hyperlink that you must click on in order to activate your @ subscription.</p> } alert_sender_free(pSender); if( zGoto ){ @ <p><a href='%h(zGoto)'>Continue</a> } style_footer(); return; } redirect_to_g(); } /* Prepare the captcha. */ uSeed = captcha_seed(); zDecoded = captcha_decode(uSeed); zCaptcha = captcha_render(zDecoded); style_header("Register"); /* Print out the registration form. */ form_begin(0, "%R/register"); if( P("g") ){ @ <input type="hidden" name="g" value="%h(P("g"))" /> } @ <p><input type="hidden" name="captchaseed" value="%u(uSeed)" /> @ <table class="login_out"> @ <tr> @ <td class="form_label" align="right">User ID:</td> @ <td><input type="text" name="u" value="%h(zUserID)" size="30"></td> @ if( iErrLine==1 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ <tr> @ <td class="form_label" align="right">Display Name:</td> @ <td><input type="text" name="dn" value="%h(zDName)" size="30"></td> @ </tr> if( iErrLine==2 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ </tr> @ <tr> @ <td class="form_label" align="right">Email Address:</td> @ <td><input type="text" name="ea" value="%h(zEAddr)" size="30"></td> @ </tr> if( iErrLine==3 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } if( canDoAlerts ){ int a = atoi(PD("alerts","1")); @ <tr> @ <td class="form_label" align="right">Email Alerts?</td> @ <td><select size='1' name='alerts'> @ <option value="1" %s(a?"selected":"")>Yes</option> @ <option value="0" %s(!a?"selected":"")>No</option> @ </select></td></tr> } @ <tr> @ <td class="form_label" align="right">Password:</td> @ <td><input type="password" name="p" value="%h(zPasswd)" size="30"></td> @ <tr> if( iErrLine==4 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ <tr> @ <td class="form_label" align="right">Confirm:</td> @ <td><input type="password" name="cp" value="%h(zConfirm)" size="30"></td> @ </tr> if( iErrLine==5 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ <tr> @ <td class="form_label" align="right">Captcha:</td> @ <td><input type="text" name="captcha" value="" size="30"></td> @ </tr> if( iErrLine==6 ){ @ <tr><td><td><span class='loginError'>↑ %h(zErr)</span></td></tr> } @ <tr><td></td> @ <td><input type="submit" name="new" value="Register" /></td></tr> @ </table> @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha"> @ %h(zCaptcha) @ </pre> @ Enter this 8-letter code in the "Captcha" box above. @ </td></tr></table></div> @ </form> style_footer(); free(zCaptcha); } /* ** Run SQL on the repository database for every repository in our ** login group. The SQL is run in a separate database connection. ** |
︙ | ︙ | |||
2409 2410 2411 2412 2413 2414 2415 | zSelfCode ); while( db_step(&q)==SQLITE_ROW ){ const char *zRepoName = db_column_text(&q, 1); if( file_size(zRepoName, ExtFILE)<0 ){ /* Silently remove non-existent repositories from the login group. */ const char *zLabel = db_column_text(&q, 0); | < < | 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 | zSelfCode ); while( db_step(&q)==SQLITE_ROW ){ const char *zRepoName = db_column_text(&q, 1); if( file_size(zRepoName, ExtFILE)<0 ){ /* Silently remove non-existent repositories from the login group. */ const char *zLabel = db_column_text(&q, 0); db_multi_exec( "DELETE FROM config WHERE name GLOB 'peer-*-%q'", &zLabel[10] ); continue; } rc = sqlite3_open_v2( zRepoName, &pPeer, SQLITE_OPEN_READWRITE, g.zVfsName ); |
︙ | ︙ | |||
2462 2463 2464 2465 2466 2467 2468 | /* ** Attempt to join a login-group. ** ** If problems arise, leave an error message in *pzErrMsg. */ void login_group_join( const char *zRepo, /* Repository file in the login group */ | < > | 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 | /* ** Attempt to join a login-group. ** ** If problems arise, leave an error message in *pzErrMsg. */ void login_group_join( const char *zRepo, /* Repository file in the login group */ const char *zLogin, /* Login name for the other repo */ const char *zPassword, /* Password to prove we are authorized to join */ const char *zNewName, /* Name of new login group if making a new one */ char **pzErrMsg /* Leave an error message here */ ){ Blob fullName; /* Blob for finding full pathnames */ sqlite3 *pOther; /* The other repository */ int rc; /* Return code from sqlite3 functions */ char *zOtherProjCode; /* Project code for pOther */ char *zPwHash; /* Password hash on pOther */ char *zSelfRepo; /* Name of our repository */ char *zSelfLabel; /* Project-name for our repository */ char *zSelfProjCode; /* Our project-code */ char *zSql; /* SQL to run on all peers */ const char *zSelf; /* The ATTACH name of our repository */ *pzErrMsg = 0; /* Default to no errors */ |
︙ | ︙ | |||
2527 2528 2529 2530 2531 2532 2533 | /* Attach the other repository. Make sure the username/password is ** valid and has Setup permission. */ db_attach(zRepo, "other"); zOtherProjCode = db_text("x", "SELECT value FROM other.config" " WHERE name='project-code'"); | < < | | | | | | | | | | | < < | 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 | /* Attach the other repository. Make sure the username/password is ** valid and has Setup permission. */ db_attach(zRepo, "other"); zOtherProjCode = db_text("x", "SELECT value FROM other.config" " WHERE name='project-code'"); zPwHash = sha1_shared_secret(zPassword, zLogin, zOtherProjCode); if( !db_exists( "SELECT 1 FROM other.user" " WHERE login=%Q AND cap GLOB '*s*'" " AND (pw=%Q OR pw=%Q)", zLogin, zPassword, zPwHash) ){ db_detach("other"); *pzErrMsg = "The supplied username/password does not correspond to a" " user Setup permission on the other repository."; return; } /* Create all the necessary CONFIG table entries on both the ** other repository and on our own repository. */ zSelfProjCode = abbreviated_project_code(zSelfProjCode); zOtherProjCode = abbreviated_project_code(zOtherProjCode); db_begin_transaction(); db_multi_exec( "DELETE FROM \"%w\".config WHERE name GLOB 'peer-*';" "INSERT INTO \"%w\".config(name,value) VALUES('peer-repo-%q',%Q);" "INSERT INTO \"%w\".config(name,value) " " SELECT 'peer-name-%q', value FROM other.config" " WHERE name='project-name';", zSelf, |
︙ | ︙ | |||
2573 2574 2575 2576 2577 2578 2579 | ); db_multi_exec( "REPLACE INTO \"%w\".config(name,value)" " SELECT name, value FROM other.config" " WHERE name GLOB 'peer-*' OR name GLOB 'login-group-*'", zSelf ); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 | ); db_multi_exec( "REPLACE INTO \"%w\".config(name,value)" " SELECT name, value FROM other.config" " WHERE name GLOB 'peer-*' OR name GLOB 'login-group-*'", zSelf ); db_end_transaction(0); db_multi_exec("DETACH other"); /* Propagate the changes to all other members of the login-group */ zSql = mprintf( "BEGIN;" "REPLACE INTO config(name,value,mtime) VALUES('peer-name-%q',%Q,now());" "REPLACE INTO config(name,value,mtime) VALUES('peer-repo-%q',%Q,now());" "COMMIT;", zSelfProjCode, zSelfLabel, zSelfProjCode, zSelfRepo ); login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); fossil_free(zSql); } /* ** Leave the login group that we are currently part of. */ void login_group_leave(char **pzErrMsg){ char *zProjCode; char *zSql; *pzErrMsg = 0; zProjCode = abbreviated_project_code(db_get("project-code","x")); zSql = mprintf( "DELETE FROM config WHERE name GLOB 'peer-*-%q';" "DELETE FROM config" " WHERE name='login-group-name'" " AND (SELECT count(*) FROM config WHERE name GLOB 'peer-*')==0;", zProjCode ); fossil_free(zProjCode); login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); fossil_free(zSql); db_multi_exec( "DELETE FROM config " " WHERE name GLOB 'peer-*'" " OR name GLOB 'login-group-*';" ); } |
Changes to src/lookslike.c.
︙ | ︙ | |||
268 269 270 271 272 273 274 | const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent); unsigned int n = blob_size(pContent); int j, c, flags = LOOK_NONE; /* Assume UTF-16 text, prove otherwise */ if( n%sizeof(WCHAR_T) ){ flags |= LOOK_ODD; /* Odd number of bytes -> binary (UTF-8?) */ } | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent); unsigned int n = blob_size(pContent); int j, c, flags = LOOK_NONE; /* Assume UTF-16 text, prove otherwise */ if( n%sizeof(WCHAR_T) ){ flags |= LOOK_ODD; /* Odd number of bytes -> binary (UTF-8?) */ } if( n<sizeof(WCHAR_T) ) return flags; /* Zero or One byte -> binary (UTF-8?) */ c = *z; if( bReverse ){ c = UTF16_SWAP(c); } if( c==0 ){ flags |= LOOK_NUL; /* NUL character in a file -> binary */ }else if( c=='\r' ){ |
︙ | ︙ | |||
341 342 343 344 345 346 347 | */ int starts_with_utf8_bom(const Blob *pContent, int *pnByte){ const char *z = blob_buffer(pContent); int bomSize = 0; const unsigned char *bom = get_utf8_bom(&bomSize); if( pnByte ) *pnByte = bomSize; | | | < | < | | | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | */ int starts_with_utf8_bom(const Blob *pContent, int *pnByte){ const char *z = blob_buffer(pContent); int bomSize = 0; const unsigned char *bom = get_utf8_bom(&bomSize); if( pnByte ) *pnByte = bomSize; if( blob_size(pContent)<bomSize ) return 0; return memcmp(z, bom, bomSize)==0; } /* ** This function returns non-zero if the blob starts with a UTF-16 ** byte-order-mark (BOM), either in the endianness of the machine ** or in reversed byte order. The UTF-32 BOM is ruled out by checking ** if the UTF-16 BOM is not immediately followed by (utf16) 0. ** pnByte is only set when the function returns 1. ** ** pbReverse is always set, even when no BOM is found. Without a BOM, ** it is set to 1 on little-endian and 0 on big-endian platforms. See ** clause D98 of conformance (section 3.10) of the Unicode standard. */ int starts_with_utf16_bom( const Blob *pContent, /* IN: Blob content to perform BOM detection on. */ int *pnByte, /* OUT: The number of bytes used for the BOM. */ int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */ ){ const unsigned short *z = (unsigned short *)blob_buffer(pContent); int bomSize = sizeof(unsigned short); int size = blob_size(pContent); if( size<bomSize ) goto noBom; /* No: cannot read BOM. */ if( size>=(2*bomSize) && z[1]==0 ) goto noBom; /* No: possible UTF-32. */ if( z[0]==0xfeff ){ if( pbReverse ) *pbReverse = 0; }else if( z[0]==0xfffe ){ if( pbReverse ) *pbReverse = 1; }else{ static const int one = 1; noBom: if( pbReverse ) *pbReverse = *(char *) &one; return 0; /* No: UTF-16 byte-order-mark not found. */ } |
︙ | ︙ | |||
398 399 400 401 402 403 404 | /* ** COMMAND: test-looks-like-utf ** ** Usage: %fossil test-looks-like-utf FILENAME ** ** Options: | | | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | /* ** COMMAND: test-looks-like-utf ** ** Usage: %fossil test-looks-like-utf FILENAME ** ** Options: ** -n|--limit <num> Repeat looks-like function <num> times, for ** performance measurement. Default = 1; ** --utf8 Ignoring BOM and file size, force UTF-8 checking ** --utf16 Ignoring BOM and file size, force UTF-16 checking ** ** FILENAME is the name of a file to check for textual content in the UTF-8 ** and/or UTF-16 encodings. */ void looks_like_utf_test_cmd(void){ |
︙ | ︙ | |||
458 459 460 461 462 463 464 | fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no"); fossil_print("Has flag LOOK_INVALID: %s\n", (lookFlags&LOOK_INVALID)?"yes":"no"); fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no"); fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no"); blob_reset(&blob); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 456 457 458 459 460 461 462 | fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no"); fossil_print("Has flag LOOK_INVALID: %s\n", (lookFlags&LOOK_INVALID)?"yes":"no"); fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no"); fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no"); blob_reset(&blob); } |
Changes to src/main.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | #include "config.h" #if defined(_WIN32) # include <windows.h> # include <io.h> # define isatty(h) _isatty(h) # define GETPID (int)GetCurrentProcessId #endif | < < < < < < < < < < < > > > > > > < < < < < < < < < > | 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 | #include "config.h" #if defined(_WIN32) # include <windows.h> # include <io.h> # define isatty(h) _isatty(h) # define GETPID (int)GetCurrentProcessId #endif #include "main.h" #include <string.h> #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> /* atexit() */ #if !defined(_WIN32) # include <errno.h> /* errno global */ # include <unistd.h> # include <signal.h> # define GETPID getpid #endif #ifdef FOSSIL_ENABLE_SSL # include "openssl/crypto.h" #endif #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #if INTERFACE #ifdef FOSSIL_ENABLE_TCL # include "tcl.h" #endif #ifdef FOSSIL_ENABLE_JSON # include "cson_amalgamation.h" /* JSON API. */ # include "json_detail.h" #endif #ifdef HAVE_BACKTRACE # include <execinfo.h> #endif /* ** Maximum number of auxiliary parameters on reports */ #define MX_AUX 5 /* ** Holds flags for fossil user permissions. */ struct FossilUserPerms { char Setup; /* s: use Setup screens on web interface */ char Admin; /* a: administrative permission */ char Delete; /* d: delete wiki or tickets */ char Password; /* p: change password */ char Query; /* q: create new reports */ char Write; /* i: xfer inbound. check-in */ char Read; /* o: xfer outbound. check-out */ char Hyperlink; /* h: enable the display of hyperlinks */ char Clone; /* g: clone */ char RdWiki; /* j: view wiki via web */ |
︙ | ︙ | |||
107 108 109 110 111 112 113 | char Zip; /* z: download zipped artifact via /zip URL */ char Private; /* x: can send and receive private content */ char WrUnver; /* y: can push unversioned content */ char RdForum; /* 2: Read forum posts */ char WrForum; /* 3: Create new forum posts */ char WrTForum; /* 4: Post to forums not subject to moderation */ char ModForum; /* 5: Moderate (approve or reject) forum posts */ | | < | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | char Zip; /* z: download zipped artifact via /zip URL */ char Private; /* x: can send and receive private content */ char WrUnver; /* y: can push unversioned content */ char RdForum; /* 2: Read forum posts */ char WrForum; /* 3: Create new forum posts */ char WrTForum; /* 4: Post to forums not subject to moderation */ char ModForum; /* 5: Moderate (approve or reject) forum posts */ char AdminForum; /* 6: Set or remove capability 4 on other users */ char EmailAlert; /* 7: Sign up for email notifications */ char Announce; /* A: Send announcements */ char Debug; /* D: show extra Fossil debugging features */ /* These last two are included to block infinite recursion */ char XReader; /* u: Inherit all privileges of "reader" */ char XDeveloper; /* v: Inherit all privileges of "developer" */ }; #ifdef FOSSIL_ENABLE_TCL |
︙ | ︙ | |||
144 145 146 147 148 149 150 | void *xPostEval; /* Optional, called after Tcl_Eval*(). */ void *pPostContext; /* Optional, provided to xPostEval(). */ }; #endif struct Global { int argc; char **argv; /* Command-line arguments to the program */ | < < < | < | < < | < < < < < | < < < < < < < < | < | | < < < < | 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 | void *xPostEval; /* Optional, called after Tcl_Eval*(). */ void *pPostContext; /* Optional, provided to xPostEval(). */ }; #endif struct Global { int argc; char **argv; /* Command-line arguments to the program */ char *nameOfExe; /* Full path of executable. */ const char *zErrlog; /* Log errors to this file, if not NULL */ int isConst; /* True if the output is unchanging & cacheable */ const char *zVfsName; /* The VFS to use for database connections */ sqlite3 *db; /* The connection to the databases */ sqlite3 *dbConfig; /* Separate connection for global_config table */ char *zAuxSchema; /* Main repository aux-schema */ int dbIgnoreErrors; /* Ignore database errors if true */ const char *zConfigDbName;/* Path of the config database. NULL if not open */ sqlite3_int64 now; /* Seconds since 1970 */ int repositoryOpen; /* True if the main repository database is open */ unsigned iRepoDataVers; /* Initial data version for repository database */ char *zRepositoryOption; /* Most recent cached repository option value */ char *zRepositoryName; /* Name of the repository database file */ char *zLocalDbName; /* Name of the local database file */ char *zOpenRevision; /* Check-in version to use during database open */ int localOpen; /* True if the local database is open */ char *zLocalRoot; /* The directory holding the local database */ int minPrefix; /* Number of digits needed for a distinct UUID */ int eHashPolicy; /* Current hash policy. One of HPOLICY_* */ int fSqlTrace; /* True if --sqltrace flag is present */ int fSqlStats; /* True if --sqltrace or --sqlstats are present */ int fSqlPrint; /* True if --sqlprint flag is present */ int fCgiTrace; /* True if --cgitrace is enabled */ int fQuiet; /* True if -quiet flag is present */ int fJail; /* True if running with a chroot jail */ int fHttpTrace; /* Trace outbound HTTP requests */ int fAnyTrace; /* Any kind of tracing */ char *zHttpAuth; /* HTTP Authorization user:pass information */ int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */ int fSshTrace; /* Trace the SSH setup traffic */ int fSshClient; /* HTTP client flags for SSH client */ int fNoHttpCompress; /* Do not compress HTTP traffic (for debugging) */ char *zSshCmd; /* SSH command string */ int fNoSync; /* Do not do an autosync ever. --nosync */ int fIPv4; /* Use only IPv4, not IPv6. --ipv4 */ char *zPath; /* Name of webpage being served */ char *zExtra; /* Extra path information past the webpage name */ char *zBaseURL; /* Full text of the URL being served */ char *zHttpsURL; /* zBaseURL translated to https: */ char *zTop; /* Parent directory of zPath */ const char *zContentType; /* The content type of the input HTTP request */ int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ int sslNotAvailable; /* SSL is not available. Do not redirect to https: */ Blob cgiIn; /* Input to an xfer www method */ int cgiOutput; /* 0: command-line 1: CGI. 2: after CGI */ int xferPanic; /* Write error messages in XFER protocol */ int fullHttpReply; /* True for full HTTP reply. False for CGI reply */ Th_Interp *interp; /* The TH1 interpreter */ char *th1Setup; /* The TH1 post-creation setup script, if any */ int th1Flags; /* The TH1 integration state flags */ FILE *httpIn; /* Accept HTTP input from here */ FILE *httpOut; /* Send HTTP output here */ int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ UrlData url; /* Information about current URL */ const char *zLogin; /* Login name. NULL or "" if not logged in. */ const char *zSSLIdentity; /* Value of --ssl-identity option, filename of ** SSL client identity */ int useLocalauth; /* No login required if from 127.0.0.1 */ int noPswd; /* Logged in without password (on 127.0.0.1) */ int userUid; /* Integer user id */ int isHuman; /* True if access by a human, not a spider or bot */ int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags */ /* Information used to populate the RCVFROM table */ int rcvid; /* The rcvid. 0 if not yet defined. */ char *zIpAddr; /* The remote IP address */ char *zNonce; /* The nonce used for login */ /* permissions available to current user */ struct FossilUserPerms perm; /* permissions available to current user or to "anonymous". ** This is the logical union of perm permissions above with ** the value that perm would take if g.zLogin were "anonymous". */ struct FossilUserPerms anon; #ifdef FOSSIL_ENABLE_TCL /* all Tcl related context necessary for integration */ struct TclContext tcl; #endif /* For defense against Cross-site Request Forgery attacks */ char zCsrfToken[12]; /* Value of the anti-CSRF token */ int okCsrf; /* Anti-CSRF token is present and valid */ int parseCnt[10]; /* Counts of artifacts parsed */ FILE *fDebug; /* Write debug information here, if the file exists */ #ifdef FOSSIL_ENABLE_TH1_HOOKS int fNoThHook; /* Disable all TH1 command/webpage hooks */ #endif int thTrace; /* True to enable TH1 debugging output */ |
︙ | ︙ | |||
284 285 286 287 288 289 290 | const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ int anAuxCols[MX_AUX]; /* Number of columns for option() values */ int allowSymlinks; /* Cached "allow-symlinks" option */ int mainTimerId; /* Set to fossil_timer_start() */ int nPendingRequest; /* # of HTTP requests in "fossil server" */ int nRequest; /* Total # of HTTP request */ | < | | < < < < | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ int anAuxCols[MX_AUX]; /* Number of columns for option() values */ int allowSymlinks; /* Cached "allow-symlinks" option */ int mainTimerId; /* Set to fossil_timer_start() */ int nPendingRequest; /* # of HTTP requests in "fossil server" */ int nRequest; /* Total # of HTTP request */ #ifdef FOSSIL_ENABLE_JSON struct FossilJsonBits { int isJsonMode; /* True if running in JSON mode, else false. This changes how errors are reported. In JSON mode we try to always output JSON-form error responses and always exit() with code 0 to avoid an HTTP 500 error. */ int resultCode; /* used for passing back specific codes ** from /json callbacks. */ int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */ cson_output_opt outOpt; /* formatting options for JSON mode. */ cson_value *authToken; /* authentication token */ const char *jsonp; /* Name of JSONP function wrapper. */ unsigned char dispatchDepth /* Tells JSON command dispatching |
︙ | ︙ | |||
340 341 342 343 344 345 346 | cson_value *v; cson_object *o; } reqPayload; /* request payload object (if any) */ cson_array *warnings; /* response warnings */ int timerId; /* fetched from fossil_timer_start() */ } json; #endif /* FOSSIL_ENABLE_JSON */ | < < < < | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | cson_value *v; cson_object *o; } reqPayload; /* request payload object (if any) */ cson_array *warnings; /* response warnings */ int timerId; /* fetched from fossil_timer_start() */ } json; #endif /* FOSSIL_ENABLE_JSON */ }; /* ** Macro for debugging: */ #define CGIDEBUG(X) if( g.fDebug ) cgi_debug X #endif Global g; /* ** atexit() handler which frees up "some" of the resources ** used by fossil. */ static void fossil_atexit(void) { #if USE_SEE /* ** Zero, unlock, and free the saved database encryption key now. */ db_unsave_encryption_key(); #endif #if defined(_WIN32) || defined(__BIONIC__) /* ** Free the secure getpass() buffer now. */ freepass(); #endif #if defined(_WIN32) && !defined(_WIN64) && defined(FOSSIL_ENABLE_TCL) && \ defined(USE_TCL_STUBS) |
︙ | ︙ | |||
394 395 396 397 398 399 400 | cson_value_free(g.json.gc.v); memset(&g.json, 0, sizeof(g.json)); #endif free(g.zErrMsg); if(g.db){ db_close(0); } | < < < < < < < < < | < > > > | | > > > > | > | < < < < | | < < < | < | | < < < | | | | < | | | | | > < < | | < < < < < < | > | < < > < < < | < < | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | cson_value_free(g.json.gc.v); memset(&g.json, 0, sizeof(g.json)); #endif free(g.zErrMsg); if(g.db){ db_close(0); } /* ** FIXME: The next two lines cannot always be enabled; however, they ** are very useful for tracking down TH1 memory leaks. */ if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){ if( g.interp ){ Th_DeleteInterp(g.interp); g.interp = 0; } assert( Th_GetOutstandingMalloc()==0 ); } } /* ** Convert all arguments from mbcs (or unicode) to UTF-8. Then ** search g.argv for arguments "--args FILENAME". If found, then ** (1) remove the two arguments from g.argv ** (2) Read the file FILENAME ** (3) Use the contents of FILE to replace the two removed arguments: ** (a) Ignore blank lines in the file ** (b) Each non-empty line of the file is an argument, except ** (c) If the line begins with "-" and contains a space, it is broken ** into two arguments at the space. */ static void expand_args_option(int argc, void *argv){ Blob file = empty_blob; /* Content of the file */ Blob line = empty_blob; /* One line of the file */ unsigned int nLine; /* Number of lines in the file*/ unsigned int i, j, k; /* Loop counters */ int n; /* Number of bytes in one line */ char *z; /* General use string pointer */ char **newArgv; /* New expanded g.argv under construction */ const char *zFileName; /* input file name */ FILE *inFile; /* input FILE */ #if defined(_WIN32) wchar_t buf[MAX_PATH]; #endif g.argc = argc; g.argv = argv; sqlite3_initialize(); #if defined(_WIN32) && defined(BROKEN_MINGW_CMDLINE) for(i=0; i<g.argc; i++) g.argv[i] = fossil_mbcs_to_utf8(g.argv[i]); #else for(i=0; i<g.argc; i++) g.argv[i] = fossil_path_to_utf8(g.argv[i]); #endif #if defined(_WIN32) GetModuleFileNameW(NULL, buf, MAX_PATH); g.nameOfExe = fossil_path_to_utf8(buf); #else g.nameOfExe = g.argv[0]; #endif for(i=1; i<g.argc-1; i++){ z = g.argv[i]; if( z[0]!='-' ) continue; z++; if( z[0]=='-' ) z++; if( z[0]==0 ) return; /* Stop searching at "--" */ if( fossil_strcmp(z, "args")==0 ) break; } if( i>=g.argc-1 ) return; zFileName = g.argv[i+1]; inFile = (0==strcmp("-",zFileName)) ? stdin : fossil_fopen(zFileName,"rb"); if(!inFile){ fossil_fatal("Cannot open -args file [%s]", zFileName); }else{ blob_read_from_channel(&file, inFile, -1); if(stdin != inFile){ fclose(inFile); } inFile = NULL; } blob_to_utf8_no_bom(&file, 1); z = blob_str(&file); for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++; newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) ); for(j=0; j<i; j++) newArgv[j] = g.argv[j]; blob_rewind(&file); while( (n = blob_line(&file, &line))>0 ){ if( n<1 ) continue /** ** Reminder: corner-case: a line with 1 byte and no newline. */; z = blob_buffer(&line); if('\n'==z[n-1]){ z[n-1] = 0; } if((n>1) && ('\r'==z[n-2])){ if(n==2) continue /*empty line*/; z[n-2] = 0; } if(!z[0]) continue; newArgv[j++] = z; if( z[0]=='-' ){ for(k=1; z[k] && !fossil_isspace(z[k]); k++){} if( z[k] ){ z[k] = 0; k++; if( z[k] ) newArgv[j++] = &z[k]; } } } i += 2; while( i<g.argc ) newArgv[j++] = g.argv[i++]; newArgv[j] = 0; g.argc = j; g.argv = newArgv; } #ifdef FOSSIL_ENABLE_TCL /* ** Make a deep copy of the provided argument array and return it. */ static char **copy_args(int argc, char **argv){ |
︙ | ︙ | |||
637 638 639 640 641 642 643 | ** This function attempts to find command line options known to contain ** bitwise flags and initializes the associated global variables. After ** this function executes, all global variables (i.e. in the "g" struct) ** containing option-settable bitwise flag fields must be initialized. */ static void fossil_init_flags_from_options(void){ const char *zValue = find_option("comfmtflags", 0, 1); | < < < | | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | ** This function attempts to find command line options known to contain ** bitwise flags and initializes the associated global variables. After ** this function executes, all global variables (i.e. in the "g" struct) ** containing option-settable bitwise flag fields must be initialized. */ static void fossil_init_flags_from_options(void){ const char *zValue = find_option("comfmtflags", 0, 1); if( zValue ){ g.comFmtFlags = atoi(zValue); }else{ g.comFmtFlags = COMMENT_PRINT_DEFAULT; } } /* ** Check to see if the Fossil binary contains an appended repository ** file using the appendvfs extension. If so, change command-line arguments ** to cause Fossil to launch with "fossil ui" on that repo. |
︙ | ︙ | |||
669 670 671 672 673 674 675 | return 0; } } /* ** This procedure runs first. */ | < < < | | | > | | < | | | < < < < < < < < < < < < | < < | < | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | return 0; } } /* ** This procedure runs first. */ #if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE) int _dowildcard = -1; /* This turns on command-line globbing in MinGW-w64 */ int wmain(int argc, wchar_t **argv) #else #if defined(_WIN32) int _CRT_glob = 0x0001; /* See MinGW bug #2062 */ #endif int main(int argc, char **argv) #endif { const char *zCmdName = "unknown"; const CmdOrPage *pCmd = 0; int rc; #if !defined(_WIN32_WCE) if( fossil_getenv("FOSSIL_BREAK") ){ if( isatty(0) && isatty(2) ){ fprintf(stderr, "attach debugger to process %d and press any key to continue.\n", GETPID()); fgetc(stdin); }else{ #if defined(_WIN32) || defined(WIN32) DebugBreak(); #elif defined(SIGTRAP) raise(SIGTRAP); #endif } } #endif fossil_limit_memory(1); if( sqlite3_libversion_number()<3014000 ){ fossil_panic("Unsuitable SQLite version %s, must be at least 3.14.0", sqlite3_libversion()); } sqlite3_config(SQLITE_CONFIG_MULTITHREAD); sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); memset(&g, 0, sizeof(g)); g.now = time(0); g.httpHeader = empty_blob; #ifdef FOSSIL_ENABLE_JSON #if defined(NDEBUG) |
︙ | ︙ | |||
761 762 763 764 765 766 767 | sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); }else{ fossil_fatal("no such VFS: \"%s\"", g.zVfsName); } } | | | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); }else{ fossil_fatal("no such VFS: \"%s\"", g.zVfsName); } } if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){ zCmdName = "cgi"; g.isHTTP = 1; }else if( g.argc<2 && !fossilExeHasAppendedRepo() ){ fossil_print( "Usage: %s COMMAND ...\n" " or: %s help -- for a list of common commands\n" " or: %s help COMMAND -- for help with the named command\n", |
︙ | ︙ | |||
795 796 797 798 799 800 801 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; g.fSshTrace = find_option("sshtrace", 0, 0)!=0; g.fCgiTrace = find_option("cgitrace", 0, 0)!=0; g.fSshClient = 0; g.zSshCmd = 0; if( g.fSqlTrace ) g.fSqlStats = 1; | < < < < < < | < | | | < < < < < < < < < < | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; g.fSshTrace = find_option("sshtrace", 0, 0)!=0; g.fCgiTrace = find_option("cgitrace", 0, 0)!=0; g.fSshClient = 0; g.zSshCmd = 0; if( g.fSqlTrace ) g.fSqlStats = 1; g.fHttpTrace = find_option("httptrace", 0, 0)!=0; #ifdef FOSSIL_ENABLE_TH1_HOOKS g.fNoThHook = find_option("no-th-hook", 0, 0)!=0; #endif g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace| g.fHttpTrace|g.fCgiTrace; g.zHttpAuth = 0; g.zLogin = find_option("user", "U", 1); g.zSSLIdentity = find_option("ssl-identity", 0, 1); g.zErrlog = find_option("errorlog", 0, 1); fossil_init_flags_from_options(); if( find_option("utc",0,0) ) g.fTimeFormat = 1; if( find_option("localtime",0,0) ) g.fTimeFormat = 2; if( zChdir && file_chdir(zChdir, 0) ){ fossil_fatal("unable to change directories to %s", zChdir); } if( find_option("help",0,0)!=0 ){ /* If --help is found anywhere on the command line, translate the command * to "fossil help cmdname" where "cmdname" is the first argument that * does not begin with a "-" character. If all arguments start with "-", * translate to "fossil help argv[1] argv[2]...". */ int i, nNewArgc; char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) ); zNewArgv[0] = g.argv[0]; zNewArgv[1] = "help"; for(i=1; i<g.argc; i++){ if( g.argv[i][0]!='-' ){ nNewArgc = 3; zNewArgv[2] = g.argv[i]; zNewArgv[3] = 0; break; } } if( i==g.argc ){ for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i]; nNewArgc = g.argc+1; zNewArgv[i+1] = 0; } g.argc = nNewArgc; g.argv = zNewArgv; } zCmdName = g.argv[1]; } #ifndef _WIN32 /* There is a bug in stunnel4 in which it sometimes starts up client ** processes without first opening file descriptor 2 (standard error). ** If this happens, and a subsequent open() of a database returns file |
︙ | ︙ | |||
880 881 882 883 884 885 886 | g.httpOut = stdout; g.fullHttpReply = !g.isHTTP; fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)", fd, x); } } #endif | < < < < < < < < < < < < < < < < | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | g.httpOut = stdout; g.fullHttpReply = !g.isHTTP; fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)", fd, x); } } #endif rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd); if( rc==1 ){ #ifdef FOSSIL_ENABLE_TH1_HOOKS if( !g.isHTTP && !g.fNoThHook ){ rc = Th_CommandHook(zCmdName, 0); }else{ rc = TH_OK; } |
︙ | ︙ | |||
921 922 923 924 925 926 927 | } } fossil_exit(0); #endif }else if( rc==2 ){ Blob couldbe; blob_init(&couldbe,0,0); | | < < < < < < < | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | } } fossil_exit(0); #endif }else if( rc==2 ){ Blob couldbe; blob_init(&couldbe,0,0); dispatch_matching_names(zCmdName, &couldbe); fossil_print("%s: ambiguous command prefix: %s\n" "%s: could be any of:%s\n" "%s: use \"help\" for more information\n", g.argv[0], zCmdName, g.argv[0], blob_str(&couldbe), g.argv[0]); fossil_exit(1); } atexit( fossil_atexit ); #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** The TH1 return codes from the hook will be handled as follows: ** ** TH_OK: The xFunc() and the TH1 notification will both be executed. ** |
︙ | ︙ | |||
962 963 964 965 966 967 968 | rc = Th_CommandHook(pCmd->zName, pCmd->eCmdFlags); }else{ rc = TH_OK; } if( rc==TH_OK || rc==TH_RETURN || rc==TH_CONTINUE ){ if( rc==TH_OK || rc==TH_RETURN ){ #endif | < < | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | rc = Th_CommandHook(pCmd->zName, pCmd->eCmdFlags); }else{ rc = TH_OK; } if( rc==TH_OK || rc==TH_RETURN || rc==TH_CONTINUE ){ if( rc==TH_OK || rc==TH_RETURN ){ #endif pCmd->xFunc(); #ifdef FOSSIL_ENABLE_TH1_HOOKS } if( !g.isHTTP && !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){ Th_CommandNotify(pCmd->zName, pCmd->eCmdFlags); } } #endif |
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 | g.argv[i] = g.argv[j]; } g.argc = i; } /* | | < < | < < < < | < < < | < < < > | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | g.argv[i] = g.argv[j]; } g.argc = i; } /* ** Look for a command-line option. If present, return a pointer. ** Return NULL if missing. ** ** hasArg==0 means the option is a flag. It is either present or not. ** hasArg==1 means the option has an argument. Return a pointer to the ** argument. */ const char *find_option(const char *zLong, const char *zShort, int hasArg){ int i; int nLong; const char *zReturn = 0; assert( hasArg==0 || hasArg==1 ); nLong = strlen(zLong); for(i=1; i<g.argc; i++){ char *z; if( i+hasArg >= g.argc ) break; z = g.argv[i]; if( z[0]!='-' ) continue; z++; if( z[0]=='-' ){ if( z[1]==0 ){ remove_from_argv(i, 1); break; } z++; } if( strncmp(z,zLong,nLong)==0 ){ if( hasArg && z[nLong]=='=' ){ zReturn = &z[nLong+1]; remove_from_argv(i, 1); break; }else if( z[nLong]==0 ){ zReturn = g.argv[i+hasArg]; remove_from_argv(i, 1+hasArg); break; } }else if( fossil_strcmp(z,zShort)==0 ){ zReturn = g.argv[i+hasArg]; remove_from_argv(i, 1+hasArg); break; } } return zReturn; } /* ** Look for multiple occurrences of a command-line option with the ** corresponding argument. ** ** Return a malloc allocated array of pointers to the arguments. ** ** pnUsedArgs is used to store the number of matched arguments. ** ** Caller is responsible to free allocated memory. */ const char **find_repeatable_option( const char *zLong, const char *zShort, int *pnUsedArgs ){ const char *zOption; |
︙ | ︙ | |||
1133 1134 1135 1136 1137 1138 1139 | return g.zRepositoryOption; } /* ** Verify that there are no unprocessed command-line options. If ** Any remaining command-line argument begins with "-" print ** an error message and quit. | < < < < < < < < < < < < | < < < < < < < | | | < > | | | < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > < | < | > | 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 | return g.zRepositoryOption; } /* ** Verify that there are no unprocessed command-line options. If ** Any remaining command-line argument begins with "-" print ** an error message and quit. */ void verify_all_options(void){ int i; for(i=1; i<g.argc; i++){ if( g.argv[i][0]=='-' && g.argv[i][1]!=0 ){ fossil_fatal( "unrecognized command-line option, or missing argument: %s", g.argv[i]); } } } /* ** This function returns a human readable version string. */ const char *get_version(){ static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " " MANIFEST_DATE " UTC"; return version; } /* ** This function populates a blob with version information. It is used by ** the "version" command and "test-version" web page. It assumes the blob ** passed to it is uninitialized; otherwise, it will leak memory. */ static void get_version_blob( Blob *pOut, /* Write the manifest here */ int bVerbose /* Non-zero for full information. */ ){ #if defined(FOSSIL_ENABLE_TCL) int rc; const char *zRc; #endif Stmt q; size_t pageSize = 0; blob_zero(pOut); blob_appendf(pOut, "This is fossil version %s\n", get_version()); if( !bVerbose ) return; blob_appendf(pOut, "Compiled on %s %s using %s (%d-bit)\n", __DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8); blob_appendf(pOut, "Schema version %s\n", AUX_SCHEMA_MAX); fossil_get_page_size(&pageSize); blob_appendf(pOut, "Detected memory page size is %lu bytes\n", (unsigned long)pageSize); #if defined(FOSSIL_ENABLE_MINIZ) blob_appendf(pOut, "miniz %s, loaded %s\n", MZ_VERSION, mz_version()); #else blob_appendf(pOut, "zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion()); #endif #if FOSSIL_HARDENED_SHA1 blob_appendf(pOut, "hardened-SHA1 by Marc Stevens and Dan Shumow\n"); #endif #if defined(FOSSIL_ENABLE_SSL) blob_appendf(pOut, "SSL (%s)\n", SSLeay_version(SSLEAY_VERSION)); #endif #if defined(FOSSIL_HAVE_FUSEFS) blob_appendf(pOut, "libfuse %s, loaded %s\n", fusefs_inc_version(), fusefs_lib_version()); #endif #if defined(FOSSIL_DEBUG) blob_append(pOut, "FOSSIL_DEBUG\n", -1); #endif #if defined(FOSSIL_ENABLE_DELTA_CKSUM_TEST) blob_append(pOut, "FOSSIL_ENABLE_DELTA_CKSUM_TEST\n", -1); #endif #if defined(FOSSIL_ENABLE_LEGACY_MV_RM) blob_append(pOut, "FOSSIL_ENABLE_LEGACY_MV_RM\n", -1); #endif #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) blob_append(pOut, "FOSSIL_ENABLE_EXEC_REL_PATHS\n", -1); #endif #if defined(FOSSIL_ENABLE_TH1_DOCS) blob_append(pOut, "FOSSIL_ENABLE_TH1_DOCS\n", -1); #endif #if defined(FOSSIL_ENABLE_TH1_HOOKS) blob_append(pOut, "FOSSIL_ENABLE_TH1_HOOKS\n", -1); #endif #if defined(FOSSIL_ENABLE_TCL) Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL); rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1); zRc = Th_ReturnCodeName(rc, 0); blob_appendf(pOut, "TCL (Tcl %s, loaded %s: %s)\n", TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0) ); #endif #if defined(USE_TCL_STUBS) blob_append(pOut, "USE_TCL_STUBS\n", -1); #endif #if defined(FOSSIL_ENABLE_TCL_STUBS) blob_append(pOut, "FOSSIL_TCL_STUBS\n", -1); #endif #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) blob_append(pOut, "FOSSIL_ENABLE_TCL_PRIVATE_STUBS\n", -1); #endif #if defined(FOSSIL_ENABLE_JSON) blob_appendf(pOut, "JSON (API %s)\n", FOSSIL_JSON_API_VERSION); #endif #if defined(BROKEN_MINGW_CMDLINE) blob_append(pOut, "MBCS_COMMAND_LINE\n", -1); #else blob_append(pOut, "UNICODE_COMMAND_LINE\n", -1); #endif #if defined(FOSSIL_DYNAMIC_BUILD) blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1); #else blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1); #endif #if defined(HAVE_PLEDGE) blob_append(pOut, "HAVE_PLEDGE\n", -1); #endif #if defined(USE_MMAN_H) blob_append(pOut, "USE_MMAN_H\n", -1); #endif #if defined(USE_SEE) blob_append(pOut, "USE_SEE\n", -1); #endif #if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES) blob_append(pOut, "FOSSIL_ALLOW_OUT_OF_ORDER_DATES\n"); #endif blob_appendf(pOut, "SQLite %s %.30s\n", sqlite3_libversion(), sqlite3_sourceid()); if( g.db==0 ) sqlite3_open(":memory:", &g.db); db_prepare(&q, "pragma compile_options"); while( db_step(&q)==SQLITE_ROW ){ const char *text = db_column_text(&q, 0); if( strncmp(text, "COMPILER", 8) ){ blob_appendf(pOut, "SQLITE_%s\n", text); |
︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 | return version; } /* ** COMMAND: version ** | | | < < | < < < | | | | | < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < | < < < < < < | | | < < < < < < < < < < | | < < < | | < < < < < < < < < < < < < > > | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 | return version; } /* ** COMMAND: version ** ** Usage: %fossil version ?-verbose|-v? ** ** Print the source code version number for the fossil executable. ** If the verbose option is specified, additional details will ** be output about what optional features this binary was compiled ** with */ void version_cmd(void){ Blob versionInfo; int verboseFlag = find_option("verbose","v",0)!=0; /* We should be done with options.. */ verify_all_options(); get_version_blob(&versionInfo, verboseFlag); fossil_print("%s", blob_str(&versionInfo)); } /* ** WEBPAGE: version ** ** Show the version information for Fossil. ** ** Query parameters: ** ** verbose Show details */ void test_version_page(void){ Blob versionInfo; int verboseFlag; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } verboseFlag = PD("verbose", 0) != 0; style_header("Version Information"); style_submenu_element("Stat", "stat"); get_version_blob(&versionInfo, verboseFlag); @ <pre> @ %h(blob_str(&versionInfo)) @ </pre> style_footer(); } /* ** Set the g.zBaseURL value to the full URL for the toplevel of ** the fossil tree. Set g.zTop to g.zBaseURL without the ** leading "http://" and the host and port. ** ** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME ** environment variables. However, if zAltBase is not NULL then it ** is the argument to the --baseurl option command-line option and ** g.zBaseURL and g.zTop is set from that instead. */ static void set_base_url(const char *zAltBase){ int i; const char *zHost; const char *zMode; const char *zCur; if( g.zBaseURL!=0 ) return; if( zAltBase ){ int i, n, c; g.zTop = g.zBaseURL = mprintf("%s", zAltBase); if( strncmp(g.zTop, "http://", 7)==0 ){ /* it is HTTP, replace prefix with HTTPS. */ g.zHttpsURL = mprintf("https://%s", &g.zTop[7]); }else if( strncmp(g.zTop, "https://", 8)==0 ){ /* it is already HTTPS, use it. */ g.zHttpsURL = mprintf("%s", g.zTop); }else{ fossil_fatal("argument to --baseurl should be 'http://host/path'" " or 'https://host/path'"); } for(i=n=0; (c = g.zTop[i])!=0; i++){ if( c=='/' ){ n++; if( n==3 ){ g.zTop += i; break; } } } if( g.zTop==g.zBaseURL ){ fossil_fatal("argument to --baseurl should be 'http://host/path'" " or 'https://host/path'"); } if( g.zTop[1]==0 ) g.zTop++; }else{ zHost = PD("HTTP_HOST",""); zMode = PD("HTTPS","off"); zCur = PD("SCRIPT_NAME","/"); i = strlen(zCur); while( i>0 && zCur[i-1]=='/' ) i--; if( fossil_stricmp(zMode,"on")==0 ){ g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur); g.zTop = &g.zBaseURL[8+strlen(zHost)]; g.zHttpsURL = g.zBaseURL; }else{ g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); g.zTop = &g.zBaseURL[7+strlen(zHost)]; g.zHttpsURL = mprintf("https://%s%.*s", zHost, i, zCur); } } if( db_is_writeable("repository") ){ if( !db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'", g.zBaseURL)){ db_multi_exec("INSERT INTO config(name,value,mtime)" "VALUES('baseurl:%q',1,now())", g.zBaseURL); }else{ db_optional_sql("repository", "REPLACE INTO config(name,value,mtime)" "VALUES('baseurl:%q',1,now())", g.zBaseURL ); } } } /* ** Send an HTTP redirect back to the designated Index Page. */ NORETURN void fossil_redirect_home(void){ cgi_redirectf("%s%s", g.zTop, db_get("index-page", "/index")); } /* ** If running as root, chroot to the directory containing the ** repository zRepo and then drop root privileges. Return the ** new repository name. ** ** zRepo might be a directory itself. In that case chroot into ** the directory zRepo. ** ** Assume the user-id and group-id of the repository, or if zRepo ** is a directory, of that directory. ** ** The noJail flag means that the chroot jail is not entered. But ** privileges are still lowered to that of the user-id and group-id ** of the repository file. */ char *enter_chroot_jail(char *zRepo, int noJail){ #if !defined(_WIN32) if( getuid()==0 ){ int i; struct stat sStat; Blob dir; char *zDir; if( g.db!=0 ){ db_close(1); } file_canonical_name(zRepo, &dir, 0); zDir = blob_str(&dir); if( !noJail ){ if( file_isdir(zDir, ExtFILE)==1 ){ if( file_chdir(zDir, 1) ){ fossil_panic("unable to chroot into %s", zDir); } g.fJail = 1; zRepo = "/"; }else{ for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo); if( i>0 ){ zDir[i] = 0; if( file_chdir(zDir, 1) ){ fossil_panic("unable to chroot into %s", zDir); } zDir[i] = '/'; } zRepo = &zDir[i]; } } if( stat(zRepo, &sStat)!=0 ){ fossil_fatal("cannot stat() repository: %s", zRepo); } i = setgid(sStat.st_gid); i = i || setuid(sStat.st_uid); if(i){ fossil_fatal("setgid/uid() failed with errno %d", errno); } if( g.db==0 && file_isfile(zRepo, ExtFILE) ){ db_open_repository(zRepo); } } #endif return zRepo; } /* ** Generate a web-page that lists all repositories located under the ** g.zRepositoryName directory and return non-zero. ** ** For the special case when g.zRepositoryName a non-chroot-jail "/", ** compose the list using the "repo:" entries in the global_config ** table of the configuration database. These entries comprise all ** of the repositories known to the "all" command. The special case ** processing is disallowed for chroot jails because g.zRepositoryName ** is always "/" inside a chroot jail and so it cannot be used as a flag ** to signal the special processing in that case. The special case ** processing is intended for the "fossil all ui" command which never ** runs in a chroot jail anyhow. ** ** Or, if no repositories can be located beneath g.zRepositoryName, ** return 0. */ static int repo_list_page(void){ Blob base; int n = 0; int allRepo; assert( g.db==0 ); if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ /* For the special case of the "repository directory" being "/", ** show all of the repositories named in the ~/.fossil database. ** ** On unix systems, then entries are of the form "repo:/home/..." ** and on Windows systems they are like on unix, starting with a "/" ** or they can begin with a drive letter: "repo:C:/Users/...". In either ** case, we want returned path to omit any initial "/". */ db_open_config(1, 0); db_multi_exec( "CREATE TEMP VIEW sfile AS" " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" " WHERE name GLOB 'repo:*'" ); allRepo = 1; }else{ /* The default case: All repositories under the g.zRepositoryName ** directory. */ blob_init(&base, g.zRepositoryName, -1); sqlite3_open(":memory:", &g.db); db_multi_exec("CREATE TABLE sfile(pathname TEXT);"); db_multi_exec("CREATE TABLE vfile(pathname);"); vfile_scan(&base, blob_size(&base), 0, 0, 0); db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'"); allRepo = 0; } @ <html> @ <head> @ <base href="%s(g.zBaseURL)/" /> @ <meta name="viewport" content="width=device-width, initial-scale=1.0"> @ <title>Repository List</title> @ </head> @ <body> n = db_int(0, "SELECT count(*) FROM sfile"); if( n>0 ){ Stmt q; sqlite3_int64 iNow, iMTime; @ <h1 align="center">Fossil Repositories</h1> @ <table border="0" class="sortable" data-init-sort="1" \ @ data-column-types="tnk"><thead> @ <tr><th>Filename<th width="20"><th>Last Modified</tr> @ </thead><tbody> db_prepare(&q, "SELECT pathname" " FROM sfile ORDER BY pathname COLLATE nocase;"); iNow = db_int64(0, "SELECT strftime('%%s','now')"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); int nName = (int)strlen(zName); char *zUrl; char *zAge; char *zFull; if( nName<7 ) continue; zUrl = sqlite3_mprintf("%.*s", nName-7, zName); if( zName[0]=='/' #ifdef _WIN32 || sqlite3_strglob("[a-zA-Z]:/*", zName)==0 #endif ){ zFull = mprintf("%s", zName); }else if ( allRepo ){ zFull = mprintf("/%s", zName); }else{ zFull = mprintf("%s/%s", g.zRepositoryName, zName); } iMTime = file_mtime(zFull, ExtFILE); fossil_free(zFull); if( iMTime<=0 ){ zAge = mprintf("..."); }else{ zAge = human_readable_age((iNow - iMTime)/86400.0); } if( sqlite3_strglob("*.fossil", zName)!=0 ){ /* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands ** do not work for repositories whose names do not end in ".fossil". ** So do not hyperlink those cases. */ @ <tr><td>%h(zName) } else if( sqlite3_strglob("*/.*", zName)==0 ){ /* Do not show hidden repos */ @ <tr><td>%h(zName) (hidden) } else if( allRepo && sqlite3_strglob("[a-zA-Z]:/?*", zName)!=0 ){ @ <tr><td><a href="%R/%T(zUrl)/home" target="_blank">/%h(zName)</a> }else{ @ <tr><td><a href="%R/%T(zUrl)/home" target="_blank">%h(zName)</a> } @ <td></td><td data-sortkey='%010llx(iNow - iMTime)'>%h(zAge)</tr> fossil_free(zAge); sqlite3_free(zUrl); } @ </tbody></table> }else{ @ <h1>No Repositories Found</h1> } @ <script>%s(builtin_text("sorttable.js"))</script> @ </body> @ </html> cgi_reply(); sqlite3_close(g.db); g.db = 0; return n; } /* ** COMMAND: test-list-page ** ** Usage: %fossil test-list-page DIRECTORY ** ** Show all repositories underneath DIRECTORY. Or if DIRECTORY is "/" ** show all repositories in the ~/.fossil file. */ void test_list_page(void){ if( g.argc<3 ){ g.zRepositoryName = "/"; }else{ g.zRepositoryName = g.argv[2]; } g.httpOut = stdout; repo_list_page(); } /* ** Called whenever a crash is encountered while processing a webpage. */ void sigsegv_handler(int x){ #if HAVE_BACKTRACE void *array[20]; size_t size; char **strings; size_t i; Blob out; size = backtrace(array, sizeof(array)/sizeof(array[0])); strings = backtrace_symbols(array, size); blob_init(&out, 0, 0); blob_appendf(&out, "Segfault"); for(i=0; i<size; i++){ blob_appendf(&out, "\n(%d) %s", i, strings[i]); } fossil_panic("%s", blob_str(&out)); #else fossil_panic("Segfault"); #endif exit(1); } /* ** Called if a server gets a SIGPIPE. This often happens when a client ** webbrowser opens a connection but never sends the HTTP request */ void sigpipe_handler(int x){ #ifndef _WIN32 if( g.fAnyTrace ){ fprintf(stderr,"/***** sigpipe received by subprocess %d ****\n", getpid()); } #endif db_panic_close(); exit(1); } /* ** Preconditions: ** ** * Environment variables are set up according to the CGI standard. ** ** If the repository is known, it has already been opened. If unknown, ** then g.zRepositoryName holds the directory that contains the repository |
︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 | int allowRepoList /* Send repo list for "/" URL */ ){ const char *zPathInfo = PD("PATH_INFO", ""); char *zPath = NULL; int i; const CmdOrPage *pCmd = 0; const char *zBase = g.zRepositoryName; | < < < < < < < < < < < < < < | < < < < | | < < < < < < | 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 | int allowRepoList /* Send repo list for "/" URL */ ){ const char *zPathInfo = PD("PATH_INFO", ""); char *zPath = NULL; int i; const CmdOrPage *pCmd = 0; const char *zBase = g.zRepositoryName; #if !defined(_WIN32) signal(SIGSEGV, sigsegv_handler); #endif /* Handle universal query parameters */ if( PB("utc") ){ g.fTimeFormat = 1; }else if( PB("localtime") ){ g.fTimeFormat = 2; } /* If the repository has not been opened already, then find the ** repository based on the first element of PATH_INFO and open it. */ if( !g.repositoryOpen ){ char *zRepo; /* Candidate repository name */ char *zToFree = 0; /* Malloced memory that needs to be freed */ const char *zCleanRepo; /* zRepo with surplus leading "/" removed */ const char *zOldScript = PD("SCRIPT_NAME", ""); /* Original SCRIPT_NAME */ char *zNewScript; /* Revised SCRIPT_NAME after processing */ int j, k; /* Loop variables */ i64 szFile; /* File size of the candidate repository */ i = zPathInfo[0]!=0; if( fossil_strcmp(g.zRepositoryName, "/")==0 ){ zBase++; #if defined(_WIN32) || defined(__CYGWIN__) if( sqlite3_strglob("/[a-zA-Z]:/*", zPathInfo)==0 ) i = 4; #endif } while( 1 ){ while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } /* The candidate repository name is some prefix of the PATH_INFO ** with ".fossil" appended */ zRepo = zToFree = mprintf("%s%.*s.fossil",zBase,i,zPathInfo); if( g.fHttpTrace ){ @ <!-- Looking for repository named "%h(zRepo)" --> fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo); } /* For safety -- to prevent an attacker from accessing arbitrary disk ** files by sending a maliciously crafted request URI to a public ** server -- make sure the repository basename contains no ** characters other than alphanumerics, "/", "_", "-", and ".", and ** that "-" never occurs immediately after a "/" and that "." is always ** surrounded by two alphanumerics. Any character that does not ** satisfy these constraints is converted into "_". */ szFile = 0; for(j=strlen(zBase)+1, k=0; zRepo[j] && k<i-1; j++, k++){ char c = zRepo[j]; if( fossil_isalnum(c) ) continue; #if defined(_WIN32) || defined(__CYGWIN__) /* Allow names to begin with "/X:/" on windows */ if( c==':' && j==2 && sqlite3_strglob("/[a-zA-Z]:/*", zRepo)==0 ){ continue; } #endif if( c=='/' ) continue; if( c=='_' ) continue; if( c=='-' && zRepo[j-1]!='/' ) continue; if( c=='.' && fossil_isalnum(zRepo[j-1]) && fossil_isalnum(zRepo[j+1])){ continue; } /* If we reach this point, it means that the request URI contains ** an illegal character or character combination. Provoke a ** "Not Found" error. */ szFile = 1; if( g.fHttpTrace ){ @ <!-- Unsafe pathname rejected: "%h(zRepo)" --> fprintf(stderr, "# unsafe pathname rejected: %s\n", zRepo); |
︙ | ︙ | |||
1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 | ** Special case: Assume any file with a basename of ".fossil" does ** not exist. */ zCleanRepo = file_cleanup_fullpath(zRepo); if( szFile==0 && sqlite3_strglob("*/.fossil",zRepo)!=0 ){ szFile = file_size(zCleanRepo, ExtFILE); if( g.fHttpTrace ){ sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", szFile); @ <!-- file_size(%h(zCleanRepo)) is %s(zBuf) --> fprintf(stderr, "# file_size(%s) = %s\n", zCleanRepo, zBuf); } } /* If no file named by zRepo exists, remove the added ".fossil" suffix ** and check to see if there is a file or directory with the same ** name as the raw PATH_INFO text. */ if( szFile<0 && i>0 ){ const char *zMimetype; | > | | 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 | ** Special case: Assume any file with a basename of ".fossil" does ** not exist. */ zCleanRepo = file_cleanup_fullpath(zRepo); if( szFile==0 && sqlite3_strglob("*/.fossil",zRepo)!=0 ){ szFile = file_size(zCleanRepo, ExtFILE); if( g.fHttpTrace ){ char zBuf[24]; sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", szFile); @ <!-- file_size(%h(zCleanRepo)) is %s(zBuf) --> fprintf(stderr, "# file_size(%s) = %s\n", zCleanRepo, zBuf); } } /* If no file named by zRepo exists, remove the added ".fossil" suffix ** and check to see if there is a file or directory with the same ** name as the raw PATH_INFO text. */ if( szFile<0 && i>0 ){ const char *zMimetype; assert( fossil_strcmp(&zRepo[j], ".fossil")==0 ); zRepo[j] = 0; /* Remove the ".fossil" suffix */ /* The PATH_INFO prefix seen so far is a valid directory. ** Continue the loop with the next element of the PATH_INFO */ if( zPathInfo[i]=='/' && file_isdir(zCleanRepo, ExtFILE)==1 ){ fossil_free(zToFree); i++; |
︙ | ︙ | |||
1842 1843 1844 1845 1846 1847 1848 | ** being delivered accidently. This is not intended to be a ** general-purpose web server. The "--file GLOB" mechanism is ** designed to allow the delivery of a few static images or HTML ** pages. */ if( pFileGlob!=0 && file_isfile(zCleanRepo, ExtFILE) | | | < < < < < < < < < < < < < < < | < < < < < < < | > > > > > > > > > > > > | > | < < < < < < < < < < < < < < < < | 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 | ** being delivered accidently. This is not intended to be a ** general-purpose web server. The "--file GLOB" mechanism is ** designed to allow the delivery of a few static images or HTML ** pages. */ if( pFileGlob!=0 && file_isfile(zCleanRepo, ExtFILE) && glob_match(pFileGlob, file_cleanup_fullpath(zRepo)) && sqlite3_strglob("*.fossil*",zRepo)!=0 && (zMimetype = mimetype_from_name(zRepo))!=0 && strcmp(zMimetype, "application/x-fossil-artifact")!=0 ){ Blob content; blob_read_from_file(&content, file_cleanup_fullpath(zRepo), ExtFILE); cgi_set_content_type(zMimetype); cgi_set_content(&content); cgi_reply(); return; } zRepo[j] = '.'; } /* If we reach this point, it means that the search of the PATH_INFO ** string is finished. Either zRepo contains the name of the ** repository to be used, or else no repository could be found an ** some kind of error response is required. */ if( szFile<1024 ){ set_base_url(0); if( strcmp(zPathInfo,"/")==0 && allowRepoList && repo_list_page() ){ /* Will return a list of repositories */ }else if( zNotFound ){ cgi_redirect(zNotFound); }else{ #ifdef FOSSIL_ENABLE_JSON if(g.json.isJsonMode){ json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); return; } #endif @ <html><head> @ <meta name="viewport" \ @ content="width=device-width, initial-scale=1.0"> @ </head><body> @ <h1>Not Found</h1> @ </body> cgi_set_status(404, "not found"); cgi_reply(); } return; } break; } /* Add the repository name (without the ".fossil" suffix) to the end ** of SCRIPT_NAME and g.zTop and g.zBaseURL and remove the repository ** name from the beginning of PATH_INFO. */ zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo); if( g.zTop ) g.zTop = mprintf("%s%.*s", g.zTop, i, zPathInfo); if( g.zBaseURL ) g.zBaseURL = mprintf("%s%.*s", g.zBaseURL, i, zPathInfo); cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]); zPathInfo += i; cgi_replace_parameter("SCRIPT_NAME", zNewScript); db_open_repository(file_cleanup_fullpath(zRepo)); if( g.fHttpTrace ){ @ <!-- repository: "%h(zRepo)" --> @ <!-- translated PATH_INFO: "%h(zPathInfo)" --> @ <!-- translated SCRIPT_NAME: "%h(zNewScript)" --> fprintf(stderr, "# repository: [%s]\n" |
︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 | fprintf(stderr, "# translated g.zBaseURL = [%s]\n", g.zBaseURL); } } } /* At this point, the appropriate repository database file will have ** been opened. | | < < < < | | < < < < < | < < | < > | | | | | | | | > > > > > > > > > > > > > | | | 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | fprintf(stderr, "# translated g.zBaseURL = [%s]\n", g.zBaseURL); } } } /* At this point, the appropriate repository database file will have ** been opened. ** ** Check to see if the the PATH_INFO begins with "draft[1-9]" and if ** so activate the special handling for draft skins */ if( zPathInfo && strncmp(zPathInfo,"/draft",6)==0 && zPathInfo[6]>='1' && zPathInfo[6]<='9' && (zPathInfo[7]=='/' || zPathInfo[7]==0) ){ int iSkin = zPathInfo[6] - '0'; char *zNewScript; skin_use_draft(iSkin); zNewScript = mprintf("%T/draft%d", P("SCRIPT_NAME"), iSkin); if( g.zTop ) g.zTop = mprintf("%s/draft%d", g.zTop, iSkin); if( g.zBaseURL ) g.zBaseURL = mprintf("%s/draft%d", g.zBaseURL, iSkin); zPathInfo += 7; cgi_replace_parameter("PATH_INFO", zPathInfo); cgi_replace_parameter("SCRIPT_NAME", zNewScript); } /* If the content type is application/x-fossil or ** application/x-fossil-debug, then a sync/push/pull/clone is ** desired, so default the PATH_INFO to /xfer */ if( g.zContentType && strncmp(g.zContentType, "application/x-fossil", 20)==0 ){ /* Special case: If the content mimetype shows that it is "fossil sync" ** payload, then pretend that the PATH_INFO is /xfer so that we always ** invoke the sync page. */ zPathInfo = "/xfer"; } /* Use the first element of PATH_INFO as the page name ** and deliver the appropriate page back to the user. */ set_base_url(0); if( zPathInfo==0 || zPathInfo[0]==0 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ /* Second special case: If the PATH_INFO is blank, issue a redirect to ** the home page identified by the "index-page" setting in the repository ** CONFIG table, to "/index" if there no "index-page" setting. */ #ifdef FOSSIL_ENABLE_JSON if(g.json.isJsonMode){ json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); fossil_exit(0); } #endif fossil_redirect_home() /*does not return*/; }else{ zPath = mprintf("%s", zPathInfo); } /* Make g.zPath point to the first element of the path. Make ** g.zExtra point to everything past that point. */ while(1){ g.zPath = &zPath[1]; for(i=1; zPath[i] && zPath[i]!='/'; i++){} if( zPath[i]=='/' ){ zPath[i] = 0; g.zExtra = &zPath[i+1]; }else{ g.zExtra = 0; } break; } #ifdef FOSSIL_ENABLE_JSON /* ** Workaround to allow us to customize some following behaviour for ** JSON mode. The problem is, we don't always know if we're in JSON ** mode at this point (namely, for GET mode we don't know but POST ** we do), so we snoop g.zPath and cheat a bit. */ if( !g.json.isJsonMode && g.zPath && (0==strncmp("json",g.zPath,4)) ){ g.json.isJsonMode = 1; } #endif if( g.zExtra ){ /* CGI parameters get this treatment elsewhere, but places like getfile ** will use g.zExtra directly. ** Reminder: the login mechanism uses 'name' differently, and may ** eventually have a problem/collision with this. ** ** Disabled by stephan when running in JSON mode because this ** particular parameter name is very common and i have had no end ** of grief with this handling. The JSON API never relies on the ** handling below, and by disabling it in JSON mode I can remove ** lots of special-case handling in several JSON handlers. */ #ifdef FOSSIL_ENABLE_JSON if(!g.json.isJsonMode){ #endif dehttpize(g.zExtra); cgi_set_parameter_nocopy("name", g.zExtra, 1); #ifdef FOSSIL_ENABLE_JSON } #endif } /* Locate the method specified by the path and execute the function ** that implements that method. */ if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd) && dispatch_alias(g.zPath-1, &pCmd) ){ #ifdef FOSSIL_ENABLE_JSON if(g.json.isJsonMode){ json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0); }else #endif { #ifdef FOSSIL_ENABLE_TH1_HOOKS int rc; if( !g.fNoThHook ){ |
︙ | ︙ | |||
2080 2081 2082 2083 2084 2085 2086 | Th_WebpageNotify(g.zPath, 0); } } #endif } }else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){ #ifdef FOSSIL_ENABLE_JSON | | < < < < < < < < < < < < < < < < < < < < | | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 | Th_WebpageNotify(g.zPath, 0); } } #endif } }else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){ #ifdef FOSSIL_ENABLE_JSON if(g.json.isJsonMode){ json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0); }else #endif { @ <h1>Server Configuration Error</h1> @ <p>The database schema on the server is out-of-date. Please ask @ the administrator to run <b>fossil rebuild</b>.</p> } }else{ if( g.fCgiTrace ){ fossil_trace("######## Calling %s #########\n", pCmd->zName); cgi_print_all(1, 1); } #ifdef FOSSIL_ENABLE_TH1_HOOKS { /* ** The TH1 return codes from the hook will be handled as follows: ** ** TH_OK: The xFunc() and the TH1 notification will both be executed. |
︙ | ︙ | |||
2142 2143 2144 2145 2146 2147 2148 | rc = Th_WebpageHook(pCmd->zName+1, pCmd->eCmdFlags); }else{ rc = TH_OK; } if( rc==TH_OK || rc==TH_RETURN || rc==TH_CONTINUE ){ if( rc==TH_OK || rc==TH_RETURN ){ #endif | < < < < < | < | | | < < < < < | < < < < < < < < < < < < < < < < < < < < < | | < > | | | | | | | | | < < < < | < < < < < < < < < < | 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 | rc = Th_WebpageHook(pCmd->zName+1, pCmd->eCmdFlags); }else{ rc = TH_OK; } if( rc==TH_OK || rc==TH_RETURN || rc==TH_CONTINUE ){ if( rc==TH_OK || rc==TH_RETURN ){ #endif pCmd->xFunc(); #ifdef FOSSIL_ENABLE_TH1_HOOKS } if( !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){ Th_WebpageNotify(pCmd->zName+1, pCmd->eCmdFlags); } } } #endif } /* Return the result. */ cgi_reply(); } /* If the CGI program contains one or more lines of the form ** ** redirect: repository-filename http://hostname/path/%s ** ** then control jumps here. Search each repository for an artifact ID ** or ticket ID that matches the "name" CGI parameter and for the ** first match, redirect to the corresponding URL with the "name" CGI ** parameter inserted. Paint an error page if no match is found. ** ** If there is a line of the form: ** ** redirect: * URL ** ** Then a redirect is made to URL if no match is found. Otherwise a ** very primitive error message is returned. */ static void redirect_web_page(int nRedirect, char **azRedirect){ int i; /* Loop counter */ const char *zNotFound = 0; /* Not found URL */ const char *zName = P("name"); set_base_url(0); if( zName==0 ){ zName = P("SCRIPT_NAME"); if( zName && zName[0]=='/' ) zName++; } if( zName && validate16(zName, strlen(zName)) ){ for(i=0; i<nRedirect; i++){ if( fossil_strcmp(azRedirect[i*2],"*")==0 ){ zNotFound = azRedirect[i*2+1]; continue; } db_open_repository(azRedirect[i*2]); if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%q*'", zName) || db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ cgi_redirectf(azRedirect[i*2+1] /*works-like:"%s"*/, zName); return; } db_close(1); } } if( zNotFound ){ cgi_redirectf(zNotFound /*works-like:"%s"*/, zName); }else{ @ <html> @ <head><title>No Such Object</title></head> @ <body> @ <p>No such object: <b>%h(zName)</b></p> @ </body> cgi_reply(); |
︙ | ︙ | |||
2295 2296 2297 2298 2299 2300 2301 | ** repolist When in "directory:" mode, display a page ** showing a list of available repositories if ** the URL is "/". ** ** localauth Grant administrator privileges to connections ** from 127.0.0.1 or ::1. ** | < < < < | < < < < < < < < < < < < < < < < < < | > | > > > > < < < < < < < < < < < | | 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 | ** repolist When in "directory:" mode, display a page ** showing a list of available repositories if ** the URL is "/". ** ** localauth Grant administrator privileges to connections ** from 127.0.0.1 or ::1. ** ** skin: LABEL Use the built-in skin called LABEL rather than ** the default. If there are no skins called LABEL ** then this line is a no-op. ** ** files: GLOBLIST GLOBLIST is a comma-separated list of GLOB ** patterns that specify files that can be ** returned verbatim. This feature allows Fossil ** to act as a web server returning static ** content. ** ** setenv: NAME VALUE Set environment variable NAME to VALUE. Or ** if VALUE is omitted, unset NAME. ** ** HOME: PATH Shorthand for "setenv: HOME PATH" ** ** debug: FILE Causing debugging information to be written ** into FILE. ** ** errorlog: FILE Warnings, errors, and panics written to FILE. ** ** redirect: REPO URL Extract the "name" query parameter and search ** REPO for a check-in or ticket that matches the ** value of "name", then redirect to URL. There ** can be multiple "redirect:" lines that are ** processed in order. If the REPO is "*", then ** an unconditional redirect to URL is taken. ** ** Most CGI files contain only a "repository:" line. It is uncommon to ** use any other option. ** ** See also: http, server, winsrv */ void cmd_cgi(void){ const char *zFile; const char *zNotFound = 0; char **azRedirect = 0; /* List of repositories to redirect to */ int nRedirect = 0; /* Number of entries in azRedirect */ Glob *pFileGlob = 0; /* Pattern for files */ int allowRepoList = 0; /* Allow lists of repository files */ Blob config, line, key, value, value2; if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ zFile = g.argv[2]; }else{ zFile = g.argv[1]; } g.httpOut = stdout; g.httpIn = stdin; fossil_binary_mode(g.httpOut); fossil_binary_mode(g.httpIn); g.cgiOutput = 1; blob_read_from_file(&config, zFile, ExtFILE); while( blob_line(&config, &line) ){ if( !blob_token(&line, &key) ) continue; if( blob_buffer(&key)[0]=='#' ) continue; if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){ /* repository: FILENAME ** ** The name of the Fossil repository to be served via CGI. Most |
︙ | ︙ | |||
2420 2421 2422 2423 2424 2425 2426 | ** ** Grant "administrator" privileges to users connecting with HTTP ** from IP address 127.0.0.1. Do not bother checking credentials. */ g.useLocalauth = 1; continue; } | < < < < < < < < < < < < < < < < | 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 | ** ** Grant "administrator" privileges to users connecting with HTTP ** from IP address 127.0.0.1. Do not bother checking credentials. */ g.useLocalauth = 1; continue; } if( blob_eq(&key, "repolist") ){ /* repolist ** ** If using "directory:" and the URL is "/" then generate a page ** showing a list of available repositories. */ allowRepoList = 1; |
︙ | ︙ | |||
2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 | ** the environment variable is unset. */ blob_token(&line,&value2); fossil_setenv(blob_str(&value), blob_str(&value2)); blob_reset(&value); blob_reset(&value2); continue; } if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ /* errorlog: FILENAME ** ** Causes messages from warnings, errors, and panics to be appended ** to FILENAME. */ g.zErrlog = mprintf("%s", blob_str(&value)); blob_reset(&value); continue; } | > > > > > > > > > > < < < < < < < < < < < < < < < < < < | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 | ** the environment variable is unset. */ blob_token(&line,&value2); fossil_setenv(blob_str(&value), blob_str(&value2)); blob_reset(&value); blob_reset(&value2); continue; } if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ /* debug: FILENAME ** ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go ** into FILENAME. */ g.fDebug = fossil_fopen(blob_str(&value), "ab"); blob_reset(&value); continue; } if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ /* errorlog: FILENAME ** ** Causes messages from warnings, errors, and panics to be appended ** to FILENAME. */ g.zErrlog = mprintf("%s", blob_str(&value)); blob_reset(&value); continue; } if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){ /* HOME: VALUE ** ** Set CGI parameter "HOME" to VALUE. This is legacy. Use ** setenv: instead. */ cgi_setenv("HOME", blob_str(&value)); blob_reset(&value); continue; } if( blob_eq(&key, "skin:") && blob_token(&line, &value) ){ /* skin: LABEL ** ** Use one of the built-in skins defined by LABEL. LABEL is the ** name of the subdirectory under the skins/ directory that holds ** the elements of the built-in skin. If LABEL does not match, ** this directive is a silent no-op. */ skin_use_alternative(blob_str(&value)); blob_reset(&value); continue; } } blob_reset(&config); if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ cgi_panic("Unable to find or open the project repository"); } |
︙ | ︙ | |||
2626 2627 2628 2629 2630 2631 2632 | file_simplify_name(g.zRepositoryName, -1, 0); }else{ if( isDir==0 && fCreate ){ const char *zPassword; db_create_repository(zRepo); db_open_repository(zRepo); db_begin_transaction(); | | | < | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > > > > > > > < | < < < < < < | > | | < < | | < < < < < < < < < < < < < < < < < | | < | | < | | < < | | | < | | | | < > > > < < < < < < < < < < < < < > > | | < > > > > > < < > < < < < < < < < < < < < | < < < < < < < < < < < < > > | < < < < < < < < < < < < < < < < < < < < | < < < < < > | < < < < < < < < < | | > > < > | < | > > | | > > > > > | | < < < < > > | | > > > > > > > | < < < < < < < < < < < < < < < < < < < | | | < < < < < < < < < < < < < < < < | | | | < < < < < < < | < < < | | | < < < < < < < < < < < < < < < < < | < < | < < | > | < | | < | < < < < < | | < < < < < < | | < < < | < < < | < < | < < < < | > | > > > > > > | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 | file_simplify_name(g.zRepositoryName, -1, 0); }else{ if( isDir==0 && fCreate ){ const char *zPassword; db_create_repository(zRepo); db_open_repository(zRepo); db_begin_transaction(); g.eHashPolicy = HPOLICY_AUTO; db_set_int("hash-policy", HPOLICY_AUTO, 0); db_initial_setup(0, "now", g.zLogin); db_end_transaction(0); fossil_print("project-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); cache_initialize(); g.zLogin = 0; g.userUid = 0; }else{ db_open_repository(zRepo); } } } } #if defined(_WIN32) && USE_SEE /* ** This function attempts to parse a string value in the following ** format: ** ** "%lu:%p:%u" ** ** There are three parts, which must be delimited by colons. The ** first part is an unsigned long integer in base-10 (decimal) format. ** The second part is a numerical representation of a native pointer, ** in the appropriate implementation defined format. The third part ** is an unsigned integer in base-10 (decimal) format. ** ** If the specified value cannot be parsed, for any reason, a fatal ** error will be raised and the process will be terminated. */ void parse_pid_key_value( const char *zPidKey, /* The value to be parsed. */ DWORD *pProcessId, /* The extracted process identifier. */ LPVOID *ppAddress, /* The extracted pointer value. */ SIZE_T *pnSize /* The extracted size value. */ ){ unsigned int nSize = 0; if( sscanf(zPidKey, "%lu:%p:%u", pProcessId, ppAddress, &nSize)==3 ){ *pnSize = (SIZE_T)nSize; }else{ fossil_fatal("failed to parse pid key"); } } #endif /* ** COMMAND: http* ** ** Usage: %fossil http ?REPOSITORY? ?OPTIONS? ** ** Handle a single HTTP request appearing on stdin. The resulting webpage ** is delivered on stdout. This method is used to launch an HTTP request ** handler from inetd, for example. The argument is the name of the ** repository. ** ** If REPOSITORY is a directory that contains one or more repositories, ** either directly in REPOSITORY itself or in subdirectories, and ** with names of the form "*.fossil" then a prefix of the URL pathname ** selects from among the various repositories. If the pathname does ** not select a valid repository and the --notfound option is available, ** then the server redirects (HTTP code 302) to the URL of --notfound. ** When REPOSITORY is a directory, the pathname must contain only ** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/" ** and every "." must be surrounded on both sides by alphanumerics or else ** a 404 error is returned. Static content files in the directory are ** returned if they match comma-separate GLOB pattern specified by --files ** and do not match "*.fossil*" and have a well-known suffix. ** ** The --host option can be used to specify the hostname for the server. ** The --https option indicates that the request came from HTTPS rather ** than HTTP. If --nossl is given, then SSL connections will not be available, ** thus also no redirecting from http: to https: will take place. ** ** If the --localauth option is given, then automatic login is performed ** for requests coming from localhost, if the "localauth" setting is not ** enabled. ** ** Options: ** --baseurl URL base URL (useful with reverse proxies) ** --files GLOB comma-separate glob patterns for static file to serve ** --localauth enable automatic login for local connections ** --host NAME specify hostname of the server ** --https signal a request coming in via https ** --in FILE Take input from FILE instead of standard input ** --ipaddr ADDR Assume the request comes from the given IP address ** --nocompress do not compress HTTP replies ** --nodelay omit backoffice processing if it would delay process exit ** --nojail drop root privilege but do not enter the chroot jail ** --nossl signal that no SSL connections are available ** --notfound URL use URL as "HTTP 404, object not found" page. ** --out FILE write results to FILE instead of to standard output ** --repolist If REPOSITORY is directory, URL "/" lists all repos ** --scgi Interpret input as SCGI rather than HTTP ** --skin LABEL Use override skin LABEL ** --th-trace trace TH1 execution (for debugging purposes) ** --usepidkey Use saved encryption key from parent process. This is ** only necessary when using SEE on Windows. ** ** See also: cgi, server, winsrv */ void cmd_http(void){ const char *zIpAddr = 0; const char *zNotFound; const char *zHost; const char *zAltBase; const char *zFileGlob; const char *zInFile; const char *zOutFile; int useSCGI; int noJail; int allowRepoList; #if defined(_WIN32) && USE_SEE const char *zPidKey; #endif Th_InitTraceLog(); /* The winhttp module passes the --files option as --files-urlenc with ** the argument being URL encoded, to avoid wildcard expansion in the ** shell. This option is for internal use and is undocumented. */ zFileGlob = find_option("files-urlenc",0,1); if( zFileGlob ){ char *z = mprintf("%s", zFileGlob); dehttpize(z); zFileGlob = z; }else{ zFileGlob = find_option("files",0,1); } skin_override(); zNotFound = find_option("notfound", 0, 1); noJail = find_option("nojail",0,0)!=0; allowRepoList = find_option("repolist",0,0)!=0; g.useLocalauth = find_option("localauth", 0, 0)!=0; g.sslNotAvailable = find_option("nossl", 0, 0)!=0; g.fNoHttpCompress = find_option("nocompress",0,0)!=0; zInFile = find_option("in",0,1); if( zInFile ){ g.httpIn = fossil_fopen(zInFile, "rb"); if( g.httpIn==0 ) fossil_fatal("cannot open \"%s\" for reading", zInFile); }else{ g.httpIn = stdin; } zOutFile = find_option("out",0,1); if( zOutFile ){ g.httpOut = fossil_fopen(zOutFile, "wb"); if( g.httpOut==0 ) fossil_fatal("cannot open \"%s\" for writing", zOutFile); }else{ g.httpOut = stdout; } zIpAddr = find_option("ipaddr",0,1); useSCGI = find_option("scgi", 0, 0)!=0; zAltBase = find_option("baseurl", 0, 1); if( find_option("nodelay",0,0)!=0 ) backoffice_no_delay(); if( zAltBase ) set_base_url(zAltBase); if( find_option("https",0,0)!=0 ){ zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */ cgi_replace_parameter("HTTPS","on"); } zHost = find_option("host", 0, 1); if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); #if defined(_WIN32) && USE_SEE zPidKey = find_option("usepidkey", 0, 1); if( zPidKey ){ DWORD processId = 0; LPVOID pAddress = NULL; SIZE_T nSize = 0; parse_pid_key_value(zPidKey, &processId, &pAddress, &nSize); db_read_saved_encryption_key_from_process(processId, pAddress, nSize); } #endif /* We should be done with options.. */ verify_all_options(); if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); g.cgiOutput = 1; g.fullHttpReply = 1; find_server_repository(2, 0); if( zIpAddr==0 ){ zIpAddr = cgi_ssh_remote_addr(0); if( zIpAddr && zIpAddr[0] ){ g.fSshClient |= CGI_SSH_CLIENT; } } g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); if( useSCGI ){ cgi_handle_scgi_request(); }else if( g.fSshClient & CGI_SSH_CLIENT ){ ssh_request_loop(zIpAddr, glob_create(zFileGlob)); }else{ cgi_handle_http_request(zIpAddr); } process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); } /* ** Process all requests in a single SSH connection if possible. */ void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){ blob_zero(&g.cgiIn); do{ cgi_handle_ssh_http_request(zIpAddr); process_one_web_page(0, FileGlob, 0); blob_reset(&g.cgiIn); } while ( g.fSshClient & CGI_SSH_FOSSIL || g.fSshClient & CGI_SSH_COMPAT ); } /* ** Note that the following command is used by ssh:// processing. ** ** COMMAND: test-http ** ** Works like the http command but gives setup permission to all users. ** ** Options: ** --th-trace trace TH1 execution (for debugging purposes) ** */ void cmd_test_http(void){ const char *zIpAddr; /* IP address of remote client */ Th_InitTraceLog(); login_set_capabilities("sx", 0); g.useLocalauth = 1; g.httpIn = stdin; g.httpOut = stdout; find_server_repository(2, 0); g.cgiOutput = 1; g.fNoHttpCompress = 1; g.fullHttpReply = 1; zIpAddr = cgi_ssh_remote_addr(0); if( zIpAddr && zIpAddr[0] ){ g.fSshClient |= CGI_SSH_CLIENT; ssh_request_loop(zIpAddr, 0); }else{ cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); cgi_handle_http_request(0); process_one_web_page(0, 0, 0); } } #if !defined(_WIN32) #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) /* ** Search for an executable on the PATH environment variable. ** Return true (1) if found and false (0) if not found. */ static int binaryOnPath(const char *zBinary){ const char *zPath = fossil_getenv("PATH"); char *zFull; int i; int bExists; while( zPath && zPath[0] ){ while( zPath[0]==':' ) zPath++; for(i=0; zPath[i] && zPath[i]!=':'; i++){} zFull = mprintf("%.*s/%s", i, zPath, zBinary); bExists = file_access(zFull, X_OK); fossil_free(zFull); if( bExists==0 ) return 1; zPath += i; } return 0; } #endif #endif /* ** Send a time-out reply */ void sigalrm_handler(int x){ fossil_panic("TIMEOUT"); } /* ** COMMAND: server* ** COMMAND: ui ** ** Usage: %fossil server ?OPTIONS? ?REPOSITORY? ** or: %fossil ui ?OPTIONS? ?REPOSITORY? ** ** Open a socket and begin listening and responding to HTTP requests on ** TCP port 8080, or on any other TCP port defined by the -P or ** --port option. The optional argument is the name of the repository. ** The repository argument may be omitted if the working directory is ** within an open checkout. ** ** The "ui" command automatically starts a web browser after initializing ** the web server. The "ui" command also binds to 127.0.0.1 and so will ** only process HTTP traffic from the local machine. ** ** The REPOSITORY can be a directory (aka folder) that contains one or ** more repositories with names ending in ".fossil". In this case, a ** prefix of the URL pathname is used to search the directory for an ** appropriate repository. To thwart mischief, the pathname in the URL must ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may ** occur after "/", and every "." must be surrounded on both sides by ** alphanumerics. Any pathname that does not satisfy these constraints ** results in a 404 error. Files in REPOSITORY that match the comma-separated ** list of glob patterns given by --files and that have known suffixes ** such as ".txt" or ".html" or ".jpeg" and do not match the pattern ** "*.fossil*" will be served as static content. With the "ui" command, ** the REPOSITORY can only be a directory if the --notfound option is ** also present. ** ** For the special case REPOSITORY name of "/", the list global configuration ** database is consulted for a list of all known repositories. The --repolist ** option is implied by this special case. See also the "fossil all ui" ** command. ** ** By default, the "ui" command provides full administrative access without ** having to log in. This can be disabled by turning off the "localauth" ** setting. Automatic login for the "server" command is available if the ** --localauth option is present and the "localauth" setting is off and the ** connection is from localhost. The "ui" command also enables --repolist ** by default. ** ** Options: ** --baseurl URL Use URL as the base (useful for reverse proxies) ** --create Create a new REPOSITORY if it does not already exist ** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci" ** --files GLOBLIST Comma-separated list of glob patterns for static files ** --localauth enable automatic login for requests from localhost ** --localhost listen on 127.0.0.1 only (always true for "ui") ** --https signal a request coming in via https ** --max-latency N Do not let any single HTTP request run for more than N ** seconds (only works on unix) ** --nocompress Do not compress HTTP replies ** --nojail Drop root privileges but do not enter the chroot jail ** --nossl signal that no SSL connections are available ** --notfound URL Redirect ** -P|--port TCPPORT listen to request on port TCPPORT ** --th-trace trace TH1 execution (for debugging purposes) ** --repolist If REPOSITORY is dir, URL "/" lists repos. ** --scgi Accept SCGI rather than HTTP ** --skin LABEL Use override skin LABEL ** --usepidkey Use saved encryption key from parent process. This is ** only necessary when using SEE on Windows. ** ** See also: cgi, http, winsrv */ void cmd_webserver(void){ int iPort, mxPort; /* Range of TCP ports allowed */ const char *zPort; /* Value of the --port option */ const char *zBrowser; /* Name of web browser program */ char *zBrowserCmd = 0; /* Command to launch the web browser */ int isUiCmd; /* True if command is "ui", not "server' */ const char *zNotFound; /* The --notfound option or NULL */ int flags = 0; /* Server flags */ #if !defined(_WIN32) int noJail; /* Do not enter the chroot jail */ const char *zMaxLatency; /* Maximum runtime of any single HTTP request */ #endif int allowRepoList; /* List repositories on URL "/" */ const char *zAltBase; /* Argument to the --baseurl option */ const char *zFileGlob; /* Static content must match this */ char *zIpAddr = 0; /* Bind to this IP address */ int fCreate = 0; /* The --create flag */ const char *zInitPage = 0; /* Start on this page. --page option */ #if defined(_WIN32) && USE_SEE const char *zPidKey; #endif #if defined(_WIN32) const char *zStopperFile; /* Name of file used to terminate server */ zStopperFile = find_option("stopper", 0, 1); #endif if( g.zErrlog==0 ){ g.zErrlog = "-"; } zFileGlob = find_option("files-urlenc",0,1); if( zFileGlob ){ char *z = mprintf("%s", zFileGlob); dehttpize(z); zFileGlob = z; }else{ zFileGlob = find_option("files",0,1); } skin_override(); #if !defined(_WIN32) noJail = find_option("nojail",0,0)!=0; zMaxLatency = find_option("max-latency",0,1); #endif g.useLocalauth = find_option("localauth", 0, 0)!=0; Th_InitTraceLog(); zPort = find_option("port", "P", 1); isUiCmd = g.argv[1][0]=='u'; if( isUiCmd ){ zInitPage = find_option("page", 0, 1); } zNotFound = find_option("notfound", 0, 1); allowRepoList = find_option("repolist",0,0)!=0; if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1; zAltBase = find_option("baseurl", 0, 1); fCreate = find_option("create",0,0)!=0; if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; if( zAltBase ){ set_base_url(zAltBase); } g.sslNotAvailable = find_option("nossl", 0, 0)!=0; if( find_option("https",0,0)!=0 ){ cgi_replace_parameter("HTTPS","on"); } if( find_option("localhost", 0, 0)!=0 ){ flags |= HTTP_SERVER_LOCALHOST; } #if defined(_WIN32) && USE_SEE zPidKey = find_option("usepidkey", 0, 1); if( zPidKey ){ DWORD processId = 0; LPVOID pAddress = NULL; SIZE_T nSize = 0; parse_pid_key_value(zPidKey, &processId, &pAddress, &nSize); db_read_saved_encryption_key_from_process(processId, pAddress, nSize); } #endif /* We should be done with options.. */ verify_all_options(); if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); if( isUiCmd ){ flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; g.useLocalauth = 1; allowRepoList = 1; } find_server_repository(2, fCreate); if( zInitPage==0 ){ if( isUiCmd && g.localOpen ){ zInitPage = "timeline?c=current"; }else{ zInitPage = ""; } } |
︙ | ︙ | |||
3335 3336 3337 3338 3339 3340 3341 | }else{ zIpAddr = mprintf("%.*s", i, zPort); } zPort += i+1; } } iPort = mxPort = atoi(zPort); | < > > | > > | | | > | < | < < < < < | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < | | < < < | | < < | > | > | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < < > > > > | < < < < < < > > | > | > | > | > > > > | < | > > | < | 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 | }else{ zIpAddr = mprintf("%.*s", i, zPort); } zPort += i+1; } } iPort = mxPort = atoi(zPort); }else{ iPort = db_get_int("http-port", 8080); mxPort = iPort+100; } #if !defined(_WIN32) /* Unix implementation */ if( isUiCmd ){ #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) zBrowser = db_get("web-browser", 0); if( zBrowser==0 ){ static const char *const azBrowserProg[] = { "xdg-open", "gnome-open", "firefox", "google-chrome" }; int i; zBrowser = "echo"; for(i=0; i<count(azBrowserProg); i++){ if( binaryOnPath(azBrowserProg[i]) ){ zBrowser = azBrowserProg[i]; break; } } } #else zBrowser = db_get("web-browser", "open"); #endif if( zIpAddr==0 ){ zBrowserCmd = mprintf("%s http://localhost:%%d/%s &", zBrowser, zInitPage); }else if( strchr(zIpAddr,':') ){ zBrowserCmd = mprintf("%s http://[%s]:%%d/%s &", zBrowser, zIpAddr, zInitPage); }else{ zBrowserCmd = mprintf("%s http://%s:%%d/%s &", zBrowser, zIpAddr, zInitPage); } } if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; db_close(1); if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ fossil_fatal("unable to listen on TCP socket %d", iPort); } if( zMaxLatency ){ signal(SIGALRM, sigalrm_handler); alarm(atoi(zMaxLatency)); } g.httpIn = stdin; g.httpOut = stdout; #if !defined(_WIN32) signal(SIGSEGV, sigsegv_handler); signal(SIGPIPE, sigpipe_handler); #endif if( g.fAnyTrace ){ fprintf(stderr, "/***** Subprocess %d *****/\n", getpid()); } g.cgiOutput = 1; find_server_repository(2, 0); if( fossil_strcmp(g.zRepositoryName,"/")==0 ){ allowRepoList = 1; }else{ g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); } if( flags & HTTP_SERVER_SCGI ){ cgi_handle_scgi_request(); }else{ cgi_handle_http_request(0); } process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); if( g.fAnyTrace ){ fprintf(stderr, "/***** Webpage finished in subprocess %d *****/\n", getpid()); } #else /* Win32 implementation */ if( isUiCmd ){ zBrowser = db_get("web-browser", "start"); if( zIpAddr==0 ){ zBrowserCmd = mprintf("%s http://localhost:%%d/%s &", zBrowser, zInitPage); }else if( strchr(zIpAddr,':') ){ zBrowserCmd = mprintf("%s http://[%s]:%%d/%s &", zBrowser, zIpAddr, zInitPage); }else{ zBrowserCmd = mprintf("%s http://%s:%%d/%s &", zBrowser, zIpAddr, zInitPage); } } if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; db_close(1); if( allowRepoList ){ flags |= HTTP_SERVER_REPOLIST; } if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){ win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zAltBase, zNotFound, zFileGlob, zIpAddr, flags); } |
︙ | ︙ | |||
3563 3564 3565 3566 3567 3568 3569 | ** case=6 Call webpage_assert() ** case=7 Call webpage_error() */ void test_warning_page(void){ int iCase = atoi(PD("case","0")); int i; login_check_credentials(); | | < | | 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 | ** case=6 Call webpage_assert() ** case=7 Call webpage_error() */ void test_warning_page(void){ int iCase = atoi(PD("case","0")); int i; login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } style_header("Warning Test Page"); style_submenu_element("Error Log","%R/errorlog"); if( iCase<1 || iCase>4 ){ @ <p>Generate a message to the <a href="%R/errorlog">error log</a> @ by clicking on one of the following cases: }else{ @ <p>This is the test page for case=%d(iCase). All possible cases: } for(i=1; i<=7; i++){ @ <a href='./test-warning?case=%d(i)'>[%d(i)]</a> } @ </p> @ <p><ol> @ <li value='1'> Call fossil_warning() if( iCase==1 ){ fossil_warning("Test warning message from /test-warning"); |
︙ | ︙ | |||
3614 3615 3616 3617 3618 3619 3620 | webpage_assert( 5==7 ); } @ <li value='7'> call webpage_error()" if( iCase==7 ){ cgi_reset_content(); webpage_error("Case 7 from /test-warning"); } | < < < < < < | | 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 | webpage_assert( 5==7 ); } @ <li value='7'> call webpage_error()" if( iCase==7 ){ cgi_reset_content(); webpage_error("Case 7 from /test-warning"); } @ </ol> @ <p>End of test</p> style_footer(); } |
Changes to src/main.mk.
1 2 | # ############################################################################## | | | < < < < < < < < < < | 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 | # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This file is included by primary Makefile. # XBCC = $(BCC) $(BCCFLAGS) XTCC = $(TCC) -I. -I$(SRCDIR) -I$(OBJDIR) $(TCCFLAGS) TESTFLAGS := -quiet SRC = \ $(SRCDIR)/add.c \ $(SRCDIR)/alerts.c \ $(SRCDIR)/allrepo.c \ $(SRCDIR)/attach.c \ $(SRCDIR)/backoffice.c \ $(SRCDIR)/bag.c \ $(SRCDIR)/bisect.c \ $(SRCDIR)/blob.c \ $(SRCDIR)/branch.c \ $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ $(SRCDIR)/cookies.c \ $(SRCDIR)/db.c \ $(SRCDIR)/delta.c \ $(SRCDIR)/deltacmd.c \ $(SRCDIR)/descendants.c \ $(SRCDIR)/diff.c \ $(SRCDIR)/diffcmd.c \ $(SRCDIR)/dispatch.c \ $(SRCDIR)/doc.c \ $(SRCDIR)/encode.c \ $(SRCDIR)/etag.c \ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ $(SRCDIR)/file.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ $(SRCDIR)/forum.c \ $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ $(SRCDIR)/hname.c \ $(SRCDIR)/http.c \ $(SRCDIR)/http_socket.c \ $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_config.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_dir.c \ $(SRCDIR)/json_finfo.c \ |
︙ | ︙ | |||
102 103 104 105 106 107 108 | $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ $(SRCDIR)/moderate.c \ $(SRCDIR)/name.c \ | < < < | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ $(SRCDIR)/moderate.c \ $(SRCDIR)/name.c \ $(SRCDIR)/path.c \ $(SRCDIR)/piechart.c \ $(SRCDIR)/pivot.c \ $(SRCDIR)/popen.c \ $(SRCDIR)/pqueue.c \ $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ |
︙ | ︙ | |||
137 138 139 140 141 142 143 | $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ | < > > < | < > > > > > | | | | > | | | | > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ $(SRCDIR)/th_main.c \ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/unicode.c \ $(SRCDIR)/unversioned.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/webmail.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c EXTRA_FILES = \ $(SRCDIR)/../skins/aht/details.txt \ $(SRCDIR)/../skins/ardoise/css.txt \ $(SRCDIR)/../skins/ardoise/details.txt \ $(SRCDIR)/../skins/ardoise/footer.txt \ $(SRCDIR)/../skins/ardoise/header.txt \ $(SRCDIR)/../skins/black_and_white/css.txt \ $(SRCDIR)/../skins/black_and_white/details.txt \ $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ $(SRCDIR)/../skins/blitz_no_logo/css.txt \ $(SRCDIR)/../skins/blitz_no_logo/details.txt \ $(SRCDIR)/../skins/blitz_no_logo/footer.txt \ $(SRCDIR)/../skins/blitz_no_logo/header.txt \ $(SRCDIR)/../skins/blitz_no_logo/ticket.txt \ $(SRCDIR)/../skins/bootstrap/css.txt \ $(SRCDIR)/../skins/bootstrap/details.txt \ $(SRCDIR)/../skins/bootstrap/footer.txt \ $(SRCDIR)/../skins/bootstrap/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ $(SRCDIR)/../skins/default/header.txt \ $(SRCDIR)/../skins/default/js.txt \ $(SRCDIR)/../skins/eagle/css.txt \ $(SRCDIR)/../skins/eagle/details.txt \ $(SRCDIR)/../skins/eagle/footer.txt \ $(SRCDIR)/../skins/eagle/header.txt \ $(SRCDIR)/../skins/enhanced1/css.txt \ $(SRCDIR)/../skins/enhanced1/details.txt \ $(SRCDIR)/../skins/enhanced1/footer.txt \ $(SRCDIR)/../skins/enhanced1/header.txt \ $(SRCDIR)/../skins/khaki/css.txt \ $(SRCDIR)/../skins/khaki/details.txt \ $(SRCDIR)/../skins/khaki/footer.txt \ $(SRCDIR)/../skins/khaki/header.txt \ $(SRCDIR)/../skins/original/css.txt \ $(SRCDIR)/../skins/original/details.txt \ $(SRCDIR)/../skins/original/footer.txt \ $(SRCDIR)/../skins/original/header.txt \ $(SRCDIR)/../skins/plain_gray/css.txt \ $(SRCDIR)/../skins/plain_gray/details.txt \ $(SRCDIR)/../skins/plain_gray/footer.txt \ $(SRCDIR)/../skins/plain_gray/header.txt \ $(SRCDIR)/../skins/rounded1/css.txt \ $(SRCDIR)/../skins/rounded1/details.txt \ $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/graph.js \ $(SRCDIR)/href.js \ $(SRCDIR)/login.js \ $(SRCDIR)/markdown.md \ $(SRCDIR)/menu.js \ $(SRCDIR)/sbsdiff.js \ $(SRCDIR)/scroll.js \ $(SRCDIR)/skin.js \ $(SRCDIR)/sorttable.js \ $(SRCDIR)/tree.js \ $(SRCDIR)/useredit.js \ $(SRCDIR)/wiki.wiki TRANS_SRC = \ $(OBJDIR)/add_.c \ $(OBJDIR)/alerts_.c \ $(OBJDIR)/allrepo_.c \ $(OBJDIR)/attach_.c \ $(OBJDIR)/backoffice_.c \ $(OBJDIR)/bag_.c \ $(OBJDIR)/bisect_.c \ $(OBJDIR)/blob_.c \ $(OBJDIR)/branch_.c \ $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ $(OBJDIR)/cookies_.c \ $(OBJDIR)/db_.c \ $(OBJDIR)/delta_.c \ $(OBJDIR)/deltacmd_.c \ $(OBJDIR)/descendants_.c \ $(OBJDIR)/diff_.c \ $(OBJDIR)/diffcmd_.c \ $(OBJDIR)/dispatch_.c \ $(OBJDIR)/doc_.c \ $(OBJDIR)/encode_.c \ $(OBJDIR)/etag_.c \ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ $(OBJDIR)/file_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ $(OBJDIR)/forum_.c \ $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ $(OBJDIR)/hname_.c \ $(OBJDIR)/http_.c \ $(OBJDIR)/http_socket_.c \ $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_config_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_dir_.c \ $(OBJDIR)/json_finfo_.c \ |
︙ | ︙ | |||
365 366 367 368 369 370 371 | $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ $(OBJDIR)/moderate_.c \ $(OBJDIR)/name_.c \ | < < < | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ $(OBJDIR)/moderate_.c \ $(OBJDIR)/name_.c \ $(OBJDIR)/path_.c \ $(OBJDIR)/piechart_.c \ $(OBJDIR)/pivot_.c \ $(OBJDIR)/popen_.c \ $(OBJDIR)/pqueue_.c \ $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ |
︙ | ︙ | |||
400 401 402 403 404 405 406 | $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ | < > > < < < < < < < < < < | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ $(OBJDIR)/th_main_.c \ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ $(OBJDIR)/unicode_.c \ $(OBJDIR)/unversioned_.c \ $(OBJDIR)/update_.c \ $(OBJDIR)/url_.c \ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/webmail_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ $(OBJDIR)/add.o \ $(OBJDIR)/alerts.o \ $(OBJDIR)/allrepo.o \ $(OBJDIR)/attach.o \ $(OBJDIR)/backoffice.o \ $(OBJDIR)/bag.o \ $(OBJDIR)/bisect.o \ $(OBJDIR)/blob.o \ $(OBJDIR)/branch.o \ $(OBJDIR)/browse.o \ $(OBJDIR)/builtin.o \ $(OBJDIR)/bundle.o \ $(OBJDIR)/cache.o \ $(OBJDIR)/capabilities.o \ $(OBJDIR)/captcha.o \ $(OBJDIR)/cgi.o \ $(OBJDIR)/checkin.o \ $(OBJDIR)/checkout.o \ $(OBJDIR)/clearsign.o \ $(OBJDIR)/clone.o \ $(OBJDIR)/comformat.o \ $(OBJDIR)/configure.o \ $(OBJDIR)/content.o \ $(OBJDIR)/cookies.o \ $(OBJDIR)/db.o \ $(OBJDIR)/delta.o \ $(OBJDIR)/deltacmd.o \ $(OBJDIR)/descendants.o \ $(OBJDIR)/diff.o \ $(OBJDIR)/diffcmd.o \ $(OBJDIR)/dispatch.o \ $(OBJDIR)/doc.o \ $(OBJDIR)/encode.o \ $(OBJDIR)/etag.o \ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ $(OBJDIR)/file.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ $(OBJDIR)/forum.o \ $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ $(OBJDIR)/hname.o \ $(OBJDIR)/http.o \ $(OBJDIR)/http_socket.o \ $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_config.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_dir.o \ $(OBJDIR)/json_finfo.o \ |
︙ | ︙ | |||
514 515 516 517 518 519 520 | $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ $(OBJDIR)/moderate.o \ $(OBJDIR)/name.o \ | < < < | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ $(OBJDIR)/moderate.o \ $(OBJDIR)/name.o \ $(OBJDIR)/path.o \ $(OBJDIR)/piechart.o \ $(OBJDIR)/pivot.o \ $(OBJDIR)/popen.o \ $(OBJDIR)/pqueue.o \ $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ |
︙ | ︙ | |||
549 550 551 552 553 554 555 | $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ | < > > > > > > > | | | | | | | | | | | > > > | | | | < < > | < < > > > > | < < < > > > > < < | | > > | | < < < | < | > > > > > > | | | | | | < | | | | < | | | > < | | | < < < < < < < < < < | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ $(OBJDIR)/th_main.o \ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ $(OBJDIR)/unicode.o \ $(OBJDIR)/unversioned.o \ $(OBJDIR)/update.o \ $(OBJDIR)/url.o \ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/webmail.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil$(E) all: $(OBJDIR) $(APPNAME) install: $(APPNAME) mkdir -p $(INSTALLDIR) cp $(APPNAME) $(INSTALLDIR) codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 $(OBJDIR)/codecheck1 $(TRANS_SRC) $(OBJDIR): -mkdir $(OBJDIR) $(OBJDIR)/translate: $(SRCDIR)/translate.c $(XBCC) -o $(OBJDIR)/translate $(SRCDIR)/translate.c $(OBJDIR)/makeheaders: $(SRCDIR)/makeheaders.c $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR)/makeheaders.c $(OBJDIR)/mkindex: $(SRCDIR)/mkindex.c $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c $(OBJDIR)/mkbuiltin: $(SRCDIR)/mkbuiltin.c $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR)/mkbuiltin.c $(OBJDIR)/mkversion: $(SRCDIR)/mkversion.c $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c $(OBJDIR)/mkcss: $(SRCDIR)/mkcss.c $(XBCC) -o $(OBJDIR)/mkcss $(SRCDIR)/mkcss.c $(OBJDIR)/codecheck1: $(SRCDIR)/codecheck1.c $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR)/codecheck1.c # Run the test suite. # Other flags that can be included in TESTFLAGS are: # # -halt Stop testing after the first failed test # -keep Keep the temporary workspace for debugging # -prot Write a detailed log of the tests to the file ./prot # -verbose Include even more details in the output # -quiet Hide most output from the terminal # -strict Treat known bugs as failures # # TESTFLAGS can also include names of specific test files to limit # the run to just those test cases. # test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h $(OBJDIR)/default_css.h: $(SRCDIR)/default_css.txt $(OBJDIR)/mkcss $(OBJDIR)/mkcss $(SRCDIR)/default_css.txt $(OBJDIR)/default_css.h # Setup the options used to compile the included SQLite library. SQLITE_OPTIONS = -DNDEBUG=1 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_GET_TABLE \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_HAVE_ZLIB \ -DSQLITE_INTROSPECTION_PRAGMAS \ -DSQLITE_ENABLE_DBPAGE_VTAB # Setup the options used to compile the included SQLite shell. SHELL_OPTIONS = -DNDEBUG=1 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_GET_TABLE \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_HAVE_ZLIB \ -DSQLITE_INTROSPECTION_PRAGMAS \ -DSQLITE_ENABLE_DBPAGE_VTAB \ -Dmain=sqlite3_shell \ -DSQLITE_SHELL_IS_UTF8=1 \ -DSQLITE_OMIT_LOAD_EXTENSION=1 \ -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc # Setup the options used to compile the included miniz library. MINIZ_OPTIONS = -DMINIZ_NO_STDIO \ -DMINIZ_NO_TIME \ -DMINIZ_NO_ARCHIVE_APIS # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ.1 = SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_MINIZ variable may be undefined, set to 0, or # set to 1. If it is set to 1, the miniz library included in the # source tree should be used; otherwise, it should not. MINIZ_OBJ.0 = MINIZ_OBJ.1 = $(OBJDIR)/miniz.o MINIZ_OBJ. = $(MINIZ_OBJ.0) # The USE_LINENOISE variable may be undefined, set to 0, or set # to 1. If it is set to 0, then there is no need to build or link # the linenoise.o object. LINENOISE_DEF.0 = LINENOISE_DEF.1 = -DHAVE_LINENOISE LINENOISE_DEF. = $(LINENOISE_DEF.0) LINENOISE_OBJ.0 = LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o LINENOISE_OBJ. = $(LINENOISE_OBJ.0) # The USE_SEE variable may be undefined, 0 or 1. If undefined or # 0, ordinary SQLite is used. If 1, then sqlite3-see.c (not part of # the source tree) is used and extra flags are provided to enable # the SQLite Encryption Extension. SQLITE3_SRC.0 = sqlite3.c SQLITE3_SRC.1 = sqlite3-see.c SQLITE3_SRC. = sqlite3.c SQLITE3_SRC = $(SRCDIR)/$(SQLITE3_SRC.$(USE_SEE)) SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) EXTRAOBJ = \ $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) \ $(LINENOISE_OBJ.$(USE_LINENOISE)) \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o $(APPNAME): $(OBJDIR)/headers $(OBJDIR)/codecheck1 $(OBJ) $(EXTRAOBJ) $(OBJDIR)/codecheck1 $(TRANS_SRC) $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: # noop clean: -rm -rf $(OBJDIR)/* $(APPNAME) $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(OBJDIR)/mkindex $(TRANS_SRC) >$@ $(OBJDIR)/builtin_data.h: $(OBJDIR)/mkbuiltin $(EXTRA_FILES) $(OBJDIR)/mkbuiltin --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \ $(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \ $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \ $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \ $(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \ $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \ $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \ $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \ $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \ $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ $(OBJDIR)/cookies_.c:$(OBJDIR)/cookies.h \ $(OBJDIR)/db_.c:$(OBJDIR)/db.h \ $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h \ $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h \ $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h \ $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h \ $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h \ $(OBJDIR)/dispatch_.c:$(OBJDIR)/dispatch.h \ $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h \ $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h \ $(OBJDIR)/etag_.c:$(OBJDIR)/etag.h \ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ $(OBJDIR)/forum_.c:$(OBJDIR)/forum.h \ $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \ $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \ $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \ $(OBJDIR)/import_.c:$(OBJDIR)/import.h \ $(OBJDIR)/info_.c:$(OBJDIR)/info.h \ $(OBJDIR)/json_.c:$(OBJDIR)/json.h \ $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h \ $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h \ $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h \ $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h \ $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \ $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \ |
︙ | ︙ | |||
849 850 851 852 853 854 855 | $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \ $(OBJDIR)/name_.c:$(OBJDIR)/name.h \ | < < < | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \ $(OBJDIR)/name_.c:$(OBJDIR)/name.h \ $(OBJDIR)/path_.c:$(OBJDIR)/path.h \ $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \ $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \ $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \ $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \ $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ |
︙ | ︙ | |||
884 885 886 887 888 889 890 | $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \ $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \ $(OBJDIR)/style_.c:$(OBJDIR)/style.h \ $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \ $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \ $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \ | < > > < | < < < < < < < < | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 | $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \ $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \ $(OBJDIR)/style_.c:$(OBJDIR)/style.h \ $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \ $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \ $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \ $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ $(OBJDIR)/unversioned_.c:$(OBJDIR)/unversioned.h \ $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ $(OBJDIR)/VERSION.h touch $(OBJDIR)/headers $(OBJDIR)/headers: Makefile $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/add.c >$@ $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c $(OBJDIR)/add.h: $(OBJDIR)/headers $(OBJDIR)/alerts_.c: $(SRCDIR)/alerts.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/alerts.c >$@ $(OBJDIR)/alerts.o: $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/alerts.o -c $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h: $(OBJDIR)/headers |
︙ | ︙ | |||
954 955 956 957 958 959 960 | $(OBJDIR)/translate $(SRCDIR)/attach.c >$@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers | < < < < < < < < | 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | $(OBJDIR)/translate $(SRCDIR)/attach.c >$@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers $(OBJDIR)/backoffice_.c: $(SRCDIR)/backoffice.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/backoffice.c >$@ $(OBJDIR)/backoffice.o: $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 | $(OBJDIR)/translate $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers | < < < < < < < < | 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | $(OBJDIR)/translate $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 | $(OBJDIR)/translate $(SRCDIR)/clone.c >$@ $(OBJDIR)/clone.o: $(OBJDIR)/clone_.c $(OBJDIR)/clone.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/clone.o -c $(OBJDIR)/clone_.c $(OBJDIR)/clone.h: $(OBJDIR)/headers | < < < < < < < < | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | $(OBJDIR)/translate $(SRCDIR)/clone.c >$@ $(OBJDIR)/clone.o: $(OBJDIR)/clone_.c $(OBJDIR)/clone.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/clone.o -c $(OBJDIR)/clone_.c $(OBJDIR)/clone.h: $(OBJDIR)/headers $(OBJDIR)/comformat_.c: $(SRCDIR)/comformat.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/comformat.c >$@ $(OBJDIR)/comformat.o: $(OBJDIR)/comformat_.c $(OBJDIR)/comformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/comformat.o -c $(OBJDIR)/comformat_.c $(OBJDIR)/comformat.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 | $(OBJDIR)/translate $(SRCDIR)/deltacmd.c >$@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers | < < < < < < < < | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 | $(OBJDIR)/translate $(SRCDIR)/deltacmd.c >$@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers $(OBJDIR)/descendants_.c: $(SRCDIR)/descendants.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/descendants.c >$@ $(OBJDIR)/descendants.o: $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/descendants.o -c $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 | $(OBJDIR)/translate $(SRCDIR)/export.c >$@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers | < < < < < < < < < < < < < < < < | 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 | $(OBJDIR)/translate $(SRCDIR)/export.c >$@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers $(OBJDIR)/file_.c: $(SRCDIR)/file.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/file.c >$@ $(OBJDIR)/file.o: $(OBJDIR)/file_.c $(OBJDIR)/file.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/file.o -c $(OBJDIR)/file_.c $(OBJDIR)/file.h: $(OBJDIR)/headers $(OBJDIR)/finfo_.c: $(SRCDIR)/finfo.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/finfo.c >$@ $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1306 1307 1308 1309 1310 1311 1312 | $(OBJDIR)/translate $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers | < < < < < < < < | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 | $(OBJDIR)/translate $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/glob.c >$@ $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c $(OBJDIR)/glob.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | $(OBJDIR)/translate $(SRCDIR)/hname.c >$@ $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c $(OBJDIR)/hname.h: $(OBJDIR)/headers | < < < < < < < < | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | $(OBJDIR)/translate $(SRCDIR)/hname.c >$@ $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c $(OBJDIR)/hname.h: $(OBJDIR)/headers $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/http.c >$@ $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/http.o -c $(OBJDIR)/http_.c $(OBJDIR)/http.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1402 1403 1404 1405 1406 1407 1408 | $(OBJDIR)/translate $(SRCDIR)/info.c >$@ $(OBJDIR)/info.o: $(OBJDIR)/info_.c $(OBJDIR)/info.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/info.o -c $(OBJDIR)/info_.c $(OBJDIR)/info.h: $(OBJDIR)/headers | < < < < < < < < | 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | $(OBJDIR)/translate $(SRCDIR)/info.c >$@ $(OBJDIR)/info.o: $(OBJDIR)/info_.c $(OBJDIR)/info.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/info.o -c $(OBJDIR)/info_.c $(OBJDIR)/info.h: $(OBJDIR)/headers $(OBJDIR)/json_.c: $(SRCDIR)/json.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json.c >$@ $(OBJDIR)/json.o: $(OBJDIR)/json_.c $(OBJDIR)/json.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json.o -c $(OBJDIR)/json_.c $(OBJDIR)/json.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1634 1635 1636 1637 1638 1639 1640 | $(OBJDIR)/translate $(SRCDIR)/name.c >$@ $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c $(OBJDIR)/name.h: $(OBJDIR)/headers | < < < < < < < < < < < < < < < < | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | $(OBJDIR)/translate $(SRCDIR)/name.c >$@ $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c $(OBJDIR)/name.h: $(OBJDIR)/headers $(OBJDIR)/path_.c: $(SRCDIR)/path.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/path.c >$@ $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c $(OBJDIR)/path.h: $(OBJDIR)/headers $(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/piechart.c >$@ $(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h: $(OBJDIR)/headers $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/pivot.c >$@ $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 | $(OBJDIR)/translate $(SRCDIR)/regexp.c >$@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers | < < < < < < < < | 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 | $(OBJDIR)/translate $(SRCDIR)/regexp.c >$@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1885 1886 1887 1888 1889 1890 1891 | $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h: $(OBJDIR)/headers $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/style.c >$@ | | | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 | $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h: $(OBJDIR)/headers $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/style.c >$@ $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(OBJDIR)/default_css.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/style.o -c $(OBJDIR)/style_.c $(OBJDIR)/style.h: $(OBJDIR)/headers $(OBJDIR)/sync_.c: $(SRCDIR)/sync.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/sync.c >$@ |
︙ | ︙ | |||
1914 1915 1916 1917 1918 1919 1920 | $(OBJDIR)/translate $(SRCDIR)/tar.c >$@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers | < < < < < < < < | 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | $(OBJDIR)/translate $(SRCDIR)/tar.c >$@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers $(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/th_main.c >$@ $(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/th_main.o -c $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 | $(OBJDIR)/vfile_.c: $(SRCDIR)/vfile.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/vfile.c >$@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wiki.o -c $(OBJDIR)/wiki_.c | > > > > > > > > | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 | $(OBJDIR)/vfile_.c: $(SRCDIR)/vfile.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/vfile.c >$@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers $(OBJDIR)/webmail_.c: $(SRCDIR)/webmail.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/webmail.c >$@ $(OBJDIR)/webmail.o: $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/webmail.o -c $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wiki.o -c $(OBJDIR)/wiki_.c |
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 | $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winhttp.c >$@ $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/xfer.c >$@ $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c | > > > > > > > > | 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 | $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winhttp.c >$@ $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers $(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wysiwyg.c >$@ $(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/xfer.c >$@ $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c |
︙ | ︙ | |||
2090 2091 2092 2093 2094 2095 2096 | $(OBJDIR)/translate $(SRCDIR)/zip.c >$@ $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers | | | | | | | | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 | $(OBJDIR)/translate $(SRCDIR)/zip.c >$@ $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SQLITE3_SRC) $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) \ -c $(SQLITE3_SRC) -o $@ $(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) $(LINENOISE_DEF.$(USE_LINENOISE)) -c $(SQLITE3_SHELL_SRC) -o $@ $(OBJDIR)/linenoise.o: $(SRCDIR)/linenoise.c $(SRCDIR)/linenoise.h $(XTCC) -c $(SRCDIR)/linenoise.c -o $@ $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $@ $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ $(OBJDIR)/miniz.o: $(SRCDIR)/miniz.c $(XTCC) $(MINIZ_OPTIONS) -c $(SRCDIR)/miniz.c -o $@ $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@ # # The list of all the targets that do not correspond to real files. This stops # 'make' from getting confused when someone makes an error in a rule. # .PHONY: all install test clean |
Added src/makeheaders.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 | /* ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** Copyright 1993 D. Richard Hipp. 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. ** ** This software is provided "as is" and any express or implied warranties, ** including, but not limited to, the implied warranties of merchantability ** and fitness for a particular purpose are disclaimed. In no event shall ** the author 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. ** ** 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. ** appropriate header files. */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <memory.h> #include <sys/stat.h> #include <assert.h> #include <string.h> #if defined( __MINGW32__) || defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__) # ifndef WIN32 # define WIN32 # endif #else # include <unistd.h> #endif /* ** Macros for debugging. */ #ifdef DEBUG static int debugMask = 0; # define debug0(F,M) if( (F)&debugMask ){ fprintf(stderr,M); } # define debug1(F,M,A) if( (F)&debugMask ){ fprintf(stderr,M,A); } # define debug2(F,M,A,B) if( (F)&debugMask ){ fprintf(stderr,M,A,B); } # define debug3(F,M,A,B,C) if( (F)&debugMask ){ fprintf(stderr,M,A,B,C); } # define PARSER 0x00000001 # define DECL_DUMP 0x00000002 # define TOKENIZER 0x00000004 #else # define debug0(Flags, Format) # define debug1(Flags, Format, A) # define debug2(Flags, Format, A, B) # define debug3(Flags, Format, A, B, C) #endif /* ** The following macros are purely for the purpose of testing this ** program on itself. They don't really contribute to the code. */ #define INTERFACE 1 #define EXPORT_INTERFACE 1 #define EXPORT /* ** Each token in a source file is represented by an instance of ** the following structure. Tokens are collected onto a list. */ typedef struct Token Token; struct Token { const char *zText; /* The text of the token */ int nText; /* Number of characters in the token's text */ int eType; /* The type of this token */ int nLine; /* The line number on which the token starts */ Token *pComment; /* Most recent block comment before this token */ Token *pNext; /* Next token on the list */ Token *pPrev; /* Previous token on the list */ }; /* ** During tokenization, information about the state of the input ** stream is held in an instance of the following structure */ typedef struct InStream InStream; struct InStream { const char *z; /* Complete text of the input */ int i; /* Next character to read from the input */ int nLine; /* The line number for character z[i] */ }; /* ** Each declaration in the C or C++ source files is parsed out and stored as ** an instance of the following structure. ** ** A "forward declaration" is a declaration that an object exists that ** doesn't tell about the objects structure. A typical forward declaration ** is: ** ** struct Xyzzy; ** ** Not every object has a forward declaration. If it does, thought, the ** forward declaration will be contained in the zFwd field for C and ** the zFwdCpp for C++. The zDecl field contains the complete ** declaration text. */ typedef struct Decl Decl; struct Decl { char *zName; /* Name of the object being declared. The appearance ** of this name is a source file triggers the declaration ** to be added to the header for that file. */ const char *zFile; /* File from which extracted. */ char *zIf; /* Surround the declaration with this #if */ char *zFwd; /* A forward declaration. NULL if there is none. */ char *zFwdCpp; /* Use this forward declaration for C++. */ char *zDecl; /* A full declaration of this object */ char *zExtra; /* Extra declaration text inserted into class objects */ int extraType; /* Last public:, protected: or private: in zExtraDecl */ struct Include *pInclude; /* #includes that come before this declaration */ int flags; /* See the "Properties" below */ Token *pComment; /* A block comment associated with this declaration */ Token tokenCode; /* Implementation of functions and procedures */ Decl *pSameName; /* Next declaration with the same "zName" */ Decl *pSameHash; /* Next declaration with same hash but different zName */ Decl *pNext; /* Next declaration with a different name */ }; /* ** Properties associated with declarations. ** ** DP_Forward and DP_Declared are used during the generation of a single ** header file in order to prevent duplicate declarations and definitions. ** DP_Forward is set after the object has been given a forward declaration ** and DP_Declared is set after the object gets a full declarations. ** (Example: A forward declaration is "typedef struct Abc Abc;" and the ** full declaration is "struct Abc { int a; float b; };".) ** ** The DP_Export and DP_Local flags are more permanent. They mark objects ** that have EXPORT scope and LOCAL scope respectively. If both of these ** marks are missing, then the object has library scope. The meanings of ** the scopes are as follows: ** ** LOCAL scope The object is only usable within the file in ** which it is declared. ** ** library scope The object is visible and usable within other ** files in the same project. By if the project is ** a library, then the object is not visible to users ** of the library. (i.e. the object does not appear ** in the output when using the -H option.) ** ** EXPORT scope The object is visible and usable everywhere. ** ** The DP_Flag is a temporary use flag that is used during processing to ** prevent an infinite loop. It's use is localized. ** ** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent ** and are used to specify what type of declaration the object requires. */ #define DP_Forward 0x001 /* Has a forward declaration in this file */ #define DP_Declared 0x002 /* Has a full declaration in this file */ #define DP_Export 0x004 /* Export this declaration */ #define DP_Local 0x008 /* Declare in its home file only */ #define DP_Flag 0x010 /* Use to mark a subset of a Decl list ** for special processing */ #define DP_Cplusplus 0x020 /* Has C++ linkage and cannot appear in a ** C header file */ #define DP_ExternCReqd 0x040 /* Prepend 'extern "C"' in a C++ header. ** Prepend nothing in a C header */ #define DP_ExternReqd 0x080 /* Prepend 'extern "C"' in a C++ header if ** DP_Cplusplus is not also set. If DP_Cplusplus ** is set or this is a C header then ** prepend 'extern' */ /* ** Convenience macros for dealing with declaration properties */ #define DeclHasProperty(D,P) (((D)->flags&(P))==(P)) #define DeclHasAnyProperty(D,P) (((D)->flags&(P))!=0) #define DeclSetProperty(D,P) (D)->flags |= (P) #define DeclClearProperty(D,P) (D)->flags &= ~(P) /* ** These are state properties of the parser. Each of the values is ** distinct from the DP_ values above so that both can be used in ** the same "flags" field. ** ** Be careful not to confuse PS_Export with DP_Export or ** PS_Local with DP_Local. Their names are similar, but the meanings ** of these flags are very different. */ #define PS_Extern 0x000800 /* "extern" has been seen */ #define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE" ** and "#endif" */ #define PS_Export2 0x002000 /* If "EXPORT" seen */ #define PS_Typedef 0x004000 /* If "typedef" has been seen */ #define PS_Static 0x008000 /* If "static" has been seen */ #define PS_Interface 0x010000 /* If within #if INTERFACE..#endif */ #define PS_Method 0x020000 /* If "::" token has been seen */ #define PS_Local 0x040000 /* If within #if LOCAL_INTERFACE..#endif */ #define PS_Local2 0x080000 /* If "LOCAL" seen. */ #define PS_Public 0x100000 /* If "PUBLIC" seen. */ #define PS_Protected 0x200000 /* If "PROTECTED" seen. */ #define PS_Private 0x400000 /* If "PRIVATE" seen. */ #define PS_PPP 0x700000 /* If any of PUBLIC, PRIVATE, PROTECTED */ /* ** The following set of flags are ORed into the "flags" field of ** a Decl in order to identify what type of object is being ** declared. */ #define TY_Class 0x00100000 #define TY_Subroutine 0x00200000 #define TY_Macro 0x00400000 #define TY_Typedef 0x00800000 #define TY_Variable 0x01000000 #define TY_Structure 0x02000000 #define TY_Union 0x04000000 #define TY_Enumeration 0x08000000 #define TY_Defunct 0x10000000 /* Used to erase a declaration */ /* ** Each nested #if (or #ifdef or #ifndef) is stored in a stack of ** instances of the following structure. */ typedef struct Ifmacro Ifmacro; struct Ifmacro { int nLine; /* Line number where this macro occurs */ char *zCondition; /* Text of the condition for this macro */ Ifmacro *pNext; /* Next down in the stack */ int flags; /* Can hold PS_Export, PS_Interface or PS_Local flags */ }; /* ** When parsing a file, we need to keep track of what other files have ** be #include-ed. For each #include found, we create an instance of ** the following structure. */ typedef struct Include Include; struct Include { char *zFile; /* The name of file include. Includes "" or <> */ char *zIf; /* If not NULL, #include should be enclosed in #if */ char *zLabel; /* A unique label used to test if this #include has * appeared already in a file or not */ Include *pNext; /* Previous include file, or NULL if this is the first */ }; /* ** Identifiers found in a source file that might be used later to provoke ** the copying of a declaration into the corresponding header file are ** stored in a hash table as instances of the following structure. */ typedef struct Ident Ident; struct Ident { char *zName; /* The text of this identifier */ Ident *pCollide; /* Next identifier with the same hash */ Ident *pNext; /* Next identifier in a list of them all */ }; /* ** A complete table of identifiers is stored in an instance of ** the next structure. */ #define IDENT_HASH_SIZE 2237 typedef struct IdentTable IdentTable; struct IdentTable { Ident *pList; /* List of all identifiers in this table */ Ident *apTable[IDENT_HASH_SIZE]; /* The hash table */ }; /* ** The following structure holds all information for a single ** source file named on the command line of this program. */ typedef struct InFile InFile; struct InFile { char *zSrc; /* Name of input file */ char *zHdr; /* Name of the generated .h file for this input. ** Will be NULL if input is to be scanned only */ int flags; /* One or more DP_, PS_ and/or TY_ flags */ InFile *pNext; /* Next input file in the list of them all */ IdentTable idTable; /* All identifiers in this input file */ }; /* ** An unbounded string is able to grow without limit. We use these ** to construct large in-memory strings from lots of smaller components. */ typedef struct String String; struct String { int nAlloc; /* Number of bytes allocated */ int nUsed; /* Number of bytes used (not counting null terminator) */ char *zText; /* Text of the string */ }; /* ** The following structure contains a lot of state information used ** while generating a .h file. We put the information in this structure ** and pass around a pointer to this structure, rather than pass around ** all of the information separately. This helps reduce the number of ** arguments to generator functions. */ typedef struct GenState GenState; struct GenState { String *pStr; /* Write output to this string */ IdentTable *pTable; /* A table holding the zLabel of every #include that * has already been generated. Used to avoid * generating duplicate #includes. */ const char *zIf; /* If not NULL, then we are within a #if with * this argument. */ int nErr; /* Number of errors */ const char *zFilename; /* Name of the source file being scanned */ int flags; /* Various flags (DP_ and PS_ flags above) */ }; /* ** The following text line appears at the top of every file generated ** by this program. By recognizing this line, the program can be sure ** never to read a file that it generated itself. ** ** The "#undef INTERFACE" part is a hack to work around a name collision ** in MSVC 2008. */ const char zTopLine[] = "/* \aThis file was automatically generated. Do not edit! */\n" "#undef INTERFACE\n"; #define nTopLine (sizeof(zTopLine)-1) /* ** The name of the file currently being parsed. */ static const char *zFilename; /* ** The stack of #if macros for the file currently being parsed. */ static Ifmacro *ifStack = 0; /* ** A list of all files that have been #included so far in a file being ** parsed. */ static Include *includeList = 0; /* ** The last block comment seen. */ static Token *blockComment = 0; /* ** The following flag is set if the -doc flag appears on the ** command line. */ static int doc_flag = 0; /* ** If the following flag is set, then makeheaders will attempt to ** generate prototypes for static functions and procedures. */ static int proto_static = 0; /* ** A list of all declarations. The list is held together using the ** pNext field of the Decl structure. */ static Decl *pDeclFirst; /* First on the list */ static Decl *pDeclLast; /* Last on the list */ /* ** A hash table of all declarations */ #define DECL_HASH_SIZE 3371 static Decl *apTable[DECL_HASH_SIZE]; /* ** The TEST macro must be defined to something. Make sure this is the ** case. */ #ifndef TEST # define TEST 0 #endif #ifdef NOT_USED /* ** We do our own assertion macro so that we can have more control ** over debugging. */ #define Assert(X) if(!(X)){ CantHappen(__LINE__); } #define CANT_HAPPEN CantHappen(__LINE__) static void CantHappen(int iLine){ fprintf(stderr,"Assertion failed on line %d\n",iLine); *(char*)1 = 0; /* Force a core-dump */ } #endif /* ** Memory allocation functions that are guaranteed never to return NULL. */ static void *SafeMalloc(int nByte){ void *p = malloc( nByte ); if( p==0 ){ fprintf(stderr,"Out of memory. Can't allocate %d bytes.\n",nByte); exit(1); } return p; } static void SafeFree(void *pOld){ if( pOld ){ free(pOld); } } static void *SafeRealloc(void *pOld, int nByte){ void *p; if( pOld==0 ){ p = SafeMalloc(nByte); }else{ p = realloc(pOld, nByte); if( p==0 ){ fprintf(stderr, "Out of memory. Can't enlarge an allocation to %d bytes\n",nByte); exit(1); } } return p; } static char *StrDup(const char *zSrc, int nByte){ char *zDest; if( nByte<=0 ){ nByte = strlen(zSrc); } zDest = SafeMalloc( nByte + 1 ); strncpy(zDest,zSrc,nByte); zDest[nByte] = 0; return zDest; } /* ** Return TRUE if the character X can be part of an identifier */ #define ISALNUM(X) ((X)=='_' || isalnum(X)) /* ** Routines for dealing with unbounded strings. */ static void StringInit(String *pStr){ pStr->nAlloc = 0; pStr->nUsed = 0; pStr->zText = 0; } static void StringReset(String *pStr){ SafeFree(pStr->zText); StringInit(pStr); } static void StringAppend(String *pStr, const char *zText, int nByte){ if( nByte<=0 ){ nByte = strlen(zText); } if( pStr->nUsed + nByte >= pStr->nAlloc ){ if( pStr->nAlloc==0 ){ pStr->nAlloc = nByte + 100; pStr->zText = SafeMalloc( pStr->nAlloc ); }else{ pStr->nAlloc = pStr->nAlloc*2 + nByte; pStr->zText = SafeRealloc(pStr->zText, pStr->nAlloc); } } strncpy(&pStr->zText[pStr->nUsed],zText,nByte); pStr->nUsed += nByte; pStr->zText[pStr->nUsed] = 0; } #define StringGet(S) ((S)->zText?(S)->zText:"") /* ** Compute a hash on a string. The number returned is a non-negative ** value between 0 and 2**31 - 1 */ static int Hash(const char *z, int n){ int h = 0; if( n<=0 ){ n = strlen(z); } while( n-- ){ h = h ^ (h<<5) ^ *z++; } return h & 0x7fffffff; } /* ** Given an identifier name, try to find a declaration for that ** identifier in the hash table. If found, return a pointer to ** the Decl structure. If not found, return 0. */ static Decl *FindDecl(const char *zName, int len){ int h; Decl *p; if( len<=0 ){ len = strlen(zName); } h = Hash(zName,len) % DECL_HASH_SIZE; p = apTable[h]; while( p && (strncmp(p->zName,zName,len)!=0 || p->zName[len]!=0) ){ p = p->pSameHash; } return p; } /* ** Install the given declaration both in the hash table and on ** the list of all declarations. */ static void InstallDecl(Decl *pDecl){ int h; Decl *pOther; h = Hash(pDecl->zName,0) % DECL_HASH_SIZE; pOther = apTable[h]; while( pOther && strcmp(pDecl->zName,pOther->zName)!=0 ){ pOther = pOther->pSameHash; } if( pOther ){ pDecl->pSameName = pOther->pSameName; pOther->pSameName = pDecl; }else{ pDecl->pSameName = 0; pDecl->pSameHash = apTable[h]; apTable[h] = pDecl; } pDecl->pNext = 0; if( pDeclFirst==0 ){ pDeclFirst = pDeclLast = pDecl; }else{ pDeclLast->pNext = pDecl; pDeclLast = pDecl; } } /* ** Look at the current ifStack. If anything declared at the current ** position must be surrounded with ** ** #if STUFF ** #endif ** ** Then this routine computes STUFF and returns a pointer to it. Memory ** to hold the value returned is obtained from malloc(). */ static char *GetIfString(void){ Ifmacro *pIf; char *zResult = 0; int hasIf = 0; String str; for(pIf = ifStack; pIf; pIf=pIf->pNext){ if( pIf->zCondition==0 || *pIf->zCondition==0 ) continue; if( !hasIf ){ hasIf = 1; StringInit(&str); }else{ StringAppend(&str," && ",4); } StringAppend(&str,pIf->zCondition,0); } if( hasIf ){ zResult = StrDup(StringGet(&str),0); StringReset(&str); }else{ zResult = 0; } return zResult; } /* ** Create a new declaration and put it in the hash table. Also ** return a pointer to it so that we can fill in the zFwd and zDecl ** fields, and so forth. */ static Decl *CreateDecl( const char *zName, /* Name of the object being declared. */ int nName /* Length of the name */ ){ Decl *pDecl; pDecl = SafeMalloc( sizeof(Decl) + nName + 1); memset(pDecl,0,sizeof(Decl)); pDecl->zName = (char*)&pDecl[1]; sprintf(pDecl->zName,"%.*s",nName,zName); pDecl->zFile = zFilename; pDecl->pInclude = includeList; pDecl->zIf = GetIfString(); InstallDecl(pDecl); return pDecl; } /* ** Insert a new identifier into an table of identifiers. Return TRUE if ** a new identifier was inserted and return FALSE if the identifier was ** already in the table. */ static int IdentTableInsert( IdentTable *pTable, /* The table into which we will insert */ const char *zId, /* Name of the identifiers */ int nId /* Length of the identifier name */ ){ int h; Ident *pId; if( nId<=0 ){ nId = strlen(zId); } h = Hash(zId,nId) % IDENT_HASH_SIZE; for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){ if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){ /* printf("Already in table: %.*s\n",nId,zId); */ return 0; } } pId = SafeMalloc( sizeof(Ident) + nId + 1 ); pId->zName = (char*)&pId[1]; sprintf(pId->zName,"%.*s",nId,zId); pId->pNext = pTable->pList; pTable->pList = pId; pId->pCollide = pTable->apTable[h]; pTable->apTable[h] = pId; /* printf("Add to table: %.*s\n",nId,zId); */ return 1; } /* ** Check to see if the given value is in the given IdentTable. Return ** true if it is and false if it is not. */ static int IdentTableTest( IdentTable *pTable, /* The table in which to search */ const char *zId, /* Name of the identifiers */ int nId /* Length of the identifier name */ ){ int h; Ident *pId; if( nId<=0 ){ nId = strlen(zId); } h = Hash(zId,nId) % IDENT_HASH_SIZE; for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){ if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){ return 1; } } return 0; } /* ** Remove every identifier from the given table. Reset the table to ** its initial state. */ static void IdentTableReset(IdentTable *pTable){ Ident *pId, *pNext; for(pId = pTable->pList; pId; pId = pNext){ pNext = pId->pNext; SafeFree(pId); } memset(pTable,0,sizeof(IdentTable)); } #ifdef DEBUG /* ** Print the name of every identifier in the given table, one per line */ static void IdentTablePrint(IdentTable *pTable, FILE *pOut){ Ident *pId; for(pId = pTable->pList; pId; pId = pId->pNext){ fprintf(pOut,"%s\n",pId->zName); } } #endif /* ** Read an entire file into memory. Return a pointer to the memory. ** ** The memory is obtained from SafeMalloc and must be freed by the ** calling function. ** ** If the read fails for any reason, 0 is returned. */ static char *ReadFile(const char *zFilename){ struct stat sStat; FILE *pIn; char *zBuf; int n; if( stat(zFilename,&sStat)!=0 #ifndef WIN32 || !S_ISREG(sStat.st_mode) #endif ){ return 0; } pIn = fopen(zFilename,"r"); if( pIn==0 ){ return 0; } zBuf = SafeMalloc( sStat.st_size + 1 ); n = fread(zBuf,1,sStat.st_size,pIn); zBuf[n] = 0; fclose(pIn); return zBuf; } /* ** Write the contents of a string into a file. Return the number of ** errors */ static int WriteFile(const char *zFilename, const char *zOutput){ FILE *pOut; pOut = fopen(zFilename,"w"); if( pOut==0 ){ return 1; } fwrite(zOutput,1,strlen(zOutput),pOut); fclose(pOut); return 0; } /* ** Major token types */ #define TT_Space 1 /* Contiguous white space */ #define TT_Id 2 /* An identifier */ #define TT_Preprocessor 3 /* Any C preprocessor directive */ #define TT_Comment 4 /* Either C or C++ style comment */ #define TT_Number 5 /* Any numeric constant */ #define TT_String 6 /* String or character constants. ".." or '.' */ #define TT_Braces 7 /* All text between { and a matching } */ #define TT_EOF 8 /* End of file */ #define TT_Error 9 /* An error condition */ #define TT_BlockComment 10 /* A C-Style comment at the left margin that * spans multiple lines */ #define TT_Other 0 /* None of the above */ /* ** Get a single low-level token from the input file. Update the ** file pointer so that it points to the first character beyond the ** token. ** ** A "low-level token" is any token except TT_Braces. A TT_Braces token ** consists of many smaller tokens and is assembled by a routine that ** calls this one. ** ** The function returns the number of errors. An error is an ** unterminated string or character literal or an unterminated ** comment. ** ** Profiling shows that this routine consumes about half the ** CPU time on a typical run of makeheaders. */ static int GetToken(InStream *pIn, Token *pToken){ int i; const char *z; int cStart; int c; int startLine; /* Line on which a structure begins */ int nlisc = 0; /* True if there is a new-line in a ".." or '..' */ int nErr = 0; /* Number of errors seen */ z = pIn->z; i = pIn->i; pToken->nLine = pIn->nLine; pToken->zText = &z[i]; switch( z[i] ){ case 0: pToken->eType = TT_EOF; pToken->nText = 0; break; case '#': if( i==0 || z[i-1]=='\n' || (i>1 && z[i-1]=='\r' && z[i-2]=='\n')){ /* We found a preprocessor statement */ pToken->eType = TT_Preprocessor; i++; while( z[i]!=0 && z[i]!='\n' ){ if( z[i]=='\\' ){ i++; if( z[i]=='\n' ) pIn->nLine++; } i++; } pToken->nText = i - pIn->i; }else{ /* Just an operator */ pToken->eType = TT_Other; pToken->nText = 1; } break; case ' ': case '\t': case '\r': case '\f': case '\n': while( isspace(z[i]) ){ if( z[i]=='\n' ) pIn->nLine++; i++; } pToken->eType = TT_Space; pToken->nText = i - pIn->i; break; case '\\': pToken->nText = 2; pToken->eType = TT_Other; if( z[i+1]=='\n' ){ pIn->nLine++; pToken->eType = TT_Space; }else if( z[i+1]==0 ){ pToken->nText = 1; } break; case '\'': case '\"': cStart = z[i]; startLine = pIn->nLine; do{ i++; c = z[i]; if( c=='\n' ){ if( !nlisc ){ fprintf(stderr, "%s:%d: (warning) Newline in string or character literal.\n", zFilename, pIn->nLine); nlisc = 1; } pIn->nLine++; } if( c=='\\' ){ i++; c = z[i]; if( c=='\n' ){ pIn->nLine++; } }else if( c==cStart ){ i++; c = 0; }else if( c==0 ){ fprintf(stderr, "%s:%d: Unterminated string or character literal.\n", zFilename, startLine); nErr++; } }while( c ); pToken->eType = TT_String; pToken->nText = i - pIn->i; break; case '/': if( z[i+1]=='/' ){ /* C++ style comment */ while( z[i] && z[i]!='\n' ){ i++; } pToken->eType = TT_Comment; pToken->nText = i - pIn->i; }else if( z[i+1]=='*' ){ /* C style comment */ int isBlockComment = i==0 || z[i-1]=='\n'; i += 2; startLine = pIn->nLine; while( z[i] && (z[i]!='*' || z[i+1]!='/') ){ if( z[i]=='\n' ){ pIn->nLine++; if( isBlockComment ){ if( z[i+1]=='*' || z[i+2]=='*' ){ isBlockComment = 2; }else{ isBlockComment = 0; } } } i++; } if( z[i] ){ i += 2; }else{ isBlockComment = 0; fprintf(stderr,"%s:%d: Unterminated comment\n", zFilename, startLine); nErr++; } pToken->eType = isBlockComment==2 ? TT_BlockComment : TT_Comment; pToken->nText = i - pIn->i; }else{ /* A divide operator */ pToken->eType = TT_Other; pToken->nText = 1 + (z[i+1]=='+'); } break; case '0': if( z[i+1]=='x' || z[i+1]=='X' ){ /* A hex constant */ i += 2; while( isxdigit(z[i]) ){ i++; } }else{ /* An octal constant */ while( isdigit(z[i]) ){ i++; } } pToken->eType = TT_Number; pToken->nText = i - pIn->i; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while( isdigit(z[i]) ){ i++; } if( (c=z[i])=='.' ){ i++; while( isdigit(z[i]) ){ i++; } c = z[i]; if( c=='e' || c=='E' ){ i++; if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; } while( isdigit(z[i]) ){ i++; } c = z[i]; } if( c=='f' || c=='F' || c=='l' || c=='L' ){ i++; } }else if( c=='e' || c=='E' ){ i++; if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; } while( isdigit(z[i]) ){ i++; } }else if( c=='L' || c=='l' ){ i++; c = z[i]; if( c=='u' || c=='U' ){ i++; } }else if( c=='u' || c=='U' ){ i++; c = z[i]; if( c=='l' || c=='L' ){ i++; } } pToken->eType = TT_Number; pToken->nText = i - pIn->i; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': while( isalnum(z[i]) || z[i]=='_' ){ i++; }; pToken->eType = TT_Id; pToken->nText = i - pIn->i; break; case ':': pToken->eType = TT_Other; pToken->nText = 1 + (z[i+1]==':'); break; case '=': case '<': case '>': case '+': case '-': case '*': case '%': case '^': case '&': case '|': pToken->eType = TT_Other; pToken->nText = 1 + (z[i+1]=='='); break; default: pToken->eType = TT_Other; pToken->nText = 1; break; } pIn->i += pToken->nText; return nErr; } /* ** This routine recovers the next token from the input file which is ** not a space or a comment or any text between an "#if 0" and "#endif". ** ** This routine returns the number of errors encountered. An error ** is an unterminated token or unmatched "#if 0". ** ** Profiling shows that this routine uses about a quarter of the ** CPU time in a typical run. */ static int GetNonspaceToken(InStream *pIn, Token *pToken){ int nIf = 0; int inZero = 0; const char *z; int value; int startLine; int nErr = 0; startLine = pIn->nLine; while( 1 ){ nErr += GetToken(pIn,pToken); /* printf("%04d: Type=%d nIf=%d [%.*s]\n", pToken->nLine,pToken->eType,nIf,pToken->nText, pToken->eType!=TT_Space ? pToken->zText : "<space>"); */ pToken->pComment = blockComment; switch( pToken->eType ){ case TT_Comment: /*0123456789 12345678 */ if( strncmp(pToken->zText, "/*MAKEHEADERS-STOP", 18)==0 ) return nErr; break; case TT_Space: break; case TT_BlockComment: if( doc_flag ){ blockComment = SafeMalloc( sizeof(Token) ); *blockComment = *pToken; } break; case TT_EOF: if( nIf ){ fprintf(stderr,"%s:%d: Unterminated \"#if\"\n", zFilename, startLine); nErr++; } return nErr; case TT_Preprocessor: z = &pToken->zText[1]; while( *z==' ' || *z=='\t' ) z++; if( sscanf(z,"if %d",&value)==1 && value==0 ){ nIf++; inZero = 1; }else if( inZero ){ if( strncmp(z,"if",2)==0 ){ nIf++; }else if( strncmp(z,"endif",5)==0 ){ nIf--; if( nIf==0 ) inZero = 0; } }else{ return nErr; } break; default: if( !inZero ){ return nErr; } break; } } /* NOT REACHED */ } /* ** This routine looks for identifiers (strings of contiguous alphanumeric ** characters) within a preprocessor directive and adds every such string ** found to the given identifier table */ static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){ Token sToken; InStream sIn; int go = 1; sIn.z = pToken->zText; sIn.i = 1; sIn.nLine = 1; while( go && sIn.i < pToken->nText ){ GetToken(&sIn,&sToken); switch( sToken.eType ){ case TT_Id: IdentTableInsert(pTable,sToken.zText,sToken.nText); break; case TT_EOF: go = 0; break; default: break; } } } /* ** This routine gets the next token. Everything contained within ** {...} is collapsed into a single TT_Braces token. Whitespace is ** omitted. ** ** If pTable is not NULL, then insert every identifier seen into the ** IdentTable. This includes any identifiers seen inside of {...}. ** ** The number of errors encountered is returned. An error is an ** unterminated token. */ static int GetBigToken(InStream *pIn, Token *pToken, IdentTable *pTable){ const char *zStart; int iStart; int nBrace; int c; int nLine; int nErr; nErr = GetNonspaceToken(pIn,pToken); switch( pToken->eType ){ case TT_Id: if( pTable!=0 ){ IdentTableInsert(pTable,pToken->zText,pToken->nText); } return nErr; case TT_Preprocessor: if( pTable!=0 ){ FindIdentifiersInMacro(pToken,pTable); } return nErr; case TT_Other: if( pToken->zText[0]=='{' ) break; return nErr; default: return nErr; } iStart = pIn->i; zStart = pToken->zText; nLine = pToken->nLine; nBrace = 1; while( nBrace ){ nErr += GetNonspaceToken(pIn,pToken); /* printf("%04d: nBrace=%d [%.*s]\n",pToken->nLine,nBrace, pToken->nText,pToken->zText); */ switch( pToken->eType ){ case TT_EOF: fprintf(stderr,"%s:%d: Unterminated \"{\"\n", zFilename, nLine); nErr++; pToken->eType = TT_Error; return nErr; case TT_Id: if( pTable ){ IdentTableInsert(pTable,pToken->zText,pToken->nText); } break; case TT_Preprocessor: if( pTable!=0 ){ FindIdentifiersInMacro(pToken,pTable); } break; case TT_Other: if( (c = pToken->zText[0])=='{' ){ nBrace++; }else if( c=='}' ){ nBrace--; } break; default: break; } } pToken->eType = TT_Braces; pToken->nText = 1 + pIn->i - iStart; pToken->zText = zStart; pToken->nLine = nLine; return nErr; } /* ** This routine frees up a list of Tokens. The pComment tokens are ** not cleared by this. So we leak a little memory when using the -doc ** option. So what. */ static void FreeTokenList(Token *pList){ Token *pNext; while( pList ){ pNext = pList->pNext; SafeFree(pList); pList = pNext; } } /* ** Tokenize an entire file. Return a pointer to the list of tokens. ** ** Space for each token is obtained from a separate malloc() call. The ** calling function is responsible for freeing this space. ** ** If pTable is not NULL, then fill the table with all identifiers seen in ** the input file. */ static Token *TokenizeFile(const char *zFile, IdentTable *pTable){ InStream sIn; Token *pFirst = 0, *pLast = 0, *pNew; int nErr = 0; sIn.z = zFile; sIn.i = 0; sIn.nLine = 1; blockComment = 0; while( sIn.z[sIn.i]!=0 ){ pNew = SafeMalloc( sizeof(Token) ); nErr += GetBigToken(&sIn,pNew,pTable); debug3(TOKENIZER, "Token on line %d: [%.*s]\n", pNew->nLine, pNew->nText<50 ? pNew->nText : 50, pNew->zText); if( pFirst==0 ){ pFirst = pLast = pNew; pNew->pPrev = 0; }else{ pLast->pNext = pNew; pNew->pPrev = pLast; pLast = pNew; } if( pNew->eType==TT_EOF ) break; } if( pLast ) pLast->pNext = 0; blockComment = 0; if( nErr ){ FreeTokenList(pFirst); pFirst = 0; } return pFirst; } #if TEST==1 /* ** Use the following routine to test or debug the tokenizer. */ void main(int argc, char **argv){ char *zFile; Token *pList, *p; IdentTable sTable; if( argc!=2 ){ fprintf(stderr,"Usage: %s filename\n",*argv); exit(1); } memset(&sTable,0,sizeof(sTable)); zFile = ReadFile(argv[1]); if( zFile==0 ){ fprintf(stderr,"Can't read file \"%s\"\n",argv[1]); exit(1); } pList = TokenizeFile(zFile,&sTable); for(p=pList; p; p=p->pNext){ int j; switch( p->eType ){ case TT_Space: printf("%4d: Space\n",p->nLine); break; case TT_Id: printf("%4d: Id %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Preprocessor: printf("%4d: Preprocessor %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Comment: printf("%4d: Comment\n",p->nLine); break; case TT_BlockComment: printf("%4d: Block Comment\n",p->nLine); break; case TT_Number: printf("%4d: Number %.*s\n",p->nLine,p->nText,p->zText); break; case TT_String: printf("%4d: String %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Other: printf("%4d: Other %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Braces: for(j=0; j<p->nText && j<30 && p->zText[j]!='\n'; j++){} printf("%4d: Braces %.*s...}\n",p->nLine,j,p->zText); break; case TT_EOF: printf("%4d: End of file\n",p->nLine); break; default: printf("%4d: type %d\n",p->nLine,p->eType); break; } } FreeTokenList(pList); SafeFree(zFile); IdentTablePrint(&sTable,stdout); } #endif #ifdef DEBUG /* ** For debugging purposes, write out a list of tokens. */ static void PrintTokens(Token *pFirst, Token *pLast){ int needSpace = 0; int c; pLast = pLast->pNext; while( pFirst!=pLast ){ switch( pFirst->eType ){ case TT_Preprocessor: printf("\n%.*s\n",pFirst->nText,pFirst->zText); needSpace = 0; break; case TT_Id: case TT_Number: printf("%s%.*s", needSpace ? " " : "", pFirst->nText, pFirst->zText); needSpace = 1; break; default: c = pFirst->zText[0]; printf("%s%.*s", (needSpace && (c=='*' || c=='{')) ? " " : "", pFirst->nText, pFirst->zText); needSpace = pFirst->zText[0]==','; break; } pFirst = pFirst->pNext; } } #endif /* ** Convert a sequence of tokens into a string and return a pointer ** to that string. Space to hold the string is obtained from malloc() ** and must be freed by the calling function. ** ** Certain keywords (EXPORT, PRIVATE, PUBLIC, PROTECTED) are always ** skipped. ** ** If pSkip!=0 then skip over nSkip tokens beginning with pSkip. ** ** If zTerm!=0 then append the text to the end. */ static char *TokensToString( Token *pFirst, /* First token in the string */ Token *pLast, /* Last token in the string */ char *zTerm, /* Terminate the string with this text if not NULL */ Token *pSkip, /* Skip this token if not NULL */ int nSkip /* Skip a total of this many tokens */ ){ char *zReturn; String str; int needSpace = 0; int c; int iSkip = 0; int skipOne = 0; StringInit(&str); pLast = pLast->pNext; while( pFirst!=pLast ){ if( pFirst==pSkip ){ iSkip = nSkip; } if( iSkip>0 ){ iSkip--; pFirst=pFirst->pNext; continue; } switch( pFirst->eType ){ case TT_Preprocessor: StringAppend(&str,"\n",1); StringAppend(&str,pFirst->zText,pFirst->nText); StringAppend(&str,"\n",1); needSpace = 0; break; case TT_Id: switch( pFirst->zText[0] ){ case 'E': if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){ skipOne = 1; } break; case 'P': switch( pFirst->nText ){ case 6: skipOne = !strncmp(pFirst->zText,"PUBLIC", 6); break; case 7: skipOne = !strncmp(pFirst->zText,"PRIVATE",7); break; case 9: skipOne = !strncmp(pFirst->zText,"PROTECTED",9); break; default: break; } break; default: break; } if( skipOne ){ pFirst = pFirst->pNext; continue; } /* Fall thru to the next case */ case TT_Number: if( needSpace ){ StringAppend(&str," ",1); } StringAppend(&str,pFirst->zText,pFirst->nText); needSpace = 1; break; default: c = pFirst->zText[0]; if( needSpace && (c=='*' || c=='{') ){ StringAppend(&str," ",1); } StringAppend(&str,pFirst->zText,pFirst->nText); /* needSpace = pFirst->zText[0]==','; */ needSpace = 0; break; } pFirst = pFirst->pNext; } if( zTerm && *zTerm ){ StringAppend(&str,zTerm,strlen(zTerm)); } zReturn = StrDup(StringGet(&str),0); StringReset(&str); return zReturn; } /* ** This routine is called when we see one of the keywords "struct", ** "enum", "union" or "class". This might be the beginning of a ** type declaration. This routine will process the declaration and ** remove the declaration tokens from the input stream. ** ** If this is a type declaration that is immediately followed by a ** semicolon (in other words it isn't also a variable definition) ** then set *pReset to ';'. Otherwise leave *pReset at 0. The ** *pReset flag causes the parser to skip ahead to the next token ** that begins with the value placed in the *pReset flag, if that ** value is different from 0. */ static int ProcessTypeDecl(Token *pList, int flags, int *pReset){ Token *pName, *pEnd; Decl *pDecl; String str; int need_to_collapse = 1; int type = 0; *pReset = 0; if( pList==0 || pList->pNext==0 || pList->pNext->eType!=TT_Id ){ return 0; } pName = pList->pNext; /* Catch the case of "struct Foo;" and skip it. */ if( pName->pNext && pName->pNext->zText[0]==';' ){ *pReset = ';'; return 0; } for(pEnd=pName->pNext; pEnd && pEnd->eType!=TT_Braces; pEnd=pEnd->pNext){ switch( pEnd->zText[0] ){ case '(': case ')': case '*': case '[': case '=': case ';': return 0; } } if( pEnd==0 ){ return 0; } /* ** At this point, we know we have a type declaration that is bounded ** by pList and pEnd and has the name pName. */ /* ** If the braces are followed immediately by a semicolon, then we are ** dealing a type declaration only. There is not variable definition ** following the type declaration. So reset... */ if( pEnd->pNext==0 || pEnd->pNext->zText[0]==';' ){ *pReset = ';'; need_to_collapse = 0; }else{ need_to_collapse = 1; } if( proto_static==0 && (flags & (PS_Local|PS_Export|PS_Interface))==0 ){ /* Ignore these objects unless they are explicitly declared as interface, ** or unless the "-local" command line option was specified. */ *pReset = ';'; return 0; } #ifdef DEBUG if( debugMask & PARSER ){ printf("**** Found type: %.*s %.*s...\n", pList->nText, pList->zText, pName->nText, pName->zText); PrintTokens(pList,pEnd); printf(";\n"); } #endif /* ** Create a new Decl object for this definition. Actually, if this ** is a C++ class definition, then the Decl object might already exist, ** so check first for that case before creating a new one. */ switch( *pList->zText ){ case 'c': type = TY_Class; break; case 's': type = TY_Structure; break; case 'e': type = TY_Enumeration; break; case 'u': type = TY_Union; break; default: /* Can't Happen */ break; } if( type!=TY_Class ){ pDecl = 0; }else{ pDecl = FindDecl(pName->zText, pName->nText); if( pDecl && (pDecl->flags & type)!=type ) pDecl = 0; } if( pDecl==0 ){ pDecl = CreateDecl(pName->zText,pName->nText); } if( (flags & PS_Static) || !(flags & (PS_Interface|PS_Export)) ){ DeclSetProperty(pDecl,DP_Local); } DeclSetProperty(pDecl,type); /* The object has a full declaration only if it is contained within ** "#if INTERFACE...#endif" or "#if EXPORT_INTERFACE...#endif" or ** "#if LOCAL_INTERFACE...#endif". Otherwise, we only give it a ** forward declaration. */ if( flags & (PS_Local | PS_Export | PS_Interface) ){ pDecl->zDecl = TokensToString(pList,pEnd,";\n",0,0); }else{ pDecl->zDecl = 0; } pDecl->pComment = pList->pComment; StringInit(&str); StringAppend(&str,"typedef ",0); StringAppend(&str,pList->zText,pList->nText); StringAppend(&str," ",0); StringAppend(&str,pName->zText,pName->nText); StringAppend(&str," ",0); StringAppend(&str,pName->zText,pName->nText); StringAppend(&str,";\n",2); pDecl->zFwd = StrDup(StringGet(&str),0); StringReset(&str); StringInit(&str); StringAppend(&str,pList->zText,pList->nText); StringAppend(&str," ",0); StringAppend(&str,pName->zText,pName->nText); StringAppend(&str,";\n",2); pDecl->zFwdCpp = StrDup(StringGet(&str),0); StringReset(&str); if( flags & PS_Export ){ DeclSetProperty(pDecl,DP_Export); }else if( flags & PS_Local ){ DeclSetProperty(pDecl,DP_Local); } /* Here's something weird. ANSI-C doesn't allow a forward declaration ** of an enumeration. So we have to build the typedef into the ** definition. */ if( pDecl->zDecl && DeclHasProperty(pDecl, TY_Enumeration) ){ StringInit(&str); StringAppend(&str,pDecl->zDecl,0); StringAppend(&str,pDecl->zFwd,0); SafeFree(pDecl->zDecl); SafeFree(pDecl->zFwd); pDecl->zFwd = 0; pDecl->zDecl = StrDup(StringGet(&str),0); StringReset(&str); } if( pName->pNext->zText[0]==':' ){ DeclSetProperty(pDecl,DP_Cplusplus); } if( pName->nText==5 && strncmp(pName->zText,"class",5)==0 ){ DeclSetProperty(pDecl,DP_Cplusplus); } /* ** Remove all but pList and pName from the input stream. */ if( need_to_collapse ){ while( pEnd!=pName ){ Token *pPrev = pEnd->pPrev; pPrev->pNext = pEnd->pNext; pEnd->pNext->pPrev = pPrev; SafeFree(pEnd); pEnd = pPrev; } } return 0; } /* ** Given a list of tokens that declare something (a function, procedure, ** variable or typedef) find the token which contains the name of the ** thing being declared. ** ** Algorithm: ** ** The name is: ** ** 1. The first identifier that is followed by a "[", or ** ** 2. The first identifier that is followed by a "(" where the ** "(" is followed by another identifier, or ** ** 3. The first identifier followed by "::", or ** ** 4. If none of the above, then the last identifier. ** ** In all of the above, certain reserved words (like "char") are ** not considered identifiers. */ static Token *FindDeclName(Token *pFirst, Token *pLast){ Token *pName = 0; Token *p; int c; if( pFirst==0 || pLast==0 ){ return 0; } pLast = pLast->pNext; for(p=pFirst; p && p!=pLast; p=p->pNext){ if( p->eType==TT_Id ){ static IdentTable sReserved; static int isInit = 0; static const char *aWords[] = { "char", "class", "const", "double", "enum", "extern", "EXPORT", "ET_PROC", "float", "int", "long", "PRIVATE", "PROTECTED", "PUBLIC", "register", "static", "struct", "sizeof", "signed", "typedef", "union", "volatile", "virtual", "void", }; if( !isInit ){ int i; for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){ IdentTableInsert(&sReserved,aWords[i],0); } isInit = 1; } if( !IdentTableTest(&sReserved,p->zText,p->nText) ){ pName = p; } }else if( p==pFirst ){ continue; }else if( (c=p->zText[0])=='[' && pName ){ break; }else if( c=='(' && p->pNext && p->pNext->eType==TT_Id && pName ){ break; }else if( c==':' && p->zText[1]==':' && pName ){ break; } } return pName; } /* ** This routine is called when we see a method for a class that begins ** with the PUBLIC, PRIVATE, or PROTECTED keywords. Such methods are ** added to their class definitions. */ static int ProcessMethodDef(Token *pFirst, Token *pLast, int flags){ Token *pClass; char *zDecl; Decl *pDecl; String str; int type; pLast = pLast->pPrev; while( pFirst->zText[0]=='P' ){ int rc = 1; switch( pFirst->nText ){ case 6: rc = strncmp(pFirst->zText,"PUBLIC",6); break; case 7: rc = strncmp(pFirst->zText,"PRIVATE",7); break; case 9: rc = strncmp(pFirst->zText,"PROTECTED",9); break; default: break; } if( rc ) break; pFirst = pFirst->pNext; } pClass = FindDeclName(pFirst,pLast); if( pClass==0 ){ fprintf(stderr,"%s:%d: Unable to find the class name for this method\n", zFilename, pFirst->nLine); return 1; } pDecl = FindDecl(pClass->zText, pClass->nText); if( pDecl==0 || (pDecl->flags & TY_Class)!=TY_Class ){ pDecl = CreateDecl(pClass->zText, pClass->nText); DeclSetProperty(pDecl, TY_Class); } StringInit(&str); if( pDecl->zExtra ){ StringAppend(&str, pDecl->zExtra, 0); SafeFree(pDecl->zExtra); pDecl->zExtra = 0; } type = flags & PS_PPP; if( pDecl->extraType!=type ){ if( type & PS_Public ){ StringAppend(&str, "public:\n", 0); pDecl->extraType = PS_Public; }else if( type & PS_Protected ){ StringAppend(&str, "protected:\n", 0); pDecl->extraType = PS_Protected; }else if( type & PS_Private ){ StringAppend(&str, "private:\n", 0); pDecl->extraType = PS_Private; } } StringAppend(&str, " ", 0); zDecl = TokensToString(pFirst, pLast, ";\n", pClass, 2); StringAppend(&str, zDecl, 0); SafeFree(zDecl); pDecl->zExtra = StrDup(StringGet(&str), 0); StringReset(&str); return 0; } /* ** This routine is called when we see a function or procedure definition. ** We make an entry in the declaration table that is a prototype for this ** function or procedure. */ static int ProcessProcedureDef(Token *pFirst, Token *pLast, int flags){ Token *pName; Decl *pDecl; Token *pCode; if( pFirst==0 || pLast==0 ){ return 0; } if( flags & PS_Method ){ if( flags & PS_PPP ){ return ProcessMethodDef(pFirst, pLast, flags); }else{ return 0; } } if( (flags & PS_Static)!=0 && !proto_static ){ return 0; } pCode = pLast; while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){ pLast = pLast->pPrev; } if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){ fprintf(stderr,"%s:%d: Unrecognized syntax.\n", zFilename, pFirst->nLine); return 1; } if( flags & (PS_Interface|PS_Export|PS_Local) ){ fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n", zFilename, pFirst->nLine); return 1; } pName = FindDeclName(pFirst,pLast); if( pName==0 ){ fprintf(stderr,"%s:%d: Malformed function or procedure definition.\n", zFilename, pFirst->nLine); return 1; } /* ** At this point we've isolated a procedure declaration between pFirst ** and pLast with the name pName. */ #ifdef DEBUG if( debugMask & PARSER ){ printf("**** Found routine: %.*s on line %d...\n", pName->nText, pName->zText, pFirst->nLine); PrintTokens(pFirst,pLast); printf(";\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); pDecl->pComment = pFirst->pComment; if( pCode && pCode->eType==TT_Braces ){ pDecl->tokenCode = *pCode; } DeclSetProperty(pDecl,TY_Subroutine); pDecl->zDecl = TokensToString(pFirst,pLast,";\n",0,0); if( (flags & (PS_Static|PS_Local2))!=0 ){ DeclSetProperty(pDecl,DP_Local); }else if( (flags & (PS_Export2))!=0 ){ DeclSetProperty(pDecl,DP_Export); } if( flags & DP_Cplusplus ){ DeclSetProperty(pDecl,DP_Cplusplus); }else{ DeclSetProperty(pDecl,DP_ExternCReqd); } return 0; } /* ** This routine is called whenever we see the "inline" keyword. We ** need to seek-out the inline function or procedure and make a ** declaration out of the entire definition. */ static int ProcessInlineProc(Token *pFirst, int flags, int *pReset){ Token *pName; Token *pEnd; Decl *pDecl; for(pEnd=pFirst; pEnd; pEnd = pEnd->pNext){ if( pEnd->zText[0]=='{' || pEnd->zText[0]==';' ){ *pReset = pEnd->zText[0]; break; } } if( pEnd==0 ){ *pReset = ';'; fprintf(stderr,"%s:%d: incomplete inline procedure definition\n", zFilename, pFirst->nLine); return 1; } pName = FindDeclName(pFirst,pEnd); if( pName==0 ){ fprintf(stderr,"%s:%d: malformed inline procedure definition\n", zFilename, pFirst->nLine); return 1; } #ifdef DEBUG if( debugMask & PARSER ){ printf("**** Found inline routine: %.*s on line %d...\n", pName->nText, pName->zText, pFirst->nLine); PrintTokens(pFirst,pEnd); printf("\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); pDecl->pComment = pFirst->pComment; DeclSetProperty(pDecl,TY_Subroutine); pDecl->zDecl = TokensToString(pFirst,pEnd,";\n",0,0); if( (flags & (PS_Static|PS_Local|PS_Local2)) ){ DeclSetProperty(pDecl,DP_Local); }else if( flags & (PS_Export|PS_Export2) ){ DeclSetProperty(pDecl,DP_Export); } if( flags & DP_Cplusplus ){ DeclSetProperty(pDecl,DP_Cplusplus); }else{ DeclSetProperty(pDecl,DP_ExternCReqd); } return 0; } /* ** Determine if the tokens between pFirst and pEnd form a variable ** definition or a function prototype. Return TRUE if we are dealing ** with a variable defintion and FALSE for a prototype. ** ** pEnd is the token that ends the object. It can be either a ';' or ** a '='. If it is '=', then assume we have a variable definition. ** ** If pEnd is ';', then the determination is more difficult. We have ** to search for an occurrence of an ID followed immediately by '('. ** If found, we have a prototype. Otherwise we are dealing with a ** variable definition. */ static int isVariableDef(Token *pFirst, Token *pEnd){ if( pEnd && pEnd->zText[0]=='=' && (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0) ){ return 1; } while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){ if( pFirst->eType==TT_Id && pFirst->pNext->zText[0]=='(' ){ return 0; } pFirst = pFirst->pNext; } return 1; } /* ** This routine is called whenever we encounter a ";" or "=". The stuff ** between pFirst and pLast constitutes either a typedef or a global ** variable definition. Do the right thing. */ static int ProcessDecl(Token *pFirst, Token *pEnd, int flags){ Token *pName; Decl *pDecl; int isLocal = 0; int isVar; int nErr = 0; if( pFirst==0 || pEnd==0 ){ return 0; } if( flags & PS_Typedef ){ if( (flags & (PS_Export2|PS_Local2))!=0 ){ fprintf(stderr,"%s:%d: \"EXPORT\" or \"LOCAL\" ignored before typedef.\n", zFilename, pFirst->nLine); nErr++; } if( (flags & (PS_Interface|PS_Export|PS_Local|DP_Cplusplus))==0 ){ /* It is illegal to duplicate a typedef in C (but OK in C++). ** So don't record typedefs that aren't within a C++ file or ** within #if INTERFACE..#endif */ return nErr; } if( (flags & (PS_Interface|PS_Export|PS_Local))==0 && proto_static==0 ){ /* Ignore typedefs that are not with "#if INTERFACE..#endif" unless ** the "-local" command line option is used. */ return nErr; } if( (flags & (PS_Interface|PS_Export))==0 ){ /* typedefs are always local, unless within #if INTERFACE..#endif */ isLocal = 1; } }else if( flags & (PS_Static|PS_Local2) ){ if( proto_static==0 && (flags & PS_Local2)==0 ){ /* Don't record static variables unless the "-local" command line ** option was specified or the "LOCAL" keyword is used. */ return nErr; } while( pFirst!=0 && pFirst->pNext!=pEnd && ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0) || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0)) ){ /* Lose the initial "static" or local from local variables. ** We'll prepend "extern" later. */ pFirst = pFirst->pNext; isLocal = 1; } if( pFirst==0 || !isLocal ){ return nErr; } }else if( flags & PS_Method ){ /* Methods are declared by their class. Don't declare separately. */ return nErr; } isVar = (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd); if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0 && (flags & PS_Extern)==0 ){ fprintf(stderr,"%s:%d: Can't define a variable in this context\n", zFilename, pFirst->nLine); nErr++; } pName = FindDeclName(pFirst,pEnd->pPrev); if( pName==0 ){ if( pFirst->nText==4 && strncmp(pFirst->zText,"enum",4)==0 ){ /* Ignore completely anonymous enums. See documentation section 3.8.1. */ return nErr; }else{ fprintf(stderr,"%s:%d: Can't find a name for the object declared here.\n", zFilename, pFirst->nLine); return nErr+1; } } #ifdef DEBUG if( debugMask & PARSER ){ if( flags & PS_Typedef ){ printf("**** Found typedef %.*s at line %d...\n", pName->nText, pName->zText, pName->nLine); }else if( isVar ){ printf("**** Found variable %.*s at line %d...\n", pName->nText, pName->zText, pName->nLine); }else{ printf("**** Found prototype %.*s at line %d...\n", pName->nText, pName->zText, pName->nLine); } PrintTokens(pFirst,pEnd->pPrev); printf(";\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); if( (flags & PS_Typedef) ){ DeclSetProperty(pDecl, TY_Typedef); }else if( isVar ){ DeclSetProperty(pDecl,DP_ExternReqd | TY_Variable); if( !(flags & DP_Cplusplus) ){ DeclSetProperty(pDecl,DP_ExternCReqd); } }else{ DeclSetProperty(pDecl, TY_Subroutine); if( !(flags & DP_Cplusplus) ){ DeclSetProperty(pDecl,DP_ExternCReqd); } } pDecl->pComment = pFirst->pComment; pDecl->zDecl = TokensToString(pFirst,pEnd->pPrev,";\n",0,0); if( isLocal || (flags & (PS_Local|PS_Local2))!=0 ){ DeclSetProperty(pDecl,DP_Local); }else if( flags & (PS_Export|PS_Export2) ){ DeclSetProperty(pDecl,DP_Export); } if( flags & DP_Cplusplus ){ DeclSetProperty(pDecl,DP_Cplusplus); } return nErr; } /* ** Push an if condition onto the if stack */ static void PushIfMacro( const char *zPrefix, /* A prefix, like "define" or "!" */ const char *zText, /* The condition */ int nText, /* Number of characters in zText */ int nLine, /* Line number where this macro occurs */ int flags /* Either 0, PS_Interface, PS_Export or PS_Local */ ){ Ifmacro *pIf; int nByte; nByte = sizeof(Ifmacro); if( zText ){ if( zPrefix ){ nByte += strlen(zPrefix) + 2; } nByte += nText + 1; } pIf = SafeMalloc( nByte ); if( zText ){ pIf->zCondition = (char*)&pIf[1]; if( zPrefix ){ sprintf(pIf->zCondition,"%s(%.*s)",zPrefix,nText,zText); }else{ sprintf(pIf->zCondition,"%.*s",nText,zText); } }else{ pIf->zCondition = 0; } pIf->nLine = nLine; pIf->flags = flags; pIf->pNext = ifStack; ifStack = pIf; } /* ** This routine is called to handle all preprocessor directives. ** ** This routine will recompute the value of *pPresetFlags to be the ** logical or of all flags on all nested #ifs. The #ifs that set flags ** are as follows: ** ** conditional flag set ** ------------------------ -------------------- ** #if INTERFACE PS_Interface ** #if EXPORT_INTERFACE PS_Export ** #if LOCAL_INTERFACE PS_Local ** ** For example, if after processing the preprocessor token given ** by pToken there is an "#if INTERFACE" on the preprocessor ** stack, then *pPresetFlags will be set to PS_Interface. */ static int ParsePreprocessor(Token *pToken, int flags, int *pPresetFlags){ const char *zCmd; int nCmd; const char *zArg; int nArg; int nErr = 0; Ifmacro *pIf; zCmd = &pToken->zText[1]; while( isspace(*zCmd) && *zCmd!='\n' ){ zCmd++; } if( !isalpha(*zCmd) ){ return 0; } nCmd = 1; while( isalpha(zCmd[nCmd]) ){ nCmd++; } if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){ /* ** Pop the if stack */ pIf = ifStack; if( pIf==0 ){ fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine); return 1; } ifStack = pIf->pNext; SafeFree(pIf); }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){ /* ** Record a #define if we are in PS_Interface or PS_Export */ Decl *pDecl; if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; } zArg = &zCmd[6]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } for(nArg=0; ISALNUM(zArg[nArg]); nArg++){} if( nArg==0 ){ return 0; } pDecl = CreateDecl(zArg,nArg); pDecl->pComment = pToken->pComment; DeclSetProperty(pDecl,TY_Macro); pDecl->zDecl = SafeMalloc( pToken->nText + 2 ); sprintf(pDecl->zDecl,"%.*s\n",pToken->nText,pToken->zText); if( flags & PS_Export ){ DeclSetProperty(pDecl,DP_Export); }else if( flags & PS_Local ){ DeclSetProperty(pDecl,DP_Local); } }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){ /* ** Record an #include if we are in PS_Interface or PS_Export */ Include *pInclude; char *zIf; if( !(flags & (PS_Interface|PS_Export)) ){ return 0; } zArg = &zCmd[7]; while( *zArg && isspace(*zArg) ){ zArg++; } for(nArg=0; !isspace(zArg[nArg]); nArg++){} if( (zArg[0]=='"' && zArg[nArg-1]!='"') ||(zArg[0]=='<' && zArg[nArg-1]!='>') ){ fprintf(stderr,"%s:%d: malformed #include statement.\n", zFilename,pToken->nLine); return 1; } zIf = GetIfString(); if( zIf ){ pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 ); pInclude->zFile = (char*)&pInclude[1]; pInclude->zLabel = &pInclude->zFile[nArg+1]; sprintf(pInclude->zFile,"%.*s",nArg,zArg); sprintf(pInclude->zLabel,"%.*s:%s",nArg,zArg,zIf); pInclude->zIf = &pInclude->zLabel[nArg+1]; SafeFree(zIf); }else{ pInclude = SafeMalloc( sizeof(Include) + nArg + 1 ); pInclude->zFile = (char*)&pInclude[1]; sprintf(pInclude->zFile,"%.*s",nArg,zArg); pInclude->zIf = 0; pInclude->zLabel = pInclude->zFile; } pInclude->pNext = includeList; includeList = pInclude; }else if( nCmd==2 && strncmp(zCmd,"if",2)==0 ){ /* ** Push an #if. Watch for the special cases of INTERFACE ** and EXPORT_INTERFACE and LOCAL_INTERFACE */ zArg = &zCmd[2]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } nArg = pToken->nText + (int)(pToken->zText - zArg); if( nArg==9 && strncmp(zArg,"INTERFACE",9)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Interface); }else if( nArg==16 && strncmp(zArg,"EXPORT_INTERFACE",16)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Export); }else if( nArg==15 && strncmp(zArg,"LOCAL_INTERFACE",15)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Local); }else if( nArg==15 && strncmp(zArg,"MAKEHEADERS_STOPLOCAL_INTERFACE",15)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Local); }else{ PushIfMacro(0,zArg,nArg,pToken->nLine,0); } }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){ /* ** Push an #ifdef. */ zArg = &zCmd[5]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } nArg = pToken->nText + (int)(pToken->zText - zArg); PushIfMacro("defined",zArg,nArg,pToken->nLine,0); }else if( nCmd==6 && strncmp(zCmd,"ifndef",6)==0 ){ /* ** Push an #ifndef. */ zArg = &zCmd[6]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } nArg = pToken->nText + (int)(pToken->zText - zArg); PushIfMacro("!defined",zArg,nArg,pToken->nLine,0); }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){ /* ** Invert the #if on the top of the stack */ if( ifStack==0 ){ fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename, pToken->nLine); return 1; } pIf = ifStack; if( pIf->zCondition ){ ifStack = ifStack->pNext; PushIfMacro("!",pIf->zCondition,strlen(pIf->zCondition),pIf->nLine,0); SafeFree(pIf); }else{ pIf->flags = 0; } }else{ /* ** This directive can be safely ignored */ return 0; } /* ** Recompute the preset flags */ *pPresetFlags = 0; for(pIf = ifStack; pIf; pIf=pIf->pNext){ *pPresetFlags |= pIf->flags; } return nErr; } /* ** Parse an entire file. Return the number of errors. ** ** pList is a list of tokens in the file. Whitespace tokens have been ** eliminated, and text with {...} has been collapsed into a ** single TT_Brace token. ** ** initFlags are a set of parse flags that should always be set for this ** file. For .c files this is normally 0. For .h files it is PS_Interface. */ static int ParseFile(Token *pList, int initFlags){ int nErr = 0; Token *pStart = 0; int flags = initFlags; int presetFlags = initFlags; int resetFlag = 0; includeList = 0; while( pList ){ switch( pList->eType ){ case TT_EOF: goto end_of_loop; case TT_Preprocessor: nErr += ParsePreprocessor(pList,flags,&presetFlags); pStart = 0; presetFlags |= initFlags; flags = presetFlags; break; case TT_Other: switch( pList->zText[0] ){ case ';': nErr += ProcessDecl(pStart,pList,flags); pStart = 0; flags = presetFlags; break; case '=': if( pList->pPrev->nText==8 && strncmp(pList->pPrev->zText,"operator",8)==0 ){ break; } nErr += ProcessDecl(pStart,pList,flags); pStart = 0; while( pList && pList->zText[0]!=';' ){ pList = pList->pNext; } if( pList==0 ) goto end_of_loop; flags = presetFlags; break; case ':': if( pList->zText[1]==':' ){ flags |= PS_Method; } break; default: break; } break; case TT_Braces: nErr += ProcessProcedureDef(pStart,pList,flags); pStart = 0; flags = presetFlags; break; case TT_Id: if( pStart==0 ){ pStart = pList; flags = presetFlags; } resetFlag = 0; switch( pList->zText[0] ){ case 'c': if( pList->nText==5 && strncmp(pList->zText,"class",5)==0 ){ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } break; case 'E': if( pList->nText==6 && strncmp(pList->zText,"EXPORT",6)==0 ){ flags |= PS_Export2; /* pStart = 0; */ } break; case 'e': if( pList->nText==4 && strncmp(pList->zText,"enum",4)==0 ){ if( pList->pNext && pList->pNext->eType==TT_Braces ){ pList = pList->pNext; }else{ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } }else if( pList->nText==6 && strncmp(pList->zText,"extern",6)==0 ){ pList = pList->pNext; if( pList && pList->nText==3 && strncmp(pList->zText,"\"C\"",3)==0 ){ pList = pList->pNext; flags &= ~DP_Cplusplus; }else{ flags |= PS_Extern; } pStart = pList; } break; case 'i': if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0 && (flags & PS_Static)==0 ){ nErr += ProcessInlineProc(pList,flags,&resetFlag); } break; case 'L': if( pList->nText==5 && strncmp(pList->zText,"LOCAL",5)==0 ){ flags |= PS_Local2; pStart = pList; } break; case 'P': if( pList->nText==6 && strncmp(pList->zText, "PUBLIC",6)==0 ){ flags |= PS_Public; pStart = pList; }else if( pList->nText==7 && strncmp(pList->zText, "PRIVATE",7)==0 ){ flags |= PS_Private; pStart = pList; }else if( pList->nText==9 && strncmp(pList->zText,"PROTECTED",9)==0 ){ flags |= PS_Protected; pStart = pList; } break; case 's': if( pList->nText==6 && strncmp(pList->zText,"struct",6)==0 ){ if( pList->pNext && pList->pNext->eType==TT_Braces ){ pList = pList->pNext; }else{ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } }else if( pList->nText==6 && strncmp(pList->zText,"static",6)==0 ){ flags |= PS_Static; } break; case 't': if( pList->nText==7 && strncmp(pList->zText,"typedef",7)==0 ){ flags |= PS_Typedef; } break; case 'u': if( pList->nText==5 && strncmp(pList->zText,"union",5)==0 ){ if( pList->pNext && pList->pNext->eType==TT_Braces ){ pList = pList->pNext; }else{ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } } break; default: break; } if( resetFlag!=0 ){ while( pList && pList->zText[0]!=resetFlag ){ pList = pList->pNext; } if( pList==0 ) goto end_of_loop; pStart = 0; flags = presetFlags; } break; case TT_String: case TT_Number: break; default: pStart = pList; flags = presetFlags; break; } pList = pList->pNext; } end_of_loop: /* Verify that all #ifs have a matching "#endif" */ while( ifStack ){ Ifmacro *pIf = ifStack; ifStack = pIf->pNext; fprintf(stderr,"%s:%d: This '#if' has no '#endif'\n",zFilename, pIf->nLine); SafeFree(pIf); } return nErr; } /* ** If the given Decl object has a non-null zExtra field, then the text ** of that zExtra field needs to be inserted in the middle of the ** zDecl field before the last "}" in the zDecl. This routine does that. ** If the zExtra is NULL, this routine is a no-op. ** ** zExtra holds extra method declarations for classes. The declarations ** have to be inserted into the class definition. */ static void InsertExtraDecl(Decl *pDecl){ int i; String str; if( pDecl==0 || pDecl->zExtra==0 || pDecl->zDecl==0 ) return; i = strlen(pDecl->zDecl) - 1; while( i>0 && pDecl->zDecl[i]!='}' ){ i--; } StringInit(&str); StringAppend(&str, pDecl->zDecl, i); StringAppend(&str, pDecl->zExtra, 0); StringAppend(&str, &pDecl->zDecl[i], 0); SafeFree(pDecl->zDecl); SafeFree(pDecl->zExtra); pDecl->zDecl = StrDup(StringGet(&str), 0); StringReset(&str); pDecl->zExtra = 0; } /* ** Reset the DP_Forward and DP_Declared flags on all Decl structures. ** Set both flags for anything that is tagged as local and isn't ** in the file zFilename so that it won't be printing in other files. */ static void ResetDeclFlags(char *zFilename){ Decl *pDecl; for(pDecl = pDeclFirst; pDecl; pDecl = pDecl->pNext){ DeclClearProperty(pDecl,DP_Forward|DP_Declared); if( DeclHasProperty(pDecl,DP_Local) && pDecl->zFile!=zFilename ){ DeclSetProperty(pDecl,DP_Forward|DP_Declared); } } } /* ** Forward declaration of the ScanText() function. */ static void ScanText(const char*, GenState *pState); /* ** The output in pStr is currently within an #if CONTEXT where context ** is equal to *pzIf. (*pzIf might be NULL to indicate that we are ** not within any #if at the moment.) We are getting ready to output ** some text that needs to be within the context of "#if NEW" where ** NEW is zIf. Make an appropriate change to the context. */ static void ChangeIfContext( const char *zIf, /* The desired #if context */ GenState *pState /* Current state of the code generator */ ){ if( zIf==0 ){ if( pState->zIf==0 ) return; StringAppend(pState->pStr,"#endif\n",0); pState->zIf = 0; }else{ if( pState->zIf ){ if( strcmp(zIf,pState->zIf)==0 ) return; StringAppend(pState->pStr,"#endif\n",0); pState->zIf = 0; } ScanText(zIf, pState); if( pState->zIf!=0 ){ StringAppend(pState->pStr,"#endif\n",0); } StringAppend(pState->pStr,"#if ",0); StringAppend(pState->pStr,zIf,0); StringAppend(pState->pStr,"\n",0); pState->zIf = zIf; } } /* ** Add to the string pStr a #include of every file on the list of ** include files pInclude. The table pTable contains all files that ** have already been #included at least once. Don't add any ** duplicates. Update pTable with every new #include that is added. */ static void AddIncludes( Include *pInclude, /* Write every #include on this list */ GenState *pState /* Current state of the code generator */ ){ if( pInclude ){ if( pInclude->pNext ){ AddIncludes(pInclude->pNext,pState); } if( IdentTableInsert(pState->pTable,pInclude->zLabel,0) ){ ChangeIfContext(pInclude->zIf,pState); StringAppend(pState->pStr,"#include ",0); StringAppend(pState->pStr,pInclude->zFile,0); StringAppend(pState->pStr,"\n",1); } } } /* ** Add to the string pStr a declaration for the object described ** in pDecl. ** ** If pDecl has already been declared in this file, detect that ** fact and abort early. Do not duplicate a declaration. ** ** If the needFullDecl flag is false and this object has a forward ** declaration, then supply the forward declaration only. A later ** call to CompleteForwardDeclarations() will finish the declaration ** for us. But if needFullDecl is true, we must supply the full ** declaration now. Some objects do not have a forward declaration. ** For those objects, we must print the full declaration now. ** ** Because it is illegal to duplicate a typedef in C, care is taken ** to insure that typedefs for the same identifier are only issued once. */ static void DeclareObject( Decl *pDecl, /* The thing to be declared */ GenState *pState, /* Current state of the code generator */ int needFullDecl /* Must have the full declaration. A forward * declaration isn't enough */ ){ Decl *p; /* The object to be declared */ int flag; int isCpp; /* True if generating C++ */ int doneTypedef = 0; /* True if a typedef has been done for this object */ /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/ /* ** For any object that has a forward declaration, go ahead and do the ** forward declaration first. */ isCpp = (pState->flags & DP_Cplusplus) != 0; for(p=pDecl; p; p=p->pSameName){ if( p->zFwd ){ if( !DeclHasProperty(p,DP_Forward) ){ DeclSetProperty(p,DP_Forward); if( strncmp(p->zFwd,"typedef",7)==0 ){ if( doneTypedef ) continue; doneTypedef = 1; } ChangeIfContext(p->zIf,pState); StringAppend(pState->pStr,isCpp ? p->zFwdCpp : p->zFwd,0); } } } /* ** Early out if everything is already suitably declared. ** ** This is a very important step because it prevents us from ** executing the code the follows in a recursive call to this ** function with the same value for pDecl. */ flag = needFullDecl ? DP_Declared|DP_Forward : DP_Forward; for(p=pDecl; p; p=p->pSameName){ if( !DeclHasProperty(p,flag) ) break; } if( p==0 ){ return; } /* ** Make sure we have all necessary #includes */ for(p=pDecl; p; p=p->pSameName){ AddIncludes(p->pInclude,pState); } /* ** Go ahead an mark everything as being declared, to prevent an ** infinite loop thru the ScanText() function. At the same time, ** we decide which objects need a full declaration and mark them ** with the DP_Flag bit. We are only able to use DP_Flag in this ** way because we know we'll never execute this far into this ** function on a recursive call with the same pDecl. Hence, recursive ** calls to this function (through ScanText()) can never change the ** value of DP_Flag out from under us. */ for(p=pDecl; p; p=p->pSameName){ if( !DeclHasProperty(p,DP_Declared) && (p->zFwd==0 || needFullDecl) && p->zDecl!=0 ){ DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag); }else{ DeclClearProperty(p,DP_Flag); } } /* ** Call ScanText() recursively (this routine is called from ScanText()) ** to include declarations required to come before these declarations. */ for(p=pDecl; p; p=p->pSameName){ if( DeclHasProperty(p,DP_Flag) ){ if( p->zDecl[0]=='#' ){ ScanText(&p->zDecl[1],pState); }else{ InsertExtraDecl(p); ScanText(p->zDecl,pState); } } } /* ** Output the declarations. Do this in two passes. First ** output everything that isn't a typedef. Then go back and ** get the typedefs by the same name. */ for(p=pDecl; p; p=p->pSameName){ if( DeclHasProperty(p,DP_Flag) && !DeclHasProperty(p,TY_Typedef) ){ if( DeclHasAnyProperty(p,TY_Enumeration) ){ if( doneTypedef ) continue; doneTypedef = 1; } ChangeIfContext(p->zIf,pState); if( !isCpp && DeclHasAnyProperty(p,DP_ExternReqd) ){ StringAppend(pState->pStr,"extern ",0); }else if( isCpp && DeclHasProperty(p,DP_Cplusplus|DP_ExternReqd) ){ StringAppend(pState->pStr,"extern ",0); }else if( isCpp && DeclHasAnyProperty(p,DP_ExternCReqd|DP_ExternReqd) ){ StringAppend(pState->pStr,"extern \"C\" ",0); } InsertExtraDecl(p); StringAppend(pState->pStr,p->zDecl,0); if( !isCpp && DeclHasProperty(p,DP_Cplusplus) ){ fprintf(stderr, "%s: C code ought not reference the C++ object \"%s\"\n", pState->zFilename, p->zName); pState->nErr++; } DeclClearProperty(p,DP_Flag); } } for(p=pDecl; p && !doneTypedef; p=p->pSameName){ if( DeclHasProperty(p,DP_Flag) ){ /* This has to be a typedef */ doneTypedef = 1; ChangeIfContext(p->zIf,pState); InsertExtraDecl(p); StringAppend(pState->pStr,p->zDecl,0); } } } /* ** This routine scans the input text given, and appends to the ** string in pState->pStr the text of any declarations that must ** occur before the text in zText. ** ** If an identifier in zText is immediately followed by '*', then ** only forward declarations are needed for that identifier. If the ** identifier name is not followed immediately by '*', we must supply ** a full declaration. */ static void ScanText( const char *zText, /* The input text to be scanned */ GenState *pState /* Current state of the code generator */ ){ int nextValid = 0; /* True is sNext contains valid data */ InStream sIn; /* The input text */ Token sToken; /* The current token being examined */ Token sNext; /* The next non-space token */ /* printf("BEGIN SCAN TEXT on %s\n", zText); */ sIn.z = zText; sIn.i = 0; sIn.nLine = 1; while( sIn.z[sIn.i]!=0 ){ if( nextValid ){ sToken = sNext; nextValid = 0; }else{ GetNonspaceToken(&sIn,&sToken); } if( sToken.eType==TT_Id ){ int needFullDecl; /* True if we need to provide the full declaration, ** not just the forward declaration */ Decl *pDecl; /* The declaration having the name in sToken */ /* ** See if there is a declaration in the database with the name given ** by sToken. */ pDecl = FindDecl(sToken.zText,sToken.nText); if( pDecl==0 ) continue; /* ** If we get this far, we've found an identifier that has a ** declaration in the database. Now see if we the full declaration ** or just a forward declaration. */ GetNonspaceToken(&sIn,&sNext); if( sNext.zText[0]=='*' ){ needFullDecl = 0; }else{ needFullDecl = 1; nextValid = sNext.eType==TT_Id; } /* ** Generate the needed declaration. */ DeclareObject(pDecl,pState,needFullDecl); }else if( sToken.eType==TT_Preprocessor ){ sIn.i -= sToken.nText - 1; } } /* printf("END SCANTEXT\n"); */ } /* ** Provide a full declaration to any object which so far has had only ** a forward declaration. */ static void CompleteForwardDeclarations(GenState *pState){ Decl *pDecl; int progress; do{ progress = 0; for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){ if( DeclHasProperty(pDecl,DP_Forward) && !DeclHasProperty(pDecl,DP_Declared) ){ DeclareObject(pDecl,pState,1); progress = 1; assert( DeclHasProperty(pDecl,DP_Declared) ); } } }while( progress ); } /* ** Generate an include file for the given source file. Return the number ** of errors encountered. ** ** if nolocal_flag is true, then we do not generate declarations for ** objected marked DP_Local. */ static int MakeHeader(InFile *pFile, FILE *report, int nolocal_flag){ int nErr = 0; GenState sState; String outStr; IdentTable includeTable; Ident *pId; char *zNewVersion; char *zOldVersion; if( pFile->zHdr==0 || *pFile->zHdr==0 ) return 0; sState.pStr = &outStr; StringInit(&outStr); StringAppend(&outStr,zTopLine,nTopLine); sState.pTable = &includeTable; memset(&includeTable,0,sizeof(includeTable)); sState.zIf = 0; sState.nErr = 0; sState.zFilename = pFile->zSrc; sState.flags = pFile->flags & DP_Cplusplus; ResetDeclFlags(nolocal_flag ? "no" : pFile->zSrc); for(pId = pFile->idTable.pList; pId; pId=pId->pNext){ Decl *pDecl = FindDecl(pId->zName,0); if( pDecl ){ DeclareObject(pDecl,&sState,1); } } CompleteForwardDeclarations(&sState); ChangeIfContext(0,&sState); nErr += sState.nErr; zOldVersion = ReadFile(pFile->zHdr); zNewVersion = StringGet(&outStr); if( report ) fprintf(report,"%s: ",pFile->zHdr); if( zOldVersion==0 ){ if( report ) fprintf(report,"updated\n"); if( WriteFile(pFile->zHdr,zNewVersion) ){ fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr); nErr++; } }else if( strncmp(zOldVersion,zTopLine,nTopLine)!=0 ){ if( report ) fprintf(report,"error!\n"); fprintf(stderr, "%s: Can't overwrite this file because it wasn't previously\n" "%*s generated by 'makeheaders'.\n", pFile->zHdr, (int)strlen(pFile->zHdr), ""); nErr++; }else if( strcmp(zOldVersion,zNewVersion)!=0 ){ if( report ) fprintf(report,"updated\n"); if( WriteFile(pFile->zHdr,zNewVersion) ){ fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr); nErr++; } }else if( report ){ fprintf(report,"unchanged\n"); } SafeFree(zOldVersion); IdentTableReset(&includeTable); StringReset(&outStr); return nErr; } /* ** Generate a global header file -- a header file that contains all ** declarations. If the forExport flag is true, then only those ** objects that are exported are included in the header file. */ static int MakeGlobalHeader(int forExport){ GenState sState; String outStr; IdentTable includeTable; Decl *pDecl; sState.pStr = &outStr; StringInit(&outStr); /* StringAppend(&outStr,zTopLine,nTopLine); */ sState.pTable = &includeTable; memset(&includeTable,0,sizeof(includeTable)); sState.zIf = 0; sState.nErr = 0; sState.zFilename = "(all)"; sState.flags = 0; ResetDeclFlags(0); for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){ if( forExport==0 || DeclHasProperty(pDecl,DP_Export) ){ DeclareObject(pDecl,&sState,1); } } ChangeIfContext(0,&sState); printf("%s",StringGet(&outStr)); IdentTableReset(&includeTable); StringReset(&outStr); return 0; } #ifdef DEBUG /* ** Return the number of characters in the given string prior to the ** first newline. */ static int ClipTrailingNewline(char *z){ int n = strlen(z); while( n>0 && (z[n-1]=='\n' || z[n-1]=='\r') ){ n--; } return n; } /* ** Dump the entire declaration list for debugging purposes */ static void DumpDeclList(void){ Decl *pDecl; for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){ printf("**** %s from file %s ****\n",pDecl->zName,pDecl->zFile); if( pDecl->zIf ){ printf("If: [%.*s]\n",ClipTrailingNewline(pDecl->zIf),pDecl->zIf); } if( pDecl->zFwd ){ printf("Decl: [%.*s]\n",ClipTrailingNewline(pDecl->zFwd),pDecl->zFwd); } if( pDecl->zDecl ){ InsertExtraDecl(pDecl); printf("Def: [%.*s]\n",ClipTrailingNewline(pDecl->zDecl),pDecl->zDecl); } if( pDecl->flags ){ static struct { int mask; char *desc; } flagSet[] = { { TY_Class, "class" }, { TY_Enumeration, "enum" }, { TY_Structure, "struct" }, { TY_Union, "union" }, { TY_Variable, "variable" }, { TY_Subroutine, "function" }, { TY_Typedef, "typedef" }, { TY_Macro, "macro" }, { DP_Export, "export" }, { DP_Local, "local" }, { DP_Cplusplus, "C++" }, }; int i; printf("flags:"); for(i=0; i<sizeof(flagSet)/sizeof(flagSet[0]); i++){ if( flagSet[i].mask & pDecl->flags ){ printf(" %s", flagSet[i].desc); } } printf("\n"); } if( pDecl->pInclude ){ Include *p; printf("includes:"); for(p=pDecl->pInclude; p; p=p->pNext){ printf(" %s",p->zFile); } printf("\n"); } } } #endif /* ** When the "-doc" command-line option is used, this routine is called ** to print all of the database information to standard output. */ static void DocumentationDump(void){ Decl *pDecl; static struct { int mask; char flag; } flagSet[] = { { TY_Class, 'c' }, { TY_Enumeration, 'e' }, { TY_Structure, 's' }, { TY_Union, 'u' }, { TY_Variable, 'v' }, { TY_Subroutine, 'f' }, { TY_Typedef, 't' }, { TY_Macro, 'm' }, { DP_Export, 'x' }, { DP_Local, 'l' }, { DP_Cplusplus, '+' }, }; for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){ int i; int nLabel = 0; char *zDecl; char zLabel[50]; for(i=0; i<sizeof(flagSet)/sizeof(flagSet[0]); i++){ if( DeclHasProperty(pDecl,flagSet[i].mask) ){ zLabel[nLabel++] = flagSet[i].flag; } } if( nLabel==0 ) continue; zLabel[nLabel] = 0; InsertExtraDecl(pDecl); zDecl = pDecl->zDecl; if( zDecl==0 ) zDecl = pDecl->zFwd; printf("%s %s %s %p %d %d %d %d %d\n", pDecl->zName, zLabel, pDecl->zFile, pDecl->pComment, pDecl->pComment ? pDecl->pComment->nText+1 : 0, pDecl->zIf ? (int)strlen(pDecl->zIf)+1 : 0, zDecl ? (int)strlen(zDecl) : 0, pDecl->pComment ? pDecl->pComment->nLine : 0, pDecl->tokenCode.nText ? pDecl->tokenCode.nText+1 : 0 ); if( pDecl->pComment ){ printf("%.*s\n",pDecl->pComment->nText, pDecl->pComment->zText); } if( pDecl->zIf ){ printf("%s\n",pDecl->zIf); } if( zDecl ){ printf("%s",zDecl); } if( pDecl->tokenCode.nText ){ printf("%.*s\n",pDecl->tokenCode.nText, pDecl->tokenCode.zText); } } } /* ** Given the complete text of an input file, this routine prints a ** documentation record for the header comment at the beginning of the ** file (if the file has a header comment.) */ void PrintModuleRecord(const char *zFile, const char *zFilename){ int i; static int addr = 5; while( isspace(*zFile) ){ zFile++; } if( *zFile!='/' || zFile[1]!='*' ) return; for(i=2; zFile[i] && (zFile[i-1]!='/' || zFile[i-2]!='*'); i++){} if( zFile[i]==0 ) return; printf("%s M %s %d %d 0 0 0 0\n%.*s\n", zFilename, zFilename, addr, i+1, i, zFile); addr += 4; } /* ** Given an input argument to the program, construct a new InFile ** object. */ static InFile *CreateInFile(char *zArg, int *pnErr){ int nSrc; char *zSrc; InFile *pFile; int i; /* ** Get the name of the input file to be scanned. The input file is ** everything before the first ':' or the whole file if no ':' is seen. ** ** Except, on windows, ignore any ':' that occurs as the second character ** since it might be part of the drive specifier. So really, the ":' has ** to be the 3rd or later character in the name. This precludes 1-character ** file names, which really should not be a problem. */ zSrc = zArg; for(nSrc=2; zSrc[nSrc] && zArg[nSrc]!=':'; nSrc++){} pFile = SafeMalloc( sizeof(InFile) ); memset(pFile,0,sizeof(InFile)); pFile->zSrc = StrDup(zSrc,nSrc); /* Figure out if we are dealing with C or C++ code. Assume any ** file with ".c" or ".h" is C code and all else is C++. */ if( nSrc>2 && zSrc[nSrc-2]=='.' && (zSrc[nSrc-1]=='c' || zSrc[nSrc-1]=='h')){ pFile->flags &= ~DP_Cplusplus; }else{ pFile->flags |= DP_Cplusplus; } /* ** If a separate header file is specified, use it */ if( zSrc[nSrc]==':' ){ int nHdr; char *zHdr; zHdr = &zSrc[nSrc+1]; for(nHdr=0; zHdr[nHdr]; nHdr++){} pFile->zHdr = StrDup(zHdr,nHdr); } /* Look for any 'c' or 'C' in the suffix of the file name and change ** that character to 'h' or 'H' respectively. If no 'c' or 'C' is found, ** then assume we are dealing with a header. */ else{ int foundC = 0; pFile->zHdr = StrDup(zSrc,nSrc); for(i = nSrc-1; i>0 && pFile->zHdr[i]!='.'; i--){ if( pFile->zHdr[i]=='c' ){ foundC = 1; pFile->zHdr[i] = 'h'; }else if( pFile->zHdr[i]=='C' ){ foundC = 1; pFile->zHdr[i] = 'H'; } } if( !foundC ){ SafeFree(pFile->zHdr); pFile->zHdr = 0; } } /* ** If pFile->zSrc contains no 'c' or 'C' in its extension, it ** must be a header file. In that case, we need to set the ** PS_Interface flag. */ pFile->flags |= PS_Interface; for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){ if( zSrc[i]=='c' || zSrc[i]=='C' ){ pFile->flags &= ~PS_Interface; break; } } /* Done! */ return pFile; } /* MS-Windows and MS-DOS both have the following serious OS bug: the ** length of a command line is severely restricted. But this program ** occasionally requires long command lines. Hence the following ** work around. ** ** If the parameters "-f FILENAME" appear anywhere on the command line, ** then the named file is scanned for additional command line arguments. ** These arguments are substituted in place of the "FILENAME" argument ** in the original argument list. ** ** This first parameter to this routine is the index of the "-f" ** parameter in the argv[] array. The argc and argv are passed by ** pointer so that they can be changed. ** ** Parsing of the parameters in the file is very simple. Parameters ** can be separated by any amount of white-space (including newlines ** and carriage returns.) There are now quoting characters of any ** kind. The length of a token is limited to about 1000 characters. */ static void AddParameters(int index, int *pArgc, char ***pArgv){ int argc = *pArgc; /* The original argc value */ char **argv = *pArgv; /* The original argv value */ int newArgc; /* Value for argc after inserting new arguments */ char **zNew = 0; /* The new argv after this routine is done */ char *zFile; /* Name of the input file */ int nNew = 0; /* Number of new entries in the argv[] file */ int nAlloc = 0; /* Space allocated for zNew[] */ int i; /* Loop counter */ int n; /* Number of characters in a new argument */ int c; /* Next character of input */ int startOfLine = 1; /* True if we are where '#' can start a comment */ FILE *in; /* The input file */ char zBuf[1000]; /* A single argument is accumulated here */ if( index+1==argc ) return; zFile = argv[index+1]; in = fopen(zFile,"r"); if( in==0 ){ fprintf(stderr,"Can't open input file \"%s\"\n",zFile); exit(1); } c = ' '; while( c!=EOF ){ while( c!=EOF && isspace(c) ){ if( c=='\n' ){ startOfLine = 1; } c = getc(in); if( startOfLine && c=='#' ){ while( c!=EOF && c!='\n' ){ c = getc(in); } } } n = 0; while( c!=EOF && !isspace(c) ){ if( n<sizeof(zBuf)-1 ){ zBuf[n++] = c; } startOfLine = 0; c = getc(in); } zBuf[n] = 0; if( n>0 ){ nNew++; if( nNew + argc > nAlloc ){ if( nAlloc==0 ){ nAlloc = 100 + argc; zNew = malloc( sizeof(char*) * nAlloc ); }else{ nAlloc *= 2; zNew = realloc( zNew, sizeof(char*) * nAlloc ); } } if( zNew ){ int j = nNew + index; zNew[j] = malloc( n + 1 ); if( zNew[j] ){ strcpy( zNew[j], zBuf ); } } } } newArgc = argc + nNew - 1; for(i=0; i<=index; i++){ zNew[i] = argv[i]; } for(i=nNew + index + 1; i<newArgc; i++){ zNew[i] = argv[i + 1 - nNew]; } zNew[newArgc] = 0; *pArgc = newArgc; *pArgv = zNew; } #ifdef NOT_USED /* ** Return the time that the given file was last modified. If we can't ** locate the file (because, for example, it doesn't exist), then ** return 0. */ static unsigned int ModTime(const char *zFilename){ unsigned int mTime = 0; struct stat sStat; if( stat(zFilename,&sStat)==0 ){ mTime = sStat.st_mtime; } return mTime; } #endif /* ** Print a usage comment for this program. */ static void Usage(const char *argv0, const char *argvN){ fprintf(stderr,"%s: Illegal argument \"%s\"\n",argv0,argvN); fprintf(stderr,"Usage: %s [options] filename...\n" "Options:\n" " -h Generate a single .h to standard output.\n" " -H Like -h, but only output EXPORT declarations.\n" " -v (verbose) Write status information to the screen.\n" " -doc Generate no header files. Instead, output information\n" " that can be used by an automatic program documentation\n" " and cross-reference generator.\n" " -local Generate prototypes for \"static\" functions and\n" " procedures.\n" " -f FILE Read additional command-line arguments from the file named\n" " \"FILE\".\n" #ifdef DEBUG " -! MASK Set the debugging mask to the number \"MASK\".\n" #endif " -- Treat all subsequent comment-line parameters as filenames,\n" " even if they begin with \"-\".\n", argv0 ); } /* ** The following text contains a few simple #defines that we want ** to be available to every file. */ static const char zInit[] = "#define INTERFACE 0\n" "#define EXPORT_INTERFACE 0\n" "#define LOCAL_INTERFACE 0\n" "#define EXPORT\n" "#define LOCAL static\n" "#define PUBLIC\n" "#define PRIVATE\n" "#define PROTECTED\n" ; #if TEST==0 int main(int argc, char **argv){ int i; /* Loop counter */ int nErr = 0; /* Number of errors encountered */ Token *pList; /* List of input tokens for one file */ InFile *pFileList = 0;/* List of all input files */ InFile *pTail = 0; /* Last file on the list */ InFile *pFile; /* for looping over the file list */ int h_flag = 0; /* True if -h is present. Output unified header */ int H_flag = 0; /* True if -H is present. Output EXPORT header */ int v_flag = 0; /* Verbose */ int noMoreFlags; /* True if -- has been seen. */ FILE *report; /* Send progress reports to this, if not NULL */ noMoreFlags = 0; for(i=1; i<argc; i++){ if( argv[i][0]=='-' && !noMoreFlags ){ switch( argv[i][1] ){ case 'h': h_flag = 1; break; case 'H': H_flag = 1; break; case 'v': v_flag = 1; break; case 'd': doc_flag = 1; proto_static = 1; break; case 'l': proto_static = 1; break; case 'f': AddParameters(i, &argc, &argv); break; case '-': noMoreFlags = 1; break; #ifdef DEBUG case '!': i++; debugMask = strtol(argv[i],0,0); break; #endif default: Usage(argv[0],argv[i]); return 1; } }else{ pFile = CreateInFile(argv[i],&nErr); if( pFile ){ if( pFileList ){ pTail->pNext = pFile; pTail = pFile; }else{ pFileList = pTail = pFile; } } } } if( h_flag && H_flag ){ h_flag = 0; } if( v_flag ){ report = (h_flag || H_flag) ? stderr : stdout; }else{ report = 0; } if( nErr>0 ){ return nErr; } for(pFile=pFileList; pFile; pFile=pFile->pNext){ char *zFile; zFilename = pFile->zSrc; if( zFilename==0 ) continue; zFile = ReadFile(zFilename); if( zFile==0 ){ fprintf(stderr,"Can't read input file \"%s\"\n",zFilename); nErr++; continue; } if( strncmp(zFile,zTopLine,nTopLine)==0 ){ pFile->zSrc = 0; }else{ if( report ) fprintf(report,"Reading %s...\n",zFilename); pList = TokenizeFile(zFile,&pFile->idTable); if( pList ){ nErr += ParseFile(pList,pFile->flags); FreeTokenList(pList); }else if( zFile[0]==0 ){ fprintf(stderr,"Input file \"%s\" is empty.\n", zFilename); nErr++; }else{ fprintf(stderr,"Errors while processing \"%s\"\n", zFilename); nErr++; } } if( !doc_flag ) SafeFree(zFile); if( doc_flag ) PrintModuleRecord(zFile,zFilename); } if( nErr>0 ){ return nErr; } #ifdef DEBUG if( debugMask & DECL_DUMP ){ DumpDeclList(); return nErr; } #endif if( doc_flag ){ DocumentationDump(); return nErr; } zFilename = "--internal--"; pList = TokenizeFile(zInit,0); if( pList==0 ){ return nErr+1; } ParseFile(pList,PS_Interface); FreeTokenList(pList); if( h_flag || H_flag ){ nErr += MakeGlobalHeader(H_flag); }else{ for(pFile=pFileList; pFile; pFile=pFile->pNext){ if( pFile->zSrc==0 ) continue; nErr += MakeHeader(pFile,report,0); } } return nErr; } #endif |
Added src/makeheaders.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | <html> <head><title>The Makeheaders Program</title></head> <body bgcolor=white> <h1 align=center>The Makeheaders Program</h1> <p> This document describes <em>makeheaders</em>, a tool that automatically generates “<code>.h</code>” files for a C or C++ programming project. </p> <h2>Table Of Contents</h2> <ul> <li><a href="#H0002">1,0 Background</a> <ul> <li><a href="#H0003">1.1 Problems With The Traditional Approach</a> <li><a href="#H0004">1.2 The Makeheaders Solution</a> </ul> <li><a href="#H0005">2.0 Running The Makeheaders Program</a> <li><a href="#H0006">3.0 Preparing Source Files For Use With Makeheaders</a> <ul> <li><a href="#H0007">3.1 The Basic Setup</a> <li><a href="#H0008">3.2 What Declarations Get Copied</a> <li><a href="#H0009">3.3 How To Avoid Having To Write Any Header Files</a> <li><a href="#H0010">3.4 Designating Declarations For Export</a> <li><a href="#H0011">3.5 Local declarations processed by makeheaders</a> <li><a href="#H0012">3.6 Using Makeheaders With C++ Code</a> <li><a href="#H0013">3.7 Conditional Compilation</a> <li><a href="#H0014">3.8 Caveats</a> </ul> <li><a href="#H0015">4.0 Using Makeheaders To Generate Documentation</a> <li><a href="#H0016">5.0 Compiling The Makeheaders Program</a> <li><a href="#H0017">6.0 History</a> <li><a href="#H0018">7.0 Summary And Conclusion</a> </ul><a name="H0002"></a> <h2>1.0 Background</h2> <p> A piece of C source code can be one of two things: a <em>declaration</em> or a <em>definition</em>. A declaration is source text that gives information to the compiler but doesn't directly result in any code being generated. A definition is source text that results in executable machine instructions or initialization data. (These two terms are sometimes used inconsistently by other authors. In particular, many people reverse the meanings of these words when discussing Pascal or Ada code. The meanings described here are the same as used in the ANSI-C standards document.) </p> <p> Declarations in C include things such as the following: <ul> <li> Typedefs. <li> Structure, union and enumeration declarations. <li> Function and procedure prototypes. <li> Preprocessor macros and #defines. <li> “<code>extern</code>” variable declarations. </ul> </p> <p> Definitions in C, on the other hand, include these kinds of things: <ul> <li> Variable definitions. <li> The bodies of functions and procedures. <li> Initialization data. </ul> </p> <p> The distinction between a declaration and a definition is common in modern software engineering. Another way of looking at the difference is that the declaration is the <em>interface</em> and the definition is the <em>implementation</em>. </p> <p> In C programs, it has always been the tradition that declarations are put in files with the “<code>.h</code>” suffix and definitions are placed in “<code>.c</code>” files. The .c files contain “<code>#include</code>” preprocessor statements that cause the contents of .h files to be included as part of the source code when the .c file is compiled. In this way, the .h files define the interface to a subsystem and the .c files define how the subsystem is implemented. </p> <a name="H0003"></a> <h3>1.1 Problems With The Traditional Approach</h3> <p> As the art of computer programming continues to advance, and the size and complexity of programs continues to swell, the traditional C approach of placing declarations and definitions in separate files begins to present the programmer with logistics and maintenance problems. To wit: </p> <p> <ol> <p><li> In large codes with many source files, it becomes difficult to determine which .h files should be included in which .c files. <p><li> It is typically the case that a .h file will be forced to include another .h files, which in turn might include other .h files, and so forth. The .c file must be recompiled when any of the .h files in this chain are altered, but it can be difficult to determine what .h files are found in the include chain. A frequent Makefile error is to omit some .h files from a dependency list even though those files are on the include file chain. <p><li> Some information is common to both the declaration and the definition of an object in C, and so must be repeated in both the .h and the .c files for that object. In a large project, it can become increasingly difficult to keep the two files in sync. <p><li> When a .c file includes a .h file and the .h files changes, the .c file must be recompiled, even if the part of the .h file that changed is not actually used by the .c file. In a large program, it is generally the case that almost every .c file ends up depending on one or two of the more important .h files, and so when those .h files change, the entire program must be recompiled. It also happens that those important .h files tend to be the ones that change most frequently. This means that the entire program must be recompiled frequently, leading to a lengthy modify-compile-test cycle and a corresponding decrease in programmer productivity. <p><li> The C programming language requires that declarations depending upon each other must occur in a particular order. In a program with complex, interwoven data structures, the correct declaration order can become very difficult to determine manually, especially when the declarations involved are spread out over several files. </ol> </p> <a name="H0004"></a> <h3>1.2 The Makeheaders Solution</h3> <p> The makeheaders program is designed to ameliorate the problems associated with the traditional C programming model by automatically generating the interface information in the .h files from interface information contained in other .h files and from implementation information in the .c files. When the makeheaders program is run, it scans the source files for a project, then generates a series of new .h files, one for each .c file. The generated .h files contain exactly those declarations required by the corresponding .c files, no more and no less. </p> <p> The makeheaders programming model overcomes all of the objections to the traditional C programming model. <ol> <p><li> Because all declarations needed by a .c file are contained in a single .h file, there is never any question about what .h files a .c will need to include. If the .c file is named <code>alpha.c</code> then it must include only the single .h file named <code>alpha.h</code>. (The .c file might also use some include files from the standard library, such as <code><stdio.h></code>, but that is another matter.) <p><li> The generated .h files do not include other .h files, and so there are no include chains to worry about. The file <code>alpha.c</code> depends on <code>alpha.h</code> and nothing more. <p><li> There is still duplication in the .h and the .c file, but because the duplicate information is automatically generated, it is no longer a problem. Simply rerun makeheaders to resynchronize everything. <p><li> The generated .h file contains the minimal set of declarations needed by the .c file. This means that when something changes, a minimal amount of recompilation is required to produce an updated executable. Experience has shown that this gives a dramatic improvement in programmer productivity by facilitating a rapid modify-compile-test cycle during development. <p><li> The makeheaders program automatically sorts declarations into the correct order, completely eliminating the wearisome and error-prone task of sorting declarations by hand. </ol> <p> <p> In addition, the makeheaders program is fast and unintrusive. It is a simple matter to incorporate makeheaders into a Makefile so that makeheaders will be run automatically whenever the project is rebuilt. And the burden of running makeheaders is light. It will easily process tens of thousands of lines of source code per second. </p> <a name="H0005"></a> <h2>2.0 Running The Makeheaders Program</h2> <p> The makeheaders program is very easy to run. If you have a collection of C source code and include files in the working directory, then you can run makeheaders to generate appropriate .h files using the following command: <pre> makeheaders *.[ch] </pre> That's really all there is to it! This command will generate one .h file for every .c file. Any .h files that were generated by a prior run of makeheaders are ignored, but manually entered .h files that contain structure declarations and so forth will be scanned and the declarations will be copied into the generated .h files as appropriate. But if makeheaders sees that the .h file that it has generated is no different from the .h file it generated last time, it doesn't update the file. This prevents the corresponding .c files from having to be needlessly recompiled. </p> <p> There are several options to the makeheaders program that can be used to alter its behavior. The default behavior is to write a single .h file for each .c file and to give the .h file the same base name as the .c file. Instead of generating a whole mess of .h files, you can, if you choose, generate a single big .h file that contains all declarations needed by all the .c files. Do this using the -h option to makeheaders. As follows: <pre> makeheaders -h *.[ch] >common.h </pre> With the -h option, the .h file is not actually written to a disk file but instead appears on standard output, where you are free to redirect it into the file of your choice. </p> <p> A similar option is -H. Like the lower-case -h option, big -H generates a single include file on standard output. But unlike small -h, the big -H only emits prototypes and declarations that have been designated as “exportable”. The idea is that -H will generate an include file that defines the interface to a library. More will be said about this in section 3.4. </p> <p> Sometimes you want the base name of the .c file and the .h file to be different. For example, suppose you want the include file for <code>alpha.c</code> to be called <code>beta.h</code>. In this case, you would invoke makeheaders as follows: <pre> makeheaders alpha.c:beta.h </pre> Any time a filename argument contains a colon, the name before the colon is taken to be the name of the .c file and the name after the colon is taken to be the name of the .h file. You can't use the shell's wildcard mechanism with this approach, but that normally isn't a problem in Makefiles, which is where this stuff comes in handy. </p> <p> If you want a particular file to be scanned by makeheaders but you don't want makeheaders to generate a header file for that file, then you can supply an empty header filename, like this: <pre> makeheaders alpha.c beta.c gamma.c: </pre> In this example, makeheaders will scan the three files named “<code>alpha.c</code>”, “<code>beta.c</code>” and “<code>gamma.c</code>” but because of the colon on the end of third filename it will only generate headers for the first two files. Unfortunately, it is not possible to get makeheaders to process any file whose name contains a colon. </p> <p> In a large project, the length of the command line for makeheaders can become very long. If the operating system doesn't support long command lines (example: DOS and Win32) you may not be able to list all of the input files in the space available. In that case, you can use the “<code>-f</code>” option followed by the name of a file to cause makeheaders to read command line options and filename from the file instead of from the command line. For example, you might prepare a file named “<code>mkhdr.dat</code>” that contains text like this: <pre> src/alpha.c:hdr/alpha.h src/beta.c:hdr/beta.h src/gamma.c:hdr/gamma.h ... </pre> Then invoke makeheaders as follows: <pre> makeheaders -f mkhdr.dat </pre> </p> <p> The “<code>-local</code>” option causes makeheaders to generate of prototypes for “<code>static</code>” functions and procedures. Such prototypes are normally omitted. </p> <p> Finally, makeheaders also includes a “<code>-doc</code>” option. This command line option prevents makeheaders from generating any headers at all. Instead, makeheaders will write to standard output information about every definition and declaration that it encounters in its scan of source files. The information output includes the type of the definition or declaration and any comment that preceeds the definition or declaration. The output is in a format that can be easily parsed, and is intended to be read by another program that will generate documentation about the program. We'll talk more about this feature later. </p> <p> If you forget what command line options are available, or forget their exact name, you can invoke makeheaders using an unknown command line option (like “<code>--help</code>” or “<code>-?</code>”) and it will print a summary of the available options on standard error. If you need to process a file whose name begins with “<code>-</code>”, you can prepend a “<code>./</code>” to its name in order to get it accepted by the command line parser. Or, you can insert the special option “<code>--</code>” on the command line to cause all subsequent command line arguments to be treated as filenames even if their names begin with “<code>-</code>”. </p> <a name="H0006"></a> <h2>3.0 Preparing Source Files For Use With Makeheaders</h2> <p> Very little has to be done to prepare source files for use with makeheaders since makeheaders will read and understand ordinary C code. But it is important that you structure your files in a way that makes sense in the makeheaders context. This section will describe several typical uses of makeheaders. </p> <a name="H0007"></a> <h3>3.1 The Basic Setup</h3> <p> The simplest way to use makeheaders is to put all definitions in one or more .c files and all structure and type declarations in separate .h files. The only restriction is that you should take care to chose basenames for your .h files that are different from the basenames for your .c files. Recall that if your .c file is named (for example) “<code>alpha.c</code>” makeheaders will attempt to generate a corresponding header file named “<code>alpha.h</code>”. For that reason, you don't want to use that name for any of the .h files you write since that will prevent makeheaders from generating the .h file automatically. </p> <p> The structure of a .c file intented for use with makeheaders is very simple. All you have to do is add a single “<code>#include</code>” to the top of the file that sources the header file that makeheaders will generate. Hence, the beginning of a source file named “<code>alpha.c</code>” might look something like this: </p> <pre> /* * Introductory comment... */ #include "alpha.h" /* The rest of your code... */ </pre> <p> Your manually generated header files require no special attention at all. Code them as you normally would. However, makeheaders will work better if you omit the “<code>#if</code>” statements people often put around the outside of header files that prevent the files from being included more than once. For example, to create a header file named “<code>beta.h</code>”, many people will habitually write the following: <pre> #ifndef BETA_H #define BETA_H /* declarations for beta.h go here */ #endif </pre> You can forego this cleverness with makeheaders. Remember that the header files you write will never really be included by any C code. Instead, makeheaders will scan your header files to extract only those declarations that are needed by individual .c files and then copy those declarations to the .h files corresponding to the .c files. Hence, the “<code>#if</code>” wrapper serves no useful purpose. But it does make makeheaders work harder, forcing it to put the statements <pre> #if !defined(BETA_H) #endif </pre> around every declaration that it copies out of your header file. No ill effect should come of this, but neither is there any benefit. </p> <p> Having prepared your .c and .h files as described above, you can cause makeheaders to generate its .h files using the following simple command: <pre> makeheaders *.[ch] </pre> The makeheaders program will scan all of the .c files and all of the manually written .h files and then automatically generate .h files corresponding to all .c files. </p> <p> Note that the wildcard expression used in the above example, “<code>*.[ch]</code>”, will expand to include all .h files in the current directory, both those entered manually be the programmer and others generated automatically by a prior run of makeheaders. But that is not a problem. The makeheaders program will recognize and ignore any files it has previously generated that show up on its input list. </p> <a name="H0008"></a> <h3>3.2 What Declarations Get Copied</h3> <p> The following list details all of the code constructs that makeheaders will extract and place in the automatically generated .h files: </p> <ul> <p><li> When a function is defined in any .c file, a prototype of that function is placed in the generated .h file of every .c file that calls the function.</p> <P>If the “<code>static</code>” keyword of C appears at the beginning of the function definition, the prototype is suppressed. If you use the “<code>LOCAL</code>” keyword where you would normally say “<code>static</code>”, then a prototype is generated, but it will only appear in the single header file that corresponds to the source file containing the function. For example, if the file <code>alpha.c</code> contains the following: <pre> LOCAL int testFunc(void){ return 0; } </pre> Then the header file <code>alpha.h</code> will contain <pre> #define LOCAL static LOCAL int testFunc(void); </pre> However, no other generated header files will contain a prototype for <code>testFunc()</code> since the function has only file scope.</p> <p>When the “<code>LOCAL</code>” keyword is used, makeheaders will also generate a #define for LOCAL, like this: <pre> #define LOCAL static </pre> so that the C compiler will know what it means.</p> <p>If you invoke makeheaders with a “<code>-local</code>” command-line option, then it treats the “<code>static</code>” keyword like “<code>LOCAL</code>” and generates prototypes in the header file that corresponds to the source file containing the function definition.</p> <p><li> When a global variable is defined in a .c file, an “<code>extern</code>” declaration of that variable is placed in the header of every .c file that uses the variable. </p> <p><li> When a structure, union or enumeration declaration or a function prototype or a C++ class declaration appears in a manually produced .h file, that declaration is copied into the automatically generated .h files of all .c files that use the structure, union, enumeration, function or class. But declarations that appear in a .c file are considered private to that .c file and are not copied into any automatically generated files. </p> <p><li> All #defines and typedefs that appear in manually produced .h files are copied into automatically generated .h files as needed. Similar constructs that appear in .c files are considered private to those files and are not copied. </p> <p><li> When a structure, union or enumeration declaration appears in a .h file, makeheaders will automatically generate a typedef that allows the declaration to be referenced without the “<code>struct</code>”, “<code>union</code>” or “<code>enum</code>” qualifier. In other words, if makeheaders sees the code: <pre> struct Examp { /* ... */ }; </pre> it will automatically generate a corresponding typedef like this: <pre> typedef struct Examp Examp; </pre> </p> <p><li> Makeheaders generates an error message if it encounters a function or variable definition within a .h file. The .h files are suppose to contain only interface, not implementation. C compilers will not enforce this convention, but makeheaders does. </ul> <p> As a final note, we observe that automatically generated declarations are ordered as required by the ANSI-C programming language. If the declaration of some structure “<code>X</code>” requires a prior declaration of another structure “<code>Y</code>”, then Y will appear first in the generated headers. </p> <a name="H0009"></a> <h3>3.3 How To Avoid Having To Write Any Header Files</h3> <p> In my experience, large projects work better if all of the manually written code is placed in .c files and all .h files are generated automatically. This is slightly different for the traditional C method of placing the interface in .h files and the implementation in .c files, but it is a refreshing change that brings a noticable improvement to the coding experience. Others, I believe, share this view since I've noticed recent languages (ex: java, tcl, perl, awk) tend to support the one-file approach to coding as the only option. </p> <p> The makeheaders program supports putting both interface and implementation into the same source file. But you do have to tell makeheaders which part of the source file is the interface and which part is the implementation. Makeheaders has to know this in order to be able to figure out whether or not structures declarations, typedefs, #defines and so forth should be copied into the generated headers of other source files. </p> <p> You can instruct makeheaders to treat any part of a .c file as if it were a .h file by enclosing that part of the .c file within: <pre> #if INTERFACE #endif </pre> Thus any structure definitions that appear after the “<code>#if INTERFACE</code>” but before the corresponding “<code>#endif</code>” are eligable to be copied into the automatically generated .h files of other .c files. </p> <p> If you use the “<code>#if INTERFACE</code>” mechanism in a .c file, then the generated header for that .c file will contain a line like this: <pre> #define INTERFACE 0 </pre> In other words, the C compiler will never see any of the text that defines the interface. But makeheaders will copy all necessary definitions and declarations into the .h file it generates, so .c files will compile as if the declarations were really there. This approach has the advantage that you don't have to worry with putting the declarations in the correct ANSI-C order -- makeheaders will do that for you automatically. </p> <p> Note that you don't have to use this approach exclusively. You can put some declarations in .h files and others within the “<code>#if INTERFACE</code>” regions of .c files. Makeheaders treats all declarations alike, no matter where they come from. You should also note that a single .c file can contain as many “<code>#if INTERFACE</code>” regions as desired. </p> <a name="H0010"></a> <h3>3.4 Designating Declarations For Export</h3> <p> In a large project, one will often construct a hierarchy of interfaces. For example, you may have a group of 20 or so files that form a library used in several other parts of the system. Each file in this library will present two interfaces. One interface will be the routines and data structures it is willing to share with other files in the same library, and the second interface is those routines and data structures it wishes to make available to other subsystems. (The second interface is normally a subset of the first.) Ordinary C does not provide support for a tiered interface like this, but makeheaders does. </p> <p> Using makeheaders, it is possible to designate routines and data structures as being for “<code>export</code>”. Exported objects are visible not only to other files within the same library or subassembly but also to other libraries and subassemblies in the larger program. By default, makeheaders only makes objects visible to other members of the same library. </p> <p> That isn't the complete truth, actually. The semantics of C are such that once an object becomes visible outside of a single source file, it is also visible to any user of the library that is made from the source file. Makeheaders can not prevent outsiders for using non-exported resources, but it can discourage the practice by refusing to provide prototypes and declarations for the services it does not want to export. Thus the only real effect of the making an object exportable is to include it in the output makeheaders generates when it is run using the -H command line option. This is not a perfect solution, but it works well in practice. </p> <p> But trouble quickly arises when we attempt to devise a mechanism for telling makeheaders which prototypes it should export and which it should keep local. The built-in “<code>static</code>” keyword of C works well for prohibiting prototypes from leaving a single source file, but because C doesn't support a linkage hierarchy, there is nothing in the C language to help us. We'll have to invite our own keyword: “<code>EXPORT</code>” </p> <p> Makeheaders allows the EXPORT keyword to precede any function or procedure definition. The routine following the EXPORT keyword is then eligable to appear in the header file generated using the -H command line option. Note that if a .c file contains the EXPORT keyword, makeheaders will put the macro <pre> #define EXPORT </pre> in the header file it generates for the .c file so that the EXPORT keyword will never be seen by the C compiler. </p> <p> But the EXPORT keyword only works for function and procedure definitions. For structure, union and enum definitions, typedefs, #defines and class declarations, a second mechanism is used. Just as any declarations or definition contained within <pre> #if INTERFACE #endif </pre> are visible to all files within the library, any declarations or definitions within <pre> #if EXPORT_INTERFACE #endif </pre> will become part of the exported interface. The “<code>#if EXPORT_INTERFACE</code>” mechanism can be used in either .c or .h files. (The “<code>#if INTERFACE</code>” can also be used in both .h and .c files, but since it's use in a .h file would be redundant, we haven't mentioned it before.) </p> <a name="H0011"></a> <h3>3.5 Local declarations processed by makeheaders</h3> <p> Structure declarations and typedefs that appear in .c files are normally ignored by makeheaders. Such declarations are only intended for use by the source file in which they appear and so makeheaders doesn't need to copy them into any generated header files. We call such declarations “<code>private</code>”. </p> <p> Sometimes it is convenient to have makeheaders sort a sequence of private declarations into the correct order for us automatically. Or, we could have static functions and procedures for which we would like makeheaders to generate prototypes, but the arguments to these functions and procedures uses private declarations. In both of these cases, we want makeheaders to be aware of the private declarations and copy them into the local header file, but we don't want makeheaders to propagate the declarations outside of the file in which they are declared. </p> <p> When this situation arises, enclose the private declarations within <pre> #if LOCAL_INTERFACE #endif </pre> A “<code>LOCAL_INTERFACE</code>” block works very much like the “<code>INTERFACE</code>” and “<code>EXPORT_INTERFACE</code>” blocks described above, except that makeheaders insures that the objects declared in a LOCAL_INTERFACE are only visible to the file containing the LOCAL_INTERFACE. </p> <a name="H0012"></a> <h3>3.6 Using Makeheaders With C++ Code</h3> <p> You can use makeheaders to generate header files for C++ code, in addition to C. Makeheaders will recognize and copy both “<code>class</code>” declarations and inline function definitions, and it knows not to try to generate prototypes for methods. </p> <p> In fact, makeheaders is smart enough to be used in projects that employ a mixture of C and C++. For example, if a C function is called from within a C++ code module, makeheaders will know to prepend the text <pre> extern "C" </pre> to the prototype for that function in the C++ header file. Going the other way, if you try to call a C++ function from within C, an appropriate error message is issued, since C++ routines can not normally be called by C code (due to fact that most C++ compilers use name mangling to facilitate type-safe linkage.) </p> <p> No special command-line options are required to use makeheaders with C++ input. Makeheaders will recognize that its source code is C++ by the suffix on the source code filename. Simple ".c" or ".h" suffixes are assumed to be ANSI-C. Anything else, including ".cc", ".C" and ".cpp" is assumed to be C++. The name of the header file generated by makeheaders is derived from the name of the source file by converting every "c" to "h" and every "C" to "H" in the suffix of the filename. Thus the C++ source file “<code>alpha.cpp</code>” will induce makeheaders to generate a header file named “<code>alpha.hpp</code>”. </p> <p> Makeheaders augments class definitions by inserting prototypes to methods where appropriate. If a method definition begins with one of the special keywords <b>PUBLIC</b>, <b>PROTECTED</b>, or <b>PRIVATE</b> (in upper-case to distinguish them from the regular C++ keywords with the same meaning) then a prototype for that method will be inserted into the class definition. If none of these keywords appear, then the prototype is not inserted. For example, in the following code, the constructor is not explicitly declared in the class definition but makeheaders will add it there because of the PUBLIC keyword that appears before the constructor definition. </p> <blockquote><pre> #if INTERFACE class Example1 { private: int v1; }; #endif PUBLIC Example1::Example1(){ v1 = 0; } </pre></blockquote> <p> The code above is equivalent to the following: </p> <blockquote><pre> #if INTERFACE class Example1 { private: int v1; public: Example1(); }; #endif Example1::Example1(){ v1 = 0; } </pre></blockquote> <p> The first form is preferred because only a single declaration of the constructor is required. The second form requires two declarations, one in the class definition and one on the defintion of the constructor. </p> <h4>3.6.1 C++ Limitations</h4> <p> Makeheaders does not understand more recent C++ syntax such as templates and namespaces. Perhaps these issues will be addressed in future revisions. </p> <a name="H0013"></a> <h3>3.7 Conditional Compilation</h3> <p> The makeheaders program understands and tracks the conditional compilation constructs in the source code files it scans. Hence, if the following code appears in a source file <pre> #ifdef UNIX # define WORKS_WELL 1 #else # define WORKS_WELL 0 #endif </pre> then the next patch of code will appear in the generated header for every .c file that uses the WORKS_WELL constant: <pre> #if defined(UNIX) # define WORKS_WELL 1 #endif #if !defined(UNIX) # define WORKS_WELL 0 #endif </pre> The conditional compilation constructs can be nested to any depth. Makeheaders also recognizes the special case of <pre> #if 0 #endif </pre> and treats the enclosed text as a comment. </p> <a name="H0014"></a> <h3>3.8 Caveats</h3> <p> The makeheaders system is designed to be robust but it is possible for a devious programmer to fool the system, usually with unhelpful consequences. This subsection is a guide to helping you avoid trouble. </p> <p> Makeheaders does not understand the old K&R style of function and procedure definitions. It only understands the modern ANSI-C style, and will probably become very confused if it encounters an old K&R function. Therefore you should take care to avoid putting K&R function definitions in your code. </p> <p> Makeheaders does not understand when you define more than one global variable with the same type separated by a comma. In other words, makeheaders does not understand this: <pre> int a = 4, b = 5; </pre> The makeheaders program wants every variable to have its own definition. Like this: <pre> int a = 4; int b = 5; </pre> Notice that this applies to global variables only, not to variables you declare inside your functions. Since global variables ought to be exceedingly rare, and since it is good style to declare them separately anyhow, this restriction is not seen as a terrible hardship. </p> <p> Makeheaders does not support defining an enumerated or aggregate type in the same statement as a variable declaration. None of the following statements work completely: <pre> struct {int field;} a; struct Tag {int field;} b; struct Tag c; </pre> Instead, define types separately from variables: <pre> #if INTERFACE struct Tag {int field;}; #endif Tag a; Tag b; /* No more than one variable per declaration. */ Tag c; /* So must put each on its own line. */ </pre> See <a href="#H0008">3.2 What Declarations Get Copied</a> for details, including on the automatic typedef. </p> <p> The makeheaders program processes its source file prior to sending those files through the C preprocessor. Hence, if you hide important structure information in preprocessor defines, makeheaders might not be able to successfully extract the information it needs from variables, functions and procedure definitions. For example, if you write this: <pre> #define BEGIN { #define END } </pre> at the beginning of your source file, and then try to create a function definition like this: <pre> char *StrDup(const char *zSrc) BEGIN /* Code here */ END </pre> then makeheaders won't be able to find the end of the function definition and bad things are likely to happen. </p> <p> For most projects the code constructs that makeheaders cannot handle are very rare. As long as you avoid excessive cleverness, makeheaders will probably be able to figure out what you want and will do the right thing. </p> <p> Makeheaders has limited understanding of enums. In particular, it does not realize the significance of enumerated values, so the enum is not emitted in the header files when its enumerated values are used unless the name associated with the enum is also used. Moreover, enums can be completely anonymous, e.g. “<code>enum {X, Y, Z};</code>”. Makeheaders ignores such enums so they can at least be used within a single source file. Makeheaders expects you to use #define constants instead. If you want enum features that #define lacks, and you need the enum in the interface, bypass makeheaders and write a header file by hand, or teach makeheaders to emit the enum definition when any of the enumerated values are used, rather than only when the top-level name (if any) is used. </p> <a name="H0015"></a> <h2>4.0 Using Makeheaders To Generate Documentation</h2> <p> Many people have observed the advantages of generating program documentation directly from the source code: <ul> <li> Less effort is involved. It is easier to write a program than it is to write a program and a document. <li> The documentation is more likely to agree with the code. When documentation is derived directly from the code, or is contained in comments immediately adjacent to the code, it is much more likely to be correct than if it is contained in a separate unrelated file in a different part of the source tree. <li> Information is kept in only one place. When a change occurs in the code, it is not necessary to make a corresponding change in a separate document. Just rerun the documentation generator. </ul> The makeheaders program does not generate program documentation itself. But you can use makeheaders to parse the program source code, extract the information that is relevant to the documentation and to pass this information to another tool to do the actual documentation preparation. </p> <p> When makeheaders is run with the “<code>-doc</code>” option, it emits no header files at all. Instead, it does a complete dump of its internal tables to standard output in a form that is easily parsed. This output can then be used by another program (the implementation of which is left as an exercise to the reader) that will use the information to prepare suitable documentation. </p> <p> The “<code>-doc</code>” option causes makeheaders to print information to standard output about all of the following objects: <ul> <li> C++ class declarations <li> Structure and union declarations <li> Enumerations <li> Typedefs <li> Procedure and function definitions <li> Global variables <li> Preprocessor macros (ex: “<code>#define</code>”) </ul> For each of these objects, the following information is output: <ul> <li> The name of the object. <li> The type of the object. (Structure, typedef, macro, etc.) <li> Flags to indicate if the declaration is exported (contained within an EXPORT_INTERFACE block) or local (contained with LOCAL_INTERFACE). <li> A flag to indicate if the object is declared in a C++ file. <li> The name of the file in which the object was declared. <li> The complete text of any block comment that preceeds the declarations. <li> If the declaration occurred inside a preprocessor conditional (“<code>#if</code>”) then the text of that conditional is provided. <li> The complete text of a declaration for the object. </ul> The exact output format will not be described here. It is simple to understand and parse and should be obvious to anyone who inspects some sample output. </p> <a name="H0016"></a> <h2>5.0 Compiling The Makeheaders Program</h2> <p> The source code for makeheaders is a single file of ANSI-C code, approximately 3000 lines in length. The program makes only modest demands of the system and C library and should compile without alteration on most ANSI C compilers and on most operating systems. It is known to compile using several variations of GCC for Unix as well as Cygwin32 and MSVC 5.0 for Win32. </p> <a name="H0017"></a> <h2>6.0 History</h2> <p> The makeheaders program was first written by D. Richard Hipp (also the original author of <a href="https://sqlite.org/">SQLite</a> and <a href="https://www.fossil-scm.org/">Fossil</a>) in 1993. Hipp open-sourced the project immediately, but it never caught on with any other developers and it continued to be used mostly by Hipp himself for over a decade. When Hipp was first writing the Fossil version control system in 2006 and 2007, he used makeheaders on that project to help simplify the source code. As the popularity of Fossil increased, the makeheaders that was incorporated into the Fossil source tree became the "official" makeheaders implementation. </p> <p> As this paragraph is being composed (2016-11-05), Fossil is the only project known to Hipp that is still using makeheaders. On the other hand, makeheaders has served the Fossil project well and there are no plans remove it. </p> <a name="H0018"></a> <h2>7.0 Summary And Conclusion</h2> <p> The makeheaders program will automatically generate a minimal header file for each of a set of C source and header files, and will generate a composite header file for the entire source file suite, for either internal or external use. It can also be used as the parser in an automated program documentation system. </p> <p> The makeheaders program has been in use since 1994, in a wide variety of projects under both UNIX and Win32. In every project where it has been used, makeheaders has proven to be a very helpful aid in the construction and maintenance of large C codes. In at least two cases, makeheaders has facilitated development of programs that would have otherwise been all but impossible due to their size and complexity. </p> </body> </html> |
Added src/makemake.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 | #!/usr/bin/tclsh # # Run this Tcl script to generate the various makefiles for a variety # of platforms. Files generated include: # # src/main.mk # makefile for all unix systems # win/Makefile.mingw # makefile for mingw on windows # win/Makefile.* # makefiles for other windows compilers # # Run this script while in the "src" subdirectory. Like this: # # tclsh makemake.tcl # # Add new source files by listing the files (without their .c suffix) # in the "src" variable. Add new resource files to the "extra_files" # variable. There are other variables that you can alter, down to # the "STOP HERE" comment. The stuff below "STOP HERE" should rarely need # to change. # ############################################################################# # Basenames of all source files that get preprocessed using # "translate" and "makeheaders". To add new C-language source files to the # project, simply add the basename to this list and rerun this script. # # Set the separate extra_files variable further down for how to add non-C # files, such as string and BLOB resources. # set src { add alerts allrepo attach backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd descendants diff diffcmd dispatch doc encode etag event export file finfo foci forum fshell fusefs glob graph gzip hname http http_socket http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip http_ssl } # Additional resource files that get built into the executable. # set extra_files { diff.tcl markdown.md wiki.wiki *.js ../skins/*/*.txt } # Options used to compile the included SQLite library. # set SQLITE_OPTIONS { -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB } #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4 #lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI #lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096 # Options used to compile the included SQLite shell. # set SHELL_OPTIONS [concat $SQLITE_OPTIONS { -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc }] # miniz (libz drop-in alternative) precompiler flags. # set MINIZ_OPTIONS { -DMINIZ_NO_STDIO -DMINIZ_NO_TIME -DMINIZ_NO_ARCHIVE_APIS } # Options used to compile the included SQLite shell on Windows. # set SHELL_WIN32_OPTIONS $SHELL_OPTIONS lappend SHELL_WIN32_OPTIONS -Daccess=file_access lappend SHELL_WIN32_OPTIONS -Dsystem=fossil_system lappend SHELL_WIN32_OPTIONS -Dgetenv=fossil_getenv lappend SHELL_WIN32_OPTIONS -Dfopen=fossil_fopen # STOP HERE. # Unless the build procedures changes, you should not have to edit anything # below this line. ############################################################################# # Name of the final application # set name fossil # The "writeln" command sends output to the target makefile. # proc writeln {args} { global output_file if {[lindex $args 0]=="-nonewline"} { puts -nonewline $output_file [lindex $args 1] } else { puts $output_file [lindex $args 0] } } # Expand any wildcards in "extra_files" set new_extra_files {} foreach file $extra_files { foreach x [glob -nocomplain $file] { lappend new_extra_files $x } } set extra_files $new_extra_files ############################################################################## ############################################################################## ############################################################################## # Start by generating the "main.mk" makefile used for all unix systems. # puts "building main.mk" set output_file [open main.mk w] fconfigure $output_file -translation binary writeln {# ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This file is included by primary Makefile. # XBCC = $(BCC) $(BCCFLAGS) XTCC = $(TCC) -I. -I$(SRCDIR) -I$(OBJDIR) $(TCCFLAGS) TESTFLAGS := -quiet } writeln -nonewline "SRC =" foreach s [lsort $src] { writeln -nonewline " \\\n \$(SRCDIR)/$s.c" } writeln "\n" writeln -nonewline "EXTRA_FILES =" foreach s [lsort $extra_files] { writeln -nonewline " \\\n \$(SRCDIR)/$s" } writeln "\n" writeln -nonewline "TRANS_SRC =" foreach s [lsort $src] { writeln -nonewline " \\\n \$(OBJDIR)/${s}_.c" } writeln "\n" writeln -nonewline "OBJ =" foreach s [lsort $src] { writeln -nonewline " \\\n \$(OBJDIR)/$s.o" } writeln "\n" writeln "APPNAME = $name\$(E)" writeln "\n" writeln [string map [list \ <<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS " \\\n "] \ <<<SHELL_OPTIONS>>> [join $SHELL_OPTIONS " \\\n "] \ <<<MINIZ_OPTIONS>>> [join $MINIZ_OPTIONS " \\\n "]] { all: $(OBJDIR) $(APPNAME) install: $(APPNAME) mkdir -p $(INSTALLDIR) cp $(APPNAME) $(INSTALLDIR) codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 $(OBJDIR)/codecheck1 $(TRANS_SRC) $(OBJDIR): -mkdir $(OBJDIR) $(OBJDIR)/translate: $(SRCDIR)/translate.c $(XBCC) -o $(OBJDIR)/translate $(SRCDIR)/translate.c $(OBJDIR)/makeheaders: $(SRCDIR)/makeheaders.c $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR)/makeheaders.c $(OBJDIR)/mkindex: $(SRCDIR)/mkindex.c $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c $(OBJDIR)/mkbuiltin: $(SRCDIR)/mkbuiltin.c $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR)/mkbuiltin.c $(OBJDIR)/mkversion: $(SRCDIR)/mkversion.c $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c $(OBJDIR)/mkcss: $(SRCDIR)/mkcss.c $(XBCC) -o $(OBJDIR)/mkcss $(SRCDIR)/mkcss.c $(OBJDIR)/codecheck1: $(SRCDIR)/codecheck1.c $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR)/codecheck1.c # Run the test suite. # Other flags that can be included in TESTFLAGS are: # # -halt Stop testing after the first failed test # -keep Keep the temporary workspace for debugging # -prot Write a detailed log of the tests to the file ./prot # -verbose Include even more details in the output # -quiet Hide most output from the terminal # -strict Treat known bugs as failures # # TESTFLAGS can also include names of specific test files to limit # the run to just those test cases. # test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ $(SRCDIR)/../manifest \ $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h $(OBJDIR)/default_css.h: $(SRCDIR)/default_css.txt $(OBJDIR)/mkcss $(OBJDIR)/mkcss $(SRCDIR)/default_css.txt $(OBJDIR)/default_css.h # Setup the options used to compile the included SQLite library. SQLITE_OPTIONS = <<<SQLITE_OPTIONS>>> # Setup the options used to compile the included SQLite shell. SHELL_OPTIONS = <<<SHELL_OPTIONS>>> # Setup the options used to compile the included miniz library. MINIZ_OPTIONS = <<<MINIZ_OPTIONS>>> # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ.1 = SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_MINIZ variable may be undefined, set to 0, or # set to 1. If it is set to 1, the miniz library included in the # source tree should be used; otherwise, it should not. MINIZ_OBJ.0 = MINIZ_OBJ.1 = $(OBJDIR)/miniz.o MINIZ_OBJ. = $(MINIZ_OBJ.0) # The USE_LINENOISE variable may be undefined, set to 0, or set # to 1. If it is set to 0, then there is no need to build or link # the linenoise.o object. LINENOISE_DEF.0 = LINENOISE_DEF.1 = -DHAVE_LINENOISE LINENOISE_DEF. = $(LINENOISE_DEF.0) LINENOISE_OBJ.0 = LINENOISE_OBJ.1 = $(OBJDIR)/linenoise.o LINENOISE_OBJ. = $(LINENOISE_OBJ.0) # The USE_SEE variable may be undefined, 0 or 1. If undefined or # 0, ordinary SQLite is used. If 1, then sqlite3-see.c (not part of # the source tree) is used and extra flags are provided to enable # the SQLite Encryption Extension. SQLITE3_SRC.0 = sqlite3.c SQLITE3_SRC.1 = sqlite3-see.c SQLITE3_SRC. = sqlite3.c SQLITE3_SRC = $(SRCDIR)/$(SQLITE3_SRC.$(USE_SEE)) SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) }] writeln [string map [list <<<NEXT_LINE>>> \\] { EXTRAOBJ = <<<NEXT_LINE>>> $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) <<<NEXT_LINE>>> $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) <<<NEXT_LINE>>> $(LINENOISE_OBJ.$(USE_LINENOISE)) <<<NEXT_LINE>>> $(OBJDIR)/shell.o <<<NEXT_LINE>>> $(OBJDIR)/th.o <<<NEXT_LINE>>> $(OBJDIR)/th_lang.o <<<NEXT_LINE>>> $(OBJDIR)/th_tcl.o <<<NEXT_LINE>>> $(OBJDIR)/cson_amalgamation.o }] writeln { $(APPNAME): $(OBJDIR)/headers $(OBJDIR)/codecheck1 $(OBJ) $(EXTRAOBJ) $(OBJDIR)/codecheck1 $(TRANS_SRC) $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: # noop clean: -rm -rf $(OBJDIR)/* $(APPNAME) } set mhargs {} foreach s [lsort $src] { append mhargs "\$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h <<<NEXT_LINE>>>" set extra_h($s) { } } append mhargs "\$(SRCDIR)/sqlite3.h <<<NEXT_LINE>>>" append mhargs "\$(SRCDIR)/th.h <<<NEXT_LINE>>>" #append mhargs "\$(SRCDIR)/cson_amalgamation.h <<<NEXT_LINE>>>" append mhargs "\$(OBJDIR)/VERSION.h " set mhargs [string map [list <<<NEXT_LINE>>> \\\n\t] $mhargs] writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex" writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >\$@\n" writeln "\$(OBJDIR)/builtin_data.h: \$(OBJDIR)/mkbuiltin \$(EXTRA_FILES)" writeln "\t\$(OBJDIR)/mkbuiltin --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n" writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/default_css.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h" writeln "\t\$(OBJDIR)/makeheaders $mhargs" writeln "\ttouch \$(OBJDIR)/headers" writeln "\$(OBJDIR)/headers: Makefile" writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/json_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h" writeln "Makefile:" set extra_h(dispatch) " \$(OBJDIR)/page_index.h " set extra_h(builtin) " \$(OBJDIR)/builtin_data.h " set extra_h(style) " \$(OBJDIR)/default_css.h " foreach s [lsort $src] { writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate" writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$@\n" writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h$extra_h($s)\$(SRCDIR)/config.h" writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n" writeln "\$(OBJDIR)/$s.h:\t\$(OBJDIR)/headers\n" } writeln "\$(OBJDIR)/sqlite3.o:\t\$(SQLITE3_SRC)" writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) \$(SEE_FLAGS) \\" writeln "\t\t-c \$(SQLITE3_SRC) -o \$@" writeln "\$(OBJDIR)/shell.o:\t\$(SQLITE3_SHELL_SRC) \$(SRCDIR)/sqlite3.h" writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) \$(SEE_FLAGS) \$(LINENOISE_DEF.\$(USE_LINENOISE)) -c \$(SQLITE3_SHELL_SRC) -o \$@\n" writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR)/linenoise.c \$(SRCDIR)/linenoise.h" writeln "\t\$(XTCC) -c \$(SRCDIR)/linenoise.c -o \$@\n" writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$@\n" writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n" writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n" writeln { $(OBJDIR)/miniz.o: $(SRCDIR)/miniz.c $(XTCC) $(MINIZ_OPTIONS) -c $(SRCDIR)/miniz.c -o $@ $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@ # # The list of all the targets that do not correspond to real files. This stops # 'make' from getting confused when someone makes an error in a rule. # .PHONY: all install test clean } close $output_file # # End of the main.mk output ############################################################################## ############################################################################## ############################################################################## # Begin win/Makefile.mingw output # puts "building ../win/Makefile.mingw" set output_file [open ../win/Makefile.mingw w] fconfigure $output_file -translation binary writeln {#!/usr/bin/make # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using # MinGW or MinGW-w64. # # Some of the special options which can be passed to make # USE_WINDOWS=1 if building under a windows command prompt # X64=1 if using an unprefixed 64-bit mingw compiler # #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers. # By default, this is an empty string (i.e. use the native compiler). # PREFIX = # PREFIX = mingw32- # PREFIX = i686-pc-mingw32- # PREFIX = i686-w64-mingw32- # PREFIX = x86_64-w64-mingw32- #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = src #### The directory into which object code files should be written. # OBJDIR = wbld #### C compiler for use in building executables that will run on # the platform that is doing the build. This is used to compile # code-generator programs as part of the build process. See TCC # and TCCEXE below for the C compiler for building the finished # binary. # BCCEXE = gcc #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 #### Enable JSON (http://www.json.org) support using "cson" # # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # # FOSSIL_ENABLE_SSL = 1 #### Automatically build OpenSSL when building Fossil (causes rebuild # issues when building incrementally). # # FOSSIL_BUILD_SSL = 1 #### Enable relative paths in external diff/gdiff # # FOSSIL_ENABLE_EXEC_REL_PATHS = 1 #### Enable legacy treatment of mv/rm (skip checkout files) # FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # # FOSSIL_ENABLE_TH1_DOCS = 1 #### Enable hooks for commands and web pages via TH1 # # FOSSIL_ENABLE_TH1_HOOKS = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Load Tcl using the stubs library mechanism # # FOSSIL_ENABLE_TCL_STUBS = 1 #### Load Tcl using the private stubs mechanism # # FOSSIL_ENABLE_TCL_PRIVATE_STUBS = 1 #### Use 'system' SQLite # # USE_SYSTEM_SQLITE = 1 #### Use POSIX memory APIs from "sys/mman.h" # # USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 #### Use the miniz compression library # # FOSSIL_ENABLE_MINIZ = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to # be enabled by default. This check may be somewhat fragile due to the # use of "findstring". # ifndef MINGW_IS_32BIT_ONLY ifeq (,$(findstring w64-mingw32,$(PREFIX))) MINGW_IS_32BIT_ONLY = 1 endif endif #### The directories where the zlib include and library files are located. # ZINCDIR = $(SRCDIR)/../compat/zlib ZLIBDIR = $(SRCDIR)/../compat/zlib #### Make an attempt to detect if Fossil is being built for the x64 processor # architecture. This check may be somewhat fragile due to "findstring". # ifndef X64 ifneq (,$(findstring x86_64-w64-mingw32,$(PREFIX))) X64 = 1 endif endif #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ifndef FOSSIL_ENABLE_MINIZ ZLIBCONFIG = LOC="-DASMV -DASMINF" OBJA="inffas86.o match.o" ZLIBTARGETS = $(ZLIBDIR)/inffas86.o $(ZLIBDIR)/match.o else ZLIBCONFIG = ZLIBTARGETS = endif else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support # for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). # SSLCONFIG += no-ssl2 no-ssl3 no-weak-ssl-ciphers no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ SSLCONFIG += --with-zlib-lib=$(PWD)/$(ZLIBDIR) --with-zlib-include=$(PWD)/$(ZLIBDIR) zlib endif #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2p OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage # here is to use the Sysinternals junction tool to create a hard # link between a "tcl-8.x" sub-directory of the Fossil source code # directory and the target Tcl directory. This removes the need to # hard-code the necessary paths in this Makefile. # TCLDIR = $(SRCDIR)/../compat/tcl-8.6 #### The Tcl source code directory. This defaults to the same value as # TCLDIR macro (above), which may not be correct. This value will # only be used if the FOSSIL_TCL_SOURCE macro is defined. # TCLSRCDIR = $(TCLDIR) #### The Tcl include and library directories. These values will only be # used if the FOSSIL_TCL_SOURCE macro is not defined. # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS ifndef FOSSIL_ENABLE_TCL_PRIVATE_STUBS LIBTCL = -ltclstub86 endif TCLTARGET = libtclstub86.a else LIBTCL = -ltcl86 TCLTARGET = binaries endif #### C compiler for use in building executables that will run on the # target platform. This is usually the same as BCCEXE, unless you # are cross-compiling. This C compiler builds the finished binary # for fossil. See BCC and BCCEXE above for the C compiler for # building intermediate code-generator tools. # TCCEXE = gcc #### C compiler and options for use in building executables that will # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement #### Add the necessary command line options to build with debugging # symbols, if enabled. # ifdef FOSSIL_ENABLE_SYMBOLS TCC += -g else TCC += -Os endif #### When not using the miniz compression library, zlib is required. # ifndef FOSSIL_ENABLE_MINIZ TCC += -L$(ZLIBDIR) -I$(ZINCDIR) endif #### Compile resources for use in building executables that will run # on the target platform. # RCC = $(PREFIX)windres -I$(SRCDIR) ifndef FOSSIL_ENABLE_MINIZ RCC += -I$(ZINCDIR) endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) RCC += -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win RCC += -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With miniz (i.e. instead of zlib) ifdef FOSSIL_ENABLE_MINIZ TCC += -DFOSSIL_ENABLE_MINIZ=1 RCC += -DFOSSIL_ENABLE_MINIZ=1 endif # With MinGW command line handling workaround ifdef MINGW_IS_32BIT_ONLY TCC += -DBROKEN_MINGW_CMDLINE=1 RCC += -DBROKEN_MINGW_CMDLINE=1 endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif # With relative paths in external diff/gdiff ifdef FOSSIL_ENABLE_EXEC_REL_PATHS TCC += -DFOSSIL_ENABLE_EXEC_REL_PATHS=1 RCC += -DFOSSIL_ENABLE_EXEC_REL_PATHS=1 endif # With legacy treatment of mv/rm ifdef FOSSIL_ENABLE_LEGACY_MV_RM TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 RCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 endif # With TH1 embedded docs support ifdef FOSSIL_ENABLE_TH1_DOCS TCC += -DFOSSIL_ENABLE_TH1_DOCS=1 RCC += -DFOSSIL_ENABLE_TH1_DOCS=1 endif # With TH1 hook support ifdef FOSSIL_ENABLE_TH1_HOOKS TCC += -DFOSSIL_ENABLE_TH1_HOOKS=1 RCC += -DFOSSIL_ENABLE_TH1_HOOKS=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 # Either statically linked or via stubs ifdef FOSSIL_ENABLE_TCL_STUBS TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS ifdef FOSSIL_ENABLE_TCL_PRIVATE_STUBS TCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 endif else TCC += -DSTATIC_BUILD RCC += -DSTATIC_BUILD endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 RCC += -DFOSSIL_ENABLE_JSON=1 endif # With "sys/mman.h" support ifdef USE_MMAN_H TCC += -DUSE_MMAN_H=1 RCC += -DUSE_MMAN_H=1 endif # With SQLite Encryption Extension support ifdef USE_SEE TCC += -DUSE_SEE=1 RCC += -DUSE_SEE=1 endif #### The option -static has no effect on MinGW(-w64), only dynamic # executables can be built when linking with MSVCRT. OpenSSL # (optional) and zlib (required) however are always linked in # statically. Therefore, the FOSSIL_DYNAMIC_BUILD option does # not really apply to MinGW (i.e. since ALL external libraries # are NOT linked dynamically). # # LIB = -static #### MinGW: If available, use the Unicode capable runtime startup code. # ifndef MINGW_IS_32BIT_ONLY LIB += -municode endif #### SQLite: If enabled, use the system SQLite library. # ifdef USE_SYSTEM_SQLITE LIB += -lsqlite3 endif #### OpenSSL: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_SSL LIB += -lssl -lcrypto -lgdi32 -lcrypt32 endif #### Tcl: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_TCL LIB += $(LIBTCL) endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. # LIB += -lmingwex #### When not using the miniz compression library, zlib is required. # ifndef FOSSIL_ENABLE_MINIZ LIB += -lz endif #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_ENABLE_TCL_STUBS LIB += -lkernel32 -lws2_32 else LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 endif else LIB += -lkernel32 -lws2_32 endif #### Library required for DNS lookups. # LIB += -ldnsapi #### Tcl shell for use in running the fossil test suite. This is only # used for testing. # TCLSH = tclsh #### Nullsoft installer MakeNSIS location # MAKENSIS = "$(PROGRAMFILES)\NSIS\MakeNSIS.exe" #### Inno Setup executable location # INNOSETUP = "$(PROGRAMFILES)\Inno Setup 5\ISCC.exe" #### Include a configuration file that can override any one of these settings. # -include config.w32 # STOP HERE # You should not need to change anything below this line #-------------------------------------------------------- XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) } writeln -nonewline "SRC =" foreach s [lsort $src] { writeln -nonewline " \\\n \$(SRCDIR)/$s.c" } writeln "\n" writeln -nonewline "EXTRA_FILES =" foreach s [lsort $extra_files] { writeln -nonewline " \\\n \$(SRCDIR)/$s" } writeln "\n" writeln -nonewline "TRANS_SRC =" foreach s [lsort $src] { writeln -nonewline " \\\n \$(OBJDIR)/${s}_.c" } writeln "\n" writeln -nonewline "OBJ =" foreach s [lsort $src] { writeln -nonewline " \\\n \$(OBJDIR)/$s.o" } writeln "\n" writeln "APPNAME = ${name}.exe" writeln "APPTARGETS =" writeln { #### If the USE_WINDOWS variable exists, it is assumed that we are building # inside of a Windows-style shell; otherwise, it is assumed that we are # building inside of a Unix-style shell. Note that the "move" command is # broken when attempting to use it from the Windows shell via MinGW make # because the SHELL variable is only used for certain commands that are # recognized internally by make. # ifdef USE_WINDOWS TRANSLATE = $(subst /,\,$(OBJDIR)/translate.exe) MAKEHEADERS = $(subst /,\,$(OBJDIR)/makeheaders.exe) MKINDEX = $(subst /,\,$(OBJDIR)/mkindex.exe) MKBUILTIN = $(subst /,\,$(OBJDIR)/mkbuiltin.exe) MKVERSION = $(subst /,\,$(OBJDIR)/mkversion.exe) MKCSS = $(subst /,\,$(OBJDIR)/mkcss.exe) CODECHECK1 = $(subst /,\,$(OBJDIR)/codecheck1.exe) CAT = type CP = copy GREP = find MV = copy RM = del /Q MKDIR = -mkdir RMDIR = rmdir /S /Q else TRANSLATE = $(OBJDIR)/translate.exe MAKEHEADERS = $(OBJDIR)/makeheaders.exe MKINDEX = $(OBJDIR)/mkindex.exe MKBUILTIN = $(OBJDIR)/mkbuiltin.exe MKVERSION = $(OBJDIR)/mkversion.exe MKCSS = $(OBJDIR)/mkcss.exe CODECHECK1 = $(OBJDIR)/codecheck1.exe CAT = cat CP = cp GREP = grep MV = mv RM = rm -f MKDIR = -mkdir -p RMDIR = rm -rf endif} writeln { all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h $(OBJDIR)/default_css.h ifdef USE_WINDOWS $(CAT) $(subst /,\,$(SRCDIR)\miniz.c) | $(GREP) "define MZ_VERSION" > $(subst /,\,$(OBJDIR)\minizver.h) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CAT) $(SRCDIR)/miniz.c | $(GREP) "define MZ_VERSION" > $(OBJDIR)/minizver.h $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(CP) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) else $(MKDIR) $(INSTALLDIR) $(CP) $(APPNAME) $(INSTALLDIR) endif $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) else $(MKDIR) $(OBJDIR) endif $(TRANSLATE): $(SRCDIR)/translate.c $(XBCC) -o $@ $(SRCDIR)/translate.c $(MAKEHEADERS): $(SRCDIR)/makeheaders.c $(XBCC) -o $@ $(SRCDIR)/makeheaders.c $(MKINDEX): $(SRCDIR)/mkindex.c $(XBCC) -o $@ $(SRCDIR)/mkindex.c $(MKBUILTIN): $(SRCDIR)/mkbuiltin.c $(XBCC) -o $@ $(SRCDIR)/mkbuiltin.c $(MKVERSION): $(SRCDIR)/mkversion.c $(XBCC) -o $@ $(SRCDIR)/mkversion.c $(MKCSS): $(SRCDIR)/mkcss.c $(XBCC) -o $@ $(SRCDIR)/mkcss.c $(CODECHECK1): $(SRCDIR)/codecheck1.c $(XBCC) -o $@ $(SRCDIR)/codecheck1.c # WARNING. DANGER. Running the test suite modifies the repository the # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@ $(OBJDIR)/default_css.h: $(SRCDIR)/default_css.txt $(MKCSS) $(MKCSS) $(SRCDIR)/default_css.txt $@ # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ.1 = SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_MINIZ variable may be undefined, set to 0, or # set to 1. If it is set to 1, the miniz library included in the # source tree should be used; otherwise, it should not. MINIZ_OBJ.0 = MINIZ_OBJ.1 = $(OBJDIR)/miniz.o MINIZ_OBJ. = $(MINIZ_OBJ.0) # The USE_SEE variable may be undefined, 0 or 1. If undefined or # 0, ordinary SQLite is used. If 1, then sqlite3-see.c (not part of # the source tree) is used and extra flags are provided to enable # the SQLite Encryption Extension. SQLITE3_SRC.0 = sqlite3.c SQLITE3_SRC.1 = sqlite3-see.c SQLITE3_SRC. = sqlite3.c SQLITE3_SRC = $(SRCDIR)/$(SQLITE3_SRC.$(USE_SEE)) SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) } writeln [string map [list <<<NEXT_LINE>>> \\] { EXTRAOBJ = <<<NEXT_LINE>>> $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) <<<NEXT_LINE>>> $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) <<<NEXT_LINE>>> $(OBJDIR)/shell.o <<<NEXT_LINE>>> $(OBJDIR)/th.o <<<NEXT_LINE>>> $(OBJDIR)/th_lang.o <<<NEXT_LINE>>> $(OBJDIR)/th_tcl.o <<<NEXT_LINE>>> $(OBJDIR)/cson_amalgamation.o }] writeln { $(ZLIBDIR)/inffas86.o: $(TCC) -c -o $@ -DASMINF -I$(ZLIBDIR) -O3 $(ZLIBDIR)/contrib/inflate86/inffas86.c $(ZLIBDIR)/match.o: $(TCC) -c -o $@ -DASMV $(ZLIBDIR)/contrib/asm686/match.S zlib: $(ZLIBTARGETS) $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(ZLIBCONFIG) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) -f win32/Makefile.gcc clean ifdef FOSSIL_ENABLE_MINIZ BLDTARGETS = else BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean tcl: cd $(TCLSRCDIR)/win;./configure $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(TCLTARGET) clean-tcl: $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) distclean APPTARGETS += $(BLDTARGETS) ifdef FOSSIL_BUILD_SSL APPTARGETS += openssl endif $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(CODECHECK1) $(TRANS_SRC) $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: # noop clean: ifdef USE_WINDOWS $(RM) $(subst /,\,$(APPNAME)) $(RMDIR) $(subst /,\,$(OBJDIR)) else $(RM) $(APPNAME) $(RMDIR) $(OBJDIR) endif setup: $(OBJDIR) $(APPNAME) $(MAKENSIS) ./setup/fossil.nsi innosetup: $(OBJDIR) $(APPNAME) $(INNOSETUP) ./setup/fossil.iss -DAppVersion=$(shell $(CAT) ./VERSION) } set mhargs {} foreach s [lsort $src] { if {[string length $mhargs] > 0} {append mhargs " \\\n\t\t"} append mhargs "\$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h" set extra_h($s) { } } append mhargs " \\\n\t\t\$(SRCDIR)/sqlite3.h" append mhargs " \\\n\t\t\$(SRCDIR)/th.h" append mhargs " \\\n\t\t\$(OBJDIR)/VERSION.h" writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(MKINDEX)" writeln "\t\$(MKINDEX) \$(TRANS_SRC) >\$@\n" writeln "\$(OBJDIR)/builtin_data.h:\t\$(MKBUILTIN) \$(EXTRA_FILES)" writeln "\t\$(MKBUILTIN) --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n" writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/default_css.h \$(MAKEHEADERS) \$(OBJDIR)/VERSION.h" writeln "\t\$(MAKEHEADERS) $mhargs" writeln "\techo Done >\$(OBJDIR)/headers\n" writeln "\$(OBJDIR)/headers: Makefile\n" writeln "Makefile:\n" set extra_h(main) " \$(OBJDIR)/page_index.h " set extra_h(builtin) " \$(OBJDIR)/builtin_data.h " set extra_h(style) " \$(OBJDIR)/default_css.h " foreach s [lsort $src] { writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(TRANSLATE)" writeln "\t\$(TRANSLATE) \$(SRCDIR)/$s.c >\$@\n" writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h$extra_h($s)\$(SRCDIR)/config.h" writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n" writeln "\$(OBJDIR)/${s}.h:\t\$(OBJDIR)/headers\n" } writeln {MINGW_OPTIONS = -D_HAVE__MINGW_H } set SQLITE_WIN32_OPTIONS $SQLITE_OPTIONS lappend SQLITE_WIN32_OPTIONS -DSQLITE_WIN32_NO_ANSI set MINGW_SQLITE_OPTIONS $SQLITE_WIN32_OPTIONS lappend MINGW_SQLITE_OPTIONS {$(MINGW_OPTIONS)} lappend MINGW_SQLITE_OPTIONS -DSQLITE_USE_MALLOC_H lappend MINGW_SQLITE_OPTIONS -DSQLITE_USE_MSIZE set MINIZ_WIN32_OPTIONS $MINIZ_OPTIONS set j " \\\n " writeln "SQLITE_OPTIONS = [join $MINGW_SQLITE_OPTIONS $j]\n" set j " \\\n " writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS $j]\n" set j " \\\n " writeln "MINIZ_OPTIONS = [join $MINIZ_WIN32_OPTIONS $j]\n" writeln "\$(OBJDIR)/sqlite3.o:\t\$(SQLITE3_SRC) \$(SRCDIR)/../win/Makefile.mingw" writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) \$(SEE_FLAGS) \\" writeln "\t\t-c \$(SQLITE3_SRC) -o \$@\n" writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/cson_amalgamation.c -o \$@\n" writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n" writeln "\$(OBJDIR)/shell.o:\t\$(SQLITE3_SHELL_SRC) \$(SRCDIR)/sqlite3.h \$(SRCDIR)/../win/Makefile.mingw" writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) \$(SEE_FLAGS) -c \$(SQLITE3_SHELL_SRC) -o \$@\n" writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$@\n" writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n" writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n" writeln "\$(OBJDIR)/miniz.o:\t\$(SRCDIR)/miniz.c" writeln "\t\$(XTCC) \$(MINIZ_OPTIONS) -c \$(SRCDIR)/miniz.c -o \$@\n" close $output_file # # End of the win/Makefile.mingw output ############################################################################## ############################################################################## ############################################################################## # Begin win/Makefile.dmc output # puts "building ../win/Makefile.dmc" set output_file [open ../win/Makefile.dmc w] fconfigure $output_file -translation binary writeln {# ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # B = .. SRCDIR = $B\src OBJDIR = . O = .obj E = .exe # Maybe DMDIR, SSL or INCL needs adjustment DMDIR = c:\DM INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include #SSL = -DFOSSIL_ENABLE_SSL=1 SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi } writeln "SQLITE_OPTIONS = [join $SQLITE_OPTIONS { }]\n" writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS { }]\n" writeln -nonewline "SRC =" foreach s [lsort $src] { writeln -nonewline " ${s}_.c" } writeln "\n" writeln -nonewline "OBJ = " foreach s [lsort $src] { writeln -nonewline "\$(OBJDIR)\\$s\$O " } writeln "\$(OBJDIR)\\shell\$O \$(OBJDIR)\\sqlite3\$O \$(OBJDIR)\\th\$O \$(OBJDIR)\\th_lang\$O" writeln { RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E codecheck1$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) codecheck1$E $(SRC) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res} writeln -nonewline "\t+echo " foreach s [lsort $src] { writeln -nonewline "$s " } writeln "shell sqlite3 th th_lang > \$@" writeln "\t+echo fossil >> \$@" writeln "\t+echo fossil >> \$@" writeln "\t+echo \$(LIBS) >> \$@" writeln "\t+echo. >> \$@" writeln "\t+echo fossil >> \$@" writeln { translate$E: $(SRCDIR)\translate.c $(BCC) -o$@ $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) -o$@ $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** mkbuiltin$E: $(SRCDIR)\mkbuiltin.c $(BCC) -o$@ $** mkversion$E: $(SRCDIR)\mkversion.c $(BCC) -o$@ $** mkcss$E: $(SRCDIR)\mkcss.c $(BCC) -o$@ $** codecheck1$E: $(SRCDIR)\codecheck1.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c $(TCC) -o$@ -c $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $** $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c $(TCC) -o$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** $(OBJDIR)\th$O : $(SRCDIR)\th.c $(TCC) -o$@ -c $** $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) -o$@ -c $** $(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h cp $@ $@ VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION +$** > $@ default_css.h : mkcss$E $B\src\default_css.txt +$** $B\src\default_css.txt $@ page_index.h: mkindex$E $(SRC) +$** > $@ builtin_data.h: mkbuiltin$E $(EXTRA_FILES) mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@ clean: -del $(OBJDIR)\*.obj -del *.obj *_.c *.h *.map realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E codecheck1$E mkbuiltin$E mkcss$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h } foreach s [lsort $src] { writeln "\$(OBJDIR)\\$s\$O : ${s}_.c ${s}.h" writeln "\t\$(TCC) -o\$@ -c ${s}_.c\n" writeln "${s}_.c : \$(SRCDIR)\\$s.c" writeln "\t+translate\$E \$** > \$@\n" } writeln -nonewline "headers: makeheaders\$E page_index.h builtin_data.h default_css.h VERSION.h\n\t +makeheaders\$E " foreach s [lsort $src] { writeln -nonewline "${s}_.c:$s.h " } writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\th.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h" writeln "\t@copy /Y nul: headers" close $output_file # # End of the win/Makefile.dmc output ############################################################################## ############################################################################## ############################################################################## # Begin win/Makefile.msc output # puts "building ../win/Makefile.msc" set output_file [open ../win/Makefile.msc w] fconfigure $output_file -translation binary writeln {# ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This Makefile will only function correctly if used from a sub-directory # that is a direct child of the top-level directory for this project. # !if !exist("..\.fossil-settings") !error "Please change the current directory to the one containing this file." !endif # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # B = .. SRCDIR = $B\src OBJDIR = . OX = . O = .obj E = .exe P = .pdb # Perl is only necessary if OpenSSL support is enabled and it must # be built from source code. The PERLDIR variable should point to # the directory containing the main Perl binary (i.e. "perl.exe"). PERLDIR = C:\Perl\bin PERL = perl.exe # Enable debugging symbols? !ifndef DEBUG DEBUG = 0 !endif # Build the OpenSSL libraries? !ifndef FOSSIL_BUILD_SSL FOSSIL_BUILD_SSL = 0 !endif # Build the included zlib library? !ifndef FOSSIL_BUILD_ZLIB FOSSIL_BUILD_ZLIB = 1 !endif # Link everything except SQLite dynamically? !ifndef FOSSIL_DYNAMIC_BUILD FOSSIL_DYNAMIC_BUILD = 0 !endif # Enable relative paths in external diff/gdiff? !ifndef FOSSIL_ENABLE_EXEC_REL_PATHS FOSSIL_ENABLE_EXEC_REL_PATHS = 0 !endif # Enable the JSON API? !ifndef FOSSIL_ENABLE_JSON FOSSIL_ENABLE_JSON = 0 !endif # Enable legacy treatment of the mv/rm commands? !ifndef FOSSIL_ENABLE_LEGACY_MV_RM FOSSIL_ENABLE_LEGACY_MV_RM = 1 !endif # Enable use of miniz instead of zlib? !ifndef FOSSIL_ENABLE_MINIZ FOSSIL_ENABLE_MINIZ = 0 !endif # Enable OpenSSL support? !ifndef FOSSIL_ENABLE_SSL FOSSIL_ENABLE_SSL = 0 !endif # Enable the Tcl integration subsystem? !ifndef FOSSIL_ENABLE_TCL FOSSIL_ENABLE_TCL = 0 !endif # Enable TH1 scripts in embedded documentation files? !ifndef FOSSIL_ENABLE_TH1_DOCS FOSSIL_ENABLE_TH1_DOCS = 0 !endif # Enable TH1 hooks for commands and web pages? !ifndef FOSSIL_ENABLE_TH1_HOOKS FOSSIL_ENABLE_TH1_HOOKS = 0 !endif # Enable support for Windows XP with Visual Studio 201x? !ifndef FOSSIL_ENABLE_WINXP FOSSIL_ENABLE_WINXP = 0 !endif # Enable support for the SQLite Encryption Extension? !ifndef USE_SEE USE_SEE = 0 !endif !if $(FOSSIL_ENABLE_SSL)!=0 SSLDIR = $(B)\compat\openssl-1.0.2p SSLINCDIR = $(SSLDIR)\inc32 !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLLIBDIR = $(SSLDIR)\out32dll !else SSLLIBDIR = $(SSLDIR)\out32 !endif SSLLFLAGS = /nologo /opt:ref /debug SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib crypt32.lib !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" !message Using 'x64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. # SSLCONFIG = VC-WIN64A no-asm no-ssl2 no-ssl3 no-weak-ssl-ciphers SSLCONFIG = VC-WIN64A no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared !endif SSLSETUP = ms\do_win64a.bat !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLNMAKE = ms\ntdll.mak all !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DOPENSSL_NO_WEAK_SSL_CIPHERS !endif !elseif "$(PLATFORM)"=="ia64" !message Using 'ia64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. # SSLCONFIG = VC-WIN64I no-asm no-ssl2 no-ssl3 no-weak-ssl-ciphers SSLCONFIG = VC-WIN64I no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared !endif SSLSETUP = ms\do_win64i.bat !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLNMAKE = ms\ntdll.mak all !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DOPENSSL_NO_WEAK_SSL_CIPHERS !endif !else !message Assuming 'x86' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. # SSLCONFIG = VC-WIN32 no-asm no-ssl2 no-ssl3 no-weak-ssl-ciphers SSLCONFIG = VC-WIN32 no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared !endif SSLSETUP = ms\do_ms.bat !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLNMAKE = ms\ntdll.mak all !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DOPENSSL_NO_WEAK_SSL_CIPHERS !endif !endif !endif !if $(FOSSIL_ENABLE_TCL)!=0 TCLDIR = $(B)\compat\tcl-8.6 TCLSRCDIR = $(TCLDIR) TCLINCDIR = $(TCLSRCDIR)\generic !endif # zlib options ZINCDIR = $(B)\compat\zlib ZLIBDIR = $(B)\compat\zlib !if $(FOSSIL_DYNAMIC_BUILD)!=0 ZLIB = zdll.lib !else ZLIB = zlib.lib !endif INCL = /I. /I$(SRCDIR) /I$B\win\include !if $(FOSSIL_ENABLE_MINIZ)==0 INCL = $(INCL) /I$(ZINCDIR) !endif !if $(FOSSIL_ENABLE_SSL)!=0 INCL = $(INCL) /I$(SSLINCDIR) !endif !if $(FOSSIL_ENABLE_TCL)!=0 INCL = $(INCL) /I$(TCLINCDIR) !endif CFLAGS = /nologo LDFLAGS = !if $(FOSSIL_DYNAMIC_BUILD)!=0 LDFLAGS = $(LDFLAGS) /MANIFEST !else LDFLAGS = $(LDFLAGS) /NODEFAULTLIB:msvcrt /MANIFEST:NO !endif !if $(FOSSIL_ENABLE_WINXP)!=0 XPCFLAGS = $(XPCFLAGS) /D_WIN32_WINNT=0x0501 /D_USING_V110_SDK71_=1 CFLAGS = $(CFLAGS) $(XPCFLAGS) !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" XPLDFLAGS = $(XPLDFLAGS) /SUBSYSTEM:CONSOLE,5.02 !else XPLDFLAGS = $(XPLDFLAGS) /SUBSYSTEM:CONSOLE,5.01 !endif LDFLAGS = $(LDFLAGS) $(XPLDFLAGS) !endif !if $(FOSSIL_DYNAMIC_BUILD)!=0 !if $(DEBUG)!=0 CRTFLAGS = /MDd !else CRTFLAGS = /MD !endif !else !if $(DEBUG)!=0 CRTFLAGS = /MTd !else CRTFLAGS = /MT !endif !endif !if $(DEBUG)!=0 CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) /Od LDFLAGS = $(LDFLAGS) /DEBUG !else CFLAGS = $(CFLAGS) $(CRTFLAGS) /O2 !endif BCC = $(CC) $(CFLAGS) TCC = $(CC) /c $(CFLAGS) $(MSCDEF) $(INCL) RCC = $(RC) /D_WIN32 /D_MSC_VER $(MSCDEF) $(INCL) MTC = mt LIBS = ws2_32.lib advapi32.lib dnsapi.lib LIBDIR = !if $(FOSSIL_DYNAMIC_BUILD)!=0 TCC = $(TCC) /DFOSSIL_DYNAMIC_BUILD=1 RCC = $(RCC) /DFOSSIL_DYNAMIC_BUILD=1 !endif !if $(FOSSIL_ENABLE_MINIZ)==0 LIBS = $(LIBS) $(ZLIB) LIBDIR = $(LIBDIR) /LIBPATH:$(ZLIBDIR) !endif !if $(FOSSIL_ENABLE_MINIZ)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_MINIZ=1 RCC = $(RCC) /DFOSSIL_ENABLE_MINIZ=1 !endif !if $(FOSSIL_ENABLE_JSON)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_JSON=1 RCC = $(RCC) /DFOSSIL_ENABLE_JSON=1 !endif !if $(FOSSIL_ENABLE_SSL)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) /DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) LIBDIR = $(LIBDIR) /LIBPATH:$(SSLLIBDIR) !endif !if $(FOSSIL_ENABLE_EXEC_REL_PATHS)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_EXEC_REL_PATHS=1 RCC = $(RCC) /DFOSSIL_ENABLE_EXEC_REL_PATHS=1 !endif !if $(FOSSIL_ENABLE_LEGACY_MV_RM)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 RCC = $(RCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 !endif !if $(FOSSIL_ENABLE_TH1_DOCS)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_TH1_DOCS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TH1_DOCS=1 !endif !if $(FOSSIL_ENABLE_TH1_HOOKS)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_TH1_HOOKS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TH1_HOOKS=1 !endif !if $(FOSSIL_ENABLE_TCL)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_TCL=1 RCC = $(RCC) /DFOSSIL_ENABLE_TCL=1 TCC = $(TCC) /DFOSSIL_ENABLE_TCL_STUBS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1 TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 TCC = $(TCC) /DUSE_TCL_STUBS=1 RCC = $(RCC) /DUSE_TCL_STUBS=1 !endif !if $(USE_SEE)!=0 TCC = $(TCC) /DUSE_SEE=1 RCC = $(RCC) /DUSE_SEE=1 !endif } regsub -all {[-]D} [join $SQLITE_WIN32_OPTIONS { }] {/D} MSC_SQLITE_OPTIONS set j " \\\n " writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n" regsub -all {[-]D} [join $SHELL_WIN32_OPTIONS { }] {/D} MSC_SHELL_OPTIONS set j " \\\n " writeln "SHELL_OPTIONS = [join $MSC_SHELL_OPTIONS $j]\n" regsub -all {[-]D} [join $MINIZ_WIN32_OPTIONS { }] {/D} MSC_MINIZ_OPTIONS set j " \\\n " writeln "MINIZ_OPTIONS = [join $MSC_MINIZ_OPTIONS $j]\n" writeln -nonewline "SRC = " set i 0 foreach s [lsort $src] { if {$i > 0} { writeln " \\" writeln -nonewline " " } writeln -nonewline "${s}_.c"; incr i } writeln "\n" writeln -nonewline "EXTRA_FILES = " set i 0 foreach s [lsort $extra_files] { if {$i > 0} { writeln " \\" writeln -nonewline " " } set s [regsub -all / $s \\] writeln -nonewline "\$(SRCDIR)\\${s}"; incr i } writeln "\n" set AdditionalObj [list shell sqlite3 th th_lang th_tcl cson_amalgamation] writeln -nonewline "OBJ = " set i 0 foreach s [lsort [concat $src $AdditionalObj]] { if {$i > 0} { writeln " \\" writeln -nonewline " " } writeln -nonewline "\$(OX)\\$s\$O"; incr i } if {$i > 0} { writeln " \\" } writeln "!if \$(FOSSIL_ENABLE_MINIZ)!=0" writeln -nonewline " " writeln "\$(OX)\\miniz\$O \\"; incr i writeln "!endif" writeln -nonewline " \$(OX)\\fossil.res\n\n" writeln [string map [list <<<NEXT_LINE>>> \\] { APPNAME = $(OX)\fossil$(E) PDBNAME = $(OX)\fossil$(P) APPTARGETS = all: $(OX) $(APPNAME) zlib: @echo Building zlib from "$(ZLIBDIR)"... !if $(FOSSIL_ENABLE_WINXP)!=0 @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc $(ZLIB) "CC=cl $(XPCFLAGS)" "LD=link $(XPLDFLAGS)" && popd !else @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc $(ZLIB) && popd !endif !if $(FOSSIL_ENABLE_SSL)!=0 openssl: @echo Building OpenSSL from "$(SSLDIR)"... !if "$(PERLDIR)" != "" @set PATH=$(PERLDIR);$(PATH) !endif @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd !if $(FOSSIL_ENABLE_WINXP)!=0 @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) "CC=cl $(SSLCFLAGS) $(XPCFLAGS)" "LFLAGS=$(SSLLFLAGS) $(XPLDFLAGS)" && popd !else @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) "CC=cl $(SSLCFLAGS)" && popd !endif !endif !if $(FOSSIL_ENABLE_MINIZ)==0 !if $(FOSSIL_BUILD_ZLIB)!=0 APPTARGETS = $(APPTARGETS) zlib !endif !endif !if $(FOSSIL_ENABLE_SSL)!=0 !if $(FOSSIL_BUILD_SSL)!=0 APPTARGETS = $(APPTARGETS) openssl !endif !endif $(APPNAME) : $(APPTARGETS) translate$E mkindex$E codecheck1$E headers $(OBJ) $(OX)\linkopts cd $(OX) codecheck1$E $(SRC) link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts if exist $@.manifest <<<NEXT_LINE>>> $(MTC) -nologo -manifest $@.manifest -outputresource:$@;1 $(OX)\linkopts: $B\win\Makefile.msc}] set redir {>} foreach s [lsort [concat $src $AdditionalObj]] { writeln "\techo \$(OX)\\$s.obj $redir \$@" set redir {>>} } set redir {>>} writeln "!if \$(FOSSIL_ENABLE_MINIZ)!=0" writeln "\techo \$(OX)\\miniz.obj $redir \$@" writeln "!endif" writeln "\techo \$(LIBS) $redir \$@" writeln { $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkbuiltin$E: $(SRCDIR)\mkbuiltin.c $(BCC) $** mkversion$E: $(SRCDIR)\mkversion.c $(BCC) $** mkcss$E: $(SRCDIR)\mkcss.c $(BCC) $** codecheck1$E: $(SRCDIR)\codecheck1.c $(BCC) $** !if $(USE_SEE)!=0 SEE_FLAGS = /DSQLITE_HAS_CODEC=1 /DSQLITE_SHELL_DBKEY_PROC=fossil_key SQLITE3_SHELL_SRC = $(SRCDIR)\shell-see.c SQLITE3_SRC = $(SRCDIR)\sqlite3-see.c !else SEE_FLAGS = SQLITE3_SHELL_SRC = $(SRCDIR)\shell.c SQLITE3_SRC = $(SRCDIR)\sqlite3.c !endif $(OX)\shell$O : $(SQLITE3_SHELL_SRC) $B\win\Makefile.msc $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) $(OX)\sqlite3$O : $(SQLITE3_SRC) $B\win\Makefile.msc $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) $(SQLITE3_SRC) $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c $(TCC) /Fo$@ -c $** $(OX)\miniz$O : $(SRCDIR)\miniz.c $(TCC) /Fo$@ -c $(MINIZ_OPTIONS) $(SRCDIR)\miniz.c VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION $** > $@ $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c $(TCC) /Fo$@ /c $** default_css.h: mkcss$E $(SRCDIR)\default_css.txt $** $@ page_index.h: mkindex$E $(SRC) $** > $@ builtin_data.h: mkbuiltin$E $(EXTRA_FILES) mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@ clean: -del $(OX)\*.obj 2>NUL -del *.obj 2>NUL -del *_.c 2>NUL -del *.h 2>NUL -del *.ilk 2>NUL -del *.map 2>NUL -del *.res 2>NUL -del headers 2>NUL -del linkopts 2>NUL -del vc*.pdb 2>NUL realclean: clean -del $(APPNAME) 2>NUL -del $(PDBNAME) 2>NUL -del translate$E 2>NUL -del translate$P 2>NUL -del mkindex$E 2>NUL -del mkindex$P 2>NUL -del makeheaders$E 2>NUL -del makeheaders$P 2>NUL -del mkversion$E 2>NUL -del mkversion$P 2>NUL -del mkcss$E 2>NUL -del mkcss$P 2>NUL -del codecheck1$E 2>NUL -del codecheck1$P 2>NUL -del mkbuiltin$E 2>NUL -del mkbuiltin$P 2>NUL $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h } foreach s [lsort $src] { writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h" writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n" writeln "${s}_.c : \$(SRCDIR)\\$s.c" writeln "\ttranslate\$E \$** > \$@\n" } writeln "fossil.res : \$B\\win\\fossil.rc" writeln "\t\$(RCC) /fo \$@ \$**\n" writeln "headers: makeheaders\$E page_index.h builtin_data.h default_css.h VERSION.h" writeln -nonewline "\tmakeheaders\$E " set i 0 foreach s [lsort $src] { if {$i > 0} { writeln " \\" writeln -nonewline "\t\t\t" } writeln -nonewline "${s}_.c:$s.h"; incr i } writeln " \\\n\t\t\t\$(SRCDIR)\\sqlite3.h \\" writeln "\t\t\t\$(SRCDIR)\\th.h \\" writeln "\t\t\tVERSION.h \\" writeln "\t\t\t\$(SRCDIR)\\cson_amalgamation.h" writeln "\t@copy /Y nul: headers" close $output_file # # End of the win/Makefile.msc output ############################################################################## ############################################################################## ############################################################################## # Begin win/Makefile.PellesCGMake output # puts "building ../win/Makefile.PellesCGMake" set output_file [open ../win/Makefile.PellesCGMake w] fconfigure $output_file -translation binary writeln [string map [list \ <<<SQLITE_OPTIONS>>> [join $SQLITE_WIN32_OPTIONS { }] \ <<<SHELL_OPTIONS>>> [join $SHELL_WIN32_OPTIONS { }]] {# ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # HowTo # ----- # # This is a Makefile to compile fossil with PellesC from # http://www.smorgasbordet.com/pellesc/index.htm # In addition to the Compiler envrionment, you need # gmake from http://sourceforge.net/projects/unxutils/, Pelles make version # couldn't handle the complex dependencies in this build # zlib sources # Then you do # 1. create a directory PellesC in the project root directory # 2. Change the variables PellesCDir/ZLIBSRCDIR to the path of your installation # 3. open a dos prompt window and change working directory into PellesC (step 1) # 4. run gmake -f ..\win\Makefile.PellesCGMake # # this file is tested with # PellesC 5.00.13 # gmake 3.80 # zlib sources 1.2.5 # Windows XP SP 2 # and # PellesC 6.00.4 # gmake 3.80 # zlib sources 1.2.5 # Windows 7 Home Premium # # PellesCDir=c:\Programme\PellesC # Select between 32/64 bit code, default is 32 bit #TARGETVERSION=64 ifeq ($(TARGETVERSION),64) # 64 bit version TARGETMACHINE_CC=amd64 TARGETMACHINE_LN=amd64 TARGETEXTEND=64 else # 32 bit version TARGETMACHINE_CC=x86 TARGETMACHINE_LN=ix86 TARGETEXTEND= endif # define the project directories B=.. SRCDIR=$(B)/src/ WINDIR=$(B)/win/ ZLIBSRCDIR=../../zlib/ # define linker command and options LINK=$(PellesCDir)/bin/polink.exe LINKFLAGS=-subsystem:console -machine:$(TARGETMACHINE_LN) /LIBPATH:$(PellesCDir)\lib\win$(TARGETEXTEND) /LIBPATH:$(PellesCDir)\lib kernel32.lib advapi32.lib delayimp$(TARGETEXTEND).lib Wsock32.lib dnsapi.lib Crtmt$(TARGETEXTEND).lib # define standard C-compiler and flags, used to compile # the fossil binary. Some special definitions follow for # special files follow CC=$(PellesCDir)\bin\pocc.exe DEFINES=-D_pgmptr=g.argv[0] CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) # define commands for building the windows resource files RESOURCE=fossil.res RC=$(PellesCDir)\bin\porc.exe RCFLAGS=$(INCLUDE) -D__POCC__=1 -D_M_X$(TARGETVERSION) # define the special utilities files, needed to generate # the automatically generated source files UTILS=translate.exe mkindex.exe makeheaders.exe mkbuiltin.exe UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the SQLite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) SQLITEDEFINES=<<<SQLITE_OPTIONS>>> # define the SQLite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) SQLITESHELLDEFINES=<<<SHELL_OPTIONS>>> # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) # define the zlib files, needed by this compile ZLIBSRC=adler32.c compress.c crc32.c deflate.c gzclose.c gzlib.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c ORIGZLIBSRC=$(foreach sf,$(ZLIBSRC),$(ZLIBSRCDIR)$(sf)) ZLIBOBJ=$(foreach sf,$(ZLIBSRC),$(sf:.c=.obj)) # define all fossil sources, using the standard compile and # source generation. These are all files in SRCDIR, which are not # mentioned as special files above: ORIGSRC=$(filter-out $(UTILS_SRC) $(ORIGTHSRC) $(ORIGSQLITESRC) $(ORIGSQLITESHELLSRC),$(wildcard $(SRCDIR)*.c)) SRC=$(subst $(SRCDIR),,$(ORIGSRC)) TRANSLATEDSRC=$(SRC:.c=_.c) TRANSLATEDOBJ=$(TRANSLATEDSRC:.c=.obj) # main target file is the application APPLICATION=fossil.exe # define the standard make target .PHONY: default default: page_index.h builtin_data.h headers $(APPLICATION) # symbolic target to generate the source generate utils .PHONY: utils utils: $(UTILS) # link utils $(UTILS) version.exe: %.exe: %.obj $(LINK) $(LINKFLAGS) -out:"$@" $< # compiling standard fossil utils $(UTILS_OBJ): %.obj: $(SRCDIR)%.c $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" # compile special windows utils version.obj: $(SRCDIR)mkversion.c $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" # generate the translated c-source files $(TRANSLATEDSRC): %_.c: $(SRCDIR)%.c translate.exe translate.exe $< >$@ # generate the index source, containing all web references,.. page_index.h: $(TRANSLATEDSRC) mkindex.exe mkindex.exe $(TRANSLATEDSRC) >$@ builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ # extracting version info from manifest VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@ default_css.h: mkcss.exe default_css.txt mkcss.exe default_css.txt $@ # generate the simplified headers headers: makeheaders.exe page_index.h builtin_data.h default_css.h VERSION.h ../src/sqlite3.h ../src/th.h makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h echo Done >$@ # compile C sources with relevant options $(TRANSLATEDOBJ): %_.obj: %_.c %.h $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" $(SQLITEOBJ): %.obj: $(SRCDIR)%.c $(SRCDIR)%.h $(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@" $(SQLITESHELLOBJ): %.obj: $(SRCDIR)%.c $(CC) $(CCFLAGS) $(SQLITESHELLDEFINES) $(INCLUDE) "$<" -Fo"$@" $(THOBJ): %.obj: $(SRCDIR)%.c $(SRCDIR)th.h $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" $(ZLIBOBJ): %.obj: $(ZLIBSRCDIR)%.c $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" # create the windows resource with icon and version info $(RESOURCE): %.res: ../win/%.rc ../win/*.ico $(RC) $(RCFLAGS) $< -Fo"$@" # link the application $(APPLICATION): $(TRANSLATEDOBJ) $(SQLITEOBJ) $(SQLITESHELLOBJ) $(THOBJ) $(ZLIBOBJ) headers $(RESOURCE) $(LINK) $(LINKFLAGS) -out:"$@" $(TRANSLATEDOBJ) $(SQLITEOBJ) $(SQLITESHELLOBJ) $(THOBJ) $(ZLIBOBJ) $(RESOURCE) # cleanup .PHONY: clean clean: -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj -del /F $(TRANSLATEDSRC) -del /F *.h headers -del /F $(RESOURCE) .PHONY: clobber clobber: clean -del /F *.exe }] |
Changes to src/manifest.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | /* ** A parsed manifest or cluster. */ struct Manifest { Blob content; /* The original content blob */ int type; /* Type of artifact. One of CFTYPE_xxxxx */ int rid; /* The blob-id for this manifest */ | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | /* ** A parsed manifest or cluster. */ struct Manifest { Blob content; /* The original content blob */ int type; /* Type of artifact. One of CFTYPE_xxxxx */ int rid; /* The blob-id for this manifest */ char *zBaseline; /* Baseline manifest. The B card. */ Manifest *pBaseline; /* The actual baseline manifest */ char *zComment; /* Decoded comment. The C card. */ double rDate; /* Date and time from D card. 0.0 if no D card. */ char *zUser; /* Name of the user from the U card. */ char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */ char *zWiki; /* Text of the wiki page. W card. */ char *zWikiTitle; /* Name of the wiki page. L card. */ |
︙ | ︙ | |||
128 129 130 131 132 133 134 | } manifestCardTypes[] = { /* Allowed Required */ /* CFTYPE_MANIFEST 1 */ { "BCDFNPQRTUZ", "DZ" }, /* Wants to be "CDUZ" ----^^^^ ** but we must limit for historical compatibility */ /* CFTYPE_CLUSTER 2 */ { "MZ", "MZ" }, /* CFTYPE_CONTROL 3 */ { "DTUZ", "DTUZ" }, | | | | 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 | } manifestCardTypes[] = { /* Allowed Required */ /* CFTYPE_MANIFEST 1 */ { "BCDFNPQRTUZ", "DZ" }, /* Wants to be "CDUZ" ----^^^^ ** but we must limit for historical compatibility */ /* CFTYPE_CLUSTER 2 */ { "MZ", "MZ" }, /* CFTYPE_CONTROL 3 */ { "DTUZ", "DTUZ" }, /* CFTYPE_WIKI 4 */ { "DLNPUWZ", "DLUWZ" }, /* CFTYPE_TICKET 5 */ { "DJKUZ", "DJKUZ" }, /* CFTYPE_ATTACHMENT 6 */ { "ACDNUZ", "ADZ" }, /* CFTYPE_EVENT 7 */ { "CDENPTUWZ", "DEWZ" }, /* CFTYPE_FORUM 8 */ { "DGHINPUWZ", "DUWZ" }, }; /* ** Names of manifest types */ static const char *azNameOfMType[] = { "manifest", "cluster", "tag", "wiki", "ticket", "attachment", "technote", |
︙ | ︙ | |||
166 167 168 169 170 171 172 | /* ** True if manifest_crosslink_begin() has been called but ** manifest_crosslink_end() is still pending. */ static int manifest_crosslink_busy = 0; | < < < < < < < < < < < < < < < < < < < < < < < < < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | /* ** True if manifest_crosslink_begin() has been called but ** manifest_crosslink_end() is still pending. */ static int manifest_crosslink_busy = 0; /* ** Clear the memory allocated in a manifest object */ void manifest_destroy(Manifest *p){ if( p ){ blob_reset(&p->content); fossil_free(p->aFile); |
︙ | ︙ | |||
312 313 314 315 316 317 318 | if( z[-2]=='\r' && z[-3]=='\n' ) return 1; return 0; } /* ** Remove the PGP signature from the artifact, if there is one. */ | | | | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | if( z[-2]=='\r' && z[-3]=='\n' ) return 1; return 0; } /* ** Remove the PGP signature from the artifact, if there is one. */ static void remove_pgp_signature(char **pz, int *pn){ char *z = *pz; int n = *pn; int i; if( strncmp(z, "-----BEGIN PGP SIGNED MESSAGE-----", 34)!=0 ) return; for(i=34; i<n && !after_blank_line(z+i); i++){} if( i>=n ) return; z += i; n -= i; |
︙ | ︙ | |||
341 342 343 344 345 346 347 | ** checksum. Return 0 if there is no Z-card. Return 1 if the Z-card ** exists and is correct. Return 2 if the Z-card exists and has the wrong ** value. ** ** 0123456789 123456789 123456789 123456789 ** Z aea84f4f863865a8d59d0384e4d2a41c */ | | < < | < < < > | | < | | | > | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | ** checksum. Return 0 if there is no Z-card. Return 1 if the Z-card ** exists and is correct. Return 2 if the Z-card exists and has the wrong ** value. ** ** 0123456789 123456789 123456789 123456789 ** Z aea84f4f863865a8d59d0384e4d2a41c */ static int verify_z_card(const char *z, int n){ if( n<35 ) return 0; if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0; md5sum_init(); md5sum_step_text(z, n-35); if( memcmp(&z[n-33], md5sum_finish(0), 32)==0 ){ return 1; }else{ return 2; } } /* ** A structure used for rapid parsing of the Manifest file */ typedef struct ManifestText ManifestText; struct ManifestText { char *z; /* The first character of the next token */ char *zEnd; /* One character beyond the end of the manifest */ int atEol; /* True if z points to the start of a new line */ }; /* ** Return a pointer to the next token. The token is zero-terminated. ** Return NULL if there are no more tokens on the current line. */ static char *next_token(ManifestText *p, int *pLen){ char *z; char *zStart; int c; if( p->atEol ) return 0; zStart = z = p->z; while( (c=(*z))!=' ' && c!='\n' ){ z++; } *z = 0; p->z = &z[1]; p->atEol = c=='\n'; if( pLen ) *pLen = z - zStart; return zStart; } /* ** Return the card-type for the next card. Or, return 0 if there are no ** more cards or if we are not at the end of the current card. */ |
︙ | ︙ | |||
410 411 412 413 414 415 416 | } /* ** Shorthand for a control-artifact parsing error */ #define SYNTAX(T) {zErr=(T); goto manifest_syntax_error;} | < < < < < < < < < < < < < | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | } /* ** Shorthand for a control-artifact parsing error */ #define SYNTAX(T) {zErr=(T); goto manifest_syntax_error;} /* ** Parse a blob into a Manifest object. The Manifest object ** takes over the input blob and will free it when the ** Manifest object is freed. Zeros are inserted into the blob ** as string terminators so that blob should not be used again. ** ** Return a pointer to an allocated Manifest object if the content |
︙ | ︙ | |||
466 467 468 469 470 471 472 473 474 475 476 477 478 479 | char *z; int n; char *zUuid; int sz = 0; int isRepeat; int nSelfTag = 0; /* Number of T cards referring to this manifest */ int nSimpleTag = 0; /* Number of T cards with "+" prefix */ const char *zErr = 0; unsigned int m; unsigned int seenCard = 0; /* Which card types have been seen */ char zErrBuf[100]; /* Write error messages here */ if( rid==0 ){ isRepeat = 1; | > | | < | < | < | < < < < | > < < < < < < | < < < < < < < < < < < < < | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | char *z; int n; char *zUuid; int sz = 0; int isRepeat; int nSelfTag = 0; /* Number of T cards referring to this manifest */ int nSimpleTag = 0; /* Number of T cards with "+" prefix */ static Bag seen; const char *zErr = 0; unsigned int m; unsigned int seenCard = 0; /* Which card types have been seen */ char zErrBuf[100]; /* Write error messages here */ if( rid==0 ){ isRepeat = 1; }else if( bag_find(&seen, rid) ){ isRepeat = 1; }else{ isRepeat = 0; bag_insert(&seen, rid); } /* Every structural artifact ends with a '\n' character. Exit early ** if that is not the case for this artifact. */ if( !isRepeat ) g.parseCnt[0]++; z = blob_materialize(pContent); n = blob_size(pContent); if( n<=0 || z[n-1]!='\n' ){ blob_reset(pContent); blob_appendf(pErr, "%s", n ? "not terminated with \\n" : "zero-length"); return 0; } /* Strip off the PGP signature if there is one. */ remove_pgp_signature(&z, &n); /* Verify that the first few characters of the artifact look like ** a control artifact. */ if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){ blob_reset(pContent); blob_appendf(pErr, "line 1 not recognized"); return 0; } /* Then verify the Z-card. */ if( verify_z_card(z, n)==2 ){ blob_reset(pContent); blob_appendf(pErr, "incorrect Z-card cksum"); return 0; } /* Allocate a Manifest object to hold the parsed control artifact. */ p = fossil_malloc( sizeof(*p) ); memset(p, 0, sizeof(*p)); memcpy(&p->content, pContent, sizeof(p->content)); p->rid = rid; blob_zero(pContent); pContent = &p->content; /* Begin parsing, card by card. */ x.z = z; x.zEnd = &z[n]; x.atEol = 1; while( (cType = next_card(&x))!=0 && cType>=cPrevType ){ lineNo++; if( cType<'A' || cType>'Z' ) SYNTAX("bad card type"); seenCard |= 1 << (cType-'A'); switch( cType ){ /* ** A <filename> <target> ?<source>? ** ** Identifies an attachment to either a wiki page or a ticket. ** <source> is the artifact that is the attachment. <source> ** is omitted to delete an attachment. <target> is the name of ** a wiki page or ticket to which that attachment is connected. */ case 'A': { char *zName, *zTarget, *zSrc; int nTarget = 0, nSrc = 0; zName = next_token(&x, 0); zTarget = next_token(&x, &nTarget); zSrc = next_token(&x, &nSrc); if( zName==0 || zTarget==0 ) goto manifest_syntax_error; if( p->zAttachName!=0 ) goto manifest_syntax_error; defossilize(zName); if( !file_is_simple_pathname(zName, 0) ){ SYNTAX("invalid filename on A-card"); } defossilize(zTarget); if( !hname_validate(zTarget,nTarget) && !wiki_name_is_wellformed((const unsigned char *)zTarget) ){ SYNTAX("invalid target on A-card"); } |
︙ | ︙ | |||
652 653 654 655 656 657 658 | ** is when the specific event is said to occur. */ case 'E': { if( p->rEventDate>0.0 ) SYNTAX("more than one E-card"); p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0)); if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card"); p->zEventId = next_token(&x, &sz); | < | < | < < < < < < < < < < > > > | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 | ** is when the specific event is said to occur. */ case 'E': { if( p->rEventDate>0.0 ) SYNTAX("more than one E-card"); p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0)); if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card"); p->zEventId = next_token(&x, &sz); if( !hname_validate(p->zEventId, sz) ){ SYNTAX("malformed hash on E-card"); } p->type = CFTYPE_EVENT; break; } /* ** F <filename> ?<uuid>? ?<permissions>? ?<old-name>? ** ** Identifies a file in a manifest. Multiple F lines are ** allowed in a manifest. F lines are not allowed in any ** other control file. The filename and old-name are fossil-encoded. */ case 'F': { char *zName, *zPerm, *zPriorName; zName = next_token(&x,0); if( zName==0 ) SYNTAX("missing filename on F-card"); defossilize(zName); if( !file_is_simple_pathname(zName, 0) ){ SYNTAX("F-card filename is not a simple path"); } zUuid = next_token(&x, &sz); if( p->zBaseline==0 || zUuid!=0 ){ if( !hname_validate(zUuid,sz) ){ SYNTAX("F-card hash invalid"); } } zPerm = next_token(&x,0); zPriorName = next_token(&x,0); if( zPriorName ){ defossilize(zPriorName); if( !file_is_simple_pathname(zPriorName, 0) ){ SYNTAX("F-card old filename is not a simple path"); } } if( p->nFile>=p->nFileAlloc ){ p->nFileAlloc = p->nFileAlloc*2 + 10; p->aFile = fossil_realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); } i = p->nFile++; p->aFile[i].zName = zName; p->aFile[i].zUuid = zUuid; p->aFile[i].zPerm = zPerm; p->aFile[i].zPrior = zPriorName; if( i>0 && fossil_strcmp(p->aFile[i-1].zName, zName)>=0 ){ SYNTAX("incorrect F-card sort order"); } p->type = CFTYPE_MANIFEST; break; } /* ** G <hash> ** |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | md5sum_init(); if( !isRepeat ) g.parseCnt[p->type]++; return p; manifest_syntax_error: { | | < | < < | | | | < | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 | md5sum_init(); if( !isRepeat ) g.parseCnt[p->type]++; return p; manifest_syntax_error: { char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); if( zUuid ){ blob_appendf(pErr, "artifact [%s] ", zUuid); fossil_free(zUuid); } } if( zErr ){ blob_appendf(pErr, "line %d: %s", lineNo, zErr); }else{ blob_appendf(pErr, "unknown error on line %d", lineNo); } md5sum_init(); manifest_destroy(p); return 0; } /* |
︙ | ︙ | |||
1189 1190 1191 1192 1193 1194 1195 | p = manifest_get(rid, CFTYPE_MANIFEST, 0); if( p==0 ){ fossil_fatal("cannot parse manifest for check-in: %s", zName); } return p; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < | | | | < | 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | p = manifest_get(rid, CFTYPE_MANIFEST, 0); if( p==0 ){ fossil_fatal("cannot parse manifest for check-in: %s", zName); } return p; } /* ** COMMAND: test-parse-manifest ** ** Usage: %fossil test-parse-manifest FILENAME ?N? ** ** Parse the manifest(s) given on the command-line and report any ** errors. If the N argument is given, run the parsing N times. */ void manifest_test_parse_cmd(void){ Manifest *p; Blob b; int i; int n = 1; db_find_and_open_repository(0,0); verify_all_options(); if( g.argc!=3 && g.argc!=4 ){ usage("FILENAME"); } blob_read_from_file(&b, g.argv[2], ExtFILE); if( g.argc>3 ) n = atoi(g.argv[3]); for(i=0; i<n; i++){ Blob b2; Blob err; blob_copy(&b2, &b); blob_zero(&err); p = manifest_parse(&b2, 0, &err); if( p==0 ) fossil_print("ERROR: %s\n", blob_str(&err)); blob_reset(&err); manifest_destroy(p); } } /* ** COMMAND: test-parse-all-blobs ** ** Usage: %fossil test-parse-all-blobs ** ** Parse all entries in the BLOB table that are believed to be non-data ** artifacts and report any errors. Run this test command on historical ** repositories after making any changes to the manifest_parse() ** implementation to confirm that the changes did not break anything. */ void manifest_test_parse_all_blobs_cmd(void){ Manifest *p; Blob err; Stmt q; int nTest = 0; int nErr = 0; db_find_and_open_repository(0, 0); verify_all_options(); db_prepare(&q, "SELECT DISTINCT objid FROM EVENT"); while( db_step(&q)==SQLITE_ROW ){ int id = db_column_int(&q,0); fossil_print("Checking %d \r", id); nTest++; fflush(stdout); blob_init(&err, 0, 0); p = manifest_get(id, CFTYPE_ANY, &err); if( p==0 ){ fossil_print("%d ERROR: %s\n", id, blob_str(&err)); nErr++; } blob_reset(&err); manifest_destroy(p); } db_finalize(&q); fossil_print("%d tests with %d errors\n", nTest, nErr); } |
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 | return fnid; } /* ** Compute an appropriate mlink.mperm integer for the permission string ** of a file. */ | | | 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | return fnid; } /* ** Compute an appropriate mlink.mperm integer for the permission string ** of a file. */ int manifest_file_mperm(ManifestFile *pFile){ int mperm = PERM_REG; if( pFile && pFile->zPerm){ if( strstr(pFile->zPerm,"x")!=0 ){ mperm = PERM_EXE; }else if( strstr(pFile->zPerm,"l")!=0 ){ mperm = PERM_LNK; } |
︙ | ︙ | |||
1849 1850 1851 1852 1853 1854 1855 | */ if( isPrim ){ for(i=1; i<pChild->nParent; i++){ pmid = uuid_to_rid(pChild->azParent[i], 0); if( pmid<=0 ) continue; add_mlink(pmid, 0, mid, pChild, 0); } | < < < < < < < | < | < < < < | | 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 | */ if( isPrim ){ for(i=1; i<pChild->nParent; i++){ pmid = uuid_to_rid(pChild->azParent[i], 0); if( pmid<=0 ) continue; add_mlink(pmid, 0, mid, pChild, 0); } } } /* ** For a check-in with RID "rid" that has nParent parent check-ins given ** by the hashes in azParent[], create all appropriate plink and mlink table ** entries. ** ** The primary parent is the first hash on the azParent[] list. ** ** Return the RID of the primary parent. */ static int manifest_add_checkin_linkages( int rid, /* The RID of the check-in */ Manifest *p, /* Manifest for this check-in */ int nParent, /* Number of parents for this check-in */ char **azParent /* hashes for each parent */ ){ int i; int parentid = 0; char zBaseId[30]; /* Baseline manifest RID for deltas. "NULL" otherwise */ Stmt q; if( p->zBaseline ){ sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d", uuid_to_rid(p->zBaseline,1)); }else{ sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL"); } for(i=0; i<nParent; i++){ int pid = uuid_to_rid(azParent[i], 1); db_multi_exec( "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)" "VALUES(%d, %d, %d, %.17g, %s)", pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/); if( i==0 ) parentid = pid; } add_mlink(parentid, 0, rid, p, 1); if( nParent>1 ){ /* Change MLINK.PID from 0 to -1 for files that are added by merge. */ db_multi_exec( "UPDATE mlink SET pid=-1" " WHERE mid=%d" " AND pid=0" " AND fnid IN " " (SELECT fnid FROM mlink WHERE mid=%d GROUP BY fnid" " HAVING count(*)<%d)", rid, rid, nParent ); } db_prepare(&q, "SELECT cid, isprim FROM plink WHERE pid=%d", rid); while( db_step(&q)==SQLITE_ROW ){ int cid = db_column_int(&q, 0); int isprim = db_column_int(&q, 1); add_mlink(rid, p, cid, 0, isprim); |
︙ | ︙ | |||
1931 1932 1933 1934 1935 1936 1937 | isPublic, 1, manifest_file_mperm(&p->aFile[i])); } } return parentid; } /* | | | 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 | isPublic, 1, manifest_file_mperm(&p->aFile[i])); } } return parentid; } /* ** There exists a "parent" tag against checkin rid that has value zValue. ** If value is well-formed (meaning that it is a list of hashes), then use ** zValue to reparent check-in rid. */ void manifest_reparent_checkin(int rid, const char *zValue){ int nParent = 0; char *zCopy = 0; char **azParent = 0; |
︙ | ︙ | |||
1957 1958 1959 1960 1961 1962 1963 | if( nParent>mxParent ) goto reparent_abort; for(j=HNAME_MIN; z[j]>' '; j++){} if( !hname_validate(z, j) ) goto reparent_abort; if( z[j]==0 ) break; z[j] = 0; i += j; } | > > > | > < > < | < < < < < < < < < < < | 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 | if( nParent>mxParent ) goto reparent_abort; for(j=HNAME_MIN; z[j]>' '; j++){} if( !hname_validate(z, j) ) goto reparent_abort; if( z[j]==0 ) break; z[j] = 0; i += j; } if( !db_exists("SELECT 1 FROM plink WHERE cid=%d AND pid=%d", rid, uuid_to_rid(azParent[0],0)) ){ p = manifest_get(rid, CFTYPE_MANIFEST, 0); } if( p!=0 ){ db_multi_exec( "DELETE FROM plink WHERE cid=%d;" "DELETE FROM mlink WHERE mid=%d;", rid, rid ); manifest_add_checkin_linkages(rid,p,nParent,azParent); } manifest_destroy(p); reparent_abort: fossil_free(azParent); fossil_free(zCopy); } /* ** Setup to do multiple manifest_crosslink() calls. ** ** This routine creates TEMP tables for holding information for ** processing that must be deferred until all artifacts have been ** seen at least once. The deferred processing is accomplished ** by the call to manifest_crosslink_end(). */ void manifest_crosslink_begin(void){ assert( manifest_crosslink_busy==0 ); manifest_crosslink_busy = 1; db_begin_transaction(); db_multi_exec( "CREATE TEMP TABLE pending_tkt(uuid TEXT UNIQUE);" "CREATE TEMP TABLE time_fudge(" " mid INTEGER PRIMARY KEY," /* The rid of a manifest */ " m1 REAL," /* The timestamp on mid */ " cid INTEGER," /* A child or mid */ " m2 REAL" /* Timestamp on the child */ ");" ); } #if INTERFACE /* Timestamps might be adjusted slightly to ensure that check-ins appear ** on the timeline in chronological order. This is the maximum amount ** of the adjustment window, in days. */ #define AGE_FUDGE_WINDOW (2.0/86400.0) /* 2 seconds */ |
︙ | ︙ | |||
2048 2049 2050 2051 2052 2053 2054 | ); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q,0); const char *zValue = db_column_text(&q,1); manifest_reparent_checkin(rid, zValue); } db_finalize(&q); | | | < < < < < | | | < < < | | 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 | ); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q,0); const char *zValue = db_column_text(&q,1); manifest_reparent_checkin(rid, zValue); } db_finalize(&q); db_prepare(&q, "SELECT uuid FROM pending_tkt"); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); ticket_rebuild_entry(zUuid); if( permitHooks && rc==TH_OK ){ rc = xfer_run_script(zScript, zUuid, 0); } } db_finalize(&q); db_multi_exec("DROP TABLE pending_tkt"); /* If multiple check-ins happen close together in time, adjust their ** times by a few milliseconds to make sure they appear in chronological ** order. */ db_prepare(&q, "UPDATE time_fudge SET m1=m2-:incr WHERE m1>=m2 AND m1<m2+:window" |
︙ | ︙ | |||
2102 2103 2104 2105 2106 2107 2108 | } db_multi_exec("DROP TABLE time_fudge;"); db_end_transaction(0); manifest_crosslink_busy = 0; return ( rc!=TH_ERROR ); } | < < < < < < < < < < < < < < < < < < < < < < | 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 | } db_multi_exec("DROP TABLE time_fudge;"); db_end_transaction(0); manifest_crosslink_busy = 0; return ( rc!=TH_ERROR ); } /* ** Make an entry in the event table for a ticket change artifact. */ void manifest_ticket_event( int rid, /* Artifact ID of the change ticket artifact */ const Manifest *pManifest, /* Parsed content of the artifact */ |
︙ | ︙ | |||
2194 2195 2196 2197 2198 2199 2200 | blob_appendf(&comment, "New ticket [%!S|%S] <i>%h</i>.", pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle ); blob_appendf(&brief, "New ticket [%!S|%S].", pManifest->zTicketUuid, pManifest->zTicketUuid); } fossil_free(zTitle); | < < < < < < | < < < < < < < | | | | | < | | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 | blob_appendf(&comment, "New ticket [%!S|%S] <i>%h</i>.", pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle ); blob_appendf(&brief, "New ticket [%!S|%S].", pManifest->zTicketUuid, pManifest->zTicketUuid); } fossil_free(zTitle); db_multi_exec( "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)" "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)", tktTagId, pManifest->rDate, rid, pManifest->zUser, blob_str(&comment), blob_str(&brief) ); blob_reset(&comment); blob_reset(&brief); } /* ** Add an extra line of text to the end of a manifest to prevent it being ** recognized as a valid manifest. ** ** This routine is called prior to writing out the text of a manifest as ** the "manifest" file in the root of a repository when ** "fossil setting manifest on" is enabled. That way, if the files of ** the project are imported into a different Fossil project, the manifest ** file will not be interpreted as a control artifact in that other project. ** ** Normally it is sufficient to simply append the extra line of text. ** However, if the manifest is PGP signed then the extra line has to be ** inserted before the PGP signature (thus invalidating the signature). */ void sterilize_manifest(Blob *p){ char *z, *zOrig; int n, nOrig; static const char zExtraLine[] = "# Remove this line to create a well-formed manifest.\n"; z = zOrig = blob_materialize(p); n = nOrig = blob_size(p); remove_pgp_signature(&z, &n); if( z==zOrig ){ blob_append(p, zExtraLine, -1); }else{ int iEnd; Blob copy; memcpy(©, p, sizeof(copy)); blob_init(p, 0, 0); iEnd = (int)(&z[n] - zOrig); blob_append(p, zOrig, iEnd); blob_append(p, zExtraLine, -1); blob_append(p, &zOrig[iEnd], -1); blob_zero(©); } } /* ** This is the comparison function used to sort the tag array. */ static int tag_compare(const void *a, const void *b){ struct TagType *pA = (struct TagType*)a; struct TagType *pB = (struct TagType*)b; int c; c = fossil_strcmp(pA->zUuid, pB->zUuid); if( c==0 ){ c = fossil_strcmp(pA->zName, pB->zName); } return c; } /* ** Scan artifact rid/pContent to see if it is a control artifact of ** any key: ** ** * Manifest ** * Control ** * Wiki Page ** * Ticket Change ** * Cluster ** * Attachment ** * Event ** ** If the input is a control artifact, then make appropriate entries ** in the auxiliary tables of the database in order to crosslink the ** artifact. ** ** If global variable g.xlinkClusterOnly is true, then ignore all ** control artifacts other than clusters. |
︙ | ︙ | |||
2337 2338 2339 2340 2341 2342 2343 | int permitHooks = (flags & MC_PERMIT_HOOKS); const char *zScript = 0; const char *zUuid = 0; if( g.fSqlTrace ){ fossil_trace("-- manifest_crosslink(%d)\n", rid); } | < < | < > | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 | int permitHooks = (flags & MC_PERMIT_HOOKS); const char *zScript = 0; const char *zUuid = 0; if( g.fSqlTrace ){ fossil_trace("-- manifest_crosslink(%d)\n", rid); } if( (p = manifest_cache_find(rid))!=0 ){ blob_reset(pContent); }else if( (p = manifest_parse(pContent, rid, 0))==0 ){ assert( blob_is_reset(pContent) || pContent==0 ); if( (flags & MC_NO_ERRORS)==0 ){ fossil_error(1, "syntax error in manifest [%S]", db_text(0, "SELECT uuid FROM blob WHERE rid=%d",rid)); } return 0; } if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){ manifest_destroy(p); assert( blob_is_reset(pContent) ); if( (flags & MC_NO_ERRORS)==0 ) fossil_error(1, "no manifest"); |
︙ | ︙ | |||
2370 2371 2372 2373 2374 2375 2376 | } db_begin_transaction(); if( p->type==CFTYPE_MANIFEST ){ if( permitHooks ){ zScript = xfer_commit_code(); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); } | < < < < < < < < < < < < | | < > > | | 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | } db_begin_transaction(); if( p->type==CFTYPE_MANIFEST ){ if( permitHooks ){ zScript = xfer_commit_code(); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); } if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ char *zCom; parentid = manifest_add_checkin_linkages(rid,p,p->nParent,p->azParent); search_doc_touch('c', rid, 0); db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment," "bgcolor,euser,ecomment,omtime)" "VALUES('ci'," " coalesce(" " (SELECT julianday(value) FROM tagxref WHERE tagid=%d AND rid=%d)," " %.17g" " )," " %d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>0)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),%.17g);", TAG_DATE, rid, p->rDate, rid, p->zUser, p->zComment, TAG_BGCOLOR, rid, TAG_USER, rid, TAG_COMMENT, rid, p->rDate ); zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event" " WHERE rowid=last_insert_rowid()"); wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE); fossil_free(zCom); /* If this is a delta-manifest, record the fact that this repository ** contains delta manifests, to free the "commit" logic to generate ** new delta manifests. */ if( p->zBaseline!=0 ){ |
︙ | ︙ | |||
2454 2455 2456 2457 2458 2459 2460 | if( tid ){ switch( p->aTag[i].zName[0] ){ case '-': type = 0; break; /* Cancel prior occurrences */ case '+': type = 1; break; /* Apply to target only */ case '*': type = 2; break; /* Propagate to descendants */ default: fossil_error(1, "unknown tag type in manifest: %s", p->aTag); | < < < < < > | | < > > > > | | < | | < < < > < < < < < < | > | > > > | > > > > | < | < > > > > > < < | 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 | if( tid ){ switch( p->aTag[i].zName[0] ){ case '-': type = 0; break; /* Cancel prior occurrences */ case '+': type = 1; break; /* Apply to target only */ case '*': type = 2; break; /* Propagate to descendants */ default: fossil_error(1, "unknown tag type in manifest: %s", p->aTag); return 0; } tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue, rid, p->rDate, tid); } } if( parentid ){ tag_propagate_all(parentid); } } if( p->type==CFTYPE_WIKI ){ char *zTag = mprintf("wiki-%s", p->zWikiTitle); int tagid = tag_findid(zTag, 1); int prior; char *zComment; int nWiki; char zLength[40]; while( fossil_isspace(p->zWiki[0]) ) p->zWiki++; nWiki = strlen(p->zWiki); sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); tag_insert(zTag, 1, zLength, rid, p->rDate, rid); fossil_free(zTag); prior = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=%d AND mtime<%.17g" " ORDER BY mtime DESC", tagid, p->rDate ); if( prior ){ content_deltify(prior, &rid, 1, 0); } if( nWiki>0 ){ zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle); }else{ zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle); } search_doc_touch('w',rid,p->zWikiTitle); db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment," " bgcolor,euser,ecomment)" "VALUES('w',%.17g,%d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", p->rDate, rid, p->zUser, zComment, TAG_BGCOLOR, rid, TAG_USER, rid, TAG_COMMENT, rid ); fossil_free(zComment); } if( p->type==CFTYPE_EVENT ){ char *zTag = mprintf("event-%s", p->zEventId); int tagid = tag_findid(zTag, 1); int prior, subsequent; int nWiki; char zLength[40]; Stmt qatt; while( fossil_isspace(p->zWiki[0]) ) p->zWiki++; nWiki = strlen(p->zWiki); sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); tag_insert(zTag, 1, zLength, rid, p->rDate, rid); fossil_free(zTag); prior = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=%d AND mtime<%.17g AND rid!=%d" " ORDER BY mtime DESC", tagid, p->rDate, rid ); subsequent = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=%d AND mtime>=%.17g AND rid!=%d" " ORDER BY mtime", tagid, p->rDate, rid ); if( prior ){ content_deltify(prior, &rid, 1, 0); |
︙ | ︙ | |||
2546 2547 2548 2549 2550 2551 2552 | ); } } if( subsequent ){ content_deltify(rid, &subsequent, 1, 0); }else{ search_doc_touch('e',rid,0); | < | 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 | ); } } if( subsequent ){ content_deltify(rid, &subsequent, 1, 0); }else{ search_doc_touch('e',rid,0); db_multi_exec( "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" "VALUES('e',%.17g,%d,%d,%Q,%Q," " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", p->rEventDate, rid, tagid, p->zUser, p->zComment, TAG_BGCOLOR, rid ); |
︙ | ︙ | |||
2593 2594 2595 2596 2597 2598 2599 | if( p->type==CFTYPE_TICKET ){ char *zTag; Stmt qatt; assert( manifest_crosslink_busy==1 ); zTag = mprintf("tkt-%s", p->zTicketUuid); tag_insert(zTag, 1, 0, rid, p->rDate, rid); fossil_free(zTag); | > | | 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 | if( p->type==CFTYPE_TICKET ){ char *zTag; Stmt qatt; assert( manifest_crosslink_busy==1 ); zTag = mprintf("tkt-%s", p->zTicketUuid); tag_insert(zTag, 1, 0, rid, p->rDate, rid); fossil_free(zTag); db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)", p->zTicketUuid); /* Locate and update comment for any attachments */ db_prepare(&qatt, "SELECT attachid, src, target, filename FROM attachment" " WHERE target=%Q", p->zTicketUuid ); while( db_step(&qatt)==SQLITE_ROW ){ |
︙ | ︙ | |||
2630 2631 2632 2633 2634 2635 2636 | char *zComment = 0; const char isAdd = (p->zAttachSrc && p->zAttachSrc[0]) ? 1 : 0; /* We assume that we're attaching to a wiki page until we ** prove otherwise (which could on a later artifact if we ** process the attachment artifact before the artifact to ** which it is attached!) */ char attachToType = 'w'; | | | 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 | char *zComment = 0; const char isAdd = (p->zAttachSrc && p->zAttachSrc[0]) ? 1 : 0; /* We assume that we're attaching to a wiki page until we ** prove otherwise (which could on a later artifact if we ** process the attachment artifact before the artifact to ** which it is attached!) */ char attachToType = 'w'; if( fossil_is_uuid(p->zAttachTarget) ){ if( db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", p->zAttachTarget) ){ attachToType = 't'; /* Attaching to known ticket */ }else if( db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", p->zAttachTarget) ){ |
︙ | ︙ | |||
2687 2688 2689 2690 2691 2692 2693 | "Add attachment [/artifact/%!S|%h] to ticket [%!S|%S]", p->zAttachSrc, p->zAttachName, p->zAttachTarget, p->zAttachTarget); }else{ zComment = mprintf("Delete attachment \"%h\" from ticket [%!S|%S]", p->zAttachName, p->zAttachTarget, p->zAttachTarget); } } | < | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 | "Add attachment [/artifact/%!S|%h] to ticket [%!S|%S]", p->zAttachSrc, p->zAttachName, p->zAttachTarget, p->zAttachTarget); }else{ zComment = mprintf("Delete attachment \"%h\" from ticket [%!S|%S]", p->zAttachName, p->zAttachTarget, p->zAttachTarget); } } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('%c',%.17g,%d,%Q,%Q)", attachToType, p->rDate, rid, p->zUser, zComment ); fossil_free(zComment); } |
︙ | ︙ | |||
2791 2792 2793 2794 2795 2796 2797 | blob_appendf(&comment, " with note \"%h\".", zValue); }else{ blob_appendf(&comment, "."); } } /*blob_appendf(&comment, " [[/info/%S | details]]");*/ if( blob_size(&comment)==0 ) blob_append(&comment, " ", 1); | < < < | 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 | blob_appendf(&comment, " with note \"%h\".", zValue); }else{ blob_appendf(&comment, "."); } } /*blob_appendf(&comment, " [[/info/%S | details]]");*/ if( blob_size(&comment)==0 ) blob_append(&comment, " ", 1); db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('g',%.17g,%d,%Q,%Q)", p->rDate, rid, p->zUser, blob_str(&comment)+1 ); blob_reset(&comment); } if( p->type==CFTYPE_FORUM ){ int froot, fprev, firt; char *zFType; char *zTitle; schema_forum(); froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid; fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0; firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0; db_multi_exec( "REPLACE INTO forumpost(fpid,froot,fprev,firt,fmtime)" "VALUES(%d,%d,nullif(%d,0),nullif(%d,0),%.17g)", p->rid, froot, fprev, firt, p->rDate ); if( firt==0 ){ /* This is the start of a new thread, either the initial entry ** or an edit of the initial entry. */ zTitle = p->zThreadTitle; if( zTitle==0 || zTitle[0]==0 ){ zTitle = "(Deleted)"; } zFType = fprev ? "Edit" : "Post"; db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('f',%.17g,%d,%Q,'%q: %q')", p->rDate, rid, p->zUser, zFType, zTitle ); /* ** If this edit is the most recent, then make it the title for |
︙ | ︙ | |||
2854 2855 2856 2857 2858 2859 2860 | if( p->zWiki[0]==0 ){ zFType = "Delete reply"; }else if( fprev ){ zFType = "Edit reply"; }else{ zFType = "Reply"; } | < < < < | < < | 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 | if( p->zWiki[0]==0 ){ zFType = "Delete reply"; }else if( fprev ){ zFType = "Edit reply"; }else{ zFType = "Reply"; } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('f',%.17g,%d,%Q,'%q: %q')", p->rDate, rid, p->zUser, zFType, zTitle ); fossil_free(zTitle); } } db_end_transaction(0); if( permitHooks ){ rc = xfer_run_common_script(); if( rc==TH_OK ){ rc = xfer_run_script(zScript, zUuid, 0); } } |
︙ | ︙ |
Changes to src/markdown.c.
︙ | ︙ | |||
43 44 45 46 47 48 49 | }; /* mkd_renderer -- functions for rendering parsed data */ struct mkd_renderer { /* document level callbacks */ void (*prolog)(struct Blob *ob, void *opaque); void (*epilog)(struct Blob *ob, void *opaque); | < < < | < < > | 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 | }; /* mkd_renderer -- functions for rendering parsed data */ struct mkd_renderer { /* document level callbacks */ void (*prolog)(struct Blob *ob, void *opaque); void (*epilog)(struct Blob *ob, void *opaque); /* block level callbacks - NULL skips the block */ void (*blockcode)(struct Blob *ob, struct Blob *text, void *opaque); void (*blockquote)(struct Blob *ob, struct Blob *text, void *opaque); void (*blockhtml)(struct Blob *ob, struct Blob *text, void *opaque); void (*header)(struct Blob *ob, struct Blob *text, int level, void *opaque); void (*hrule)(struct Blob *ob, void *opaque); void (*list)(struct Blob *ob, struct Blob *text, int flags, void *opaque); void (*listitem)(struct Blob *ob, struct Blob *text, int flags, void *opaque); void (*paragraph)(struct Blob *ob, struct Blob *text, void *opaque); void (*table)(struct Blob *ob, struct Blob *head_row, struct Blob *rows, void *opaque); void (*table_cell)(struct Blob *ob, struct Blob *text, int flags, void *opaque); void (*table_row)(struct Blob *ob, struct Blob *cells, int flags, void *opaque); /* span level callbacks - NULL or return 0 prints the span verbatim */ int (*autolink)(struct Blob *ob, struct Blob *link, enum mkd_autolink type, void *opaque); int (*codespan)(struct Blob *ob, struct Blob *text, void *opaque); int (*double_emphasis)(struct Blob *ob, struct Blob *text, char c, void *opaque); int (*emphasis)(struct Blob *ob, struct Blob *text, char c,void*opaque); int (*image)(struct Blob *ob, struct Blob *link, struct Blob *title, struct Blob *alt, void *opaque); int (*linebreak)(struct Blob *ob, void *opaque); int (*link)(struct Blob *ob, struct Blob *link, struct Blob *title, struct Blob *content, void *opaque); int (*raw_html_tag)(struct Blob *ob, struct Blob *tag, void *opaque); int (*triple_emphasis)(struct Blob *ob, struct Blob *text, char c, void *opaque); /* low level callbacks - NULL copies input directly into the output */ void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque); void (*normal_text)(struct Blob *ob, struct Blob *text, void *opaque); /* renderer data */ int max_work_stack; /* prevent arbitrary deep recursion, cf README */ const char *emph_chars; /* chars that trigger emphasis rendering */ void *opaque; /* opaque data send to every rendering callback */ }; /********* |
︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 119 | #define MKD_CELL_ALIGN_DEFAULT 0 #define MKD_CELL_ALIGN_LEFT 1 #define MKD_CELL_ALIGN_RIGHT 2 #define MKD_CELL_ALIGN_CENTER 3 /* LEFT | RIGHT */ #define MKD_CELL_ALIGN_MASK 3 #define MKD_CELL_HEAD 4 #endif /* INTERFACE */ | > > > > > > > > > > > > < < < < | < | < < < < < < < < < < < < < < < < < < < | | < < < < < < > | < < < < < > | > > > > > > > > > > > > > > > > > > > > > > > < | < < | 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 | #define MKD_CELL_ALIGN_DEFAULT 0 #define MKD_CELL_ALIGN_LEFT 1 #define MKD_CELL_ALIGN_RIGHT 2 #define MKD_CELL_ALIGN_CENTER 3 /* LEFT | RIGHT */ #define MKD_CELL_ALIGN_MASK 3 #define MKD_CELL_HEAD 4 /********************** * EXPORTED FUNCTIONS * **********************/ /* markdown -- parses the input buffer and renders it into the output buffer */ void markdown( struct Blob *ob, struct Blob *ib, const struct mkd_renderer *rndr); #endif /* INTERFACE */ /*************** * LOCAL TYPES * ***************/ /* link_ref -- reference to a link */ struct link_ref { struct Blob id; struct Blob link; struct Blob title; }; /* char_trigger -- function pointer to render active chars */ /* returns the number of chars taken care of */ /* data is the pointer of the beginning of the span */ /* offset is the number of valid chars before data */ struct render; typedef size_t (*char_trigger)( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size); /* render -- structure containing one particular render */ struct render { struct mkd_renderer make; struct Blob refs; char_trigger active_char[256]; int work_active; struct Blob *work; }; /* html_tag -- structure for quick HTML tag search (inspired from discount) */ struct html_tag { const char *text; int size; }; /******************** * GLOBAL VARIABLES * ********************/ /* block_tags -- recognised block tags, sorted by cmp_html_tag */ static const struct html_tag block_tags[] = { { "p", 1 }, { "dl", 2 }, { "h1", 2 }, { "h2", 2 }, { "h3", 2 }, { "h4", 2 }, { "h5", 2 }, { "h6", 2 }, { "ol", 2 }, { "ul", 2 }, { "del", 3 }, { "div", 3 }, { "ins", 3 }, { "pre", 3 }, { "form", 4 }, { "math", 4 }, { "table", 5 }, { "iframe", 6 }, { "script", 6 }, { "fieldset", 8 }, { "noscript", 8 }, { "blockquote", 10 } }; #define INS_TAG (block_tags + 12) #define DEL_TAG (block_tags + 10) /*************************** * STATIC HELPER FUNCTIONS * ***************************/ /* build_ref_id -- collapse whitespace from input text to make it a ref id */ static int build_ref_id(struct Blob *id, const char *data, size_t size){ size_t beg, i; char *id_data; /* skip leading whitespace */ while( size>0 && (data[0]==' ' || data[0]=='\t' || data[0]=='\n') ){ data++; |
︙ | ︙ | |||
241 242 243 244 245 246 247 | beg = i; while( i<size && !(data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; } blob_append(id, data+beg, i-beg); /* add a single space and skip all consecutive whitespace */ | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | beg = i; while( i<size && !(data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; } blob_append(id, data+beg, i-beg); /* add a single space and skip all consecutive whitespace */ if( i<size ) blob_append(id, " ", 1); while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; } } /* turn upper-case ASCII into their lower-case counterparts */ id_data = blob_buffer(id); for(i=0; i<blob_size(id); i++){ if( id_data[i]>='A' && id_data[i]<='Z' ) id_data[i] += 'a' - 'A'; |
︙ | ︙ | |||
268 269 270 271 272 273 274 | /* cmp_link_ref_sort -- comparison function for link_ref qsort */ static int cmp_link_ref_sort(const void *a, const void *b){ struct link_ref *lra = (void *)a; struct link_ref *lrb = (void *)b; return blob_compare(&lra->id, &lrb->id); } | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | /* cmp_link_ref_sort -- comparison function for link_ref qsort */ static int cmp_link_ref_sort(const void *a, const void *b){ struct link_ref *lra = (void *)a; struct link_ref *lrb = (void *)b; return blob_compare(&lra->id, &lrb->id); } /* cmp_html_tag -- comparison function for bsearch() (stolen from discount) */ static int cmp_html_tag(const void *a, const void *b){ const struct html_tag *hta = a; const struct html_tag *htb = b; if( hta->size!=htb->size ) return hta->size-htb->size; return fossil_strnicmp(hta->text, htb->text, hta->size); } /* find_block_tag -- returns the current block tag */ static const struct html_tag *find_block_tag(const char *data, size_t size){ size_t i = 0; struct html_tag key; |
︙ | ︙ | |||
355 356 357 358 359 360 361 | return bsearch(&key, block_tags, count(block_tags), sizeof block_tags[0], cmp_html_tag); } | < < < | < | < | | | | > | < < | | < | < < < < < | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | return bsearch(&key, block_tags, count(block_tags), sizeof block_tags[0], cmp_html_tag); } /* new_work_buffer -- get a new working buffer from the stack or create one */ static struct Blob *new_work_buffer(struct render *rndr){ struct Blob *ret = 0; if( rndr->work_active < rndr->make.max_work_stack ){ ret = rndr->work + rndr->work_active; rndr->work_active += 1; blob_reset(ret); } return ret; } /* release_work_buffer -- release the given working buffer */ static void release_work_buffer(struct render *rndr, struct Blob *buf){ if( !buf ) return; assert(rndr->work_active>0 && buf==(rndr->work+rndr->work_active-1)); rndr->work_active -= 1; } /**************************** * INLINE PARSING FUNCTIONS * ****************************/ |
︙ | ︙ | |||
426 427 428 429 430 431 432 | /* a valid tag can't be shorter than 3 chars */ if( size<3 ) return 0; /* begins with a '<' optionally followed by '/', followed by letter */ if( data[0]!='<' ) return 0; i = (data[1]=='/') ? 2 : 1; if( (data[i]<'a' || data[i]>'z') && (data[i]<'A' || data[i]>'Z') ){ | < < < < | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | /* a valid tag can't be shorter than 3 chars */ if( size<3 ) return 0; /* begins with a '<' optionally followed by '/', followed by letter */ if( data[0]!='<' ) return 0; i = (data[1]=='/') ? 2 : 1; if( (data[i]<'a' || data[i]>'z') && (data[i]<'A' || data[i]>'Z') ){ return 0; } /* scheme test */ *autolink = MKDA_NOT_AUTOLINK; if( size>6 && fossil_strnicmp(data+1, "http", 4)==0 |
︙ | ︙ | |||
492 493 494 495 496 497 498 | char *data, size_t size ){ size_t i = 0, end = 0; char_trigger action = 0; struct Blob work = BLOB_INITIALIZER; | < < < < | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | char *data, size_t size ){ size_t i = 0, end = 0; char_trigger action = 0; struct Blob work = BLOB_INITIALIZER; while( i<size ){ /* copying inactive chars into the output */ while( end<size && (action = rndr->active_char[(unsigned char)data[end]])==0 ){ end++; } |
︙ | ︙ | |||
526 527 528 529 530 531 532 | }else{ i += end; end = i; } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | > > | > > > > > > > > > > > > > > > > > > | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | }else{ i += end; end = i; } } } /* find_emph_char -- looks for the next emph char, skipping other constructs */ static size_t find_emph_char(char *data, size_t size, char c){ size_t i = 1; while( i<size ){ while( i<size && data[i]!=c && data[i]!='`' && data[i]!='[' ){ i++; } if( i>=size ) return 0; /* not counting escaped chars */ if( i && data[i-1]=='\\' ){ i++; continue; } if( data[i]==c ) return i; /* skipping a code span */ if( data[i]=='`' ){ size_t span_nb = 0, bt; size_t tmp_i = 0; /* counting the number of opening backticks */ while( i<size && data[i]=='`' ){ i++; span_nb++; } if( i>=size ) return 0; /* finding the matching closing sequence */ bt = 0; while( i<size && bt<span_nb ){ if( !tmp_i && data[i]==c ) tmp_i = i; if( data[i]=='`' ) bt += 1; else bt = 0; i++; } if( i>=size ) return tmp_i; i++; /* skipping a link */ }else if( data[i]=='[' ){ size_t tmp_i = 0; char cc; i++; while( i<size && data[i]!=']' ){ if( !tmp_i && data[i]==c ) tmp_i = i; i++; } |
︙ | ︙ | |||
615 616 617 618 619 620 621 | if( i>=size ) return tmp_i; i++; } } return 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | | < < < | | | > | | < < < > | | | > | | | < | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | if( i>=size ) return tmp_i; i++; } } return 0; } /* parse_emph1 -- parsing single emphasis */ /* closed by a symbol not preceded by whitespace and not followed by symbol */ static size_t parse_emph1( struct Blob *ob, struct render *rndr, char *data, size_t size, char c ){ size_t i = 0, len; struct Blob *work = 0; int r; if( !rndr->make.emphasis ) return 0; /* skipping one symbol if coming from emph3 */ if( size>1 && data[0]==c && data[1]==c ) i = 1; while( i<size ){ len = find_emph_char(data+i, size-i, c); if( !len ) return 0; i += len; if( i>=size ) return 0; if( i+1<size && data[i+1]==c ){ i++; continue; } if( data[i]==c && data[i-1]!=' ' && data[i-1]!='\t' && data[i-1]!='\n' ){ work = new_work_buffer(rndr); if( !work ) return 0; parse_inline(work, rndr, data, i); r = rndr->make.emphasis(ob, work, c, rndr->make.opaque); release_work_buffer(rndr, work); return r ? i+1 : 0; } } return 0; } /* parse_emph2 -- parsing single emphasis */ static size_t parse_emph2( struct Blob *ob, struct render *rndr, char *data, size_t size, char c ){ size_t i = 0, len; struct Blob *work = 0; int r; if( !rndr->make.double_emphasis ) return 0; while( i<size ){ len = find_emph_char(data+i, size-i, c); if( !len ) return 0; i += len; if( i+1<size && data[i]==c && data[i+1]==c && i && data[i-1]!=' ' && data[i-1]!='\t' && data[i-1]!='\n' ){ work = new_work_buffer(rndr); if( !work ) return 0; parse_inline(work, rndr, data, i); r = rndr->make.double_emphasis(ob, work, c, rndr->make.opaque); release_work_buffer(rndr, work); return r ? i+2 : 0; } i++; } return 0; } /* parse_emph3 -- parsing single emphasis */ /* finds the first closing tag, and delegates to the other emph */ static size_t parse_emph3( struct Blob *ob, struct render *rndr, char *data, size_t size, char c ){ |
︙ | ︙ | |||
764 765 766 767 768 769 770 | continue; } if( i+2<size && data[i+1]==c && data[i+2] == c && rndr->make.triple_emphasis | < > | | < < > | | > | | > | | > | | < | | < < | | | | < | < | | | < | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | continue; } if( i+2<size && data[i+1]==c && data[i+2] == c && rndr->make.triple_emphasis ){ /* triple symbol found */ struct Blob *work = new_work_buffer(rndr); if( !work ) return 0; parse_inline(work, rndr, data, i); r = rndr->make.triple_emphasis(ob, work, c, rndr->make.opaque); release_work_buffer(rndr, work); return r ? i+3 : 0; }else if( i+1<size && data[i+1]==c ){ /* double symbol found, handing over to emph1 */ len = parse_emph1(ob, rndr, data-2, size+2, c); return len ? len-2 : 0; }else{ /* single symbol found, handing over to emph2 */ len = parse_emph2(ob, rndr, data-1, size+1, c); return len ? len-1 : 0; } } return 0; } /* char_emphasis -- single and double emphasis parsing */ static size_t char_emphasis( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ char c = data[0]; size_t ret; if( size>2 && data[1]!=c ){ /* whitespace cannot follow an opening emphasis */ if( data[1]==' ' || data[1]=='\t' || data[1]=='\n' || (ret = parse_emph1(ob, rndr, data+1, size-1, c))==0 ){ return 0; } return ret+1; } if( size>3 && data[1]==c && data[2]!=c ){ if( data[2]==' ' || data[2]=='\t' || data[2]=='\n' || (ret = parse_emph2(ob, rndr, data+2, size-2, c))==0 ){ return 0; } return ret+2; } if( size>4 && data[1]==c && data[2]==c && data[3]!=c ){ if( data[3]==' ' || data[3]=='\t' || data[3]=='\n' || (ret = parse_emph3(ob, rndr, data+3, size-3, c))==0 ){ return 0; } return ret+3; } return 0; } /* char_linebreak -- '\n' preceded by two spaces (assuming linebreak != 0) */ static size_t char_linebreak( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ if( offset<2 || data[-1]!=' ' || data[-2]!=' ' ) return 0; /* removing the last space from ob and rendering */ if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]==' ' ) ob->nUsed--; return rndr->make.linebreak(ob, rndr->make.opaque) ? 1 : 0; } /* char_codespan -- '`' parsing a code span (assuming codespan != 0) */ static size_t char_codespan( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ size_t end, nb = 0, i, f_begin, f_end; /* counting the number of backticks in the delimiter */ while( nb<size && data[nb]=='`' ){ nb++; } /* finding the next delimiter */ i = 0; for(end=nb; end<size && i<nb; end++){ if( data[end]=='`' ) i++; else i = 0; } if( i<nb && end>=size ) return 0; /* no matching delimiter */ /* trimming outside whitespaces */ f_begin = nb; while( f_begin<end && (data[f_begin]==' ' || data[f_begin]=='\t') ){ f_begin++; } f_end = end-nb; while( f_end>nb && (data[f_end-1]==' ' || data[f_end-1]=='\t') ){ f_end--; } /* real code span */ if( f_begin<f_end ){ struct Blob work = BLOB_INITIALIZER; blob_init(&work, data+f_begin, f_end-f_begin); if( !rndr->make.codespan(ob, &work, rndr->make.opaque) ) end = 0; }else{ if( !rndr->make.codespan(ob, 0, rndr->make.opaque) ) end = 0; } return end; } /* char_escape -- '\\' backslash escape */ static size_t char_escape( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ struct Blob work = BLOB_INITIALIZER; if( size>1 ){ if( rndr->make.normal_text ){ blob_init(&work, data+1,1); rndr->make.normal_text(ob, &work, rndr->make.opaque); }else{ blob_append(ob, data+1, 1); } } return 2; } /* char_entity -- '&' escaped when it doesn't belong to an entity */ /* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ static size_t char_entity( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ |
︙ | ︙ | |||
949 950 951 952 953 954 955 | rndr->make.entity(ob, &work, rndr->make.opaque); }else{ blob_append(ob, data, end); } return end; } | | | < | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | rndr->make.entity(ob, &work, rndr->make.opaque); }else{ blob_append(ob, data, end); } return end; } /* char_langle_tag -- '<' when tags or autolinks are allowed */ static size_t char_langle_tag( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ |
︙ | ︙ | |||
980 981 982 983 984 985 986 | if( !ret ){ return 0; }else{ return end; } } | | | | 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 | if( !ret ){ return 0; }else{ return end; } } /* get_link_inline -- extract inline-style link and title from ** parenthesed data */ static int get_link_inline( struct Blob *link, struct Blob *title, char *data, size_t size |
︙ | ︙ | |||
1035 1036 1037 1038 1039 1040 1041 | || data[link_e-1]=='\n') ){ link_e--; } /* remove optional angle brackets around the link */ if( data[link_b]=='<' ) link_b += 1; | | < | < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < | | < | > > > > > > > > | | > > > > > > > > > > > | | < < < | | < < | | < | < < | < | | < > | < > < < < < < < < | < < < < | | | | | | < | > | | | | | | | | | | < < < | | < < | | | > | > | | | | | > | | | | | | | | < < < < < < < > | 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 | || data[link_e-1]=='\n') ){ link_e--; } /* remove optional angle brackets around the link */ if( data[link_b]=='<' ) link_b += 1; if( data[link_e-1]=='>' ) link_e -= 1; /* escape backslashed character from link */ blob_reset(link); i = link_b; while( i<link_e ){ mark = i; while( i<link_e && data[i]!='\\' ){ i++; } blob_append(link, data+mark, i-mark); while( i<link_e && data[i]=='\\' ){ i++; } } /* handing back title */ blob_reset(title); if( title_e>title_b ) blob_append(title, data+title_b, title_e-title_b); /* this function always succeed */ return 0; } /* get_link_ref -- extract referenced link and title from id */ static int get_link_ref( struct render *rndr, struct Blob *link, struct Blob *title, char *data, size_t size ){ struct link_ref *lr; /* find the link from its id (stored temporarily in link) */ blob_reset(link); if( build_ref_id(link, data, size)<0 ) return -1; lr = bsearch(link, blob_buffer(&rndr->refs), blob_size(&rndr->refs)/sizeof(struct link_ref), sizeof (struct link_ref), cmp_link_ref); if( !lr ) return -1; /* fill the output buffers */ blob_reset(link); blob_reset(title); blob_append(link, blob_buffer(&lr->link), blob_size(&lr->link)); blob_append(title, blob_buffer(&lr->title), blob_size(&lr->title)); return 0; } /* char_link -- '[': parsing a link or an image */ static size_t char_link( struct Blob *ob, struct render *rndr, char *data, size_t offset, size_t size ){ int is_img = (offset && data[-1] == '!'), level; size_t i = 1, txt_e; struct Blob *content = 0; struct Blob *link = 0; struct Blob *title = 0; int ret; /* checking whether the correct renderer exists */ if( (is_img && !rndr->make.image) || (!is_img && !rndr->make.link) ){ return 0; } /* looking for the matching closing bracket */ for(level=1; i<size; i++){ if( data[i]=='\n' ) /* do nothing */; else if( data[i-1]=='\\' ) continue; else if( data[i]=='[' ) level += 1; else if( data[i]==']' ){ level--; if( level<=0 ) break; } } if( i>=size ) return 0; txt_e = i; i++; /* skip any amount of whitespace or newline */ /* (this is much more laxist than original markdown syntax) */ while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; } /* allocate temporary buffers to store content, link and title */ content = new_work_buffer(rndr); link = new_work_buffer(rndr); title = new_work_buffer(rndr); if( !title ) return 0; ret = 0; /* error if we don't get to the callback */ /* inline style link */ if( i<size && data[i]=='(' ){ size_t span_end = i; while( span_end<size && !(data[span_end]==')' && (span_end==i || data[span_end-1]!='\\')) ){ span_end++; } if( span_end>=size || get_link_inline(link, title, data+i+1, span_end-(i+1))<0 ){ goto char_link_cleanup; } i = span_end+1; /* reference style link */ }else if( i<size && data[i]=='[' ){ char *id_data; size_t id_size, id_end = i; while( id_end<size && data[id_end]!=']' ){ id_end++; } if( id_end>=size ) goto char_link_cleanup; if( i+1==id_end ){ /* implicit id - use the contents */ id_data = data+1; id_size = txt_e-1; }else{ /* explicit id - between brackets */ id_data = data+i+1; id_size = id_end-(i+1); } if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){ goto char_link_cleanup; } i = id_end+1; /* shortcut reference style link */ }else{ if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){ goto char_link_cleanup; } /* rewinding the whitespace */ i = txt_e+1; } /* building content: img alt is escaped, link content is parsed */ if( txt_e>1 ){ if( is_img ) blob_append(content, data+1, txt_e-1); else parse_inline(content, rndr, data+1, txt_e-1); } /* calling the relevant rendering function */ if( is_img ){ if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]=='!' ) ob->nUsed--; ret = rndr->make.image(ob, link, title, content, rndr->make.opaque); }else{ ret = rndr->make.link(ob, link, title, content, rndr->make.opaque); } /* cleanup */ char_link_cleanup: release_work_buffer(rndr, title); release_work_buffer(rndr, link); release_work_buffer(rndr, content); return ret ? i : 0; } /********************************* * BLOCK-LEVEL PARSING FUNCTIONS * *********************************/ /* is_empty -- returns the line length when it is empty, 0 otherwise */ |
︙ | ︙ | |||
1507 1508 1509 1510 1511 1512 1513 | /* check for initial '|' */ if( i<size && data[i]=='|') outer_sep++; /* count the number of pipes in the line */ for(n_sep=0; i<size && data[i]!='\n'; i++){ if( is_table_sep(data, i) ) n_sep++; | < < < < | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | /* check for initial '|' */ if( i<size && data[i]=='|') outer_sep++; /* count the number of pipes in the line */ for(n_sep=0; i<size && data[i]!='\n'; i++){ if( is_table_sep(data, i) ) n_sep++; } /* march back to check for optional last '|' before blanks and EOL */ while( i && (data[i-1]==' ' || data[i-1]=='\t' || data[i-1]=='\n') ){ i--; } if( i && is_table_sep(data, i-1) ) outer_sep += 1; /* return the number of column or 0 if it's not a table line */ |
︙ | ︙ | |||
1549 1550 1551 1552 1553 1554 1555 | if( size>0 && data[0]=='\t' ) return 1; if( size>3 && data[0]==' ' && data[1]==' ' && data[2]==' ' && data[3]==' ' ){ return 4; } return 0; } | < < < < < < < < < < < < | | 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 | if( size>0 && data[0]=='\t' ) return 1; if( size>3 && data[0]==' ' && data[1]==' ' && data[2]==' ' && data[3]==' ' ){ return 4; } return 0; } /* prefix_oli -- returns ordered list item prefix */ static size_t prefix_oli(char *data, size_t size){ size_t i = 0; if( i<size && data[i]==' ') i++; if( i<size && data[i]==' ') i++; if( i<size && data[i]==' ') i++; if( i>=size || data[i]<'0' || data[i]>'9' ) return 0; while( i<size && data[i]>='0' && data[i]<='9' ){ i++; } if( i+1>=size || data[i]!='.' || (data[i+1]!=' ' && data[i+1]!='\t') ){ return 0; } i = i+2; while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; } return i; |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | /* parse_blockquote -- handles parsing of a blockquote fragment */ static size_t parse_blockquote( struct Blob *ob, struct render *rndr, char *data, size_t size ){ | | < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | > < < < | < < | < < < < > | > > > | > | > > > | > | | > > > > > < < < | < < | | > | 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 | /* parse_blockquote -- handles parsing of a blockquote fragment */ static size_t parse_blockquote( struct Blob *ob, struct render *rndr, char *data, size_t size ){ size_t beg, end = 0, pre, work_size = 0; char *work_data = 0; struct Blob *out = new_work_buffer(rndr); beg = 0; while( beg<size ){ for(end=beg+1; end<size && data[end-1]!='\n'; end++); pre = prefix_quote(data+beg, end-beg); if( pre ){ beg += pre; /* skipping prefix */ }else if( is_empty(data+beg, end-beg) && (end>=size || (prefix_quote(data+end, size-end)==0 && !is_empty(data+end, size-end))) ){ /* empty line followed by non-quote line */ break; } if( beg<end ){ /* copy into the in-place working buffer */ if( !work_data ){ work_data = data+beg; }else if( (data+beg)!=(work_data+work_size) ){ memmove(work_data+work_size, data+beg, end-beg); } work_size += end-beg; } beg = end; } if( rndr->make.blockquote ){ struct Blob fallback = BLOB_INITIALIZER; if( out ){ parse_block(out, rndr, work_data, work_size); }else{ blob_init(&fallback, work_data, work_size); } rndr->make.blockquote(ob, out ? out : &fallback, rndr->make.opaque); } release_work_buffer(rndr, out); return end; } /* parse_paragraph -- handles parsing of a regular paragraph */ static size_t parse_paragraph( struct Blob *ob, struct render *rndr, char *data, size_t size ){ size_t i = 0, end = 0; int level = 0; char *work_data = data; size_t work_size = 0; struct Blob fallback = BLOB_INITIALIZER; while( i<size ){ for(end=i+1; end<size && data[end-1]!='\n'; end++); if( is_empty(data+i, size-i) || (level = is_headerline(data+i, size-i))!= 0 ){ break; } if( (i && data[i]=='#') || is_hrule(data+i, size-i) ){ end = i; break; } i = end; } work_size = i; while( work_size && data[work_size-1]=='\n' ){ work_size--; } if( !level ){ if( rndr->make.paragraph ){ struct Blob *tmp = new_work_buffer(rndr); if( tmp ){ parse_inline(tmp, rndr, work_data, work_size); }else{ blob_init(&fallback, work_data, work_size); } rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque); release_work_buffer(rndr, tmp); } }else{ if( work_size ){ size_t beg; i = work_size; work_size -= 1; while( work_size && data[work_size]!='\n' ){ work_size--; } beg = work_size+1; while( work_size && data[work_size-1]=='\n'){ work_size--; } if( work_size ){ struct Blob *tmp = new_work_buffer(rndr); if( tmp ){ parse_inline(tmp, rndr, work_data, work_size); }else{ blob_init (&fallback, work_data, work_size); } if( rndr->make.paragraph ){ rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque); } release_work_buffer(rndr, tmp); work_data += beg; work_size = i - beg; }else{ work_size = i; } } if( rndr->make.header ){ struct Blob *span = new_work_buffer(rndr); if( span ){ parse_inline(span, rndr, work_data, work_size); rndr->make.header(ob, span, level, rndr->make.opaque); }else{ blob_init(&fallback, work_data, work_size); rndr->make.header(ob, &fallback, level, rndr->make.opaque); } release_work_buffer(rndr, span); } } return end; } /* parse_blockcode -- handles parsing of a block-level code fragment */ static size_t parse_blockcode( struct Blob *ob, struct render *rndr, char *data, size_t size ){ size_t beg, end, pre; struct Blob *work = new_work_buffer(rndr); if( !work ) work = ob; beg = 0; while( beg<size ){ for(end=beg+1; end<size && data[end-1]!='\n'; end++); pre = prefix_code(data+beg, end-beg); if( pre ){ beg += pre; /* skipping prefix */ }else if( !is_empty(data+beg, end-beg) ){ /* non-empty non-prefixed line breaks the pre */ break; } if( beg<end ){ /* verbatim copy to the working buffer, escaping entities */ if( is_empty(data + beg, end - beg) ){ blob_append(work, "\n", 1); }else{ blob_append(work, data+beg, end-beg); } } beg = end; } end = blob_size(work); while( end>0 && blob_buffer(work)[end-1]=='\n' ){ end--; } work->nUsed = end; blob_append(work, "\n", 1); if( work!=ob ){ if( rndr->make.blockcode ){ rndr->make.blockcode(ob, work, rndr->make.opaque); } release_work_buffer(rndr, work); } return beg; } /* parse_listitem -- parsing of a single list item */ /* assuming initial prefix is already removed */ static size_t parse_listitem( struct Blob *ob, struct render *rndr, char *data, size_t size, int *flags ){ struct Blob fallback = BLOB_INITIALIZER; struct Blob *work = 0, *inter = 0; size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; int in_empty = 0, has_inside_empty = 0; /* keeping track of the first indentation prefix */ if( size>1 && data[0]==' ' ){ orgpre = 1; |
︙ | ︙ | |||
1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 | /* skipping to the beginning of the following line */ end = beg; while( end<size && data[end-1]!='\n' ){ end++; } /* getting working buffers */ work = new_work_buffer(rndr); inter = new_work_buffer(rndr); /* putting the first line into the working buffer */ blob_append(work, data+beg, end-beg); beg = end; /* process the following lines */ while( beg<size ){ | > | 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 | /* skipping to the beginning of the following line */ end = beg; while( end<size && data[end-1]!='\n' ){ end++; } /* getting working buffers */ work = new_work_buffer(rndr); inter = new_work_buffer(rndr); if( !work ) work = &fallback; /* putting the first line into the working buffer */ blob_append(work, data+beg, end-beg); beg = end; /* process the following lines */ while( beg<size ){ |
︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 | if( !sublist ) sublist = blob_size(work); /* joining only indented stuff after empty lines */ }else if( in_empty && i<4 && data[beg]!='\t' ){ *flags |= MKD_LI_END; break; }else if( in_empty ){ | | | > | 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 | if( !sublist ) sublist = blob_size(work); /* joining only indented stuff after empty lines */ }else if( in_empty && i<4 && data[beg]!='\t' ){ *flags |= MKD_LI_END; break; }else if( in_empty ){ blob_append(work, "\n", 1); has_inside_empty = 1; } in_empty = 0; /* adding the line without prefix into the working buffer */ blob_append(work, data+beg+i, end-beg-i); beg = end; } /* non-recursive fallback when working buffer stack is full */ if( !inter ){ if( rndr->make.listitem ){ rndr->make.listitem(ob, work, *flags, rndr->make.opaque); } if( work!=&fallback ) release_work_buffer(rndr, work); blob_reset(&fallback); return beg; } /* render of li contents */ if( has_inside_empty ) *flags |= MKD_LI_BLOCK; if( *flags & MKD_LI_BLOCK ){ /* intermediate render of block li */ |
︙ | ︙ | |||
1944 1945 1946 1947 1948 1949 1950 | } /* render of li itself */ if( rndr->make.listitem ){ rndr->make.listitem(ob, inter, *flags, rndr->make.opaque); } release_work_buffer(rndr, inter); | | > > > | > | < > > > | > > > | | | 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 | } /* render of li itself */ if( rndr->make.listitem ){ rndr->make.listitem(ob, inter, *flags, rndr->make.opaque); } release_work_buffer(rndr, inter); if( work!=&fallback ) release_work_buffer(rndr, work); blob_reset(&fallback); return beg; } /* parse_list -- parsing ordered or unordered list block */ static size_t parse_list( struct Blob *ob, struct render *rndr, char *data, size_t size, int flags ){ struct Blob fallback = BLOB_INITIALIZER; struct Blob *work = new_work_buffer(rndr); size_t i = 0, j; if( !work ) work = &fallback; while( i<size ){ j = parse_listitem(work, rndr, data+i, size-i, &flags); i += j; if( !j || (flags & MKD_LI_END) ) break; } if( rndr->make.list ) rndr->make.list(ob, work, flags, rndr->make.opaque); if( work!=&fallback ) release_work_buffer(rndr, work); blob_reset(&fallback); return i; } /* parse_atxheader -- parsing of atx-style headers */ static size_t parse_atxheader( struct Blob *ob, struct render *rndr, char *data, size_t size ){ int level = 0; size_t i, end, skip, span_beg, span_size; if( !size || data[0]!='#' ) return 0; while( level<size && level<6 && data[level]=='#' ){ level++; } for(i=level; i<size && (data[i]==' ' || data[i]=='\t'); i++); span_beg = i; for(end=i; end<size && data[end]!='\n'; end++); skip = end; if( end<=i ) return parse_paragraph(ob, rndr, data, size); while( end && data[end-1]=='#' ){ end--; } while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; } if( end<=i ) return parse_paragraph(ob, rndr, data, size); span_size = end-span_beg; if( rndr->make.header ){ struct Blob fallback = BLOB_INITIALIZER; struct Blob *span = new_work_buffer(rndr); if( span ){ parse_inline(span, rndr, data+span_beg, span_size); }else{ blob_init(&fallback, data+span_beg, span_size); } rndr->make.header(ob, span ? span : &fallback, level, rndr->make.opaque); release_work_buffer(rndr, span); } return skip; } /* htmlblock_end -- checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */ /* returns the length on match, 0 otherwise */ static size_t htmlblock_end( const struct html_tag *tag, const char *data, size_t size ){ size_t i, w; /* assuming data[0]=='<' && data[1]=='/' already tested */ /* checking tag is a match */ if( (tag->size+3)>=size || fossil_strnicmp(data+2, tag->text, tag->size) || data[tag->size+2]!='>' ){ return 0; } /* checking white lines */ |
︙ | ︙ | |||
2105 2106 2107 2108 2109 2110 2111 | } } /* no special case recognised */ return 0; } | | | > | > > | > > > > > > > > > > > > > > > > > > > < < < < < < < | < > > > | > > > | | 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 | } } /* no special case recognised */ return 0; } /* looking for an unindented matching closing tag */ /* followed by a blank line */ i = 1; found = 0; #if 0 while( i<size ){ i++; while( i<size && !(data[i-2]=='\n' && data[i-1]=='<' && data[i]=='/') ){ i++; } if( (i+2+curtag->size)>=size ) break; j = htmlblock_end(curtag, data+i-1, size-i+1); if (j) { i += j-1; found = 1; break; } } #endif /* if not found, trying a second pass looking for indented match */ /* but not if tag is "ins" or "del" (following original Markdown.pl) */ if( !found && curtag!=INS_TAG && curtag!=DEL_TAG ){ i = 1; while( i<size ){ i++; while( i<size && !(data[i-1]=='<' && data[i]=='/') ){ i++; } if( (i+2+curtag->size)>=size ) break; j = htmlblock_end(curtag, data+i-1, size-i+1); if (j) { i += j-1; found = 1; break; } } } if( !found ) return 0; /* the end of the block has been found */ blob_init(&work, data, i); if( rndr->make.blockhtml ){ rndr->make.blockhtml(ob, &work, rndr->make.opaque); } return i; } /* parse_table_cell -- parse a cell inside a table */ static void parse_table_cell( struct Blob *ob, /* output blob */ struct render *rndr, /* renderer description */ char *data, /* input text */ size_t size, /* input text size */ int flags /* table flags */ ){ struct Blob fallback = BLOB_INITIALIZER; struct Blob *span = new_work_buffer(rndr); if( span ){ parse_inline(span, rndr, data, size); }else{ blob_init(&fallback, data, size); } rndr->make.table_cell(ob, span ? span : &fallback, flags, rndr->make.opaque); release_work_buffer(rndr, span); } /* parse_table_row -- parse an input line into a table row */ static size_t parse_table_row( struct Blob *ob, /* output blob for rendering */ |
︙ | ︙ | |||
2187 2188 2189 2190 2191 2192 2193 | } /* skip blanks */ while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; } beg = i; /* forward to the next separator or EOL */ | | < < < < < < | 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | } /* skip blanks */ while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; } beg = i; /* forward to the next separator or EOL */ while( i<size && !is_table_sep(data, i) && data[i]!='\n' ){ i++; } end = i; if( i<size ){ i++; if( data[i-1]=='\n' ) total = i; } /* check optional right/center align marker */ |
︙ | ︙ | |||
2217 2218 2219 2220 2221 2222 2223 | /* (because it is only the optional end separator) */ if( total && end<=beg ) continue; /* fallback on default alignment if not explicit */ if( align==0 && aligns && col<align_size ) align = aligns[col]; /* render cells */ | < | < > | > > > > > > > | | 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 | /* (because it is only the optional end separator) */ if( total && end<=beg ) continue; /* fallback on default alignment if not explicit */ if( align==0 && aligns && col<align_size ) align = aligns[col]; /* render cells */ if( cells ) parse_table_cell(cells, rndr, data+beg, end-beg, align|flags); col++; } /* render the whole row and clean up */ if( cells ){ rndr->make.table_row(ob, cells, flags, rndr->make.opaque); }else{ struct Blob fallback = BLOB_INITIALIZER; blob_init(&fallback, data, total ? total : size); rndr->make.table_row(ob, &fallback, flags, rndr->make.opaque); } release_work_buffer(rndr, cells); return total ? total : size; } /* parse_table -- parsing of a whole table */ static size_t parse_table( struct Blob *ob, struct render *rndr, char *data, size_t size ){ size_t i = 0, head_end, col; size_t align_size = 0; int *aligns = 0; struct Blob fallback = BLOB_INITIALIZER; struct Blob *head = 0; struct Blob *rows = new_work_buffer(rndr); if( !rows ) rows = &fallback; /* skip the first (presumably header) line */ while( i<size && data[i]!='\n' ){ i++; } head_end = i; /* fallback on end of input */ if( i>=size ){ parse_table_row(rows, rndr, data, size, 0, 0, 0); rndr->make.table(ob, 0, rows, rndr->make.opaque); if( rows!=&fallback ) release_work_buffer(rndr, rows); return i; } /* attempt to parse a table rule, i.e. blanks, dash, colons and sep */ i++; col = 0; while( i<size |
︙ | ︙ | |||
2276 2277 2278 2279 2280 2281 2282 | } if( i<size && data[i]=='\n' ){ align_size++; /* render the header row */ head = new_work_buffer(rndr); | > | > | 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 | } if( i<size && data[i]=='\n' ){ align_size++; /* render the header row */ head = new_work_buffer(rndr); if( head ){ parse_table_row(head, rndr, data, head_end, 0, 0, MKD_CELL_HEAD); } /* parse alignments if provided */ if( col && (aligns=fossil_malloc(align_size * sizeof *aligns))!=0 ){ for(i=0; i<align_size; i++) aligns[i] = 0; col = 0; i = head_end+1; |
︙ | ︙ | |||
2319 2320 2321 2322 2323 2324 2325 | i += parse_table_row(rows, rndr, data+i, size-i, aligns, align_size, 0); } /* render the full table */ rndr->make.table(ob, head, rows, rndr->make.opaque); /* cleanup */ | | | < < | | < | 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 | i += parse_table_row(rows, rndr, data+i, size-i, aligns, align_size, 0); } /* render the full table */ rndr->make.table(ob, head, rows, rndr->make.opaque); /* cleanup */ if( head ) release_work_buffer(rndr, head); if( rows!=&fallback ) release_work_buffer(rndr, rows); fossil_free(aligns); return i; } /* parse_block -- parsing of one block, returning next char to parse */ static void parse_block( struct Blob *ob, /* output blob */ struct render *rndr, /* renderer internal state */ char *data, /* input text */ size_t size /* input text size */ ){ size_t beg, end, i; char *txt_data; int has_table = (rndr->make.table && rndr->make.table_row && rndr->make.table_cell); beg = 0; while( beg<size ){ txt_data = data+beg; end = size-beg; if( data[beg]=='#' ){ beg += parse_atxheader(ob, rndr, txt_data, end); |
︙ | ︙ | |||
2369 2370 2371 2372 2373 2374 2375 | beg += parse_blockcode(ob, rndr, txt_data, end); }else if( prefix_uli(txt_data, end) ){ beg += parse_list(ob, rndr, txt_data, end, 0); }else if( prefix_oli(txt_data, end) ){ beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); }else if( has_table && is_tableline(txt_data, end) ){ beg += parse_table(ob, rndr, txt_data, end); | < < < < | | 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 | beg += parse_blockcode(ob, rndr, txt_data, end); }else if( prefix_uli(txt_data, end) ){ beg += parse_list(ob, rndr, txt_data, end, 0); }else if( prefix_oli(txt_data, end) ){ beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); }else if( has_table && is_tableline(txt_data, end) ){ beg += parse_table(ob, rndr, txt_data, end); }else{ beg += parse_paragraph(ob, rndr, txt_data, end); } } } /********************* * REFERENCE PARSING * *********************/ /* is_ref -- returns whether a line is a reference or not */ static int is_ref( char *data, /* input text */ size_t beg, /* offset of the beginning of the line */ size_t end, /* offset of the end of the text */ size_t *last, /* last character of the link */ struct Blob *refs /* array of link references */ ){ size_t i = 0; size_t id_offset, id_end; |
︙ | ︙ | |||
2421 2422 2423 2424 2425 2426 2427 | } } i += beg; /* id part: anything but a newline between brackets */ if( data[i]!='[' ) return 0; i++; | < < | 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 | } } i += beg; /* id part: anything but a newline between brackets */ if( data[i]!='[' ) return 0; i++; id_offset = i; while( i<end && data[i]!='\n' && data[i]!='\r' && data[i]!=']' ){ i++; } if( i>=end || data[i]!=']' ) return 0; id_end = i; /* spacer: colon (space | tab)* newline? (space | tab)* */ i++; |
︙ | ︙ | |||
2451 2452 2453 2454 2455 2456 2457 | && data[i]!=' ' && data[i]!='\t' && data[i]!='\n' && data[i]!='\r' ){ i += 1; } | < | 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 | && data[i]!=' ' && data[i]!='\t' && data[i]!='\n' && data[i]!='\r' ){ i += 1; } if( data[i-1]=='>' ) link_end = i-1; else link_end = i; /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ while( i<end && (data[i]==' ' || data[i]=='\t') ){ i++; } if( i<end && data[i]!='\n' && data[i]!='\r' |
︙ | ︙ | |||
2511 2512 2513 2514 2515 2516 2517 | if( title_end>title_offset ){ blob_append(&lr.title, data+title_offset, title_end-title_offset); } blob_append(refs, (char *)&lr, sizeof lr); return 1; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < < > | | > > | < < < < < < < < < < < | < | > | < < | | | | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < | | < | 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 | if( title_end>title_offset ){ blob_append(&lr.title, data+title_offset, title_end-title_offset); } blob_append(refs, (char *)&lr, sizeof lr); return 1; } /********************** * EXPORTED FUNCTIONS * **********************/ /* markdown -- parses the input buffer and renders it into the output buffer */ void markdown( struct Blob *ob, /* output blob for rendered text */ struct Blob *ib, /* input blob in markdown */ const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */ ){ struct link_ref *lr; struct Blob text = BLOB_INITIALIZER; size_t i, beg, end = 0; struct render rndr; char *ib_data; /* filling the render structure */ if( !rndrer ) return; rndr.make = *rndrer; if( rndr.make.max_work_stack<1 ) rndr.make.max_work_stack = 1; rndr.work_active = 0; rndr.work = fossil_malloc(rndr.make.max_work_stack * sizeof *rndr.work); for(i=0; i<rndr.make.max_work_stack; i++) rndr.work[i] = text; rndr.refs = text; for(i=0; i<256; i++) rndr.active_char[i] = 0; if( (rndr.make.emphasis || rndr.make.double_emphasis || rndr.make.triple_emphasis) && rndr.make.emph_chars ){ for(i=0; rndr.make.emph_chars[i]; i++){ rndr.active_char[(unsigned char)rndr.make.emph_chars[i]] = char_emphasis; } } if( rndr.make.codespan ) rndr.active_char['`'] = char_codespan; if( rndr.make.linebreak ) rndr.active_char['\n'] = char_linebreak; if( rndr.make.image || rndr.make.link ) rndr.active_char['['] = char_link; rndr.active_char['<'] = char_langle_tag; rndr.active_char['\\'] = char_escape; rndr.active_char['&'] = char_entity; /* first pass: looking for references, copying everything else */ beg = 0; ib_data = blob_buffer(ib); while( beg<blob_size(ib) ){ /* iterating over lines */ if( is_ref(ib_data, beg, blob_size(ib), &end, &rndr.refs) ){ beg = end; }else{ /* skipping to the next line */ end = beg; while( end<blob_size(ib) && ib_data[end]!='\n' && ib_data[end]!='\r' ){ end += 1; } /* adding the line body if present */ if( end>beg ) blob_append(&text, ib_data + beg, end - beg); while( end<blob_size(ib) && (ib_data[end]=='\n' || ib_data[end]=='\r') ){ /* add one \n per newline */ if( ib_data[end]=='\n' || (end+1<blob_size(ib) && ib_data[end+1]!='\n') ){ blob_append(&text, "\n", 1); } end += 1; } beg = end; } } /* sorting the reference array */ if( blob_size(&rndr.refs) ){ qsort(blob_buffer(&rndr.refs), blob_size(&rndr.refs)/sizeof(struct link_ref), sizeof(struct link_ref), cmp_link_ref_sort); } /* second pass: actual rendering */ if( rndr.make.prolog ) rndr.make.prolog(ob, rndr.make.opaque); parse_block(ob, &rndr, blob_buffer(&text), blob_size(&text)); if( rndr.make.epilog ) rndr.make.epilog(ob, rndr.make.opaque); /* clean-up */ blob_reset(&text); lr = (struct link_ref *)blob_buffer(&rndr.refs); end = blob_size(&rndr.refs)/sizeof(struct link_ref); for(i=0; i<end; i++){ blob_reset(&lr[i].id); blob_reset(&lr[i].link); blob_reset(&lr[i].title); } blob_reset(&rndr.refs); blobarray_zero(rndr.work, rndr.make.max_work_stack); fossil_free(rndr.work); } |
Changes to src/markdown.md.
︙ | ︙ | |||
24 25 26 27 28 29 30 | > 1. **\[display text\]\(URL\)** > 2. **\[display text\]\(URL "Title"\)** > 3. **\[display text\]\(URL 'Title'\)** > 4. **\<URL\>** > 5. **\[display text\]\[label\]** > 6. **\[display text\]\[\]** > 7. **\[display text\]** | < | | | | > < < < < < < < < < < < < | < < < < < > | | | | < < < > | | < < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < | 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 | > 1. **\[display text\]\(URL\)** > 2. **\[display text\]\(URL "Title"\)** > 3. **\[display text\]\(URL 'Title'\)** > 4. **\<URL\>** > 5. **\[display text\]\[label\]** > 6. **\[display text\]\[\]** > 7. **\[display text\]** > **URL** may optionally be written **\<URL\>**. With link formats 5, 6, and 7 > ("reference links"), the URL is supplied elsewhere in the document, as shown > below. Link formats 6 and 7 reuse the display text as the label. Labels are > case-insensitive. The title may be split onto the next line with optional > indenting. > * **\[label\]: URL** > * **\[label\]: URL "Title"** > * **\[label\]: URL 'Title'** > * **\[label\]: URL (Title)** ## Fonts ## > * _\*italic\*_ > * *\_italic\_* > * __\*\*bold\*\*__ > * **\_\_bold\_\_** > * ___\*\*\*italic+bold\*\*\*___ > * ***\_\_\_italic+bold\_\_\_*** > * \``code`\` > The **\`code\`** construct disables HTML markup, so one can write, for > example, **\`\<html\>\`** to yield **`<html>`**. ## Lists ## > * bullet item + bullet item - bullet item 1. numbered item > A two-level list is created by placing additional whitespace before the > **\***/**+**/**-**/**1.** of the secondary items. > * top-level item * secondary item ## Block Quotes ## > Begin each line of a paragraph with **>** to block quote that paragraph. > > > This paragraph is indented > > > > Double-indented paragraph > Begin each line with at least four spaces or one tab to produce a verbatim > code block. ## Tables ## > | Header 1 | Header 2 | Header 3 | ---------------------------------------------- | Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 | |:Left-aligned |:Centered :| Right-aligned:| | | ← Blank → | | | Row 4 Col 1 | Row 4 Col 2 | Row 4 Col 3 | > The first row is a header if followed by a horizontal rule or a blank line. > Placing **:** at the left, both, or right sides of a cell gives left-aligned, > centered, or right-aligned text, respectively. By default, header cells are > centered, and body cells are left-aligned. > The leftmost or rightmost **\|** is required only if the first or last column, > respectively, contains at least one blank cell. ## Miscellaneous ## > * In-line images are made using **\!\[alt-text\]\(image-URL\)**. > * Use HTML for advanced formatting such as forms. > * **\<!--** HTML-style comments **-->** are supported. > * Escape special characters (ex: **\[** **\(** **\|** **\***) > using backslash (ex: **\\\[** **\\\(** **\\\|** **\\\***). > * A line consisting of **---**, **\*\*\***, or **\_\_\_** is a horizontal > rule. Spaces and extra **-**/**\***/**_** are allowed. > * See [daringfireball.net][] for additional information. > * See this page's [Markdown source](/md_rules?txt=1) for complex examples. ## Special Features For Fossil ## > * In hyperlinks, if the URL begins with **/** then the root of the Fossil > repository is prepended. This allows for repository-relative hyperlinks. > * For documents that begin with a top-level heading (ex: **# heading #**), > the heading is omitted from the body of the document and becomes the > document title displayed at the top of the Fossil page. [daringfireball.net]: http://daringfireball.net/projects/markdown/syntax |
Changes to src/markdown_html.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | void markdown_to_html( struct Blob *input_markdown, struct Blob *output_title, struct Blob *output_body); #endif /* INTERFACE */ | < < < < < < < < < < < < < < < < < < < < < < < < | > > > | < < < < < < > > > | | | < | < | < < < < < < < < < < < | < < < < < < < | 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 | void markdown_to_html( struct Blob *input_markdown, struct Blob *output_title, struct Blob *output_body); #endif /* INTERFACE */ /* INTER_BLOCK -- skip a line between block level elements */ #define INTER_BLOCK(ob) \ do { if( blob_size(ob)>0 ) blob_append(ob, "\n", 1); } while (0) /* BLOB_APPEND_LITERAL -- append a string literal to a blob */ #define BLOB_APPEND_LITERAL(blob, literal) \ blob_append((blob), "" literal, (sizeof literal)-1) /* * The empty string in the second argument leads to a syntax error * when the macro is not used with a string literal. Unfortunately * the error is not overly explicit. */ /* BLOB_APPEND_BLOB -- append blob contents to another */ #define BLOB_APPEND_BLOB(dest, src) \ blob_append((dest), blob_buffer(src), blob_size(src)) /* HTML escapes ** ** html_escape() converts < to <, > to >, and & to &. ** html_quote() goes further and converts " into " and ' in '. */ static void html_quote(struct Blob *ob, const char *data, size_t size){ |
︙ | ︙ | |||
111 112 113 114 115 116 117 | && data[i]!='\'' ){ i++; } blob_append(ob, data+beg, i-beg); while( i<size ){ if( data[i]=='<' ){ | | | | | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | && data[i]!='\'' ){ i++; } blob_append(ob, data+beg, i-beg); while( i<size ){ if( data[i]=='<' ){ BLOB_APPEND_LITERAL(ob, "<"); }else if( data[i]=='>' ){ BLOB_APPEND_LITERAL(ob, ">"); }else if( data[i]=='&' ){ BLOB_APPEND_LITERAL(ob, "&"); }else if( data[i]=='"' ){ BLOB_APPEND_LITERAL(ob, """); }else if( data[i]=='\'' ){ BLOB_APPEND_LITERAL(ob, "'"); }else{ break; } i++; } } } |
︙ | ︙ | |||
141 142 143 144 145 146 147 | && data[i]!='&' ){ i++; } blob_append(ob, data+beg, i-beg); while( i<size ){ if( data[i]=='<' ){ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | < < | | < < < < < < | > > > | | < | | > > | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | && data[i]!='&' ){ i++; } blob_append(ob, data+beg, i-beg); while( i<size ){ if( data[i]=='<' ){ BLOB_APPEND_LITERAL(ob, "<"); }else if( data[i]=='>' ){ BLOB_APPEND_LITERAL(ob, ">"); }else if( data[i]=='&' ){ BLOB_APPEND_LITERAL(ob, "&"); }else{ break; } i++; } } } /* HTML block tags */ /* Size of the prolog: "<div class='markdown'>\n" */ #define PROLOG_SIZE 23 static void html_prolog(struct Blob *ob, void *opaque){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "<div class=\"markdown\">\n"); assert( blob_size(ob)==PROLOG_SIZE ); } static void html_epilog(struct Blob *ob, void *opaque){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "</div>\n"); } static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){ char *data = blob_buffer(text); size_t size = blob_size(text); Blob *title = (Blob*)opaque; while( size>0 && fossil_isspace(data[0]) ){ data++; size--; } while( size>0 && fossil_isspace(data[size-1]) ){ size--; } /* If the first raw block is an <h1> element, then use it as the title. */ if( blob_size(ob)<=PROLOG_SIZE && size>9 && title!=0 && sqlite3_strnicmp("<h1",data,3)==0 && sqlite3_strnicmp("</h1>", &data[size-5],5)==0 ){ int nTag = htmlTagLength(data); blob_append(title, data+nTag, size - nTag - 5); return; } INTER_BLOCK(ob); blob_append(ob, data, size); BLOB_APPEND_LITERAL(ob, "\n"); } static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "<pre><code>"); html_escape(ob, blob_buffer(text), blob_size(text)); BLOB_APPEND_LITERAL(ob, "</code></pre>\n"); } static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "<blockquote>\n"); BLOB_APPEND_BLOB(ob, text); BLOB_APPEND_LITERAL(ob, "</blockquote>\n"); } static void html_header( struct Blob *ob, struct Blob *text, int level, void *opaque ){ struct Blob *title = opaque; /* The first header at the beginning of a text is considered as * a title and not output. */ if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){ BLOB_APPEND_BLOB(title, text); return; } INTER_BLOCK(ob); blob_appendf(ob, "<h%d>", level); BLOB_APPEND_BLOB(ob, text); blob_appendf(ob, "</h%d>", level); } static void html_hrule(struct Blob *ob, void *opaque){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "<hr />\n"); } static void html_list( struct Blob *ob, struct Blob *text, int flags, void *opaque ){ char ol[] = "ol"; char ul[] = "ul"; char *tag = (flags & MKD_LIST_ORDERED) ? ol : ul; INTER_BLOCK(ob); blob_appendf(ob, "<%s>\n", tag); BLOB_APPEND_BLOB(ob, text); blob_appendf(ob, "</%s>\n", tag); } static void html_list_item( struct Blob *ob, struct Blob *text, int flags, void *opaque ){ char *text_data = blob_buffer(text); size_t text_size = blob_size(text); while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--; BLOB_APPEND_LITERAL(ob, "<li>"); blob_append(ob, text_data, text_size); BLOB_APPEND_LITERAL(ob, "</li>\n"); } static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "<p>"); BLOB_APPEND_BLOB(ob, text); BLOB_APPEND_LITERAL(ob, "</p>\n"); } static void html_table( struct Blob *ob, struct Blob *head_row, struct Blob *rows, void *opaque ){ INTER_BLOCK(ob); BLOB_APPEND_LITERAL(ob, "<table>\n"); if( head_row && blob_size(head_row)>0 ){ BLOB_APPEND_LITERAL(ob, "<thead>\n"); BLOB_APPEND_BLOB(ob, head_row); BLOB_APPEND_LITERAL(ob, "</thead>\n<tbody>\n"); } if( rows ){ BLOB_APPEND_BLOB(ob, rows); } if( head_row && blob_size(head_row)>0 ){ BLOB_APPEND_LITERAL(ob, "</tbody>\n"); } BLOB_APPEND_LITERAL(ob, "</table>\n"); } static void html_table_cell( struct Blob *ob, struct Blob *text, int flags, void *opaque ){ if( flags & MKD_CELL_HEAD ){ BLOB_APPEND_LITERAL(ob, " <th"); }else{ BLOB_APPEND_LITERAL(ob, " <td"); } switch( flags & MKD_CELL_ALIGN_MASK ){ case MKD_CELL_ALIGN_LEFT: { BLOB_APPEND_LITERAL(ob, " align=\"left\""); break; } case MKD_CELL_ALIGN_RIGHT: { BLOB_APPEND_LITERAL(ob, " align=\"right\""); break; } case MKD_CELL_ALIGN_CENTER: { BLOB_APPEND_LITERAL(ob, " align=\"center\""); break; } } BLOB_APPEND_LITERAL(ob, ">"); BLOB_APPEND_BLOB(ob, text); if( flags & MKD_CELL_HEAD ){ BLOB_APPEND_LITERAL(ob, "</th>\n"); }else{ BLOB_APPEND_LITERAL(ob, "</td>\n"); } } static void html_table_row( struct Blob *ob, struct Blob *cells, int flags, void *opaque ){ BLOB_APPEND_LITERAL(ob, " <tr>\n"); BLOB_APPEND_BLOB(ob, cells); BLOB_APPEND_LITERAL(ob, " </tr>\n"); } /* HTML span tags */ static int html_raw_span(struct Blob *ob, struct Blob *text, void *opaque){ /* If the document begins with a <h1> markup, take that as the header. */ BLOB_APPEND_BLOB(ob, text); return 1; } static int html_autolink( struct Blob *ob, struct Blob *link, enum mkd_autolink type, void *opaque ){ if( !link || blob_size(link)<=0 ) return 0; BLOB_APPEND_LITERAL(ob, "<a href=\""); if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITERAL(ob, "mailto:"); html_quote(ob, blob_buffer(link), blob_size(link)); BLOB_APPEND_LITERAL(ob, "\">"); if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){ /* remove "mailto:" from displayed text */ html_escape(ob, blob_buffer(link)+7, blob_size(link)-7); }else{ html_escape(ob, blob_buffer(link), blob_size(link)); } BLOB_APPEND_LITERAL(ob, "</a>"); return 1; } static int html_code_span(struct Blob *ob, struct Blob *text, void *opaque){ if( text ){ BLOB_APPEND_LITERAL(ob, "<code>"); html_escape(ob, blob_buffer(text), blob_size(text)); BLOB_APPEND_LITERAL(ob, "</code>"); } return 1; } static int html_double_emphasis( struct Blob *ob, struct Blob *text, char c, void *opaque ){ BLOB_APPEND_LITERAL(ob, "<strong>"); BLOB_APPEND_BLOB(ob, text); BLOB_APPEND_LITERAL(ob, "</strong>"); return 1; } static int html_emphasis( struct Blob *ob, struct Blob *text, char c, void *opaque ){ BLOB_APPEND_LITERAL(ob, "<em>"); BLOB_APPEND_BLOB(ob, text); BLOB_APPEND_LITERAL(ob, "</em>"); return 1; } static int html_image( struct Blob *ob, struct Blob *link, struct Blob *title, struct Blob *alt, void *opaque ){ BLOB_APPEND_LITERAL(ob, "<img src=\""); html_quote(ob, blob_buffer(link), blob_size(link)); BLOB_APPEND_LITERAL(ob, "\" alt=\""); html_quote(ob, blob_buffer(alt), blob_size(alt)); if( title && blob_size(title)>0 ){ BLOB_APPEND_LITERAL(ob, "\" title=\""); html_quote(ob, blob_buffer(title), blob_size(title)); } BLOB_APPEND_LITERAL(ob, "\" />"); return 1; } static int html_line_break(struct Blob *ob, void *opaque){ BLOB_APPEND_LITERAL(ob, "<br />\n"); return 1; } static int html_link( struct Blob *ob, struct Blob *link, struct Blob *title, struct Blob *content, void *opaque ){ char *zLink = blob_buffer(link); BLOB_APPEND_LITERAL(ob, "<a href=\""); if( zLink && zLink[0]=='/' && g.zTop ){ /* For any hyperlink that begins with "/", make it refer to the root ** of the Fossil repository */ blob_append(ob, g.zTop, -1); } html_quote(ob, blob_buffer(link), blob_size(link)); if( title && blob_size(title)>0 ){ BLOB_APPEND_LITERAL(ob, "\" title=\""); html_quote(ob, blob_buffer(title), blob_size(title)); } BLOB_APPEND_LITERAL(ob, "\">"); BLOB_APPEND_BLOB(ob, content); BLOB_APPEND_LITERAL(ob, "</a>"); return 1; } static int html_triple_emphasis( struct Blob *ob, struct Blob *text, char c, void *opaque ){ BLOB_APPEND_LITERAL(ob, "<strong><em>"); BLOB_APPEND_BLOB(ob, text); BLOB_APPEND_LITERAL(ob, "</em></strong>"); return 1; } static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){ html_escape(ob, blob_buffer(text), blob_size(text)); } |
︙ | ︙ | |||
858 859 860 861 862 863 864 | struct Blob *output_title, /* Put title here. May be NULL */ struct Blob *output_body /* Put document body here. */ ){ struct mkd_renderer html_renderer = { /* prolog and epilog */ html_prolog, html_epilog, | < | < | | | < | > | | < < < < < < < < < < | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | struct Blob *output_title, /* Put title here. May be NULL */ struct Blob *output_body /* Put document body here. */ ){ struct mkd_renderer html_renderer = { /* prolog and epilog */ html_prolog, html_epilog, /* block level elements */ html_blockcode, html_blockquote, html_raw_block, html_header, html_hrule, html_list, html_list_item, html_paragraph, html_table, html_table_cell, html_table_row, /* span level elements */ html_autolink, html_code_span, html_double_emphasis, html_emphasis, html_image, html_line_break, html_link, html_raw_span, html_triple_emphasis, /* low level elements */ 0, /* entities are copied verbatim */ html_normal_text, /* misc. parameters */ 64, /* maximum stack */ "*_", /* emphasis characters */ 0 /* opaque data */ }; html_renderer.opaque = output_title; if( output_title ) blob_reset(output_title); blob_reset(output_body); markdown(output_body, input_markdown, &html_renderer); } |
Changes to src/md5.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | */ #include "config.h" #include <string.h> #include <stdio.h> #include <sqlite3.h> #include "md5.h" | | < < < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | */ #include "config.h" #include <string.h> #include <stdio.h> #include <sqlite3.h> #include "md5.h" #ifdef FOSSIL_ENABLE_SSL # include <openssl/md5.h> # define MD5Context MD5_CTX # define MD5Init MD5_Init # define MD5Update MD5_Update # define MD5Final MD5_Final |
︙ | ︙ | |||
301 302 303 304 305 306 307 | zBuf[j++] = zEncode[(a>>4)&0xf]; zBuf[j++] = zEncode[a & 0xf]; } zBuf[j] = 0; } /* | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | zBuf[j++] = zEncode[(a>>4)&0xf]; zBuf[j++] = zEncode[a & 0xf]; } zBuf[j] = 0; } /* ** The state of a incremental MD5 checksum computation. Only one ** such computation can be underway at a time, of course. */ static MD5Context incrCtx; static int incrInit = 0; /* ** Initialize the incremental MD5 checksum. |
︙ | ︙ |
Changes to src/merge.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | } fossil_print("%-*s [%S] by %s on %s\n%*s", indent-1, zLabel, db_column_text(&q, 3), db_column_text(&q, 1), db_column_text(&q, 0), indent, ""); | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | } fossil_print("%-*s [%S] by %s on %s\n%*s", indent-1, zLabel, db_column_text(&q, 3), db_column_text(&q, 1), db_column_text(&q, 0), indent, ""); comment_print(zCom, db_column_text(&q,2), indent, -1, g.comFmtFlags); fossil_free(zCom); } db_finalize(&q); } /* Pick the most recent leaf that is (1) not equal to vid and (2) |
︙ | ︙ | |||
133 134 135 136 137 138 139 | /* ** Add an entry to the FV table for all files renamed between ** version N and the version specified by vid. */ static void add_renames( const char *zFnCol, /* The FV column for the filename in vid */ | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | < < < < < | | > | < | < > | | | | > | > | > | < < | > < < < < < | | < < < > < < < < < < < < < < < < < < < < < < < < < | > < < < < < < < < < < < < < < < | | < | < < | | < < < < < | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | /* ** Add an entry to the FV table for all files renamed between ** version N and the version specified by vid. */ static void add_renames( const char *zFnCol, /* The FV column for the filename in vid */ int vid, /* The desired version's RID */ int nid, /* Version N's RID */ int revOk, /* Ok to move backwards (child->parent) if true */ const char *zDebug /* Generate trace output if not NULL */ ){ int nChng; /* Number of file name changes */ int *aChng; /* An array of file name changes */ int i; /* Loop counter */ find_filename_changes(nid, vid, revOk, &nChng, &aChng, zDebug); if( nChng==0 ) return; for(i=0; i<nChng; i++){ char *zN, *zV; zN = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]); zV = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]); db_multi_exec( "INSERT OR IGNORE INTO fv(%s,fnn) VALUES(%Q,%Q)", zFnCol /*safe-for-%s*/, zV, zN ); if( db_changes()==0 ){ db_multi_exec( "UPDATE fv SET %s=%Q WHERE fnn=%Q", zFnCol /*safe-for-%s*/, zV, zN ); } free(zN); free(zV); } free(aChng); } /* ** COMMAND: merge ** ** Usage: %fossil merge ?OPTIONS? ?VERSION? ** ** The argument VERSION is a version that should be merged into the ** current checkout. All changes from VERSION back to the nearest ** common ancestor are merged. Except, if either of the --cherrypick or ** --backout options are used only the changes associated with the ** single check-in VERSION are merged. The --backout option causes ** the changes associated with VERSION to be removed from the current ** checkout rather than added. ** ** If the VERSION argument is omitted, then Fossil attempts to find ** a recent fork on the current branch to merge. ** ** Only file content is merged. The result continues to use the ** file and directory names from the current checkout even if those ** names might have been changed in the branch being merged in. ** ** Other options: ** ** --baseline BASELINE Use BASELINE as the "pivot" of the merge instead ** of the nearest common ancestor. This allows ** a sequence of changes in a branch to be merged ** without having to merge the entire branch. ** ** --binary GLOBPATTERN Treat files that match GLOBPATTERN as binary ** and do not try to merge parallel changes. This ** option overrides the "binary-glob" setting. ** ** --case-sensitive BOOL Override the case-sensitive setting. If false, ** files whose names differ only in case are taken ** to be the same file. ** ** -f|--force Force the merge even if it would be a no-op. ** ** --force-missing Force the merge even if there is missing content. ** ** --integrate Merged branch will be closed when committing. ** ** -n|--dry-run If given, display instead of run actions ** ** -v|--verbose Show additional details of the merge */ void merge_cmd(void){ int vid; /* Current version "V" */ int mid; /* Version we are merging from "M" */ int pid = 0; /* The pivot version - most recent common ancestor P */ int nid = 0; /* The name pivot version "N" */ int verboseFlag; /* True if the -v|--verbose option is present */ int integrateFlag; /* True if the --integrate option is present */ int pickFlag; /* True if the --cherrypick option is present */ int backoutFlag; /* True if the --backout option is present */ int dryRunFlag; /* True if the --dry-run or -n option is present */ int forceFlag; /* True if the --force or -f option is present */ int forceMissingFlag; /* True if the --force-missing option is present */ const char *zBinGlob; /* The value of --binary */ const char *zPivot; /* The value of --baseline */ int debugFlag; /* True if --debug is present */ int nConflict = 0; /* Number of conflicts seen */ int nOverwrite = 0; /* Number of unmanaged files overwritten */ char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ Stmt q; /* Notation: ** ** V The current checkout ** M The version being merged in ** P The "pivot" - the most recent common ancestor of V and M. ** N The "name pivot" - for detecting renames */ undo_capture_command_line(); verboseFlag = find_option("verbose","v",0)!=0; forceMissingFlag = find_option("force-missing",0,0)!=0; if( !verboseFlag ){ verboseFlag = find_option("detail",0,0)!=0; /* deprecated */ } pickFlag = find_option("cherrypick",0,0)!=0; integrateFlag = find_option("integrate",0,0)!=0; backoutFlag = find_option("backout",0,0)!=0; debugFlag = find_option("debug",0,0)!=0; zBinGlob = find_option("binary",0,1); dryRunFlag = find_option("dry-run","n",0)!=0; if( !dryRunFlag ){ dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */ } forceFlag = find_option("force","f",0)!=0; zPivot = find_option("baseline",0,1); verify_all_options(); db_must_be_within_tree(); if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("nothing is checked out"); } if( !dryRunFlag ){ if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, db_get_int("autosync-tries", 1), 1) ){ fossil_fatal("merge abandoned due to sync failure"); } } /* Find mid, the artifactID of the version to be merged into the current ** check-out */ if( g.argc==3 ){ /* Mid is specified as an argument on the command-line */ mid = name_to_typed_rid(g.argv[2], "ci"); if( mid==0 || !is_a_version(mid) ){ fossil_fatal("not a version: %s", g.argv[2]); } }else if( g.argc==2 ){ /* No version specified on the command-line so pick the most recent ** leaf that is (1) not the version currently checked out and (2) ** has not already been merged into the current checkout and (3) ** the leaf is not closed and (4) the leaf is in the same branch ** as the current checkout. */ Stmt q; if( pickFlag || backoutFlag || integrateFlag){ fossil_fatal("cannot use --backout, --cherrypick or --integrate " "with a fork merge"); } mid = fossil_find_nearest_fork(vid, db_open_local(0)); |
︙ | ︙ | |||
468 469 470 471 472 473 474 | " datetime(event.mtime,toLocal())," " coalesce(ecomment, comment)," " coalesce(euser, user)" " FROM event, blob" " WHERE event.objid=%d AND blob.rid=%d", mid, mid ); | < | < | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | " datetime(event.mtime,toLocal())," " coalesce(ecomment, comment)," " coalesce(euser, user)" " FROM event, blob" " WHERE event.objid=%d AND blob.rid=%d", mid, mid ); if( db_step(&q)==SQLITE_ROW ){ char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", db_column_text(&q, 0), db_column_text(&q, 1), db_column_text(&q, 3), db_column_text(&q, 2)); comment_print(zCom, db_column_text(&q,2), 0, -1, g.comFmtFlags); fossil_free(zCom); } db_finalize(&q); }else{ usage("?OPTIONS? ?VERSION?"); return; } |
︙ | ︙ | |||
499 500 501 502 503 504 505 | if( pickFlag || backoutFlag ){ if( integrateFlag ){ fossil_fatal("incompatible options: --integrate and --cherrypick " "with --backout"); } pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); if( pid<=0 ){ | | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | if( pickFlag || backoutFlag ){ if( integrateFlag ){ fossil_fatal("incompatible options: --integrate and --cherrypick " "with --backout"); } pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); if( pid<=0 ){ fossil_fatal("cannot find an ancestor for %s", g.argv[2]); } }else{ if( !zPivot ){ pivot_set_primary(mid); pivot_set_secondary(vid); db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); while( db_step(&q)==SQLITE_ROW ){ pivot_set_secondary(db_column_int(&q,0)); } db_finalize(&q); pid = pivot_find(0); if( pid<=0 ){ fossil_fatal("cannot find a common ancestor between the current " "checkout and %s", g.argv[2]); } } pivot_set_primary(mid); pivot_set_secondary(vid); nid = pivot_find(1); if( nid!=pid ){ pivot_set_primary(nid); |
︙ | ︙ | |||
540 541 542 543 544 545 546 | } if( !forceFlag && mid==pid ){ fossil_print("Merge skipped because it is a no-op. " " Use --force to override.\n"); return; } if( integrateFlag && !is_a_leaf(mid)){ | | < < < < < < < | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | } if( !forceFlag && mid==pid ){ fossil_print("Merge skipped because it is a no-op. " " Use --force to override.\n"); return; } if( integrateFlag && !is_a_leaf(mid)){ fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]); integrateFlag = 0; } if( verboseFlag ){ print_checkin_description(mid, 12, integrateFlag ? "integrate:" : "merge-from:"); print_checkin_description(pid, 12, "baseline:"); } vfile_check_signature(vid, CKSIG_ENOTFILE); db_begin_transaction(); if( !dryRunFlag ) undo_begin(); if( load_vfile_from_rid(mid) && !forceMissingFlag ){ fossil_fatal("missing content, unable to merge"); } if( load_vfile_from_rid(pid) && !forceMissingFlag ){ fossil_fatal("missing content, unable to merge"); } |
︙ | ︙ | |||
578 579 580 581 582 583 584 | "SELECT 1 FROM ancestor WHERE id=%d LIMIT 1", vid, nid, pid, pid ) ? 'p' : 'n'; } if( debugFlag ){ char *z; z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nid); | | | | | < < | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < | > > > > | > > > > | > > > > > > > > > > > > > > > > > > | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | "SELECT 1 FROM ancestor WHERE id=%d LIMIT 1", vid, nid, pid, pid ) ? 'p' : 'n'; } if( debugFlag ){ char *z; z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nid); fossil_print("N=%d %z\n", nid, z); z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pid); fossil_print("P=%d %z\n", pid, z); z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid); fossil_print("M=%d %z\n", mid, z); z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); fossil_print("V=%d %z\n", vid, z); } /* ** The vfile.pathname field is used to match files against each other. The ** FV table contains one row for each each unique filename in ** in the current checkout, the pivot, and the version being merged. */ db_multi_exec( "DROP TABLE IF EXISTS fv;" "CREATE TEMP TABLE fv(" " fn TEXT UNIQUE %s," /* The filename */ " idv INTEGER DEFAULT 0," /* VFILE entry for current version */ " idp INTEGER DEFAULT 0," /* VFILE entry for the pivot */ " idm INTEGER DEFAULT 0," /* VFILE entry for version merging in */ " chnged BOOLEAN," /* True if current version has been edited */ " ridv INTEGER DEFAULT 0," /* Record ID for current version */ " ridp INTEGER DEFAULT 0," /* Record ID for pivot */ " ridm INTEGER DEFAULT 0," /* Record ID for merge */ " isexe BOOLEAN," /* Execute permission enabled */ " fnp TEXT UNIQUE %s," /* The filename in the pivot */ " fnm TEXT UNIQUE %s," /* The filename in the merged version */ " fnn TEXT UNIQUE %s," /* The filename in the name pivot */ " islinkv BOOLEAN," /* True if current version is a symlink */ " islinkm BOOLEAN" /* True if merged version in is a symlink */ ");", filename_collation(), filename_collation(), filename_collation(), filename_collation() ); /* ** Compute name changes from N to V, P, and M */ add_renames("fn", vid, nid, 0, debugFlag ? "N->V" : 0); add_renames("fnp", pid, nid, 0, debugFlag ? "N->P" : 0); add_renames("fnm", mid, nid, backoutFlag, debugFlag ? "N->M" : 0); /* ** Add files found in V */ db_multi_exec( "UPDATE OR IGNORE fv SET fn=coalesce(fn%c,fnn) WHERE fn IS NULL;" "REPLACE INTO fv(fn,fnp,fnm,fnn,idv,ridv,islinkv,isexe,chnged)" " SELECT pathname, fnp, fnm, fnn, id, rid, islink, vf.isexe, vf.chnged" " FROM vfile vf" " LEFT JOIN fv ON fn=coalesce(origname,pathname)" " AND rid>0 AND vf.chnged NOT IN (3,5)" " WHERE vid=%d;", vAncestor, vid ); /* ** Add files found in P */ db_multi_exec( "UPDATE OR IGNORE fv SET fnp=coalesce(fnn," " (SELECT coalesce(origname,pathname) FROM vfile WHERE id=idv))" " WHERE fnp IS NULL;" "INSERT OR IGNORE INTO fv(fnp)" " SELECT coalesce(origname,pathname) FROM vfile WHERE vid=%d;", pid ); /* ** Add files found in M */ db_multi_exec( "UPDATE OR IGNORE fv SET fnm=fnp WHERE fnm IS NULL;" "INSERT OR IGNORE INTO fv(fnm)" " SELECT pathname FROM vfile WHERE vid=%d;", mid ); /* ** Compute the file version ids for P and M */ if( pid==vid ){ db_multi_exec( "UPDATE fv SET idp=idv, ridp=ridv WHERE ridv>0 AND chnged NOT IN (3,5)" ); }else{ db_multi_exec( "UPDATE fv SET" " idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND fnp=pathname),0)," " ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND fnp=pathname),0)", pid, pid ); } db_multi_exec( "UPDATE fv SET" " idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND fnm=pathname),0)," " ridm=coalesce((SELECT rid FROM vfile WHERE vid=%d AND fnm=pathname),0)," " islinkm=coalesce((SELECT islink FROM vfile" " WHERE vid=%d AND fnm=pathname),0)," " isexe=coalesce((SELECT isexe FROM vfile WHERE vid=%d AND fnm=pathname)," " isexe)", mid, mid, mid, mid ); if( debugFlag ){ db_prepare(&q, "SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, " " isexe, islinkv, islinkm, fnn FROM fv" ); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d " " islinkv=%d islinkm=%d\n", db_column_int(&q, 0), db_column_int(&q, 5), db_column_int(&q, 6), db_column_int(&q, 7), db_column_int(&q, 4), db_column_int(&q, 8), db_column_int(&q, 9), db_column_int(&q, 10)); fossil_print(" fn = [%s]\n", db_column_text(&q, 1)); fossil_print(" fnp = [%s]\n", db_column_text(&q, 2)); fossil_print(" fnm = [%s]\n", db_column_text(&q, 3)); fossil_print(" fnn = [%s]\n", db_column_text(&q, 11)); } db_finalize(&q); } /* ** Update the execute bit on files where it's changed from P->M but not P->V */ db_prepare(&q, "SELECT idv, fn, fv.isexe FROM fv, vfile p, vfile v" " WHERE p.id=idp AND v.id=idv AND fv.isexe!=p.isexe AND v.isexe=p.isexe" |
︙ | ︙ | |||
784 785 786 787 788 789 790 | char *zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); file_setexe(zFullPath, isExe); free(zFullPath); db_multi_exec("UPDATE vfile SET isexe=%d WHERE id=%d", isExe, idv); } } db_finalize(&q); | | > > > | > > > | > > > > > > > < < < < > | | < < | < < < < | | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | char *zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); file_setexe(zFullPath, isExe); free(zFullPath); db_multi_exec("UPDATE vfile SET isexe=%d WHERE id=%d", isExe, idv); } } db_finalize(&q); /* ** Find files in M and V but not in P and report conflicts. ** The file in M will be ignored. It will be treated as if it ** does not exist. */ db_prepare(&q, "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" ); while( db_step(&q)==SQLITE_ROW ){ int idm = db_column_int(&q, 0); char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); fossil_warning("WARNING: no common ancestor for %s", zName); free(zName); db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); } db_finalize(&q); /* ** Find files that have changed from P->M but not P->V. ** Copy the M content over into V. */ db_prepare(&q, "SELECT idv, ridm, fn, islinkm FROM fv" " WHERE idp>0 AND idv>0 AND idm>0" " AND ridm!=ridp AND ridv=ridp AND NOT chnged" ); while( db_step(&q)==SQLITE_ROW ){ int idv = db_column_int(&q, 0); int ridm = db_column_int(&q, 1); const char *zName = db_column_text(&q, 2); int islinkm = db_column_int(&q, 3); /* Copy content from idm over into idv. Overwrite idv. */ fossil_print("UPDATE %s\n", zName); if( !dryRunFlag ){ undo_save(zName); db_multi_exec( "UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d " " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, idv ); vfile_to_disk(0, idv, 0, 0); } } db_finalize(&q); /* ** Do a three-way merge on files that have changes on both P->M and P->V. */ db_prepare(&q, "SELECT ridm, idv, ridp, ridv, %s, fn, isexe, islinkv, islinkm FROM fv" " WHERE idp>0 AND idv>0 AND idm>0" " AND ridm!=ridp AND (ridv!=ridp OR chnged)", glob_expr("fv.fn", zBinGlob) ); while( db_step(&q)==SQLITE_ROW ){ int ridm = db_column_int(&q, 0); int idv = db_column_int(&q, 1); int ridp = db_column_int(&q, 2); |
︙ | ︙ | |||
867 868 869 870 871 872 873 | content_get(ridp, &p); content_get(ridm, &m); if( isBinary ){ rc = -1; blob_zero(&r); }else{ unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0; | < | < > | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | content_get(ridp, &p); content_get(ridm, &m); if( isBinary ){ rc = -1; blob_zero(&r); }else{ unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0; rc = merge_3way(&p, zFullPath, &m, &r, mergeFlags); } if( rc>=0 ){ if( !dryRunFlag ){ blob_write_to_file(&r, zFullPath); file_setexe(zFullPath, isExe); } db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv); if( rc>0 ){ fossil_print("***** %d merge conflicts in %s\n", rc, zName); nConflict++; } }else{ fossil_print("***** Cannot merge binary file %s\n", zName); nConflict++; } blob_reset(&p); blob_reset(&m); blob_reset(&r); } db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)", idv,ridm); } db_finalize(&q); /* ** Drop files that are in P and V but not in M */ db_prepare(&q, |
︙ | ︙ | |||
965 966 967 968 969 970 971 | zFullOldPath = db_text(0,"SELECT tmpfn FROM tmprn WHERE fn=%Q", zOldName); if( !zFullOldPath ){ zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName); } zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); if( file_size(zFullNewPath, RepoFILE)>=0 ){ Blob tmpPath; | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | zFullOldPath = db_text(0,"SELECT tmpfn FROM tmprn WHERE fn=%Q", zOldName); if( !zFullOldPath ){ zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName); } zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); if( file_size(zFullNewPath, RepoFILE)>=0 ){ Blob tmpPath; file_tempname(&tmpPath, ""); db_multi_exec("INSERT INTO tmprn(fn,tmpfn) VALUES(%Q,%Q)", zNewName, blob_str(&tmpPath)); if( file_islink(zFullNewPath) ){ symlink_copy(zFullNewPath, blob_str(&tmpPath)); }else{ file_copy(zFullNewPath, blob_str(&tmpPath)); } |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | */ db_multi_exec( "UPDATE vfile SET pathname=origname || ' (overwritten by rename)'" " WHERE pathname IS NULL" ); /* | | | < | < < < < < < < < | < < < < < < < < < < < < < < < < | | | | | | < < < < < | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | */ db_multi_exec( "UPDATE vfile SET pathname=origname || ' (overwritten by rename)'" " WHERE pathname IS NULL" ); /* ** Add to V files that are not in V or P but are in M */ db_prepare(&q, "SELECT idm, fnm FROM fv" " WHERE idp=0 AND idv=0 AND idm>0" ); while( db_step(&q)==SQLITE_ROW ){ int idm = db_column_int(&q, 0); const char *zName; char *zFullName; db_multi_exec( "REPLACE INTO vfile(vid,chnged,deleted,rid,mrid,isexe,islink,pathname)" " SELECT %d,%d,0,rid,mrid,isexe,islink,pathname FROM vfile WHERE id=%d", vid, integrateFlag?5:3, idm ); zName = db_column_text(&q, 1); zFullName = mprintf("%s%s", g.zLocalRoot, zName); if( file_isfile_or_link(zFullName) && !db_exists("SELECT 1 FROM fv WHERE fn=%Q", zName) ){ fossil_print("ADDED %s (overwrites an unmanaged file)\n", zName); nOverwrite++; }else{ fossil_print("ADDED %s\n", zName); } fossil_free(zFullName); if( !dryRunFlag ){ undo_save(zName); vfile_to_disk(0, idm, 0, 0); } } db_finalize(&q); /* Report on conflicts */ if( nConflict ){ fossil_warning("WARNING: %d merge conflicts", nConflict); } if( nOverwrite ){ fossil_warning("WARNING: %d unmanaged files were overwritten", nOverwrite); } if( dryRunFlag ){ fossil_warning("REMINDER: this was a dry run -" " no files were actually changed."); } /* ** Clean up the mid and pid VFILE entries. Then commit the changes. */ db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); if( pickFlag ){ db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-1,%d)",mid); /* For a cherry-pick merge, make the default check-in comment the same ** as the check-in comment on the check-in that is being merged in. */ db_multi_exec( "REPLACE INTO vvar(name,value)" " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event" " WHERE type='ci' AND objid=%d", mid ); }else if( backoutFlag ){ db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-2,%d)",pid); }else if( integrateFlag ){ db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid); }else{ db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid); } if( !dryRunFlag ) undo_finish(); db_end_transaction(dryRunFlag); } |
Changes to src/merge3.c.
︙ | ︙ | |||
114 115 116 117 118 119 120 | ** The aC[] array is updated and the new index into aC[] is returned. */ static int output_one_side( Blob *pOut, /* Write to this blob */ Blob *pSrc, /* The edited file that is to be copied to pOut */ int *aC, /* Array of integer triples describing the edit */ int i, /* Index in aC[] of current location in pSrc */ | | < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 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 | ** The aC[] array is updated and the new index into aC[] is returned. */ static int output_one_side( Blob *pOut, /* Write to this blob */ Blob *pSrc, /* The edited file that is to be copied to pOut */ int *aC, /* Array of integer triples describing the edit */ int i, /* Index in aC[] of current location in pSrc */ int sz /* Number of lines in unedited source to output */ ){ while( sz>0 ){ if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break; if( aC[i]>=sz ){ blob_copy_lines(pOut, pSrc, sz); aC[i] -= sz; break; } blob_copy_lines(pOut, pSrc, aC[i]); blob_copy_lines(pOut, pSrc, aC[i+2]); sz -= aC[i] + aC[i+1]; i += 3; } return i; } /* ** Text of boundary markers for merge conflicts. */ static const char *const mergeMarker[] = { /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/ "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n", "======= COMMON ANCESTOR content follows ============================\n", "======= MERGED IN content follows ==================================\n", ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" }; /* ** Do a three-way merge. Initialize pOut to contain the result. ** ** The merge is an edit against pV2. Both pV1 and pV2 have a ** common origin at pPivot. Apply the changes of pPivot ==> pV1 ** to pV2. ** ** The return is 0 upon complete success. If any input file is binary, ** -1 is returned and pOut is unmodified. If there are merge ** conflicts, the merge proceeds as best as it can and the number ** of conflicts is returns */ static int blob_merge(Blob *pPivot, Blob *pV1, Blob *pV2, Blob *pOut){ int *aC1; /* Changes from pPivot to pV1 */ int *aC2; /* Changes from pPivot to pV2 */ int i1, i2; /* Index into aC1[] and aC2[] */ int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ int limit1, limit2; /* Sizes of aC1[] and aC2[] */ int nConflict = 0; /* Number of merge conflicts seen so far */ blob_zero(pOut); /* Merge results stored in pOut */ /* Compute the edits that occur from pPivot => pV1 (into aC1) ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is ** an array of integer triples. Within each triple, the first integer ** is the number of lines of text to copy directly from the pivot, ** the second integer is the number of lines of text to omit from the ** pivot, and the third integer is the number of lines of text that are ** inserted. The edit array ends with a triple of 0,0,0. */ aC1 = text_diff(pPivot, pV1, 0, 0, 0); aC2 = text_diff(pPivot, pV2, 0, 0, 0); if( aC1==0 || aC2==0 ){ free(aC1); free(aC2); return -1; } blob_rewind(pV1); /* Rewind inputs: Needed to reconstruct output */ |
︙ | ︙ | |||
269 270 271 272 273 274 275 | /* Loop over the two edit vectors and use them to compute merged text ** which is written into pOut. i1 and i2 are multiples of 3 which are ** indices into aC1[] and aC2[] to the edit triple currently being ** processed */ i1 = i2 = 0; | < | | | | | | | | | | | | | < | | < | | < | | < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | /* Loop over the two edit vectors and use them to compute merged text ** which is written into pOut. i1 and i2 are multiples of 3 which are ** indices into aC1[] and aC2[] to the edit triple currently being ** processed */ i1 = i2 = 0; while( i1<limit1 && i2<limit2 ){ DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) if( aC1[i1]>0 && aC2[i2]>0 ){ /* Output text that is unchanged in both V1 and V2 */ nCpy = min(aC1[i1], aC2[i2]); DEBUG( printf("COPY %d\n", nCpy); ) blob_copy_lines(pOut, pPivot, nCpy); blob_copy_lines(0, pV1, nCpy); blob_copy_lines(0, pV2, nCpy); aC1[i1] -= nCpy; aC2[i2] -= nCpy; }else if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ /* Output edits to V2 that occurs within unchanged regions of V1 */ nDel = aC2[i2+1]; nIns = aC2[i2+2]; DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) blob_copy_lines(0, pPivot, nDel); blob_copy_lines(0, pV1, nDel); blob_copy_lines(pOut, pV2, nIns); aC1[i1] -= nDel; i2 += 3; }else if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ /* Output edits to V1 that occur within unchanged regions of V2 */ nDel = aC1[i1+1]; nIns = aC1[i1+2]; DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) blob_copy_lines(0, pPivot, nDel); blob_copy_lines(0, pV2, nDel); blob_copy_lines(pOut, pV1, nIns); aC2[i2] -= nDel; i1 += 3; }else if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ /* Output edits that are identical in both V1 and V2. */ assert( aC1[i1]==0 ); nDel = aC1[i1+1]; nIns = aC1[i1+2]; DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) blob_copy_lines(0, pPivot, nDel); blob_copy_lines(pOut, pV1, nIns); blob_copy_lines(0, pV2, nIns); i1 += 3; i2 += 3; }else { /* We have found a region where different edits to V1 and V2 overlap. ** This is a merge conflict. Find the size of the conflict, then ** output both possible edits separated by distinctive marks. */ int sz = 1; /* Size of the conflict in lines */ nConflict++; while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ sz++; } DEBUG( printf("CONFLICT %d\n", sz); ) blob_append(pOut, mergeMarker[0], -1); i1 = output_one_side(pOut, pV1, aC1, i1, sz); blob_append(pOut, mergeMarker[1], -1); blob_copy_lines(pOut, pPivot, sz); blob_append(pOut, mergeMarker[2], -1); i2 = output_one_side(pOut, pV2, aC2, i2, sz); blob_append(pOut, mergeMarker[3], -1); } /* If we are finished with an edit triple, advance to the next ** triple. */ if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3; |
︙ | ︙ | |||
385 386 387 388 389 390 391 | int n = blob_size(p) - len + 1; assert( len==(int)strlen(mergeMarker[1]) ); assert( len==(int)strlen(mergeMarker[2]) ); assert( len==(int)strlen(mergeMarker[3]) ); assert( count(mergeMarker)==4 ); for(i=0; i<n; ){ for(j=0; j<4; j++){ | | < | < | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | int n = blob_size(p) - len + 1; assert( len==(int)strlen(mergeMarker[1]) ); assert( len==(int)strlen(mergeMarker[2]) ); assert( len==(int)strlen(mergeMarker[3]) ); assert( count(mergeMarker)==4 ); for(i=0; i<n; ){ for(j=0; j<4; j++){ if( memcmp(&z[i], mergeMarker[j], len)==0 ) return 1; } while( i<n && z[i]!='\n' ){ i++; } while( i<n && z[i]=='\n' ){ i++; } } return 0; } /* ** Return true if the named file contains an unresolved merge marker line. */ |
︙ | ︙ | |||
454 455 456 457 458 459 460 | if( blob_read_from_file(&v1, g.argv[3], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[3]); } if( blob_read_from_file(&v2, g.argv[4], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[4]); } nConflict = blob_merge(&pivot, &v1, &v2, &merged); | | | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | if( blob_read_from_file(&v1, g.argv[3], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[3]); } if( blob_read_from_file(&v2, g.argv[4], ExtFILE)<0 ){ fossil_fatal("cannot read %s", g.argv[4]); } nConflict = blob_merge(&pivot, &v1, &v2, &merged); if( blob_write_to_file(&merged, g.argv[5])<blob_size(&merged) ){ fossil_fatal("cannot write %s", g.argv[4]); } blob_reset(&pivot); blob_reset(&v1); blob_reset(&v2); blob_reset(&merged); if( nConflict>0 ) fossil_warning("WARNING: %d merge conflicts", nConflict); |
︙ | ︙ | |||
504 505 506 507 508 509 510 | } #if INTERFACE /* ** Flags to the 3-way merger */ #define MERGE_DRYRUN 0x0001 | < < < < < < | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | } #if INTERFACE /* ** Flags to the 3-way merger */ #define MERGE_DRYRUN 0x0001 #endif /* ** This routine is a wrapper around blob_merge() with the following ** enhancements: ** |
︙ | ︙ | |||
539 540 541 542 543 544 545 | const char *zV1, /* Name of file for version merging into (mine) */ Blob *pV2, /* Version merging from (yours) */ Blob *pOut, /* Output written here */ unsigned mergeFlags /* Flags that control operation */ ){ Blob v1; /* Content of zV1 */ int rc; /* Return code of subroutines and this routine */ | < < | < < > > > > > > > < < < < < | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | const char *zV1, /* Name of file for version merging into (mine) */ Blob *pV2, /* Version merging from (yours) */ Blob *pOut, /* Output written here */ unsigned mergeFlags /* Flags that control operation */ ){ Blob v1; /* Content of zV1 */ int rc; /* Return code of subroutines and this routine */ blob_read_from_file(&v1, zV1, ExtFILE); rc = blob_merge(pPivot, &v1, pV2, pOut); if( rc!=0 && (mergeFlags & MERGE_DRYRUN)==0 ){ char *zPivot; /* Name of the pivot file */ char *zOrig; /* Name of the original content file */ char *zOther; /* Name of the merge file */ zPivot = file_newname(zV1, "baseline", 1); blob_write_to_file(pPivot, zPivot); zOrig = file_newname(zV1, "original", 1); blob_write_to_file(&v1, zOrig); zOther = file_newname(zV1, "merge", 1); blob_write_to_file(pV2, zOther); if( rc>0 ){ const char *zGMerge; /* Name of the gmerge command */ zGMerge = db_get("gmerge-command", 0); if( zGMerge && zGMerge[0] ){ char *zOut; /* Temporary output file */ char *zCmd; /* Command to invoke */ const char *azSubst[8]; /* Strings to be substituted */ zOut = file_newname(zV1, "output", 1); azSubst[0] = "%baseline"; azSubst[1] = zPivot; azSubst[2] = "%original"; azSubst[3] = zOrig; azSubst[4] = "%merge"; azSubst[5] = zOther; azSubst[6] = "%output"; azSubst[7] = zOut; zCmd = string_subst(zGMerge, 8, azSubst); printf("%s\n", zCmd); fflush(stdout); fossil_system(zCmd); if( file_size(zOut, RepoFILE)>=0 ){ blob_read_from_file(pOut, zOut, ExtFILE); file_delete(zPivot); file_delete(zOrig); file_delete(zOther); file_delete(zOut); } fossil_free(zCmd); fossil_free(zOut); } } fossil_free(zPivot); fossil_free(zOrig); fossil_free(zOther); } blob_reset(&v1); return rc; } |
Added src/miniz.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 | /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Change History 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!): - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place() (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag). - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries. Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice). - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6. - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti - Merged MZ_FORCEINLINE fix from hdeanclark - Fix <time.h> include before config #ifdef, thanks emil.brink - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can set it to 1 for real-time compression). - Merged in some compiler fixes from paulharris's github repro. - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3. - Added example6.c, which dumps an image of the mandelbrot set to a PNG file. - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect). 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com> for the feedback/bug report. 5/28/11 v1.11 - Added statement from unlicense.org 5/27/11 v1.10 - Substantial compressor optimizations: - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. - Refactored the compression code for better readability and maintainability. - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large drop in throughput on some files). 5/15/11 v1.09 - Initial stable release. * Low-level Deflate/Inflate implementation notes: Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses approximately as well as zlib. Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory block large enough to hold the entire file. The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. * zlib-style API notes: miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateEnd compress, compress2, compressBound, uncompress CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. Supports raw deflate streams or standard zlib streams with adler-32 checking. Limitations: The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but there are no guarantees that miniz.c pulls this off perfectly. * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to get the job done with minimal fuss. There are simple API's to retrieve file information, read files from existing archives, create new archives, append new files to existing archives, or clone archive data from one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), or you can specify custom file read/write callbacks. - Archive reading: Just call this function to read a single file from a disk archive: void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); The locate operation can optionally check file comments too, which (as one example) can be used to identify multiple versions of the same file in an archive. This function uses a simple linear search through the central directory, so it's not very fast. Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data to disk and builds an exact image of the central directory in memory. The central directory image is written all at once at the end of the archive file when the archive is finalized. The archive writer can optionally align each file's local header and file data to any power of 2 alignment, which can be useful when the archive will be read from optical media. Also, the writer supports placing arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still readable by any ZIP tool. - Archive appending: The simple way to add a single file to an archive is to call this function: mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); The archive will be created if it doesn't already exist, otherwise it'll be appended to. Note the appending is done in-place and is not an atomic operation, so if something goes wrong during the operation it's possible the archive could be left without a central directory (although the local file headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and you're done. This is safe but requires a bunch of temporary disk space or heap memory. 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), append new files as needed, then finalize the archive which will write an updated central directory to the original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - ZIP archive support limitations: No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. Requires streams capable of seeking. * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. * Important: For best perf. be sure to customize the below macros for your target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #ifndef MINIZ_HEADER_INCLUDED #define MINIZ_HEADER_INCLUDED #include <stdlib.h> // Defines to completely disable specific portions of miniz.c: // If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. // Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. //#define MINIZ_NO_STDIO // If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or // get/set file times, and the C run-time funcs that get/set times won't be called. // The current downside is the times written to your archives will be from 1979. //#define MINIZ_NO_TIME // Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. //#define MINIZ_NO_ARCHIVE_APIS // Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. //#define MINIZ_NO_ARCHIVE_WRITING_APIS // Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. //#define MINIZ_NO_ZLIB_APIS // Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. //#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES // Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. // Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc // callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user // functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. //#define MINIZ_NO_MALLOC #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux #define MINIZ_NO_TIME #endif #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) #include <time.h> #endif #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) // MINIZ_X86_OR_X64_CPU is only used to help set the below macros. #define MINIZ_X86_OR_X64_CPU 1 #endif #if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. #define MINIZ_LITTLE_ENDIAN 1 #endif #if MINIZ_X86_OR_X64_CPU // Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #endif #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) // Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). #define MINIZ_HAS_64BIT_REGISTERS 1 #endif #ifdef __cplusplus extern "C" { #endif // ------------------- zlib-style API Definitions. // For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! typedef unsigned long mz_ulong; // mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. void mz_free(void *p); #define MZ_ADLER32_INIT (1) // mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); #define MZ_CRC32_INIT (0) // mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); // Compression strategies. enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; // Method #define MZ_DEFLATED 8 #ifndef MINIZ_NO_ZLIB_APIS // Heap allocation callbacks. // Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); #define MZ_VERSION "9.1.15" #define MZ_VERNUM 0x91F0 #define MZ_VER_MAJOR 9 #define MZ_VER_MINOR 1 #define MZ_VER_REVISION 15 #define MZ_VER_SUBREVISION 0 // Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; // Return status codes. MZ_PARAM_ERROR is non-standard. enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; // Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; // Window bits #define MZ_DEFAULT_WINDOW_BITS 15 struct mz_internal_state; // Compression/decompression stream struct. typedef struct mz_stream_s { const unsigned char *next_in; // pointer to next byte to read unsigned int avail_in; // number of bytes available at next_in mz_ulong total_in; // total number of bytes consumed so far unsigned char *next_out; // pointer to next byte to write unsigned int avail_out; // number of bytes that can be written to next_out mz_ulong total_out; // total number of bytes produced so far char *msg; // error msg (unused) struct mz_internal_state *state; // internal state, allocated by zalloc/zfree mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) mz_free_func zfree; // optional heap free function (defaults to free) void *opaque; // heap alloc function user pointer int data_type; // data_type (unused) mz_ulong adler; // adler32 of the source or uncompressed data mz_ulong reserved; // not used } mz_stream; typedef mz_stream *mz_streamp; // Returns the version string of miniz.c. const char *mz_version(void); // mz_deflateInit() initializes a compressor with default options: // Parameters: // pStream must point to an initialized mz_stream struct. // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. // level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. // (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) // Return values: // MZ_OK on success. // MZ_STREAM_ERROR if the stream is bogus. // MZ_PARAM_ERROR if the input parameters are bogus. // MZ_MEM_ERROR on out of memory. int mz_deflateInit(mz_streamp pStream, int level); // mz_deflateInit2() is like mz_deflate(), except with more control: // Additional parameters: // method must be MZ_DEFLATED // window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) // mem_level must be between [1, 9] (it's checked but ignored by miniz.c) int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); // Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). int mz_deflateReset(mz_streamp pStream); // mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. // Parameters: // pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. // flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. // Return values: // MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). // MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. // MZ_STREAM_ERROR if the stream is bogus. // MZ_PARAM_ERROR if one of the parameters is invalid. // MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) int mz_deflate(mz_streamp pStream, int flush); // mz_deflateEnd() deinitializes a compressor: // Return values: // MZ_OK on success. // MZ_STREAM_ERROR if the stream is bogus. int mz_deflateEnd(mz_streamp pStream); // mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); // Single-call compression functions mz_compress() and mz_compress2(): // Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); // mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). mz_ulong mz_compressBound(mz_ulong source_len); // Initializes a decompressor. int mz_inflateInit(mz_streamp pStream); // mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: // window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). int mz_inflateInit2(mz_streamp pStream, int window_bits); // Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. // Parameters: // pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. // flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. // On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). // MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. // Return values: // MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. // MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. // MZ_STREAM_ERROR if the stream is bogus. // MZ_DATA_ERROR if the deflate stream is invalid. // MZ_PARAM_ERROR if one of the parameters is invalid. // MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again // with more input data, or with more room in the output buffer (except when using single call decompression, described above). int mz_inflate(mz_streamp pStream, int flush); // Deinitializes a decompressor. int mz_inflateEnd(mz_streamp pStream); // Single-call decompression. // Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); // Returns a string description of the specified error code, or NULL if the error code is invalid. const char *mz_error(int err); // Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES typedef unsigned char Byte; typedef unsigned int uInt; typedef mz_ulong uLong; typedef Byte Bytef; typedef uInt uIntf; typedef char charf; typedef int intf; typedef void *voidpf; typedef uLong uLongf; typedef void *voidp; typedef void *const voidpc; #define Z_NULL 0 #define Z_NO_FLUSH MZ_NO_FLUSH #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH #define Z_SYNC_FLUSH MZ_SYNC_FLUSH #define Z_FULL_FLUSH MZ_FULL_FLUSH #define Z_FINISH MZ_FINISH #define Z_BLOCK MZ_BLOCK #define Z_OK MZ_OK #define Z_STREAM_END MZ_STREAM_END #define Z_NEED_DICT MZ_NEED_DICT #define Z_ERRNO MZ_ERRNO #define Z_STREAM_ERROR MZ_STREAM_ERROR #define Z_DATA_ERROR MZ_DATA_ERROR #define Z_MEM_ERROR MZ_MEM_ERROR #define Z_BUF_ERROR MZ_BUF_ERROR #define Z_VERSION_ERROR MZ_VERSION_ERROR #define Z_PARAM_ERROR MZ_PARAM_ERROR #define Z_NO_COMPRESSION MZ_NO_COMPRESSION #define Z_BEST_SPEED MZ_BEST_SPEED #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY #define Z_FILTERED MZ_FILTERED #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY #define Z_RLE MZ_RLE #define Z_FIXED MZ_FIXED #define Z_DEFLATED MZ_DEFLATED #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS #define alloc_func mz_alloc_func #define free_func mz_free_func #define internal_state mz_internal_state #define z_stream mz_stream #define deflateInit mz_deflateInit #define deflateInit2 mz_deflateInit2 #define deflateReset mz_deflateReset #define deflate mz_deflate #define deflateEnd mz_deflateEnd #define deflateBound mz_deflateBound #define compress mz_compress #define compress2 mz_compress2 #define compressBound mz_compressBound #define inflateInit mz_inflateInit #define inflateInit2 mz_inflateInit2 #define inflate mz_inflate #define inflateEnd mz_inflateEnd #define uncompress mz_uncompress #define crc32 mz_crc32 #define adler32 mz_adler32 #define MAX_WBITS 15 #define MAX_MEM_LEVEL 9 #define zError mz_error #define ZLIB_VERSION MZ_VERSION #define ZLIB_VERNUM MZ_VERNUM #define ZLIB_VER_MAJOR MZ_VER_MAJOR #define ZLIB_VER_MINOR MZ_VER_MINOR #define ZLIB_VER_REVISION MZ_VER_REVISION #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION #define zlibVersion mz_version #define zlib_version mz_version() #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES #endif // MINIZ_NO_ZLIB_APIS // ------------------- Types and macros typedef unsigned char mz_uint8; typedef signed short mz_int16; typedef unsigned short mz_uint16; typedef unsigned int mz_uint32; typedef unsigned int mz_uint; typedef long long mz_int64; typedef unsigned long long mz_uint64; typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) // An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif // ------------------- ZIP archive reading/writing #ifndef MINIZ_NO_ARCHIVE_APIS enum { MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 }; typedef struct { mz_uint32 m_file_index; mz_uint32 m_central_dir_ofs; mz_uint16 m_version_made_by; mz_uint16 m_version_needed; mz_uint16 m_bit_flag; mz_uint16 m_method; #ifndef MINIZ_NO_TIME time_t m_time; #endif mz_uint32 m_crc32; mz_uint64 m_comp_size; mz_uint64 m_uncomp_size; mz_uint16 m_internal_attr; mz_uint32 m_external_attr; mz_uint64 m_local_header_ofs; mz_uint32 m_comment_size; char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; } mz_zip_archive_file_stat; typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; typedef enum { MZ_ZIP_MODE_INVALID = 0, MZ_ZIP_MODE_READING = 1, MZ_ZIP_MODE_WRITING = 2, MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; typedef struct mz_zip_archive_tag { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; mz_uint m_total_files; mz_zip_mode m_zip_mode; mz_uint m_file_offset_alignment; mz_alloc_func m_pAlloc; mz_free_func m_pFree; mz_realloc_func m_pRealloc; void *m_pAlloc_opaque; mz_file_read_func m_pRead; mz_file_write_func m_pWrite; void *m_pIO_opaque; mz_zip_internal_state *m_pState; } mz_zip_archive; typedef enum { MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 } mz_zip_flags; // ZIP archive reading // Inits a ZIP archive reader. // These functions read and validate the archive's central directory. mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); #ifndef MINIZ_NO_STDIO mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); #endif // Returns the total number of files in the archive. mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); // Returns detailed information about an archive file entry. mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); // Determines if an archive file entry is a directory entry. mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); // Retrieves the filename of an archive file entry. // Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); // Attempts to locates a file in the archive's central directory. // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH // Returns -1 if the file cannot be found. int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); // Extracts a archive file to a memory buffer using no memory allocation. mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); // Extracts a archive file to a memory buffer. mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); // Extracts a archive file to a dynamically allocated heap buffer. void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); // Extracts a archive file using a callback function to output the file's data. mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); #ifndef MINIZ_NO_STDIO // Extracts a archive file to a disk file and sets its last accessed and modified times. // This function only extracts files, not archive directory records. mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); #endif // Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. mz_bool mz_zip_reader_end(mz_zip_archive *pZip); // ZIP archive writing #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS // Inits a ZIP archive writer. mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); #endif // Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. // For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. // For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. // Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before // the archive is finalized the file's central directory will be hosed. mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); // Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. // To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); #ifndef MINIZ_NO_STDIO // Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); #endif // Adds a file to an archive by fully cloning the data from another archive. // This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); // Finalizes the archive by writing the central directory records followed by the end of central directory record. // After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). // An archive must be manually finalized by calling this function for it to be valid. mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); // Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. // Note for the archive to be valid, it must have been finalized before ending. mz_bool mz_zip_writer_end(mz_zip_archive *pZip); // Misc. high-level helper functions: // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); // Reads a single file from an archive into a heap block. // Returns NULL on failure. void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS #endif // #ifndef MINIZ_NO_ARCHIVE_APIS // ------------------- Low-level Decompression API Definitions // Decompression flags used by tinfl_decompress(). // TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. // TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. // TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, TINFL_FLAG_COMPUTE_ADLER32 = 8 }; // High level decompression functions: // tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). // On entry: // pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. // On return: // Function returns a pointer to the decompressed data, or NULL on failure. // *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. // The caller must call mz_free() on the returned block when it's no longer needed. void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); // tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. // Returns 1 on success or 0 on failure. typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; // Max size of LZ dictionary. #define TINFL_LZ_DICT_SIZE 32768 // Return status. typedef enum { TINFL_STATUS_BAD_PARAM = -3, TINFL_STATUS_ADLER32_MISMATCH = -2, TINFL_STATUS_FAILED = -1, TINFL_STATUS_DONE = 0, TINFL_STATUS_NEEDS_MORE_INPUT = 1, TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; // Initializes the decompressor to its initial state. #define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 // Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. // This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); // Internal/private bits follow. enum { TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; typedef struct { mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; } tinfl_huff_table; #if MINIZ_HAS_64BIT_REGISTERS #define TINFL_USE_64BIT_BITBUF 1 #endif #if TINFL_USE_64BIT_BITBUF typedef mz_uint64 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (64) #else typedef mz_uint32 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (32) #endif struct tinfl_decompressor_tag { mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; // ------------------- Low-level Compression API Definitions // Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). #define TDEFL_LESS_MEMORY 0 // tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. // TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. // The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, TDEFL_RLE_MATCHES = 0x10000, TDEFL_FILTER_MATCHES = 0x20000, TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; // High level compression functions: // tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). // On entry: // pSrc_buf, src_buf_len: Pointer and size of source block to compress. // flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. // On return: // Function returns a pointer to the compressed data, or NULL on failure. // *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. // The caller must free() the returned block when it's no longer needed. void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); // tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. // Returns 0 on failure. size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); // Compresses an image to a compressed PNG file in memory. // On entry: // pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. // The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. // level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL // If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). // On return: // Function returns a pointer to the compressed data, or NULL on failure. // *pLen_out will be set to the size of the PNG image file. // The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); // Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); // tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #else enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #endif // The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, TDEFL_STATUS_DONE = 1, } tdefl_status; // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; // tdefl's compression state structure. typedef struct { tdefl_put_buf_func_ptr m_pPut_buf_func; void *m_pPut_buf_user; mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; size_t *m_pIn_buf_size, *m_pOut_buf_size; tdefl_flush m_flush; const mz_uint8 *m_pSrc; size_t m_src_buf_left, m_out_buf_ofs; mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; // Initializes the compressor. // There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. // pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. // If pBut_buf_func is NULL the user should always call the tdefl_compress() API. // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); // Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. // tdefl_compress_buffer() always consumes the entire input buffer. tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); mz_uint32 tdefl_get_adler32(tdefl_compressor *d); // Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. #ifndef MINIZ_NO_ZLIB_APIS // Create tdefl_compress() flags given zlib-style compression parameters. // level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) // window_bits may be -15 (raw deflate) or 15 (zlib) // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); #endif // #ifndef MINIZ_NO_ZLIB_APIS #ifdef __cplusplus } #endif #endif // MINIZ_HEADER_INCLUDED // ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) #ifndef MINIZ_HEADER_FILE_ONLY typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; #include <string.h> #include <assert.h> #define MZ_ASSERT(x) assert(x) #ifdef MINIZ_NO_MALLOC #define MZ_MALLOC(x) NULL #define MZ_FREE(x) (void)x, ((void)0) #define MZ_REALLOC(p, x) NULL #else #define MZ_MALLOC(x) malloc(x) #define MZ_FREE(x) free(x) #define MZ_REALLOC(p, x) realloc(p, x) #endif #define MZ_MAX(a,b) (((a)>(b))?(a):(b)) #define MZ_MIN(a,b) (((a)<(b))?(a):(b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #ifdef _MSC_VER #define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) #else #define MZ_FORCEINLINE inline #endif #ifdef __cplusplus extern "C" { #endif // ------------------- zlib-style API's mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; if (!ptr) return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } return (s2 << 16) + s1; } // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; mz_uint32 crcu32 = (mz_uint32)crc; if (!ptr) return MZ_CRC32_INIT; crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } return ~crcu32; } void mz_free(void *p) { MZ_FREE(p); } #ifndef MINIZ_NO_ZLIB_APIS static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } const char *mz_version(void) { return MZ_VERSION; } int mz_deflateInit(mz_streamp pStream, int level) { return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { tdefl_compressor *pComp; mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); if (!pStream) return MZ_STREAM_ERROR; if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; pStream->msg = NULL; pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; if (!pStream->zalloc) pStream->zalloc = def_alloc_func; if (!pStream->zfree) pStream->zfree = def_free_func; pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); if (!pComp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pComp; if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; } return MZ_OK; } int mz_deflateReset(mz_streamp pStream) { if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); return MZ_OK; } int mz_deflate(mz_streamp pStream, int flush) { size_t in_bytes, out_bytes; mz_ulong orig_total_in, orig_total_out; int mz_status = MZ_OK; if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; if (!pStream->avail_out) return MZ_BUF_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; for ( ; ; ) { tdefl_status defl_status; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (defl_status < 0) { mz_status = MZ_STREAM_ERROR; break; } else if (defl_status == TDEFL_STATUS_DONE) { mz_status = MZ_STREAM_END; break; } else if (!pStream->avail_out) break; else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) break; return MZ_BUF_ERROR; // Can't make forward progress without some input. } } return mz_status; } int mz_deflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { (void)pStream; // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); // In case mz_ulong is 64-bits (argh I hate longs). if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_deflateInit(&stream, level); if (status != MZ_OK) return status; status = mz_deflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_deflateEnd(&stream); return (status == MZ_OK) ? MZ_BUF_ERROR : status; } *pDest_len = stream.total_out; return mz_deflateEnd(&stream); } int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); } mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } typedef struct { tinfl_decompressor m_decomp; mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; tinfl_status m_last_status; } inflate_state; int mz_inflateInit2(mz_streamp pStream, int window_bits) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; if (!pStream->zalloc) pStream->zalloc = def_alloc_func; if (!pStream->zfree) pStream->zfree = def_free_func; pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); if (!pDecomp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pDecomp; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; pDecomp->m_window_bits = window_bits; return MZ_OK; } int mz_inflateInit(mz_streamp pStream) { return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } int mz_inflate(mz_streamp pStream, int flush) { inflate_state* pState; mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; size_t in_bytes, out_bytes, orig_avail_in; tinfl_status status; if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState = (inflate_state*)pStream->state; if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; orig_avail_in = pStream->avail_in; first_call = pState->m_first_call; pState->m_first_call = 0; if (pState->m_last_status < 0) return MZ_DATA_ERROR; if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState->m_has_flushed |= (flush == MZ_FINISH); if ((flush == MZ_FINISH) && (first_call)) { // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (status < 0) return MZ_DATA_ERROR; else if (status != TINFL_STATUS_DONE) { pState->m_last_status = TINFL_STATUS_FAILED; return MZ_BUF_ERROR; } return MZ_STREAM_END; } // flush != MZ_FINISH then we must assume there's more input. if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; if (pState->m_dict_avail) { n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } for ( ; ; ) { in_bytes = pStream->avail_in; out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pState->m_dict_avail = (mz_uint)out_bytes; n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); if (status < 0) return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. else if (flush == MZ_FINISH) { // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. if (status == TINFL_STATUS_DONE) return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. else if (!pStream->avail_out) return MZ_BUF_ERROR; } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) break; } return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } int mz_inflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { mz_stream stream; int status; memset(&stream, 0, sizeof(stream)); // In case mz_ulong is 64-bits (argh I hate longs). if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_inflateInit(&stream); if (status != MZ_OK) return status; status = mz_inflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_inflateEnd(&stream); return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; } *pDest_len = stream.total_out; return mz_inflateEnd(&stream); } const char *mz_error(int err) { static struct { int m_err; const char *m_pDesc; } s_error_descs[] = { { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } }; mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; return NULL; } #endif //MINIZ_NO_ZLIB_APIS // ------------------- Low-level Decompression (completely independent from all compression API's) #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) #define TINFL_MEMSET(p, c, l) memset(p, c, l) #define TINFL_CR_BEGIN switch(r->m_state) { case 0: #define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END #define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END #define TINFL_CR_FINISH } // TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. #define TINFL_GET_BYTE(state_index, c) do { \ if (pIn_buf_cur >= pIn_buf_end) { \ for ( ; ; ) { \ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ if (pIn_buf_cur < pIn_buf_end) { \ c = *pIn_buf_cur++; \ break; \ } \ } else { \ c = 0; \ break; \ } \ } \ } else c = *pIn_buf_cur++; } MZ_MACRO_END #define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) #define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END #define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. // It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a // Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the // bit buffer contains >=15 bits (deflate's max. Huffman code size). #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ do { \ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ if (temp >= 0) { \ code_len = temp >> 9; \ if ((code_len) && (num_bits >= code_len)) \ break; \ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ } while (num_bits < 15); // TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read // beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully // decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. // The slow path is only executed at the very end of the input buffer. #define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ int temp; mz_uint code_len, c; \ if (num_bits < 15) { \ if ((pIn_buf_end - pIn_buf_cur) < 2) { \ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ } else { \ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ } \ } \ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ code_len = temp >> 9, temp &= 511; \ else { \ code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) { static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; static const int s_min_table_sizes[3] = { 257, 1, 4 }; tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; TINFL_CR_BEGIN bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } } do { TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; if (r->m_type == 0) { TINFL_SKIP_BITS(5, num_bits & 7); for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } while ((counter) && (num_bits)) { TINFL_GET_BITS(51, dist, 8); while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)dist; counter--; } while (counter) { size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } while (pIn_buf_cur >= pIn_buf_end) { if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); } else { TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); } } n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; } } else if (r->m_type == 3) { TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); } else { if (r->m_type == 1) { mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; } else { for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } r->m_table_sizes[2] = 19; } for ( ; (int)r->m_type >= 0; r->m_type--) { int tree_next, tree_cur; tinfl_huff_table *pTable; mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } if ((65536 != total) && (used_syms > 1)) { TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { tree_cur -= ((rev_code >>= 1) & 1); if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; } tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) { mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } if ((dist == 16) && (!counter)) { TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); } num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; } if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); } } for ( ; ; ) { mz_uint8 *pSrc; for ( ; ; ) { if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); if (counter >= 256) break; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)counter; } else { int sym2; mz_uint code_len; #if TINFL_USE_64BIT_BITBUF if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } #else if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } counter = sym2; bit_buf >>= code_len; num_bits -= code_len; if (counter & 256) break; #if !TINFL_USE_64BIT_BITBUF if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } bit_buf >>= code_len; num_bits -= code_len; pOut_buf_cur[0] = (mz_uint8)counter; if (sym2 & 256) { pOut_buf_cur++; counter = sym2; break; } pOut_buf_cur[1] = (mz_uint8)sym2; pOut_buf_cur += 2; } } if ((counter &= 511) == 256) break; num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); } pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { while (counter--) { while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; } continue; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES else if ((counter >= 9) && (counter <= dist)) { const mz_uint8 *pSrc_end = pSrc + (counter & ~7); do { ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; pOut_buf_cur += 8; } while ((pSrc += 8) < pSrc_end); if ((counter &= 7) < 3) { if (counter) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } continue; } } #endif do { pOut_buf_cur[0] = pSrc[0]; pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur[2] = pSrc[2]; pOut_buf_cur += 3; pSrc += 3; } while ((int)(counter -= 3) > 2); if ((int)counter > 0) { pOut_buf_cur[0] = pSrc[0]; if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } } } } while (!(r->m_final & 1)); if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } } TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); TINFL_CR_FINISH common_exit: r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) { const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; } return status; } // Higher level helper functions. void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); for ( ; ; ) { size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; if (status == TINFL_STATUS_DONE) break; new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); if (!pNew_buf) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; } return pBuf; } size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; } int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { int result = 0; tinfl_decompressor decomp; mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; tinfl_init(&decomp); for ( ; ; ) { size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) break; if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { result = (status == TINFL_STATUS_DONE); break; } dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); } MZ_FREE(pDict); *pIn_buf_size = in_buf_ofs; return result; } // ------------------- Low-level Compression (independent from all decompression API's) // Purposely making these tables static for faster init and thread safety. static const mz_uint16 s_tdefl_len_sym[256] = { 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; static const mz_uint8 s_tdefl_len_extra[256] = { 0,0,0,0,0,0,0,0,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,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; static const mz_uint8 s_tdefl_small_dist_sym[512] = { 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; static const mz_uint8 s_tdefl_small_dist_extra[512] = { 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7 }; static const mz_uint8 s_tdefl_large_dist_sym[128] = { 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; static const mz_uint8 s_tdefl_large_dist_extra[128] = { 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { const mz_uint32* pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } } return pCur_syms; } // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } A[0].m_key += A[1].m_key; root = 0; leaf = 2; for (next=1; next < n-1; next++) { if (leaf>=n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key; if (leaf>=n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); } A[n-2].m_key = 0; for (next=n-3; next>=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; avbl = 1; used = dpth = 0; root = n-2; next = n-1; while (avbl>0) { while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } avbl = 2*used; dpth++; used = 0; } } // Limits canonical Huffman code table's max code size. enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { int i; mz_uint32 total = 0; if (code_list_len <= 1) return; for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } total--; } } static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); for (i = 0; i < table_len; i++) { mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } #define TDEFL_PUT_BITS(b, l) do { \ mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ while (d->m_bits_in >= 8) { \ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ d->m_bit_buffer >>= 8; \ d->m_bits_in -= 8; \ } \ } MZ_MACRO_END #define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ if (rle_repeat_count < 3) { \ d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } else { \ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ } rle_repeat_count = 0; } } #define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ if (rle_z_count < 3) { \ d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ } else if (rle_z_count <= 10) { \ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ } else { \ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ } rle_z_count = 0; } } static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static void tdefl_start_dynamic_block(tdefl_compressor *d) { int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } } else { TDEFL_RLE_ZERO_CODE_SIZE(); if (code_size != prev_code_size) { TDEFL_RLE_PREV_CODE_SIZE(); d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); TDEFL_PUT_BITS(2, 2); TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) { mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); } } static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; for (i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); TDEFL_PUT_BITS(1, 2); } static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); // This sequence coaxes MSVC into using cmov's vs. jmp's. s0 = s_tdefl_small_dist_sym[match_dist & 511]; n0 = s_tdefl_small_dist_extra[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; n1 = s_tdefl_large_dist_extra[match_dist >> 8]; sym = (match_dist < 512) ? s0 : s1; num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } } if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; *(mz_uint64*)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; } #undef TDEFL_PUT_BITS_FAST d->m_pOutput_buf = pOutput_buf; d->m_bits_in = 0; d->m_bit_buffer = 0; while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; bits_in -= n; } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); if (match_dist < 512) { sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; } else { sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else tdefl_start_dynamic_block(d); return tdefl_compress_lz_codes(d); } static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; MZ_ASSERT(!d->m_output_flush_remaining); d->m_output_flush_ofs = 0; d->m_output_flush_remaining = 0; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; if (!use_raw_block) comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } for (i = 0; i < d->m_total_lz_bytes; ++i) { TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); } } // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } if (flush) { if (flush == TDEFL_FINISH) { if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } } else { mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { if (d->m_pPut_buf_func) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); } else if (pOutput_buf_start == d->m_output_buf) { int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } } else { d->m_out_buf_ofs += n; } } return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for ( ; ; ) { for ( ; ; ) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); if (!probe_len) { *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for ( ; ; ) { for ( ; ; ) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; } } } #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static mz_bool tdefl_compress_fast(tdefl_compressor *d) { // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); mz_uint32 probe_len = 32; do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; pLZ_code_buf += 3; *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; } } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } d->m_huff_count[0][lit]++; lookahead_pos++; dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } } d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } d->m_huff_count[0][lit]++; } static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } static mz_bool tdefl_compress_normal(tdefl_compressor *d) { const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; } } else { while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { mz_uint8 c = *pSrc++; mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); } } } d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; // Simple lazy/greedy parsing state machine. len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; } } else { tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); } if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } if (d->m_saved_match_len) { if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); d->m_saved_match_len = 0; len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; } } else if (!cur_match_dist) tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } // Move the lookahead forward by len_to_move bytes. d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); // Check if it's time to flush the current LZ codes to the internal output buffer. if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) { int n; d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; return MZ_TRUE; } static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } if (d->m_pOut_buf_size) { size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; *d->m_pOut_buf_size = d->m_out_buf_ofs; } return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { if (!d) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); if ((d->m_output_flush_remaining) || (d->m_finished)) return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; } else #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { return d->m_prev_return_status; } mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); MZ_FREE(pComp); return succeeded; } typedef struct { size_t m_size, m_capacity; mz_uint8 *m_pBuf; mz_bool m_expandable; } tdefl_output_buffer; static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; size_t new_size = p->m_size + len; if (new_size > p->m_capacity) { size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; } memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; return MZ_TRUE; } void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; *pOut_len = out_buf.m_size; return out_buf.m_pBuf; } size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_buf) return 0; out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; return out_buf.m_size; } #ifndef MINIZ_NO_ZLIB_APIS static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; // level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } #endif //MINIZ_NO_ZLIB_APIS #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) #endif // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. // This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) { // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; if (!pComp) return NULL; MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } // write dummy header for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); // compress image data tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } // write real header *pLen_out = out_buf.m_size-41; { static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0, (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); memcpy(out_buf.m_pBuf, pnghdr, 41); } // write footer (IDAT CRC-32, followed by IEND chunk) if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); // compute final size of file, grab compressed data buffer and return *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; } void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); } #ifdef _MSC_VER #pragma warning (pop) #endif // ------------------- .ZIP archive reading #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include <stdio.h> #include <sys/stat.h> #if defined(_MSC_VER) || defined(__MINGW64__) static FILE *mz_fopen(const char *pFilename, const char *pMode) { FILE* pFile = NULL; fopen_s(&pFile, pFilename, pMode); return pFile; } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { FILE* pFile = NULL; if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; return pFile; } #ifndef MINIZ_NO_TIME #include <sys/utime.h> #endif #define MZ_FILE FILE #define MZ_FOPEN mz_fopen #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove #elif defined(__MINGW32__) #ifndef MINIZ_NO_TIME #include <sys/utime.h> #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME #include <sys/utime.h> #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__GNUC__) && _LARGEFILE64_SOURCE #ifndef MINIZ_NO_TIME #include <utime.h> #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen64(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT stat64 #define MZ_FILE_STAT stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove #else #ifndef MINIZ_NO_TIME #include <utime.h> #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #endif // #ifdef _MSC_VER #endif // #ifdef MINIZ_NO_STDIO #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) // Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. enum { // ZIP archive identifiers and record sizes MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, // Central directory header record offsets MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, // Local directory header offsets MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, // End of central directory offsets MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, }; typedef struct { void *m_p; size_t m_size, m_capacity; mz_uint m_element_size; } mz_zip_array; struct mz_zip_internal_state_tag { mz_zip_array m_central_dir; mz_zip_array m_central_dir_offsets; mz_zip_array m_sorted_central_dir_offsets; MZ_FILE *m_pFile; void *m_pMem; size_t m_mem_size; size_t m_mem_capacity; }; #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) { pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); memset(pArray, 0, sizeof(mz_zip_array)); } static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) { void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) { if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) { if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } pArray->m_size = new_size; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) { return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) { size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); return MZ_TRUE; } #ifndef MINIZ_NO_TIME static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; return mktime(&tm); } static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef _MSC_VER struct tm tm_struct; struct tm *tm = &tm_struct; errno_t err = localtime_s(tm, &time); if (err) { *pDOS_date = 0; *pDOS_time = 0; return; } #else struct tm *tm = localtime(&time); #endif *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } #endif #ifndef MINIZ_NO_STDIO static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef MINIZ_NO_TIME (void)pFilename; *pDOS_date = *pDOS_time = 0; #else struct MZ_FILE_STAT_STRUCT file_stat; // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); #endif // #ifdef MINIZ_NO_TIME return MZ_TRUE; } #ifndef MINIZ_NO_TIME static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) { struct utimbuf t; t.actime = access_time; t.modtime = modified_time; return !utime(pFilename, &t); } #endif // #ifndef MINIZ_NO_TIME #endif // #ifndef MINIZ_NO_STDIO static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) { (void)flags; if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return MZ_FALSE; if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; pZip->m_zip_mode = MZ_ZIP_MODE_READING; pZip->m_archive_size = 0; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return MZ_FALSE; memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (l_len < r_len) : (l < r); } #define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END // Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); const int size = pZip->m_total_files; int start = (size - 2) >> 1, end; while (start >= 0) { int child, root = start; for ( ; ; ) { if ((child = (root << 1) + 1) >= size) break; child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } start--; } end = size - 1; while (end > 0) { int child, root = 0; MZ_SWAP_UINT32(pIndices[end], pIndices[0]); for ( ; ; ) { if ((child = (root << 1) + 1) >= end) break; child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } end--; } } static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) { mz_uint cdir_size, num_this_disk, cdir_disk_index; mz_uint64 cdir_ofs; mz_int64 cur_file_ofs; const mz_uint8 *p; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; // Find the end of central directory record by scanning the file from the end towards the beginning. cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); for ( ; ; ) { int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) return MZ_FALSE; for (i = n - 4; i >= 0; --i) if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; if (i >= 0) { cur_file_ofs += i; break; } if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } // Read and verify the end of central directory record. if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) return MZ_FALSE; num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) return MZ_FALSE; if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE; pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) return MZ_FALSE; if (sort_central_dir) { if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) return MZ_FALSE; } if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return MZ_FALSE; // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { mz_uint total_header_size, comp_size, decomp_size, disk_index; if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) return MZ_FALSE; MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); if (sort_central_dir) MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) return MZ_FALSE; disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) return MZ_FALSE; if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) return MZ_FALSE; n -= total_header_size; p += total_header_size; } } if (sort_central_dir) mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); return MZ_TRUE; } mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) { if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_archive_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); return s; } mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) { if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_archive_size = size; pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; #ifdef __cplusplus pZip->m_pState->m_pMem = const_cast<void *>(pMem); #else pZip->m_pState->m_pMem = (void *)pMem; #endif pZip->m_pState->m_mem_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) { mz_uint64 file_size; MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return MZ_FALSE; if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return MZ_FALSE; } file_size = MZ_FTELL64(pFile); if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { return pZip ? pZip->m_total_files : 0; } static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return NULL; return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) { mz_uint m_bit_flag; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) return MZ_FALSE; m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); return (m_bit_flag & 1); } mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) { mz_uint filename_len, external_attr; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) return MZ_FALSE; // First see if the filename ends with a '/' character. filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_len) { if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') return MZ_TRUE; } // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. // FIXME: Remove this check? Is it necessary - we already check the filename. external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); if ((external_attr & 0x10) != 0) return MZ_TRUE; return MZ_FALSE; } mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { mz_uint n; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if ((!p) || (!pStat)) return MZ_FALSE; // Unpack the central directory record. pStat->m_file_index = file_index; pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); // Copy as much of the filename and comment as possible. n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; return MZ_TRUE; } mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { mz_uint n; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_buf_size) { n = MZ_MIN(n, filename_buf_size - 1); memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pFilename[n] = '\0'; } return n + 1; } static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) { mz_uint i; if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); for (i = 0; i < len; ++i) if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; return MZ_TRUE; } static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (int)(l_len - r_len) : (l - r); } static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); const int size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); int l = 0, h = size - 1; while (l <= h) { int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); if (!comp) return file_index; else if (comp < 0) l = m + 1; else h = m - 1; } return -1; } int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) { mz_uint file_index; size_t name_len, comment_len; if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return -1; if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) return mz_zip_reader_locate_file_binary_search(pZip, pName); name_len = strlen(pName); if (name_len > 0xFFFF) return -1; comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; for (file_index = 0; file_index < pZip->m_total_files; file_index++) { const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; if (filename_len < name_len) continue; if (comment_len) { mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); const char *pFile_comment = pFilename + filename_len + file_extra_len; if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) continue; } if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { int ofs = filename_len - 1; do { if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) break; } while (--ofs >= 0); ofs++; pFilename += ofs; filename_len -= ofs; } if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) return file_index; } return -1; } mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int status = TINFL_STATUS_DONE; mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; void *pRead_buf; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; tinfl_decompressor inflator; if ((buf_size) && (!pBuf)) return MZ_FALSE; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) if (!file_stat.m_comp_size) return MZ_TRUE; // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). // I'm torn how to handle this case - should it fail instead? if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; // Encryption and patch files are not supported. if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; // This function only supports stored and deflate. if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return MZ_FALSE; // Ensure supplied output buffer is large enough. needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; if (buf_size < needed_size) return MZ_FALSE; // Read and parse the local directory entry. cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return MZ_FALSE; if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) return MZ_FALSE; return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); } // Decompress the file either directly from memory or from a file input buffer. tinfl_init(&inflator); if (pZip->m_pState->m_pMem) { // Read directly from the archive in memory. pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else if (pUser_read_buf) { // Use a user provided read buffer. if (!user_read_buf_size) return MZ_FALSE; pRead_buf = (mz_uint8 *)pUser_read_buf; read_buf_size = user_read_buf_size; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } else { // Temporarily allocate a read buffer. read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); #ifdef _MSC_VER if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #endif return MZ_FALSE; if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return MZ_FALSE; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } do { size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; out_buf_ofs += out_buf_size; } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); if (status == TINFL_STATUS_DONE) { // Make sure the entire file was decompressed, and check its CRC. if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); } void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) { mz_uint64 comp_size, uncomp_size, alloc_size; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); void *pBuf; if (pSize) *pSize = 0; if (!p) return NULL; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; #ifdef _MSC_VER if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #endif return NULL; if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) return NULL; if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } if (pSize) *pSize = (size_t)alloc_size; return pBuf; } void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) { if (pSize) *pSize = 0; return MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf = NULL; void *pWrite_buf = NULL; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) if (!file_stat.m_comp_size) return MZ_TRUE; // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). // I'm torn how to handle this case - should it fail instead? if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; // Encryption and patch files are not supported. if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; // This function only supports stored and deflate. if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return MZ_FALSE; // Read and parse the local directory entry. cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return MZ_FALSE; // Decompress the file either directly from memory or from a file input buffer. if (pZip->m_pState->m_pMem) { pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else { read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return MZ_FALSE; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. if (pZip->m_pState->m_pMem) { #ifdef _MSC_VER if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #endif return MZ_FALSE; if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) status = TINFL_STATUS_FAILED; else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); cur_file_ofs += file_stat.m_comp_size; out_buf_ofs += file_stat.m_comp_size; comp_remaining = 0; } else { while (comp_remaining) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; out_buf_ofs += read_buf_avail; comp_remaining -= read_buf_avail; } } } else { tinfl_decompressor inflator; tinfl_init(&inflator); if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) status = TINFL_STATUS_FAILED; else { do { mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; if (out_buf_size) { if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) { status = TINFL_STATUS_FAILED; break; } file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { status = TINFL_STATUS_FAILED; break; } } } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); } } if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { // Make sure the entire file was decompressed, and check its CRC. if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) { (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); } mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) { mz_bool status; mz_zip_archive_file_stat file_stat; MZ_FILE *pFile; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; pFile = MZ_FOPEN(pDst_filename, "wb"); if (!pFile) return MZ_FALSE; status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; #ifndef MINIZ_NO_TIME if (status) mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); #endif return status; } #endif // #ifndef MINIZ_NO_STDIO mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return MZ_FALSE; if (pZip->m_pState) { mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { MZ_FCLOSE(pState->m_pFile); pState->m_pFile = NULL; } #endif // #ifndef MINIZ_NO_STDIO pZip->m_pFree(pZip->m_pAlloc_opaque, pState); } pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); } #endif // ------------------- .ZIP archive writing #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return MZ_FALSE; if (pZip->m_file_offset_alignment) { // Ensure user specified file offset alignment is a power of 2. if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) return MZ_FALSE; } if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; pZip->m_archive_size = existing_size; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return MZ_FALSE; memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); return MZ_TRUE; } static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_zip_internal_state *pState = pZip->m_pState; mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); #ifdef _MSC_VER if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) #else if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) #endif return 0; if (new_size > pState->m_mem_capacity) { void *pNew_block; size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) return 0; pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; } memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); pState->m_mem_size = (size_t)new_size; return n; } mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) { pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end(pZip); return MZ_FALSE; } pZip->m_pState->m_mem_capacity = initial_allocation_size; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) { MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { mz_zip_writer_end(pZip); return MZ_FALSE; } pZip->m_pState->m_pFile = pFile; if (size_to_reserve_at_beginning) { mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { mz_zip_writer_end(pZip); return MZ_FALSE; } cur_ofs += n; size_to_reserve_at_beginning -= n; } while (size_to_reserve_at_beginning); } return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return MZ_FALSE; // No sense in trying to write to an archive that's already at the support max size if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; pState = pZip->m_pState; if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO pFilename; return MZ_FALSE; #else // Archive is being read from stdio - try to reopen as writable. if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; if (!pFilename) return MZ_FALSE; pZip->m_pWrite = mz_zip_file_write_func; if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. mz_zip_reader_end(pZip); return MZ_FALSE; } #endif // #ifdef MINIZ_NO_STDIO } else if (pState->m_pMem) { // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; } // Archive is being read via a user provided read function - make sure the user has specified a write function too. else if (!pZip->m_pWrite) return MZ_FALSE; // Start writing new files at the archive's current central directory location. pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; pZip->m_central_directory_file_ofs = 0; return MZ_TRUE; } mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); } typedef struct { mz_zip_archive *m_pZip; mz_uint64 m_cur_archive_file_ofs; mz_uint64 m_comp_size; } mz_zip_writer_add_state; static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) { mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) return MZ_FALSE; pState->m_cur_archive_file_ofs += len; pState->m_comp_size += len; return MZ_TRUE; } static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); return MZ_TRUE; } static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { (void)pZip; memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); return MZ_TRUE; } static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { mz_zip_internal_state *pState = pZip->m_pState; mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; size_t orig_central_dir_size = pState->m_central_dir.m_size; mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; // No zip64 support yet if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) return MZ_FALSE; if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) { // Try to push the central directory array back into its original state. mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. if (*pArchive_name == '/') return MZ_FALSE; while (*pArchive_name) { if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; pArchive_name++; } return MZ_TRUE; } static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { mz_uint32 n; if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); } static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { char buf[4096]; memset(buf, 0, MZ_MIN(sizeof(buf), n)); while (n) { mz_uint32 s = MZ_MIN(sizeof(buf), n); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) return MZ_FALSE; cur_file_ofs += s; n -= s; } return MZ_TRUE; } mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; tdefl_compressor *pComp = NULL; mz_bool store_data_uncompressed; mz_zip_internal_state *pState; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) return MZ_FALSE; pState = pZip->m_pState; if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) return MZ_FALSE; // No zip64 support yet if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; #ifndef MINIZ_NO_TIME { time_t cur_time; time(&cur_time); mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); } #endif // #ifndef MINIZ_NO_TIME archive_name_size = strlen(pArchive_name); if (archive_name_size > 0xFFFF) return MZ_FALSE; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { // Set DOS Subdirectory attribute bit. ext_attributes |= 0x10; // Subdirectories cannot contain data. if ((buf_size) || (uncomp_size)) return MZ_FALSE; } // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) return MZ_FALSE; if ((!store_data_uncompressed) && (buf_size)) { if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return MZ_FALSE; } if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); MZ_CLEAR_OBJ(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } cur_archive_file_ofs += archive_name_size; if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); uncomp_size = buf_size; if (uncomp_size <= 3) { level = 0; store_data_uncompressed = MZ_TRUE; } } if (store_data_uncompressed) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } cur_archive_file_ofs += buf_size; comp_size = buf_size; if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; } else if (buf_size) { mz_zip_writer_add_state state; state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; method = MZ_DEFLATED; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pComp = NULL; // no zip64 support yet if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) return MZ_FALSE; if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return MZ_FALSE; if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; MZ_FILE *pSrc_file = NULL; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return MZ_FALSE; if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; archive_name_size = strlen(pArchive_name); if (archive_name_size > 0xFFFF) return MZ_FALSE; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) return MZ_FALSE; pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) return MZ_FALSE; MZ_FSEEK64(pSrc_file, 0, SEEK_END); uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); if (uncomp_size > 0xFFFFFFFF) { // No zip64 support yet MZ_FCLOSE(pSrc_file); return MZ_FALSE; } if (uncomp_size <= 3) level = 0; if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); MZ_CLEAR_OBJ(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } cur_archive_file_ofs += archive_name_size; if (uncomp_size) { mz_uint64 uncomp_remaining = uncomp_size; void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); if (!pRead_buf) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } if (!level) { while (uncomp_remaining) { mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); uncomp_remaining -= n; cur_archive_file_ofs += n; } comp_size = uncomp_size; } else { mz_bool result = MZ_FALSE; mz_zip_writer_add_state state; tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); if (!pComp) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } for ( ; ; ) { size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); tdefl_status status; if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) break; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; break; } else if (status != TDEFL_STATUS_OKAY) break; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); if (!result) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; method = MZ_DEFLATED; } pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); } MZ_FCLOSE(pSrc_file); pSrc_file = NULL; // no zip64 support yet if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) return MZ_FALSE; if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return MZ_FALSE; if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) { mz_uint n, bit_flags, num_alignment_padding_bytes; mz_uint64 comp_bytes_remaining, local_dir_header_ofs; mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; size_t orig_central_dir_size; mz_zip_internal_state *pState; void *pBuf; const mz_uint8 *pSrc_central_header; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return MZ_FALSE; if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) return MZ_FALSE; pState = pZip->m_pState; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); cur_dst_file_ofs = pZip->m_archive_size; if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) return MZ_FALSE; cur_dst_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_dst_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) return MZ_FALSE; while (comp_bytes_remaining) { n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_src_file_ofs += n; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_dst_file_ofs += n; comp_bytes_remaining -= n; } bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); if (bit_flags & 8) { // Copy data descriptor if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_src_file_ofs += n; cur_dst_file_ofs += n; } pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); // no zip64 support yet if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE; orig_central_dir_size = pState->m_central_dir.m_size; memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) return MZ_FALSE; n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return MZ_FALSE; } if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; n = (mz_uint32)orig_central_dir_size; if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return MZ_FALSE; } pZip->m_total_files++; pZip->m_archive_size = cur_dst_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_uint64 central_dir_ofs, central_dir_size; mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return MZ_FALSE; pState = pZip->m_pState; // no zip64 support yet if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; central_dir_ofs = 0; central_dir_size = 0; if (pZip->m_total_files) { // Write central directory central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return MZ_FALSE; pZip->m_archive_size += central_dir_size; } // Write end of central directory record MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) return MZ_FALSE; #ifndef MINIZ_NO_STDIO if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE; #endif // #ifndef MINIZ_NO_STDIO pZip->m_archive_size += sizeof(hdr); pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) { if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE; if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; *pBuf = pZip->m_pState->m_pMem; *pSize = pZip->m_pState->m_mem_size; pZip->m_pState->m_pMem = NULL; pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; return MZ_TRUE; } mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_bool status = MZ_TRUE; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) return MZ_FALSE; pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { MZ_FCLOSE(pState->m_pFile); pState->m_pFile = NULL; } #endif // #ifndef MINIZ_NO_STDIO if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); pState->m_pMem = NULL; } pZip->m_pFree(pZip->m_pAlloc_opaque, pState); pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { mz_bool status, created_new_archive = MZ_FALSE; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; MZ_CLEAR_OBJ(zip_archive); if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { // Create a new archive. if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) return MZ_FALSE; created_new_archive = MZ_TRUE; } else { // Append to an existing archive. if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) return MZ_FALSE; if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { mz_zip_reader_end(&zip_archive); return MZ_FALSE; } } status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; if ((!status) && (created_new_archive)) { // It's a new archive and something went wrong, so just delete it. int ignoredStatus = MZ_DELETE_FILE(pZip_filename); (void)ignoredStatus; } return status; } void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { int file_index; mz_zip_archive zip_archive; void *p = NULL; if (pSize) *pSize = 0; if ((!pZip_filename) || (!pArchive_name)) return NULL; MZ_CLEAR_OBJ(zip_archive); if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) return NULL; if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); mz_zip_reader_end(&zip_archive); return p; } #endif // #ifndef MINIZ_NO_STDIO #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS #endif // #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus } #endif #endif // MINIZ_HEADER_FILE_ONLY /* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to <http://unlicense.org/> */ |
Added src/mkbuiltin.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Copyright (c) 2014 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This is a stand-alone utility program that is part of the Fossil build ** process. This program reads files named on the command line and converts ** them into ANSI-C static char array variables. Output is written onto ** standard output. ** ** The makefiles use this utility to package various resources (large scripts, ** GIF images, etc) that are separate files in the source code as byte ** arrays in the resulting executable. */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* ** Read the entire content of the file named zFilename into memory obtained ** from malloc() and return a pointer to that memory. Write the size of the ** file into *pnByte. */ static unsigned char *read_file(const char *zFilename, int *pnByte){ FILE *in; unsigned char *z; int nByte; int got; in = fopen(zFilename, "rb"); if( in==0 ){ return 0; } fseek(in, 0, SEEK_END); *pnByte = nByte = ftell(in); fseek(in, 0, SEEK_SET); z = malloc( nByte+1 ); if( z==0 ){ fprintf(stderr, "failed to allocate %d bytes\n", nByte+1); exit(1); } got = fread(z, 1, nByte, in); fclose(in); z[got] = 0; return z; } /* ** There is an instance of the following for each file translated. */ typedef struct Resource Resource; struct Resource { char *zName; int nByte; int idx; }; /* ** Compare two Resource objects for sorting purposes. They sort ** in zName order so that Fossil can search for resources using ** a binary search. */ static int compareResource(const void *a, const void *b){ Resource *pA = (Resource*)a; Resource *pB = (Resource*)b; return strcmp(pA->zName, pB->zName); } int main(int argc, char **argv){ int i, sz; int j, n; Resource *aRes; int nRes; unsigned char *pData; int nErr = 0; int nSkip; int nPrefix = 0; if( argc>3 && strcmp(argv[1],"--prefix")==0 ){ nPrefix = (int)strlen(argv[2]); argc -= 2; argv += 2; } nRes = argc - 1; aRes = malloc( nRes*sizeof(aRes[0]) ); if( aRes==0 ){ fprintf(stderr, "malloc failed\n"); return 1; } for(i=0; i<argc-1; i++){ aRes[i].zName = argv[i+1]; } qsort(aRes, nRes, sizeof(aRes[0]), compareResource); printf("/* Automatically generated code: Do not edit.\n**\n" "** Rerun the \"mkbuiltin.c\" program or rerun the Fossil\n" "** makefile to update this source file.\n" "*/\n"); for(i=0; i<nRes; i++){ pData = read_file(aRes[i].zName, &sz); if( pData==0 ){ fprintf(stderr, "Cannot open file [%s]\n", aRes[i].zName); nErr++; continue; } /* Skip initial lines beginning with # */ nSkip = 0; while( pData[nSkip]=='#' ){ while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; } if( pData[nSkip]=='\n' ) nSkip++; } aRes[i].nByte = sz - nSkip; aRes[i].idx = i; printf("/* Content of file %s */\n", aRes[i].zName); printf("static const unsigned char bidata%d[%d] = {\n ", i, sz+1-nSkip); for(j=nSkip, n=0; j<=sz; j++){ printf("%3d", pData[j]); if( j==sz ){ printf(" };\n"); }else if( n==14 ){ printf(",\n "); n = 0; }else{ printf(", "); n++; } } free(pData); } printf("typedef struct BuiltinFileTable BuiltinFileTable;\n"); printf("struct BuiltinFileTable {\n"); printf(" const char *zName;\n"); printf(" const unsigned char *pData;\n"); printf(" int nByte;\n"); printf("};\n"); printf("static const BuiltinFileTable aBuiltinFiles[] = {\n"); for(i=0; i<nRes; i++){ char *z = aRes[i].zName; if( strlen(z)>=nPrefix ) z += nPrefix; while( z[0]=='.' || z[0]=='/' || z[0]=='\\' ){ z++; } aRes[i].zName = z; while( z[0] ){ if( z[0]=='\\' ) z[0] = '/'; z++; } } qsort(aRes, nRes, sizeof(aRes[0]), compareResource); for(i=0; i<nRes; i++){ printf(" { \"%s\", bidata%d, %d },\n", aRes[i].zName, aRes[i].idx, aRes[i].nByte); } printf("};\n"); return nErr; } |
Added src/mkcss.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** This C program generates the "default_css.h" header file from ** "default_css.txt" source file. ** ** The default_css.h header contains a definition of a structure ** with lots of default CSS snippets. This information is used to ** generate the /style.css page as follows: ** ** (1) Read the repository-specific CSS page from the skin ** (2) Initialize the output to a copy of the repo-CSS from (1). ** (3) For each entry in the cssDefaultList[], if the selector ** described by cssDefaultList[i] is not found in the ** repo-CSS, then append it to the output. ** ** The input file, "default_css.txt", is plain text with lots of ** comments. This routine strips out the comments and breaks the ** text up into individual cssDefaultList[] elements. ** ** To run this program: ** ** ./mkcss default_css.txt default_css.h ** ** In other words, there are two arguments. The first is the name of ** the input file and the second is the name of the output file. ** Either argument can be "-" to indicate standard input or output. ** ** Input Format Summary: ** ** # comment ** selector { ** rule; # comment ** } ** # comment ** ** It would be much easier to do this using a script, but that would ** make the Fossil source-code less cross-platform because it would then ** require that the script engine be installed on the build platform. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> static FILE *open_for_reading(const char *zFilename){ FILE *f; if( strcmp(zFilename, "-")==0 ) return stdin; f = fopen(zFilename, "r"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); exit(1); } return f; } static FILE *open_for_writing(const char *zFilename){ FILE *f; if( strcmp(zFilename, "-")==0 ) return stdout; f = fopen(zFilename, "w"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename); exit(1); } return f; } static void close_file(FILE *f){ if( f!=stdin && f!=stdout){ fclose(f); } } /* ** Print a string as a quoted C-language string. */ static void clang_puts(FILE *out, const char *z){ int i; while( z[0] ){ for(i=0; z[i] && z[i]!='"' && z[i]!='\\'; i++){} fprintf(out, "%.*s", i, z); if( z[i] ){ fprintf(out, "\\%c", z[i]); z += i+1; }else{ z += i; } } } int main(int argc, char *argv[]){ FILE *in, *out; int inRules = 0; int nLine = 0; int iStart = 0; const char *zInFile; const char *zOutFile; char z[1000]; if( argc!=3 ){ fprintf(stderr, "Usage: %s INPUTFILE OUTPUTFILE\n", argv[0]); return 1; } zInFile = argv[1]; zOutFile = argv[2]; in = open_for_reading(zInFile); out = open_for_writing(zOutFile); fprintf(out, "/* DO NOT EDIT\n" "** This code is generated automatically using 'mkcss.c'\n" "*/\n" "const struct strctCssDefaults {\n" " const char *elementClass; /* Name of element needed */\n" " const char *value; /* CSS text */\n" "} cssDefaultList[] = {\n" ); while( fgets(z, sizeof(z), in) ){ int n; /* Line length */ int i; nLine++; if( z[0]=='/' && z[1]=='/' ) continue; /* Skip comments */ if( z[0]=='-' && z[1]=='-' ) continue; /* Skip comments */ if( z[0]=='#' && !isalnum(z[1]) ) continue; /* Skip comments */ n = (int)strlen(z); while( n>0 && isspace(z[n-1]) ){ z[--n] = 0; } if( z[0]==0 ) continue; /* Blank lines */ if( isspace(z[0]) ){ if( !inRules ){ fprintf(stderr, "%s:%d: CSS rule not within a selector\n", zInFile, nLine); exit(1); } for(i=0; isspace(z[i]); i++){} fprintf(out, " \" "); clang_puts(out, z+i); fprintf(out, "\\n\"\n"); }else if( z[0]=='}' ){ if( !inRules ){ fprintf(stderr, "%s:%d: surplus CSS rule terminator\n", zInFile, nLine); exit(1); } fprintf(out, " },\n"); inRules = 0; }else if( z[n-1]=='{' ){ if( inRules ){ fprintf(stderr, "%s:%d: selector where there should be rule\n", zInFile, nLine); exit(1); } inRules = 1; iStart = nLine; fprintf(out, " { \""); n--; while( n>0 && isspace(z[n-1]) ){ z[--n] = 0; } clang_puts(out, z); fprintf(out, "\",\n"); }else{ fprintf(stderr, "%s:%d: syntax error\n", zInFile, nLine); exit(1); } } if( inRules ){ fprintf(stderr, "%s:%d: unterminated CSS rule\n", zInFile, iStart); exit(1); } close_file(in); fprintf(out, " {0,0}\n};\n"); close_file(out); return 0; } |
Added src/mkindex.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | /* ** Copyright (c) 2002 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This utility program scans Fossil source text looking for specially ** formatted comments and generates C source code for constant tables ** that define the behavior of commands, webpages, and settings. ** ** The source code is scanned for comment lines of the form: ** ** WEBPAGE: /abc/xyz ** COMMAND: cmdname ** SETTING: access-log ** ** The WEBPAGE and COMMAND comments should be followed by a function that ** implements the webpage or command. The form of this function is: ** ** void function_name(void){ ** ** Command names can divided into three classes: 1st-tier, 2nd-tier, ** and test. 1st-tier commands are the most frequently used and the ** ones that show up with "fossil help". 2nd-tier are seldom-used and/or ** legacy commands. Test commands are unsupported commands used for testing ** and analysis only. ** ** Commands are 1st-tier by default. If the command name begins with ** "test-" or if the command name has a "test" argument, then it becomes ** a test command. If the command name has a "2nd-tier" argument or ends ** with a "*" character, it is second tier. Examples: ** ** COMMAND: abcde* ** COMMAND: fghij 2nd-tier ** COMMAND: test-xyzzy ** COMMAND: xyzzy test ** ** A SETTING: may be followed by arguments that give additional attributes ** to that setting: ** ** SETTING: clean-blob versionable width=40 block-text ** SETTING: auto-shun boolean default=on ** ** New arguments may be added in future releases that set additional ** bits in the eCmdFlags field. ** ** Additional lines of comment after the COMMAND: or WEBPAGE: or SETTING: ** become the built-in help text for that command or webpage or setting. ** ** Multiple COMMAND: entries can be attached to the same command, thus ** creating multiple aliases for that command. Similarly, multiple ** WEBPAGE: entries can be attached to the same webpage function, to give ** that page aliases. ** ** For SETTING: entries, the default value for the setting can be specified ** using a default=VALUE argument if the default contains no spaces. If the ** default value does contain spaces, use a separate line like this: ** ** SETTING: pgp-command ** DEFAULT: gpg --clearsign -o ** ** If no default is supplied, the default is assumed to be an empty string ** or "off" in the case of a boolean. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> /*************************************************************************** ** These macros must match similar macros in dispatch.c. ** ** Allowed values for CmdOrPage.eCmdFlags. */ #define CMDFLAG_1ST_TIER 0x0001 /* Most important commands */ #define CMDFLAG_2ND_TIER 0x0002 /* Obscure and seldom used commands */ #define CMDFLAG_TEST 0x0004 /* Commands for testing only */ #define CMDFLAG_WEBPAGE 0x0008 /* Web pages */ #define CMDFLAG_COMMAND 0x0010 /* A command */ #define CMDFLAG_SETTING 0x0020 /* A setting */ #define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */ #define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */ #define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */ /**************************************************************************/ /* ** Each entry looks like this: */ typedef struct Entry { int eType; /* CMDFLAG_* values */ char *zIf; /* Enclose in #if */ char *zFunc; /* Name of implementation */ char *zPath; /* Webpage or command name */ char *zHelp; /* Help text */ char *zDflt; /* Default value for settings */ char *zVar; /* config.name for settings, if different from zPath */ int iHelp; /* Index of Help text */ int iWidth; /* Display width for SETTING: values */ } Entry; /* ** Maximum number of entries */ #define N_ENTRY 5000 /* ** Maximum size of a help message */ #define MX_HELP 250000 /* ** Table of entries */ Entry aEntry[N_ENTRY]; /* ** Current help message accumulator */ char zHelp[MX_HELP]; int nHelp; /* ** Most recently encountered #if */ char zIf[2000]; /* ** How many entries are used */ int nUsed; int nFixed; /* ** Current filename and line number */ char *zFile; int nLine; /* ** Number of errors */ int nErr = 0; /* ** Duplicate N characters of a string. */ char *string_dup(const char *zSrc, int n){ char *z; if( n<0 ) n = strlen(zSrc); z = malloc( n+1 ); if( z==0 ){ fprintf(stderr,"Out of memory!\n"); exit(1); } strncpy(z, zSrc, n); z[n] = 0; return z; } /* ** Safe isspace macro. Works with signed characters. */ int fossil_isspace(char c){ return c==' ' || (c<='\r' && c>='\t'); } /* ** Safe isident macro. Works with signed characters. */ int fossil_isident(char c){ if( c>='a' && c<='z' ) return 1; if( c>='A' && c<='Z' ) return 1; if( c>='0' && c<='9' ) return 1; if( c=='_' ) return 1; return 0; } /* ** Scan a line looking for comments containing zLabel. Make ** new entries if found. */ void scan_for_label(const char *zLabel, char *zLine, int eType){ int i, j; int len = strlen(zLabel); if( nUsed>=N_ENTRY ) return; for(i=0; fossil_isspace(zLine[i]) || zLine[i]=='*'; i++){} if( zLine[i]!=zLabel[0] ) return; if( strncmp(&zLine[i],zLabel, len)==0 ){ i += len; }else{ return; } while( fossil_isspace(zLine[i]) ){ i++; } if( zLine[i]=='/' ) i++; for(j=0; zLine[i+j] && !fossil_isspace(zLine[i+j]); j++){} aEntry[nUsed].eType = eType; if( eType & CMDFLAG_WEBPAGE ){ aEntry[nUsed].zPath = string_dup(&zLine[i-1], j+1); aEntry[nUsed].zPath[0] = '/'; }else{ aEntry[nUsed].zPath = string_dup(&zLine[i], j); } aEntry[nUsed].zFunc = 0; if( (eType & CMDFLAG_COMMAND)!=0 ){ if( strncmp(&zLine[i], "test-", 5)==0 ){ /* Commands that start with "test-" are test-commands */ aEntry[nUsed].eType |= CMDFLAG_TEST; }else if( zLine[i+j-1]=='*' ){ /* If the command name ends in '*', remove the '*' from the name ** but move the command into the second tier */ aEntry[nUsed].zPath[j-1] = 0; aEntry[nUsed].eType |= CMDFLAG_2ND_TIER; }else{ /* Otherwise, this is a first-tier command */ aEntry[nUsed].eType |= CMDFLAG_1ST_TIER; } } /* Process additional flags that might follow the command name */ while( zLine[i+j]!=0 ){ i += j; while( fossil_isspace(zLine[i]) ){ i++; } if( zLine[i]==0 ) break; for(j=0; zLine[i+j] && !fossil_isspace(zLine[i+j]); j++){} if( j==8 && strncmp(&zLine[i], "1st-tier", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_2ND_TIER|CMDFLAG_TEST); aEntry[nUsed].eType |= CMDFLAG_1ST_TIER; }else if( j==8 && strncmp(&zLine[i], "2nd-tier", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_TEST); aEntry[nUsed].eType |= CMDFLAG_2ND_TIER; }else if( j==4 && strncmp(&zLine[i], "test", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_2ND_TIER); aEntry[nUsed].eType |= CMDFLAG_TEST; }else if( j==7 && strncmp(&zLine[i], "boolean", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_BLOCKTEXT); aEntry[nUsed].iWidth = 0; aEntry[nUsed].eType |= CMDFLAG_BOOLEAN; }else if( j==10 && strncmp(&zLine[i], "block-text", j)==0 ){ aEntry[nUsed].eType &= ~(CMDFLAG_BOOLEAN); aEntry[nUsed].eType |= CMDFLAG_BLOCKTEXT; }else if( j==11 && strncmp(&zLine[i], "versionable", j)==0 ){ aEntry[nUsed].eType |= CMDFLAG_VERSIONABLE; }else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){ aEntry[nUsed].iWidth = atoi(&zLine[i+6]); }else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){ aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8); }else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){ aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9); }else{ fprintf(stderr, "%s:%d: unknown option: '%.*s'\n", zFile, nLine, j, &zLine[i]); nErr++; } } nUsed++; return; } /* ** Check to see if the current line is an #if and if it is, add it to ** the zIf[] string. If the current line is an #endif or #else or #elif ** then cancel the current zIf[] string. */ void scan_for_if(const char *zLine){ int i; int len; if( zLine[0]!='#' ) return; for(i=1; fossil_isspace(zLine[i]); i++){} if( zLine[i]==0 ) return; len = strlen(&zLine[i]); if( strncmp(&zLine[i],"if",2)==0 ){ zIf[0] = '#'; memcpy(&zIf[1], &zLine[i], len+1); }else if( zLine[i]=='e' ){ zIf[0] = 0; } } /* ** Check to see if the current line is a "** DEFAULT: ..." line for a ** SETTING definition. If so, remember the default value. */ void scan_for_default(const char *zLine){ int len; const char *z; if( nUsed<1 ) return; if( (aEntry[nUsed-1].eType & CMDFLAG_SETTING)==0 ) return; if( strncmp(zLine, "** DEFAULT: ", 12)!=0 ) return; z = zLine + 12; while( fossil_isspace(z[0]) ) z++; len = (int)strlen(z); while( len>0 && fossil_isspace(z[len-1]) ){ len--; } aEntry[nUsed-1].zDflt = string_dup(z,len); } /* ** Scan a line for a function that implements a web page or command. */ void scan_for_func(char *zLine){ int i,j,k; char *z; int isSetting; if( nUsed<=nFixed ) return; if( strncmp(zLine, "**", 2)==0 && fossil_isspace(zLine[2]) && strlen(zLine)<sizeof(zHelp)-nHelp-1 && nUsed>nFixed && strncmp(zLine,"** COMMAND:",11)!=0 && strncmp(zLine,"** WEBPAGE:",11)!=0 && strncmp(zLine,"** SETTING:",11)!=0 && strncmp(zLine,"** DEFAULT:",11)!=0 ){ if( zLine[2]=='\n' ){ zHelp[nHelp++] = '\n'; }else{ if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0; strcpy(&zHelp[nHelp], &zLine[3]); nHelp += strlen(&zHelp[nHelp]); } return; } for(i=0; fossil_isspace(zLine[i]); i++){} if( zLine[i]==0 ) return; isSetting = (aEntry[nFixed].eType & CMDFLAG_SETTING)!=0; if( !isSetting ){ if( strncmp(&zLine[i],"void",4)!=0 ){ if( zLine[i]!='*' ) goto page_skip; return; } i += 4; if( !fossil_isspace(zLine[i]) ) goto page_skip; while( fossil_isspace(zLine[i]) ){ i++; } for(j=0; fossil_isident(zLine[i+j]); j++){} if( j==0 ) goto page_skip; } for(k=nHelp-1; k>=0 && fossil_isspace(zHelp[k]); k--){} nHelp = k+1; zHelp[nHelp] = 0; for(k=0; k<nHelp && fossil_isspace(zHelp[k]); k++){} if( k<nHelp ){ z = string_dup(&zHelp[k], nHelp-k); }else{ z = ""; } for(k=nFixed; k<nUsed; k++){ aEntry[k].zIf = zIf[0] ? string_dup(zIf, -1) : 0; aEntry[k].zFunc = isSetting ? "0" : string_dup(&zLine[i], j); aEntry[k].zHelp = z; z = 0; aEntry[k].iHelp = nFixed; } if( !isSetting ){ i+=j; while( fossil_isspace(zLine[i]) ){ i++; } if( zLine[i]!='(' ) goto page_skip; } nFixed = nUsed; nHelp = 0; return; page_skip: for(i=nFixed; i<nUsed; i++){ fprintf(stderr,"%s:%d: skipping page \"%s\"\n", zFile, nLine, aEntry[i].zPath); } nUsed = nFixed; } /* ** Compare two entries */ int e_compare(const void *a, const void *b){ const Entry *pA = (const Entry*)a; const Entry *pB = (const Entry*)b; return strcmp(pA->zPath, pB->zPath); } /* ** Build the binary search table. */ void build_table(void){ int i; int nWeb = 0; qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare); printf( "/* Automatically generated code\n" "** DO NOT EDIT!\n" "**\n" "** This file was generated by the mkindex.exe program based on\n" "** comments in other Fossil source files.\n" "*/\n" ); /* Output declarations for all the action functions */ for(i=0; i<nFixed; i++){ if( aEntry[i].eType & CMDFLAG_SETTING ) continue; if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf); printf("extern void %s(void);\n", aEntry[i].zFunc); if( aEntry[i].zIf ) printf("#endif\n"); } /* Output strings for all the help text */ for(i=0; i<nFixed; i++){ char *z = aEntry[i].zHelp; if( z==0 ) continue; if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf); printf("static const char zHelp%03d[] =\n \"", aEntry[i].iHelp); while( *z ){ if( *z=='\n' ){ printf("\\n\"\n \""); }else if( *z=='"' ){ printf("\\\""); }else{ putchar(*z); } z++; } printf("\";\n"); if( aEntry[i].zIf ) printf("#endif\n"); } /* Generate the aCommand[] table */ printf("static const CmdOrPage aCommand[] = {\n"); for(i=0; i<nFixed; i++){ const char *z = aEntry[i].zPath; int n = strlen(z); if( aEntry[i].zIf ){ printf("%s", aEntry[i].zIf); }else if( (aEntry[i].eType & CMDFLAG_WEBPAGE)!=0 ){ nWeb++; } printf(" { \"%.*s\",%*s%s,%*szHelp%03d, 0x%03x },\n", n, z, 25-n, "", aEntry[i].zFunc, (int)(29-strlen(aEntry[i].zFunc)), "", aEntry[i].iHelp, aEntry[i].eType ); if( aEntry[i].zIf ) printf("#endif\n"); } printf("};\n"); printf("#define FOSSIL_FIRST_CMD %d\n", nWeb); /* Generate the aSetting[] table */ printf("const Setting aSetting[] = {\n"); for(i=0; i<nFixed; i++){ const char *z; const char *zVar; const char *zDef; if( (aEntry[i].eType & CMDFLAG_SETTING)==0 ) continue; z = aEntry[i].zPath; zVar = aEntry[i].zVar; zDef = aEntry[i].zDflt; if( zDef==0 ) zDef = ""; if( aEntry[i].zIf ){ printf("%s", aEntry[i].zIf); } printf(" { \"%s\",%*s", z, (int)(20-strlen(z)), ""); if( zVar ){ printf(" \"%s\",%*s", zVar, (int)(15-strlen(zVar)), ""); }else{ printf(" 0,%*s", 16, ""); } printf(" %3d, %d, %d, \"%s\"%*s },\n", aEntry[i].iWidth, (aEntry[i].eType & CMDFLAG_VERSIONABLE)!=0, (aEntry[i].eType & CMDFLAG_BLOCKTEXT)!=0, zDef, (int)(10-strlen(zDef)), "" ); if( aEntry[i].zIf ){ printf("#endif\n"); } } printf("{0,0,0,0,0,0}};\n"); } /* ** Process a single file of input */ void process_file(void){ FILE *in = fopen(zFile, "r"); char zLine[2000]; if( in==0 ){ fprintf(stderr,"%s: cannot open\n", zFile); return; } nLine = 0; while( fgets(zLine, sizeof(zLine), in) ){ nLine++; scan_for_if(zLine); scan_for_label("WEBPAGE:",zLine,CMDFLAG_WEBPAGE); scan_for_label("COMMAND:",zLine,CMDFLAG_COMMAND); scan_for_func(zLine); scan_for_label("SETTING:",zLine,CMDFLAG_SETTING); scan_for_default(zLine); } fclose(in); nUsed = nFixed; } int main(int argc, char **argv){ int i; for(i=1; i<argc; i++){ zFile = argv[i]; process_file(); } build_table(); return nErr; } |
Added src/mkversion.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** This C program generates the "VERSION.h" header file from information ** extracted out of the "manifest", "manifest.uuid", and "VERSION" files. ** Call this program with three arguments: ** ** ./a.out manifest.uuid manifest VERSION ** ** Note that the manifest.uuid and manifest files are generated by Fossil. */ #include <stdio.h> #include <string.h> #include <stdlib.h> static FILE *open_for_reading(const char *zFilename){ FILE *f = fopen(zFilename, "r"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); exit(1); } return f; } int main(int argc, char *argv[]){ FILE *m,*u,*v; char *z; #if defined(__DMC__) /* e.g. 0x857 */ int i = 0; #endif int j = 0, x = 0, d = 0; int vn[3]; char b[1000]; char vx[1000]; if( argc!=4 ){ fprintf(stderr, "Usage: %s manifest.uuid manifest VERSION\n", argv[0]); exit(1); } memset(b,0,sizeof(b)); memset(vx,0,sizeof(vx)); u = open_for_reading(argv[1]); if( fgets(b, sizeof(b)-1,u)==0 ){ fprintf(stderr, "malformed manifest.uuid file: %s\n", argv[1]); exit(1); } fclose(u); for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){} *z = 0; printf("#define MANIFEST_UUID \"%s\"\n",b); printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b); m = open_for_reading(argv[2]); while(b == fgets(b, sizeof(b)-1,m)){ if(0 == strncmp("D ",b,2)){ printf("#define MANIFEST_DATE \"%.10s %.8s\"\n",b+2,b+13); printf("#define MANIFEST_YEAR \"%.4s\"\n",b+2); } } fclose(m); v = open_for_reading(argv[3]); if( fgets(b, sizeof(b)-1,v)==0 ){ fprintf(stderr, "malformed VERSION file: %s\n", argv[3]); exit(1); } fclose(v); for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){} *z = 0; printf("#define RELEASE_VERSION \"%s\"\n", b); z=b; vn[0] = vn[1] = vn[2] = 0; while(1){ if( z[0]>='0' && z[0]<='9' ){ x = x*10 + z[0] - '0'; }else{ if( j<3 ) vn[j++] = x; x = 0; if( z[0]==0 ) break; } z++; } for(z=vx; z[0]=='0'; z++){} printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]); memset(vx,0,sizeof(vx)); strcpy(vx,b); for(z=vx; z[0]; z++){ if( z[0]=='-' ){ z[0] = 0; break; } if( z[0]!='.' ) continue; if ( d<3 ){ z[0] = ','; d++; }else{ z[0] = '\0'; break; } } printf("#define RELEASE_RESOURCE_VERSION %s", vx); while( d<3 ){ printf(",0"); d++; } printf("\n"); #if defined(__DMC__) /* e.g. 0x857 */ d = (__DMC__ & 0xF00) >> 8; /* major */ x = (__DMC__ & 0x0F0) >> 4; /* minor */ i = (__DMC__ & 0x00F); /* revision */ printf("#define COMPILER_VERSION \"%d.%d.%d\"\n", d, x, i); #elif defined(__POCC__) /* e.g. 700 */ d = (__POCC__ / 100); /* major */ x = (__POCC__ % 100); /* minor */ printf("#define COMPILER_VERSION \"%d.%02d\"\n", d, x); #elif defined(_MSC_VER) /* e.g. 1800 */ d = (_MSC_VER / 100); /* major */ x = (_MSC_VER % 100); /* minor */ printf("#define COMPILER_VERSION \"%d.%02d\"\n", d, x); #endif return 0; } |
Changes to src/moderate.c.
︙ | ︙ | |||
145 146 147 148 149 150 151 | } db_end_transaction(0); } /* ** Approve an object held for moderation. */ | | | < < | 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 | } db_end_transaction(0); } /* ** Approve an object held for moderation. */ void moderation_approve(int rid){ if( !moderation_pending(rid) ) return; db_begin_transaction(); db_multi_exec( "DELETE FROM private WHERE rid=%d;" "INSERT OR IGNORE INTO unclustered VALUES(%d);" "INSERT OR IGNORE INTO unsent VALUES(%d);", rid, rid, rid ); db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid); admin_log("Approved moderation of rid %d.", rid); db_end_transaction(0); } /* ** WEBPAGE: modreq ** ** Show all pending moderation request |
︙ | ︙ | |||
184 185 186 187 188 189 190 | if( moderation_table_exists() ){ blob_init(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND event.objid IN (SELECT objid FROM modreq)" " ORDER BY event.mtime DESC" ); db_prepare(&q, "%s", blob_sql_text(&sql)); | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 182 183 184 185 186 187 188 189 190 191 192 193 | if( moderation_table_exists() ){ blob_init(&sql, timeline_query_for_www(), -1); blob_append_sql(&sql, " AND event.objid IN (SELECT objid FROM modreq)" " ORDER BY event.mtime DESC" ); db_prepare(&q, "%s", blob_sql_text(&sql)); www_print_timeline(&q, 0, 0, 0, 0, 0); db_finalize(&q); } style_footer(); } |
Changes to src/name.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** This file contains code used to resolved user-supplied object names. */ #include "config.h" #include "name.h" #include <assert.h> | < < < < < < < < < < < < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** This file contains code used to resolved user-supplied object names. */ #include "config.h" #include "name.h" #include <assert.h> /* ** Return TRUE if the string begins with something that looks roughly ** like an ISO date/time string. The SQLite date/time functions will ** have the final say-so about whether or not the date/time string is ** well-formed. */ int fossil_isdate(const char *z){ |
︙ | ︙ | |||
51 52 53 54 55 56 57 | if( z[7]!='-') return 0; if( !fossil_isdigit(z[8]) ) return 0; if( !fossil_isdigit(z[9]) ) return 0; return 1; } /* | | | < < < | < < < < | < < | | | < < < < < < | < < < | < < < < < < < < | < < < < < | < < < < < < < < < < < < < | < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | < < < | > > > | | > | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < | | < < < < < < < < | < < | < < < < | < < > | | < | < < < < | | | > > > > > > > | > | | < < < < < < < < < < < < | | < < < < < | | < < | 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 | if( z[7]!='-') return 0; if( !fossil_isdigit(z[8]) ) return 0; if( !fossil_isdigit(z[9]) ) return 0; return 1; } /* ** Return the RID that is the "root" of the branch that contains ** check-in "rid" if inBranch==0 or the first check-in in the branch ** if inBranch==1. */ int start_of_branch(int rid, int inBranch){ Stmt q; int rc; char *zBr; zBr = db_text("trunk","SELECT value FROM tagxref" " WHERE rid=%d AND tagid=%d" " AND tagtype>0", rid, TAG_BRANCH); db_prepare(&q, "SELECT pid, EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0" " AND value=%Q AND rid=plink.pid)" " FROM plink" " WHERE cid=:cid AND isprim", TAG_BRANCH, zBr ); fossil_free(zBr); do{ db_reset(&q); db_bind_int(&q, ":cid", rid); rc = db_step(&q); if( rc!=SQLITE_ROW ) break; if( inBranch && db_column_int(&q,1)==0 ) break; rid = db_column_int(&q, 0); }while( db_column_int(&q, 1)==1 && rid>0 ); db_finalize(&q); return rid; } /* ** Convert a symbolic name into a RID. Acceptable forms: ** ** * artifact hash (optionally enclosed in [...]) ** * 4-character or larger prefix of a artifact ** * Symbolic Name ** * "tag:" + symbolic name ** * Date or date-time ** * "date:" + Date or date-time ** * symbolic-name ":" date-time ** * "tip" ** ** The following additional forms are available in local checkouts: ** ** * "current" ** * "prev" or "previous" ** * "next" ** ** Return the RID of the matching artifact. Or return 0 if the name does not ** match any known object. Or return -1 if the name is ambiguous. ** ** The zType parameter specifies the type of artifact: ci, t, w, e, g, f. ** If zType is NULL or "" or "*" then any type of artifact will serve. ** If zType is "br" then find the first check-in of the named branch ** rather than the last. ** zType is "ci" in most use cases since we are usually searching for ** a check-in. ** ** Note that the input zTag for types "t" and "e" is the artifact hash of ** the ticket-change or technote-change artifact, not the randomly generated ** hexadecimal identifier assigned to tickets and events. Those identifiers ** live in a separate namespace. */ int symbolic_name_to_rid(const char *zTag, const char *zType){ int vid; int rid = 0; int nTag; int i; int startOfBranch = 0; const char *zXTag; /* zTag with optional [...] removed */ int nXTag; /* Size of zXTag */ if( zType==0 || zType[0]==0 ){ zType = "*"; }else if( zType[0]=='b' ){ zType = "ci"; startOfBranch = 1; } if( zTag==0 || zTag[0]==0 ) return 0; /* special keyword: "tip" */ if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){ rid = db_int(0, "SELECT objid" " FROM event" " WHERE type='ci'" " ORDER BY event.mtime DESC" ); if( rid ) return rid; } /* special keywords: "prev", "previous", "current", and "next" */ if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){ if( fossil_strcmp(zTag, "current")==0 ){ rid = vid; }else if( fossil_strcmp(zTag, "prev")==0 || fossil_strcmp(zTag, "previous")==0 ){ rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid); }else if( fossil_strcmp(zTag, "next")==0 ){ rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d" " ORDER BY isprim DESC, mtime DESC", vid); } if( rid ) return rid; } /* Date and times */ if( memcmp(zTag, "date:", 5)==0 ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", &zTag[5], zType); return rid; } if( fossil_isdate(zTag) ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", zTag, zType); if( rid) return rid; } /* Deprecated date & time formats: "local:" + date-time and ** "utc:" + date-time */ if( memcmp(zTag, "local:", 6)==0 ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday(%Q) AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", &zTag[6], zType); return rid; } if( memcmp(zTag, "utc:", 4)==0 ){ rid = db_int(0, "SELECT objid FROM event" " WHERE mtime<=julianday('%qz') AND type GLOB '%q'" " ORDER BY mtime DESC LIMIT 1", &zTag[4], zType); return rid; } /* "tag:" + symbolic-name */ if( memcmp(zTag, "tag:", 4)==0 ){ rid = db_int(0, "SELECT event.objid, max(event.mtime)" " FROM tag, tagxref, event" " WHERE tag.tagname='sym-%q' " " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " " AND event.objid=tagxref.rid " " AND event.type GLOB '%q'", &zTag[4], zType ); if( startOfBranch ) rid = start_of_branch(rid,1); return rid; } /* root:TAG -> The origin of the branch */ if( memcmp(zTag, "root:", 5)==0 ){ rid = symbolic_name_to_rid(zTag+5, zType); return start_of_branch(rid, 0); } /* symbolic-name ":" date-time */ nTag = strlen(zTag); for(i=0; i<nTag-10 && zTag[i]!=':'; i++){} if( zTag[i]==':' && fossil_isdate(&zTag[i+1]) ){ char *zDate = mprintf("%s", &zTag[i+1]); char *zTagBase = mprintf("%.*s", i, zTag); int nDate = strlen(zDate); if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ zDate[nDate-3] = 'z'; zDate[nDate-2] = 0; } rid = db_int(0, "SELECT event.objid, max(event.mtime)" " FROM tag, tagxref, event" " WHERE tag.tagname='sym-%q' " " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " " AND event.objid=tagxref.rid " " AND event.mtime<=julianday(%Q)" " AND event.type GLOB '%q'", zTagBase, zDate, zType ); return rid; } /* Remove optional [...] */ zXTag = zTag; nXTag = nTag; if( zXTag[0]=='[' ){ |
︙ | ︙ | |||
574 575 576 577 578 579 580 | canonical16(zUuid, nXTag); rid = 0; if( zType[0]=='*' ){ db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid); }else{ db_prepare(&q, "SELECT blob.rid" | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | | < < < > | | | | < | < | < | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | canonical16(zUuid, nXTag); rid = 0; if( zType[0]=='*' ){ db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid); }else{ db_prepare(&q, "SELECT blob.rid" " FROM blob, event" " WHERE blob.uuid GLOB '%q*'" " AND event.objid=blob.rid" " AND event.type GLOB '%q'", zUuid, zType ); } if( db_step(&q)==SQLITE_ROW ){ rid = db_column_int(&q, 0); if( db_step(&q)==SQLITE_ROW ) rid = -1; } db_finalize(&q); if( rid ) return rid; } /* Symbolic name */ rid = db_int(0, "SELECT event.objid, max(event.mtime)" " FROM tag, tagxref, event" " WHERE tag.tagname='sym-%q' " " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " " AND event.objid=tagxref.rid " " AND event.type GLOB '%q'", zTag, zType ); if( rid>0 ){ if( startOfBranch ) rid = start_of_branch(rid,1); return rid; } /* Undocumented: numeric tags get translated directly into the RID */ if( memcmp(zTag, "rid:", 4)==0 ){ zTag += 4; for(i=0; fossil_isdigit(zTag[i]); i++){} if( zTag[i]==0 ){ if( strcmp(zType,"*")==0 ){ rid = atoi(zTag); }else{ rid = db_int(0, "SELECT event.objid" " FROM event" " WHERE event.objid=%s" " AND event.type GLOB '%q'", zTag /*safe-for-%s*/, zType); } } } return rid; } /* ** This routine takes a user-entered UUID which might be in mixed ** case and might only be a prefix of the full UUID and converts it ** into the full-length UUID in canonical form. ** ** If the input is not a UUID or a UUID prefix, then try to resolve ** the name as a tag. If multiple tags match, pick the latest. ** If the input name matches "tag:*" then always resolve as a tag. ** ** If the input is not a tag, then try to match it as an ISO-8601 date ** string YYYY-MM-DD HH:MM:SS and pick the nearest check-in to that date. ** If the input is of the form "date:*" then always resolve the name as ** a date. The forms "utc:*" and "local:" are deprecated. ** ** Return 0 on success. Return 1 if the name cannot be resolved. ** Return 2 name is ambiguous. */ int name_to_uuid(Blob *pName, int iErrPriority, const char *zType){ char *zName = blob_str(pName); int rid = symbolic_name_to_rid(zName, zType); if( rid<0 ){ fossil_error(iErrPriority, "ambiguous name: %s", zName); return 2; }else if( rid==0 ){ fossil_error(iErrPriority, "not found: %s", zName); return 1; }else{ blob_reset(pName); db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid); return 0; } } /* ** This routine is similar to name_to_uuid() except in the form it ** takes its parameters and returns its value, and in that it does not ** treat errors as fatal. zName must be a UUID, as described for ** name_to_uuid(). zType is also as described for that function. If ** zName does not resolve, 0 is returned. If it is ambiguous, a ** negative value is returned. On success the rid is returned and ** pUuid (if it is not NULL) is set to a newly-allocated string, ** the full UUID, which must eventually be free()d by the caller. */ int name_to_uuid2(const char *zName, const char *zType, char **pUuid){ int rid = symbolic_name_to_rid(zName, zType); if((rid>0) && pUuid){ *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid); } return rid; } /* ** name_collisions searches through events, blobs, and tickets for ** collisions of a given UUID based on its length on UUIDs no shorter ** than 4 characters in length. */ int name_collisions(const char *zName){ int c = 0; /* count of collisions for zName */ int nLen; /* length of zName */ nLen = strlen(zName); if( nLen>=4 && nLen<=HNAME_MAX && validate16(zName, nLen) ){ c = db_int(0, |
︙ | ︙ | |||
752 753 754 755 756 757 758 | } return c; } /* ** COMMAND: test-name-to-id ** | < < | < < < < < < < < < < < < < | | | | | | | | | < | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | } return c; } /* ** COMMAND: test-name-to-id ** ** Convert a name to a full artifact ID. */ void test_name_to_id(void){ int i; Blob name; db_must_be_within_tree(); for(i=2; i<g.argc; i++){ blob_init(&name, g.argv[i], -1); fossil_print("%s -> ", g.argv[i]); if( name_to_uuid(&name, 1, "*") ){ fossil_print("ERROR: %s\n", g.zErrMsg); fossil_error_reset(); }else{ fossil_print("%s\n", blob_buffer(&name)); } blob_reset(&name); } } /* ** Convert a name to a rid. If the name can be any of the various forms ** accepted: ** |
︙ | ︙ | |||
810 811 812 813 814 815 816 | int rid; if( zName==0 || zName[0]==0 ) return 0; rid = symbolic_name_to_rid(zName, zType); if( rid<0 ){ fossil_fatal("ambiguous name: %s", zName); }else if( rid==0 ){ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | int rid; if( zName==0 || zName[0]==0 ) return 0; rid = symbolic_name_to_rid(zName, zType); if( rid<0 ){ fossil_fatal("ambiguous name: %s", zName); }else if( rid==0 ){ fossil_fatal("not found: %s", zName); } return rid; } int name_to_rid(const char *zName){ return name_to_typed_rid(zName, "*"); } /* ** WEBPAGE: ambiguous ** URL: /ambiguous?name=NAME&src=WEBPAGE ** ** The NAME given by the name parameter is ambiguous. Display a page ** that shows all possible choices and let the user select between them. */ void ambiguous_page(void){ Stmt q; const char *zName = P("name"); const char *zSrc = P("src"); char *z; if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){ fossil_redirect_home(); } style_header("Ambiguous Artifact ID"); @ <p>The artifact id <b>%h(zName)</b> is ambiguous and might @ mean any of the following: @ <ol> z = mprintf("%s", zName); canonical16(z, strlen(z)); db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); int rid = db_column_int(&q, 1); @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)"> @ %s(zUuid)</a> - object_description(rid, 0, 0); @ </p></li> } db_finalize(&q); db_prepare(&q, " SELECT tkt_rid, tkt_uuid, title" " FROM ticket, ticketchng" " WHERE ticket.tkt_id = ticketchng.tkt_id" " AND tkt_uuid GLOB '%q*'" " GROUP BY tkt_uuid" " ORDER BY tkt_ctime DESC", z); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); const char *zUuid = db_column_text(&q, 1); const char *zTitle = db_column_text(&q, 2); @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)"> @ %s(zUuid)</a> - @ <ul></ul> @ Ticket hyperlink_to_uuid(zUuid); @ - %h(zTitle). @ <ul><li> object_description(rid, 0, 0); @ </li></ul> @ </p></li> } db_finalize(&q); db_prepare(&q, "SELECT rid, uuid FROM" " (SELECT tagxref.rid AS rid, substr(tagname, 7) AS uuid" " FROM tagxref, tag WHERE tagxref.tagid = tag.tagid" " AND tagname GLOB 'event-%q*') GROUP BY uuid", z); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); const char* zUuid = db_column_text(&q, 1); @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)"> @ %s(zUuid)</a> - @ <ul><li> object_description(rid, 0, 0); @ </li></ul> @ </p></li> } @ </ol> db_finalize(&q); style_footer(); } /* ** Convert the name in CGI parameter zParamName into a rid and return that ** rid. If the CGI parameter is missing or is not a valid artifact tag, ** return 0. If the CGI parameter is ambiguous, redirect to a page that ** shows all possibilities and do not return. */ int name_to_rid_www(const char *zParamName){ int rid; const char *zName = P(zParamName); #ifdef FOSSIL_ENABLE_JSON if(!zName && fossil_has_json()){ zName = json_find_option_cstr(zParamName,NULL,NULL); } #endif if( zName==0 || zName[0]==0 ) return 0; rid = symbolic_name_to_rid(zName, "*"); if( rid<0 ){ cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath); rid = 0; } return rid; } /* ** Generate a description of artifact "rid" */ void whatis_rid(int rid, int verboseFlag){ Stmt q; int cnt; /* Basic information about the object. */ db_prepare(&q, "SELECT uuid, size, datetime(mtime,toLocal()), ipaddr" " FROM blob, rcvfrom" " WHERE rid=%d" " AND rcvfrom.rcvid=blob.rcvid", rid); if( db_step(&q)==SQLITE_ROW ){ if( verboseFlag ){ fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid); fossil_print("size: %d bytes\n", db_column_int(&q,1)); fossil_print("received: %s from %s\n", db_column_text(&q, 2), db_column_text(&q, 3)); }else{ fossil_print("artifact: %s\n", db_column_text(&q,0)); fossil_print("size: %d bytes\n", db_column_int(&q,1)); } } db_finalize(&q); /* Report any symbolic tags on this artifact */ db_prepare(&q, "SELECT substr(tagname,5)" " FROM tag JOIN tagxref ON tag.tagid=tagxref.tagid" " WHERE tagxref.rid=%d" " AND tagname GLOB 'sym-*'" " ORDER BY 1", rid ); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zPrefix = cnt++ ? ", " : "tags: "; |
︙ | ︙ | |||
1101 1102 1103 1104 1105 1106 1107 | case 't': zType = "Ticket-change"; break; case 'g': zType = "Tag-change"; break; default: zType = "Unknown"; break; } fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2), db_column_text(&q, 1)); fossil_print("comment: "); | | < | | < < < < | < | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 | case 't': zType = "Ticket-change"; break; case 'g': zType = "Tag-change"; break; default: zType = "Unknown"; break; } fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2), db_column_text(&q, 1)); fossil_print("comment: "); comment_print(db_column_text(&q,3), 0, 12, -1, g.comFmtFlags); } db_finalize(&q); /* Check to see if this object is used as a file in a check-in */ db_prepare(&q, "SELECT filename.name, blob.uuid, datetime(event.mtime,toLocal())," " coalesce(euser,user), coalesce(ecomment,comment)" " FROM mlink, filename, blob, event" " WHERE mlink.fid=%d" " AND filename.fnid=mlink.fnid" " AND event.objid=mlink.mid" " AND blob.rid=mlink.mid" " ORDER BY event.mtime DESC /*sort*/", rid); while( db_step(&q)==SQLITE_ROW ){ fossil_print("file: %s\n", db_column_text(&q,0)); fossil_print(" part of [%S] by %s on %s\n", db_column_text(&q, 1), db_column_text(&q, 3), db_column_text(&q, 2)); fossil_print(" "); comment_print(db_column_text(&q,4), 0, 12, -1, g.comFmtFlags); } db_finalize(&q); /* Check to see if this object is used as an attachment */ db_prepare(&q, "SELECT attachment.filename," " attachment.comment," |
︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 | " WHERE blob.rid=%d", rid ); while( db_step(&q)==SQLITE_ROW ){ fossil_print("attachment: %s\n", db_column_text(&q,0)); fossil_print(" attached to %s %s\n", db_column_text(&q,5), db_column_text(&q,4)); | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | > | | < < < < < < | > | | < | < | | < > | | | > | < < < < < > > > | < > | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | " WHERE blob.rid=%d", rid ); while( db_step(&q)==SQLITE_ROW ){ fossil_print("attachment: %s\n", db_column_text(&q,0)); fossil_print(" attached to %s %s\n", db_column_text(&q,5), db_column_text(&q,4)); if( verboseFlag ){ fossil_print(" via %s (%d)\n", db_column_text(&q,7), db_column_int(&q,6)); }else{ fossil_print(" via %s\n", db_column_text(&q,7)); } fossil_print(" by user %s on %s\n", db_column_text(&q,2), db_column_text(&q,3)); fossil_print(" "); comment_print(db_column_text(&q,1), 0, 12, -1, g.comFmtFlags); } db_finalize(&q); } /* ** COMMAND: whatis* ** ** Usage: %fossil whatis NAME ** ** Resolve the symbol NAME into its canonical artifact hash ** artifact name and provide a description of what role that artifact ** plays. ** ** Options: ** ** --type TYPE Only find artifacts of TYPE (one of: 'ci', 't', ** 'w', 'g', or 'e'). ** -v|--verbose Provide extra information (such as the RID) */ void whatis_cmd(void){ int rid; const char *zName; int verboseFlag; int i; const char *zType = 0; db_find_and_open_repository(0,0); verboseFlag = find_option("verbose","v",0)!=0; zType = find_option("type",0,1); /* We should be done with options.. */ verify_all_options(); if( g.argc<3 ) usage("NAME ..."); for(i=2; i<g.argc; i++){ zName = g.argv[i]; if( i>2 ) fossil_print("%.79c\n",'-'); rid = symbolic_name_to_rid(zName, zType); if( rid<0 ){ Stmt q; int cnt = 0; fossil_print("name: %s (ambiguous)\n", zName); db_prepare(&q, "SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')", zName, zName ); while( db_step(&q)==SQLITE_ROW ){ if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt); whatis_rid(db_column_int(&q, 0), verboseFlag); } db_finalize(&q); }else if( rid==0 ){ /* 0123456789 12 */ fossil_print("unknown: %s\n", zName); }else{ fossil_print("name: %s\n", zName); whatis_rid(rid, verboseFlag); } } } /* ** COMMAND: test-whatis-all ** |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | */ static const char zDescTab[] = @ CREATE TEMP TABLE IF NOT EXISTS description( @ rid INTEGER PRIMARY KEY, -- RID of the object @ uuid TEXT, -- hash of the object @ ctime DATETIME, -- Time of creation @ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < | | | | < | | | | < | | | | | | | | < | | | | < | | | < | | < < < < < < | | < | | 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 | */ static const char zDescTab[] = @ CREATE TEMP TABLE IF NOT EXISTS description( @ rid INTEGER PRIMARY KEY, -- RID of the object @ uuid TEXT, -- hash of the object @ ctime DATETIME, -- Time of creation @ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts @ type TEXT, -- file, checkin, wiki, ticket, etc. @ summary TEXT, -- Summary comment for the object @ detail TEXT -- File name, check-in comment, etc @ ); ; /* ** Create the description table if it does not already exists. ** Populate fields of this table with descriptions for all artifacts ** whose RID matches the SQL expression in zWhere. */ void describe_artifacts(const char *zWhere){ db_multi_exec("%s", zDescTab/*safe-for-%s*/); /* Describe check-ins */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, event.mtime, 'checkin',\n" " 'check-in on ' || strftime('%%Y-%%m-%%d %%H:%%M',event.mtime)\n" " FROM event, blob\n" " WHERE (event.objid %s) AND event.type='ci'\n" " AND event.objid=blob.rid;", zWhere /*safe-for-%s*/ ); /* Describe files */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, event.mtime, 'file', 'file '||filename.name\n" " FROM mlink, blob, event, filename\n" " WHERE (mlink.fid %s)\n" " AND mlink.mid=event.objid\n" " AND filename.fnid=mlink.fnid\n" " AND mlink.fid=blob.rid;", zWhere /*safe-for-%s*/ ); /* Describe tags */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, tagxref.mtime, 'tag',\n" " 'tag '||substr((SELECT uuid FROM blob WHERE rid=tagxref.rid),1,16)\n" " FROM tagxref, blob\n" " WHERE (tagxref.srcid %s) AND tagxref.srcid!=tagxref.rid\n" " AND tagxref.srcid=blob.rid;", zWhere /*safe-for-%s*/ ); /* Cluster artifacts */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, rcvfrom.mtime, 'cluster', 'cluster'\n" " FROM tagxref, blob, rcvfrom\n" " WHERE (tagxref.rid %s)\n" " AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='cluster')\n" " AND blob.rid=tagxref.rid" " AND rcvfrom.rcvid=blob.rcvid;", zWhere /*safe-for-%s*/ ); /* Ticket change artifacts */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, tagxref.mtime, 'ticket',\n" " 'ticket '||substr(tag.tagname,5,21)\n" " FROM tagxref, tag, blob\n" " WHERE (tagxref.rid %s)\n" " AND tag.tagid=tagxref.tagid\n" " AND tag.tagname GLOB 'tkt-*'" " AND blob.rid=tagxref.rid;", zWhere /*safe-for-%s*/ ); /* Wiki edit artifacts */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, tagxref.mtime, 'wiki',\n" " printf('wiki \"%%s\"',substr(tag.tagname,6))\n" " FROM tagxref, tag, blob\n" " WHERE (tagxref.rid %s)\n" " AND tag.tagid=tagxref.tagid\n" " AND tag.tagname GLOB 'wiki-*'" " AND blob.rid=tagxref.rid;", zWhere /*safe-for-%s*/ ); /* Event edit artifacts */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, tagxref.mtime, 'event',\n" " 'event '||substr(tag.tagname,7)\n" " FROM tagxref, tag, blob\n" " WHERE (tagxref.rid %s)\n" " AND tag.tagid=tagxref.tagid\n" " AND tag.tagname GLOB 'event-*'" " AND blob.rid=tagxref.rid;", zWhere /*safe-for-%s*/ ); /* Attachments */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, attachment.mtime, 'attach-control',\n" " 'attachment-control for '||attachment.filename\n" " FROM attachment, blob\n" " WHERE (attachment.attachid %s)\n" " AND blob.rid=attachment.attachid", zWhere /*safe-for-%s*/ ); db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT blob.rid, blob.uuid, attachment.mtime, 'attachment',\n" " 'attachment '||attachment.filename\n" " FROM attachment, blob\n" " WHERE (blob.rid %s)\n" " AND blob.rid NOT IN (SELECT rid FROM description)\n" " AND blob.uuid=attachment.src", zWhere /*safe-for-%s*/ ); /* Forum posts */ if( db_table_exists("repository","forumpost") ){ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,ctime,type,summary)\n" "SELECT postblob.rid, postblob.uuid, forumpost.fmtime, 'forumpost',\n" " CASE WHEN fpid=froot THEN 'forum-post '\n" " ELSE 'forum-reply-to ' END || substr(rootblob.uuid,1,14)\n" " FROM forumpost, blob AS postblob, blob AS rootblob\n" " WHERE (forumpost.fpid %s)\n" " AND postblob.rid=forumpost.fpid" " AND rootblob.rid=forumpost.froot", zWhere /*safe-for-%s*/ ); } /* Everything else */ db_multi_exec( "INSERT OR IGNORE INTO description(rid,uuid,type,summary)\n" "SELECT blob.rid, blob.uuid," " CASE WHEN blob.size<0 THEN 'phantom' ELSE '' END,\n" " 'unknown'\n" " FROM blob WHERE (blob.rid %s);", zWhere /*safe-for-%s*/ ); /* Mark private elements */ db_multi_exec( "UPDATE description SET isPrivate=1 WHERE rid IN private" ); } /* ** Print the content of the description table on stdout. ** ** The description table is computed using the WHERE clause zWhere if ** the zWhere parameter is not NULL. If zWhere is NULL, then this ** routine assumes that the description table already exists and is ** populated and merely prints the contents. */ int describe_artifacts_to_stdout(const char *zWhere, const char *zLabel){ Stmt q; int cnt = 0; if( zWhere!=0 ) describe_artifacts(zWhere); db_prepare(&q, "SELECT uuid, summary, isPrivate\n" " FROM description\n" " ORDER BY ctime, type;" ); while( db_step(&q)==SQLITE_ROW ){ if( zLabel ){ fossil_print("%s\n", zLabel); zLabel = 0; } fossil_print(" %.16s %s", db_column_text(&q,0), db_column_text(&q,1)); if( db_column_int(&q,2) ) fossil_print(" (unpublished)"); fossil_print("\n"); cnt++; } db_finalize(&q); if( zWhere!=0 ) db_multi_exec("DELETE FROM description;"); return cnt; } |
︙ | ︙ | |||
1671 1672 1673 1674 1675 1676 1677 | /* ** WEBPAGE: bloblist ** ** Return a page showing all artifacts in the repository. Query parameters: ** ** n=N Show N artifacts ** s=S Start with artifact number S | | < | < < < < < < < < < < < < | | | | < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 | /* ** WEBPAGE: bloblist ** ** Return a page showing all artifacts in the repository. Query parameters: ** ** n=N Show N artifacts ** s=S Start with artifact number S ** unpub Show only unpublished artifacts ** hclr Color code hash types (SHA1 vs SHA3) */ void bloblist_page(void){ Stmt q; int s = atoi(PD("s","0")); int n = atoi(PD("n","5000")); int mx = db_int(0, "SELECT max(rid) FROM blob"); int unpubOnly = PB("unpub"); int hashClr = PB("hclr"); char *zRange; char *zSha1Bg; char *zSha3Bg; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("List Of Artifacts"); style_submenu_element("250 Largest", "bigbloblist"); if( g.perm.Admin ){ style_submenu_element("Artifact Log", "rcvfromlist"); } if( g.perm.Write ){ style_submenu_element("Artifact Stats", "artifact_stats"); } if( !unpubOnly && mx>n && P("s")==0 ){ int i; @ <p>Select a range of artifacts to view:</p> @ <ul> for(i=1; i<=mx; i+=n){ @ <li> %z(href("%R/bloblist?s=%d&n=%d",i,n)) @ %d(i)..%d(i+n-1<mx?i+n-1:mx)</a> } @ </ul> style_footer(); return; } if( !unpubOnly && mx>n ){ style_submenu_element("Index", "bloblist"); } if( unpubOnly ){ zRange = mprintf("IN private"); }else{ zRange = mprintf("BETWEEN %d AND %d", s, s+n-1); } describe_artifacts(zRange); fossil_free(zRange); db_prepare(&q, "SELECT rid, uuid, summary, isPrivate FROM description ORDER BY rid" ); if( skin_detail_boolean("white-foreground") ){ zSha1Bg = "#714417"; zSha3Bg = "#177117"; }else{ zSha1Bg = "#ebffb0"; zSha3Bg = "#b0ffb0"; } @ <table cellpadding="0" cellspacing="0"> while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q,0); const char *zUuid = db_column_text(&q, 1); const char *zDesc = db_column_text(&q, 2); int isPriv = db_column_int(&q,3); if( hashClr ){ const char *zClr = db_column_bytes(&q,1)>40 ? zSha3Bg : zSha1Bg; @ <tr style='background-color:%s(zClr);'><td align="right">%d(rid)</td> }else{ @ <tr><td align="right">%d(rid)</td> } @ <td> %z(href("%R/info/%!S",zUuid))%S(zUuid)</a> </td> @ <td align="left">%h(zDesc)</td> if( isPriv ){ @ <td>(unpublished)</td> } @ </tr> } @ </table> db_finalize(&q); style_footer(); } /* ** WEBPAGE: bigbloblist ** ** Return a page showing the largest artifacts in the repository in order ** of decreasing size. ** ** n=N Show the top N artifacts */ void bigbloblist_page(void){ Stmt q; int n = atoi(PD("n","250")); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
︙ | ︙ | |||
1922 1923 1924 1925 1926 1927 1928 | " FROM description, blob LEFT JOIN delta ON delta.rid=blob.rid" " WHERE description.rid=blob.rid" " ORDER BY length(content) DESC" ); @ <table cellpadding="2" cellspacing="0" border="1" \ @ class='sortable' data-column-types='NnnttT' data-init-sort='0'> @ <thead><tr><th align="right">Size<th align="right">RID | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 | " FROM description, blob LEFT JOIN delta ON delta.rid=blob.rid" " WHERE description.rid=blob.rid" " ORDER BY length(content) DESC" ); @ <table cellpadding="2" cellspacing="0" border="1" \ @ class='sortable' data-column-types='NnnttT' data-init-sort='0'> @ <thead><tr><th align="right">Size<th align="right">RID @ <th align="right">Delta From<th>Hash<th>Description<th>Date</tr></thead> @ <tbody> while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q,0); const char *zUuid = db_column_text(&q, 1); const char *zDesc = db_column_text(&q, 2); int sz = db_column_int(&q,3); const char *zSrcId = db_column_text(&q,4); const char *zDate = db_column_text(&q,5); @ <tr><td align="right">%d(sz)</td> @ <td align="right">%d(rid)</td> @ <td align="right">%s(zSrcId)</td> @ <td> %z(href("%R/info/%!S",zUuid))%S(zUuid)</a> </td> @ <td align="left">%h(zDesc)</td> @ <td align="left">%z(href("%R/timeline?c=%T",zDate))%s(zDate)</a></td> @ </tr> } @ </tbody></table> db_finalize(&q); style_table_sorter(); style_footer(); } /* ** COMMAND: test-unsent ** ** Usage: %fossil test-unsent ** |
︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 | #define MAX_COLLIDE 25 /* ** Generate a report on the number of collisions in artifact hashes ** generated by the SQL given in the argument. */ static void collision_report(const char *zSql){ | | | 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 | #define MAX_COLLIDE 25 /* ** Generate a report on the number of collisions in artifact hashes ** generated by the SQL given in the argument. */ static void collision_report(const char *zSql){ int i, j, kk; int nHash = 0; Stmt q; char zPrev[HNAME_MAX+1]; struct { int cnt; char *azHit[MAX_COLLIDE]; char z[HNAME_MAX+1]; |
︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 | @ </thead><tbody> for(i=1; i<=HNAME_MAX; i++){ if( aCollide[i].cnt==0 ) continue; @ <tr><td>%d(i)<td>%d(aCollide[i].cnt)<td>%h(aCollide[i].z)</tr> } @ </tbody></table> @ <p>Total number of hashes: %d(nHash)</p> for(i=HNAME_MAX; i>=4; i--){ if( aCollide[i].cnt==0 ) continue; if( aCollide[i].cnt>200 ) break; if( aCollide[i].cnt<25 ){ @ <p>Collisions of length %d(i): }else{ @ <p>First 25 collisions of length %d(i): } for(j=0; j<aCollide[i].cnt && j<MAX_COLLIDE; j++){ char *zId = aCollide[i].azHit[j]; if( zId==0 ) continue; | > > | | 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | @ </thead><tbody> for(i=1; i<=HNAME_MAX; i++){ if( aCollide[i].cnt==0 ) continue; @ <tr><td>%d(i)<td>%d(aCollide[i].cnt)<td>%h(aCollide[i].z)</tr> } @ </tbody></table> @ <p>Total number of hashes: %d(nHash)</p> kk = 0; for(i=HNAME_MAX; i>=4; i--){ if( aCollide[i].cnt==0 ) continue; if( aCollide[i].cnt>200 ) break; kk += aCollide[i].cnt; if( aCollide[i].cnt<25 ){ @ <p>Collisions of length %d(i): }else{ @ <p>First 25 collisions of length %d(i): } for(j=0; j<aCollide[i].cnt && j<MAX_COLLIDE; j++){ char *zId = aCollide[i].azHit[j]; if( zId==0 ) continue; @ %z(href("%R/whatis/%s",zId))%h(zId)</a> } } for(i=4; i<count(aCollide); i++){ for(j=0; j<aCollide[i].cnt && j<MAX_COLLIDE; j++){ fossil_free(aCollide[i].azHit[j]); } } |
︙ | ︙ | |||
2159 2160 2161 2162 2163 2164 2165 | style_submenu_element("Stats", "stat"); @ <h1>Hash Prefix Collisions on Check-ins</h1> collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)" " FROM event WHERE event.type='ci'" " ORDER BY 1"); @ <h1>Hash Prefix Collisions on All Artifacts</h1> collision_report("SELECT uuid FROM blob ORDER BY 1"); | | | 1282 1283 1284 1285 1286 1287 1288 1289 1290 | style_submenu_element("Stats", "stat"); @ <h1>Hash Prefix Collisions on Check-ins</h1> collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)" " FROM event WHERE event.type='ci'" " ORDER BY 1"); @ <h1>Hash Prefix Collisions on All Artifacts</h1> collision_report("SELECT uuid FROM blob ORDER BY 1"); style_footer(); } |
Deleted src/patch.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/path.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | ** Local variables for this module */ static struct { PathNode *pCurrent; /* Current generation of nodes */ PathNode *pAll; /* All nodes */ Bag seen; /* Nodes seen before */ int nStep; /* Number of steps from first to last */ | < < < < < < | 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 | ** Local variables for this module */ static struct { PathNode *pCurrent; /* Current generation of nodes */ PathNode *pAll; /* All nodes */ Bag seen; /* Nodes seen before */ int nStep; /* Number of steps from first to last */ PathNode *pStart; /* Earliest node */ PathNode *pEnd; /* Most recent */ } path; /* ** Return the first (last) element of the computed path. */ PathNode *path_first(void){ return path.pStart; } PathNode *path_last(void){ return path.pEnd; } /* ** Return the number of steps in the computed path. */ int path_length(void){ return path.nStep; } /* ** Create a new node */ static PathNode *path_new_node(int rid, PathNode *pFrom, int isParent){ PathNode *p; p = fossil_malloc( sizeof(*p) ); |
︙ | ︙ | |||
125 126 127 128 129 130 131 | ** ** Return NULL if no path is found. */ PathNode *path_shortest( int iFrom, /* Path starts here */ int iTo, /* Path ends here */ int directOnly, /* No merge links if true */ | | < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | ** ** Return NULL if no path is found. */ PathNode *path_shortest( int iFrom, /* Path starts here */ int iTo, /* Path ends here */ int directOnly, /* No merge links if true */ int oneWayOnly /* Parent->child only if true */ ){ Stmt s; PathNode *pPrev; PathNode *p; path_reset(); path.pStart = path_new_node(iFrom, 0, 0); |
︙ | ︙ | |||
170 171 172 173 174 175 176 | while( pPrev ){ db_bind_int(&s, ":pid", pPrev->rid); while( db_step(&s)==SQLITE_ROW ){ int cid = db_column_int(&s, 0); int isParent = db_column_int(&s, 1); if( bag_find(&path.seen, cid) ) continue; p = path_new_node(cid, pPrev, isParent); | < < < < | | < < < < < < < < < < < < < < < < < < < < < < | | 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 | while( pPrev ){ db_bind_int(&s, ":pid", pPrev->rid); while( db_step(&s)==SQLITE_ROW ){ int cid = db_column_int(&s, 0); int isParent = db_column_int(&s, 1); if( bag_find(&path.seen, cid) ) continue; p = path_new_node(cid, pPrev, isParent); if( cid==iTo ){ db_finalize(&s); path.pEnd = p; path_reverse_path(); return path.pStart; } } db_reset(&s); pPrev = pPrev->u.pPeer; } } db_finalize(&s); path_reset(); return 0; } /* ** Find the mid-point of the path. If the path contains fewer than ** 2 steps, return 0. */ PathNode *path_midpoint(void){ PathNode *p; int i; if( path.nStep<2 ) return 0; for(p=path.pEnd, i=0; p && i<path.nStep/2; p=p->pFrom, i++){} return p; } /* ** Compute the shortest path between two check-ins and then transfer ** that path into the "ancestor" table. This is a utility used by ** both /annotate and /finfo. See also: compute_direct_ancestors(). */ void path_shortest_stored_in_ancestor_table( int origid, /* RID for check-in at start of the path */ int cid /* RID for check-in at the end of the path */ ){ PathNode *pPath; int gen = 0; Stmt ins; pPath = path_shortest(cid, origid, 1, 0); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ancestor(" " rid INT UNIQUE," " generation INTEGER PRIMARY KEY" ");" "DELETE FROM ancestor;" ); |
︙ | ︙ | |||
278 279 280 281 282 283 284 | db_find_and_open_repository(0,0); directOnly = find_option("no-merge",0,0)!=0; oneWay = find_option("one-way",0,0)!=0; if( g.argc!=4 ) usage("VERSION1 VERSION2"); iFrom = name_to_rid(g.argv[2]); iTo = name_to_rid(g.argv[3]); | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | db_find_and_open_repository(0,0); directOnly = find_option("no-merge",0,0)!=0; oneWay = find_option("one-way",0,0)!=0; if( g.argc!=4 ) usage("VERSION1 VERSION2"); iFrom = name_to_rid(g.argv[2]); iTo = name_to_rid(g.argv[3]); p = path_shortest(iFrom, iTo, directOnly, oneWay); if( p==0 ){ fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]); } for(n=1, p=path.pStart; p; p=p->u.pTo, n++){ char *z; z = db_text(0, "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
︙ | ︙ | |||
429 430 431 432 433 434 435 | ** This routine really has nothing to do with path. It is located ** in this path.c module in order to leverage some of the path ** infrastructure. */ void find_filename_changes( int iFrom, /* Ancestor check-in */ int iTo, /* Recent check-in */ | | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | ** This routine really has nothing to do with path. It is located ** in this path.c module in order to leverage some of the path ** infrastructure. */ void find_filename_changes( int iFrom, /* Ancestor check-in */ int iTo, /* Recent check-in */ int revOk, /* Ok to move backwards (child->parent) if true */ int *pnChng, /* Number of name changes along the path */ int **aiChng, /* Name changes */ const char *zDebug /* Generate trace output if no NULL */ ){ PathNode *p; /* For looping over path from iFrom to iTo */ NameChange *pAll = 0; /* List of all name changes seen so far */ NameChange *pChng; /* For looping through the name change list */ |
︙ | ︙ | |||
451 452 453 454 455 456 457 | if(0==iFrom){ fossil_fatal("Invalid 'from' RID: 0"); }else if(0==iTo){ fossil_fatal("Invalid 'to' RID: 0"); } if( iFrom==iTo ) return; path_reset(); | | < < < < < < < < | | > | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | if(0==iFrom){ fossil_fatal("Invalid 'from' RID: 0"); }else if(0==iTo){ fossil_fatal("Invalid 'to' RID: 0"); } if( iFrom==iTo ) return; path_reset(); p = path_shortest(iFrom, iTo, 1, revOk==0); if( p==0 ) return; path_reverse_path(); db_prepare(&q1, "SELECT pfnid, fnid FROM mlink" " WHERE mid=:mid AND (pfnid>0 OR fid==0)" " ORDER BY pfnid" ); for(p=path.pStart; p; p=p->u.pTo){ int fnid, pfnid; if( !p->fromIsParent && (p->u.pTo==0 || p->u.pTo->fromIsParent) ){ /* Skip nodes where the parent is not on the path */ continue; } db_bind_int(&q1, ":mid", p->rid); while( db_step(&q1)==SQLITE_ROW ){ fnid = db_column_int(&q1, 1); pfnid = db_column_int(&q1, 0); if( pfnid==0 ){ pfnid = fnid; fnid = 0; } if( !p->fromIsParent ){ int t = fnid; fnid = pfnid; pfnid = t; } if( zDebug ){ fossil_print("%s at %d%s %.10z: %d[%z] -> %d[%z]\n", zDebug, p->rid, p->fromIsParent ? ">" : "<", db_text(0, "SELECT uuid FROM blob WHERE rid=%d", p->rid), pfnid, db_text(0, "SELECT name FROM filename WHERE fnid=%d", pfnid), fnid, db_text(0, "SELECT name FROM filename WHERE fnid=%d", fnid)); } for(pChng=pAll; pChng; pChng=pChng->pNext){ if( pChng->curName==pfnid ){ |
︙ | ︙ | |||
556 557 558 559 560 561 562 | void test_name_change(void){ int iFrom; int iTo; int *aChng; int nChng; int i; const char *zDebug = 0; | | | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | void test_name_change(void){ int iFrom; int iTo; int *aChng; int nChng; int i; const char *zDebug = 0; int revOk = 0; db_find_and_open_repository(0,0); zDebug = find_option("debug",0,0)!=0 ? "debug" : 0; revOk = find_option("bidirectional",0,0)!=0; if( g.argc<4 ) usage("VERSION1 VERSION2"); while( g.argc>=4 ){ iFrom = name_to_rid(g.argv[2]); iTo = name_to_rid(g.argv[3]); find_filename_changes(iFrom, iTo, revOk, &nChng, &aChng, zDebug); fossil_print("------ Changes for (%d) %s -> (%d) %s\n", iFrom, g.argv[2], iTo, g.argv[3]); for(i=0; i<nChng; i++){ char *zFrom, *zTo; zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]); zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]); |
︙ | ︙ | |||
622 623 624 625 626 627 628 | @ GROUP BY 2, 3; ; /* ** WEBPAGE: test-rename-list ** ** Print a list of all file rename operations throughout history. | | < | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | @ GROUP BY 2, 3; ; /* ** WEBPAGE: test-rename-list ** ** Print a list of all file rename operations throughout history. ** This page is intended for for testing purposes only and may change ** or be discontinued without notice. */ void test_rename_list_page(void){ Stmt q; int nRename; int nCheckin; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( P("all")!=0 ){ style_header("List Of All Filename Changes"); db_multi_exec("%s", zRenameQuery/*safe-for-%s*/); style_submenu_element("Distinct", "%R/test-rename-list"); }else{ style_header("List Of Distinct Filename Changes"); db_multi_exec("%s", zDistinctRenameQuery/*safe-for-%s*/); |
︙ | ︙ | |||
667 668 669 670 671 672 673 | @ <td>%z(href("%R/finfo?name=%t",zOld))%h(zOld)</a></td> @ <td>%z(href("%R/finfo?name=%t",zNew))%h(zNew)</a></td> @ <td>%z(href("%R/info/%!S",zUuid))%S(zUuid)</a></td></tr> } @ </tbody></table> db_finalize(&q); style_table_sorter(); | | | 626 627 628 629 630 631 632 633 634 | @ <td>%z(href("%R/finfo?name=%t",zOld))%h(zOld)</a></td> @ <td>%z(href("%R/finfo?name=%t",zNew))%h(zNew)</a></td> @ <td>%z(href("%R/info/%!S",zUuid))%S(zUuid)</a></td></tr> } @ </tbody></table> db_finalize(&q); style_table_sorter(); style_footer(); } |
Changes to src/piechart.c.
︙ | ︙ | |||
140 141 142 143 144 145 146 | r2 = cx<cy ? cx : cy; r = r2 - 80.0; if( r<0.33333*r2 ) r = 0.33333*r2; h = 0; zFg = skin_detail_boolean("white-foreground") ? "white" : "black"; db_prepare(&q, "SELECT sum(amt), count(*) FROM piechart"); | | < < < | | 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 | r2 = cx<cy ? cx : cy; r = r2 - 80.0; if( r<0.33333*r2 ) r = 0.33333*r2; h = 0; zFg = skin_detail_boolean("white-foreground") ? "white" : "black"; db_prepare(&q, "SELECT sum(amt), count(*) FROM piechart"); if( db_step(&q)!=SQLITE_ROW ) return; rTotal = db_column_double(&q, 0); nTotal = db_column_int(&q, 1); db_finalize(&q); rTooSmall = 0.0; nTooSmall = 0; if( (pieFlags & PIE_OTHER)!=0 && nTotal>1 ){ db_prepare(&q, "SELECT sum(amt), count(*) FROM piechart WHERE amt<:amt"); db_bind_double(&q, ":amt", rTotal/OTHER_CUTOFF); if( db_step(&q)==SQLITE_ROW ){ rTooSmall = db_column_double(&q, 0); nTooSmall = db_column_double(&q, 1); } db_finalize(&q); } if( nTooSmall>1 ){ db_prepare(&q, "SELECT amt, label FROM piechart WHERE amt>=:limit" " UNION ALL SELECT %.17g, '%d others';", rTooSmall, nTooSmall); |
︙ | ︙ | |||
275 276 277 278 279 280 281 | Stmt ins; int n = 0; int width; int height; int i, j; login_check_credentials(); | < | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | Stmt ins; int n = 0; int width; int height; int i, j; login_check_credentials(); style_header("Pie Chart Test"); db_multi_exec("CREATE TEMP TABLE piechart(amt REAL, label TEXT);"); db_prepare(&ins, "INSERT INTO piechart(amt,label) VALUES(:amt,:label)"); zData = PD("data",""); width = atoi(PD("width","800")); height = atoi(PD("height","400")); i = 0; |
︙ | ︙ | |||
310 311 312 313 314 315 316 | fossil_free(zLabel); } db_finalize(&ins); if( n>1 ){ @ <svg width=%d(width) height=%d(height) style="border:1px solid #d3d3d3;"> piechart_render(width,height, PIE_OTHER|PIE_PERCENT); @ </svg> | | | | | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | fossil_free(zLabel); } db_finalize(&ins); if( n>1 ){ @ <svg width=%d(width) height=%d(height) style="border:1px solid #d3d3d3;"> piechart_render(width,height, PIE_OTHER|PIE_PERCENT); @ </svg> @ <hr /> } @ <form method="POST" action='%R/test-piechart'> @ <p>Comma-separated list of slice widths:<br /> @ <input type='text' name='data' size='80' value='%h(zData)'/><br /> @ Width: <input type='text' size='8' name='width' value='%d(width)'/> @ Height: <input type='text' size='8' name='height' value='%d(height)'/><br /> @ <input type='submit' value='Draw The Pie Chart'/> @ </form> @ <p>Interesting test cases: @ <ul> @ <li> <a href='test-piechart?data=44,2,2,2,2,2,3,2,2,2,2,2,44'>Case 1</a> @ <li> <a href='test-piechart?data=2,2,2,2,2,44,44,2,2,2,2,2'>Case 2</a> @ <li> <a href='test-piechart?data=20,2,2,2,2,2,2,2,2,2,2,80'>Case 3</a> @ <li> <a href='test-piechart?data=80,2,2,2,2,2,2,2,2,2,2,20'>Case 4</a> @ <li> <a href='test-piechart?data=2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2'>Case 5</a> @ </ul> style_footer(); } |
Deleted src/pikchrshow.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/pivot.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ** Set the primary file. The primary version is one of the two ** files that have a common ancestor. The other file is the secondary. ** There can be multiple secondaries but only a single primary. ** The primary must be set first. ** ** In the merge algorithm, the file being merged in is the primary. ** The current check-out or other files that have been merged into | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** Set the primary file. The primary version is one of the two ** files that have a common ancestor. The other file is the secondary. ** There can be multiple secondaries but only a single primary. ** The primary must be set first. ** ** In the merge algorithm, the file being merged in is the primary. ** The current check-out or other files that have been merged into ** the current checkout are the secondaries. ** ** The act of setting the primary resets the pivot-finding algorithm. */ void pivot_set_primary(int rid){ /* Set up table used to do the search */ db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS aqueue(" |
︙ | ︙ | |||
60 61 62 63 64 65 66 | /* ** Set a secondary file. The primary file must be set first. There ** must be at least one secondary but there can be more than one if ** desired. */ void pivot_set_secondary(int rid){ | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | /* ** Set a secondary file. The primary file must be set first. There ** must be at least one secondary but there can be more than one if ** desired. */ void pivot_set_secondary(int rid){ /* Insert the primary record */ db_multi_exec( "INSERT OR IGNORE INTO aqueue(rid, mtime, pending, src)" " SELECT %d, mtime, 1, 0 FROM event WHERE objid=%d AND type='ci'", rid, rid ); } |
︙ | ︙ | |||
150 151 152 153 154 155 156 | db_finalize(&q2); db_finalize(&i1); db_finalize(&u1); return rid; } /* | | | < | | | < < < < | | < > | 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 | db_finalize(&q2); db_finalize(&i1); db_finalize(&u1); return rid; } /* ** COMMAND: test-find-pivot ** ** Usage: %fossil test-find-pivot ?options? PRIMARY SECONDARY ... ** ** Test the pivot_find() procedure. ** ** Options: ** --ignore-merges Ignore merges for discovering name pivots */ void test_find_pivot(void){ int i, rid; int ignoreMerges = find_option("ignore-merges",0,0)!=0; int showDetails = find_option("details",0,0)!=0; if( g.argc<4 ){ usage("?options? PRIMARY SECONDARY ..."); } db_must_be_within_tree(); pivot_set_primary(name_to_rid(g.argv[2])); for(i=3; i<g.argc; i++){ pivot_set_secondary(name_to_rid(g.argv[i])); } rid = pivot_find(ignoreMerges); printf("pivot=%s\n", db_text("?","SELECT uuid FROM blob WHERE rid=%d",rid) ); if( showDetails ){ Stmt q; db_prepare(&q, "SELECT substr(uuid,1,12), aqueue.rid, datetime(aqueue.mtime)," " aqueue.pending, aqueue.src\n" " FROM aqueue JOIN blob ON aqueue.rid=blob.rid\n" " ORDER BY aqueue.mtime DESC" |
︙ | ︙ |
Changes to src/popen.c.
︙ | ︙ | |||
119 120 121 122 123 124 125 | ** *ppIn is stdout from the child process. (The caller ** reads from *ppIn in order to receive input from the child.) ** Note that *ppIn is an unbuffered file descriptor, not a FILE. ** The process ID of the child is written into *pChildPid. ** ** Return the number of errors. */ | | < < < < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | ** *ppIn is stdout from the child process. (The caller ** reads from *ppIn in order to receive input from the child.) ** Note that *ppIn is an unbuffered file descriptor, not a FILE. ** The process ID of the child is written into *pChildPid. ** ** Return the number of errors. */ int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){ #ifdef _WIN32 HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr; SECURITY_ATTRIBUTES saAttr; DWORD childPid = 0; int fd; saAttr.nLength = sizeof(saAttr); |
︙ | ︙ | |||
181 182 183 184 185 186 187 188 189 190 | close(pout[1]); *pChildPid = 0; return 1; } signal(SIGPIPE,SIG_IGN); if( *pChildPid==0 ){ int fd; /* This is the child process */ close(0); fd = dup(pout[0]); | > | | < < < | < | 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 | close(pout[1]); *pChildPid = 0; return 1; } signal(SIGPIPE,SIG_IGN); if( *pChildPid==0 ){ int fd; int nErr = 0; /* This is the child process */ close(0); fd = dup(pout[0]); if( fd!=0 ) nErr++; close(pout[0]); close(pout[1]); close(1); fd = dup(pin[1]); if( fd!=1 ) nErr++; close(pin[0]); close(pin[1]); execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0); return 1; }else{ /* This is the parent process */ close(pin[1]); *pfdIn = pin[0]; close(pout[0]); *ppOut = fdopen(pout[1], "w"); |
︙ | ︙ |
Changes to src/pqueue.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** Integers must be positive. */ struct PQueue { int cnt; /* Number of entries in the queue */ int sz; /* Number of slots in a[] */ struct QueueElement { int id; /* ID of the element */ double value; /* Value of element. Kept in ascending order */ } *a; }; #endif /* ** Initialize a PQueue structure | > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | ** Integers must be positive. */ struct PQueue { int cnt; /* Number of entries in the queue */ int sz; /* Number of slots in a[] */ struct QueueElement { int id; /* ID of the element */ void *p; /* Content pointer */ double value; /* Value of element. Kept in ascending order */ } *a; }; #endif /* ** Initialize a PQueue structure |
︙ | ︙ | |||
71 72 73 74 75 76 77 | p->a = fossil_realloc(p->a, sizeof(p->a[0])*N); p->sz = N; } /* ** Insert element e into the queue. */ | | > | > > | 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 | p->a = fossil_realloc(p->a, sizeof(p->a[0])*N); p->sz = N; } /* ** Insert element e into the queue. */ void pqueuex_insert(PQueue *p, int e, double v, void *pData){ int i, j; if( p->cnt+1>p->sz ){ pqueuex_resize(p, p->cnt+5); } for(i=0; i<p->cnt; i++){ if( p->a[i].value>v ){ for(j=p->cnt; j>i; j--){ p->a[j] = p->a[j-1]; } break; } } p->a[i].id = e; p->a[i].p = pData; p->a[i].value = v; p->cnt++; } /* ** Extract the first element from the queue (the element with ** the smallest value) and return its ID. Return 0 if the queue ** is empty. */ int pqueuex_extract(PQueue *p, void **pp){ int e, i; if( p->cnt==0 ){ if( pp ) *pp = 0; return 0; } e = p->a[0].id; if( pp ) *pp = p->a[0].p; for(i=0; i<p->cnt-1; i++){ p->a[i] = p->a[i+1]; } p->cnt--; return e; } |
Changes to src/printf.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | ** %S Prefix of a length appropriate for human display ** ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS ** is the default number of digits to display to humans. This value can ** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL ** is the minimum number of digits to be used in URLs. The number used ** will always be at least 6 more than the number used for human output, | | | | | | | 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 | ** %S Prefix of a length appropriate for human display ** ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS ** is the default number of digits to display to humans. This value can ** be overridden using the hash-digits setting. FOSSIL_HASH_DIGITS_URL ** is the minimum number of digits to be used in URLs. The number used ** will always be at least 6 more than the number used for human output, ** or 40 if the number of digits in human output is 34 or more. */ #ifndef FOSSIL_HASH_DIGITS # define FOSSIL_HASH_DIGITS 10 /* For %S (human display) */ #endif #ifndef FOSSIL_HASH_DIGITS_URL # define FOSSIL_HASH_DIGITS_URL 16 /* For %!S (embedded in URLs) */ #endif /* ** Return the number of artifact hash digits to display. The number is for ** human output if the bForUrl is false and is destined for a URL if ** bForUrl is false. */ static int hashDigits(int bForUrl){ static int nDigitHuman = 0; static int nDigitUrl = 0; if( nDigitHuman==0 ){ nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS); if( nDigitHuman < 6 ) nDigitHuman = 6; if( nDigitHuman > 40 ) nDigitHuman = 40; nDigitUrl = nDigitHuman + 6; if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL; if( nDigitUrl > 40 ) nDigitUrl = 40; } return bForUrl ? nDigitUrl : nDigitHuman; } /* ** Return the number of characters in a %S output. */ int length_of_S_display(void){ return hashDigits(0); } /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ #define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ |
︙ | ︙ | |||
95 96 97 98 99 100 101 | #define etPOINTER 16 /* The %p conversion */ #define etHTMLIZE 17 /* Make text safe for HTML */ #define etHTTPIZE 18 /* Make text safe for HTTP. "/" encoded as %2f */ #define etURLIZE 19 /* Make text safe for HTTP. "/" not encoded */ #define etFOSSILIZE 20 /* The fossil header encoding format. */ #define etPATH 21 /* Path type */ #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */ | | < < < < < < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | #define etPOINTER 16 /* The %p conversion */ #define etHTMLIZE 17 /* Make text safe for HTML */ #define etHTTPIZE 18 /* Make text safe for HTTP. "/" encoded as %2f */ #define etURLIZE 19 /* Make text safe for HTTP. "/" not encoded */ #define etFOSSILIZE 20 /* The fossil header encoding format. */ #define etPATH 21 /* Path type */ #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */ #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */ #define etROOT 24 /* String value of g.zTop: %R */ /* ** An "etByte" is an 8-bit unsigned value. */ typedef unsigned char etByte; |
︙ | ︙ | |||
134 135 136 137 138 139 140 | #define FLAG_INTERN 2 /* True if for internal use only */ #define FLAG_STRING 4 /* Allow infinity precision */ /* ** The following table is searched linearly, so it is good to put the ** most frequently used conversion types first. | < < < < < < < < < < < < < < < < < < < < | 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 | #define FLAG_INTERN 2 /* True if for internal use only */ #define FLAG_STRING 4 /* Allow infinity precision */ /* ** The following table is searched linearly, so it is good to put the ** most frequently used conversion types first. */ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; static const et_info fmtinfo[] = { { 'd', 10, 1, etRADIX, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 6, etDYNSTRING, 0, 0 }, { 'q', 0, 4, etSQLESCAPE, 0, 0 }, { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, { 'b', 0, 2, etBLOB, 0, 0 }, { 'B', 0, 2, etBLOBSQL, 0, 0 }, { 'W', 0, 2, etWIKISTR, 0, 0 }, { 'h', 0, 4, etHTMLIZE, 0, 0 }, { 'R', 0, 0, etROOT, 0, 0 }, { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */ { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */ { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, { 'F', 0, 4, etFOSSILIZE, 0, 0 }, { 'S', 0, 4, etSTRINGID, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, { 'u', 10, 0, etRADIX, 0, 0 }, { 'x', 16, 0, etRADIX, 16, 1 }, { 'X', 16, 0, etRADIX, 0, 4 }, { 'f', 0, 1, etFLOAT, 0, 0 }, { 'e', 0, 1, etEXP, 30, 0 }, { 'E', 0, 1, etEXP, 14, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, { 'i', 10, 1, etRADIX, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, { '/', 0, 0, etPATH, 0, 0 }, }; #define etNINFO count(fmtinfo) /* ** "*val" is a double such that 0.1 <= *val < 10.0 ** Return the ascii code for the leading digit of *val, then ** multiply "*val" by 10.0 to renormalize. ** ** Example: |
︙ | ︙ | |||
226 227 228 229 230 231 232 | /* ** Find the length of a string as long as that length does not ** exceed N bytes. If no zero terminator is seen in the first ** N bytes then return N. If N is negative, then this routine ** is an alias for strlen(). */ | < < < < | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | /* ** Find the length of a string as long as that length does not ** exceed N bytes. If no zero terminator is seen in the first ** N bytes then return N. If N is negative, then this routine ** is an alias for strlen(). */ static int StrNLen32(const char *z, int N){ int n = 0; while( (N-- != 0) && *(z++)!=0 ){ n++; } return n; } /* ** Return an appropriate set of flags for wiki_convert() for displaying ** comments on a timeline. These flag settings are determined by ** configuration parameters. ** ** The altForm2 argument is true for "%!W" (with the "!" alternate-form-2 |
︙ | ︙ | |||
257 258 259 260 261 262 263 | wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS; }else{ wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS; } if( db_get_boolean("timeline-plaintext", 0) ){ wikiFlags |= WIKI_LINKSONLY; } | < < < | | 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 256 257 258 259 260 | wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS; }else{ wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS; } if( db_get_boolean("timeline-plaintext", 0) ){ wikiFlags |= WIKI_LINKSONLY; } } return wikiFlags; } /* ** The root program. All variations call this core. ** ** INPUTS: ** pBlob This is the blob where the output will be built. ** ** fmt This is the format string, as in the usual print. ** ** ap This is a pointer to a list of arguments. Same as in ** vfprint. ** ** OUTPUTS: ** The return value is the total number of characters sent to ** the function "func". Returns -1 on a error. ** ** Note that the order in which automatic variables are declared below ** seems to make a big difference in determining how fast this beast ** will run. */ int vxprintf( Blob *pBlob, /* Append output to this blob */ |
︙ | ︙ | |||
324 325 326 327 328 329 330 | #define etSPACESIZE (sizeof(spaces)-1) int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ etByte flag_exp; /* True to force display of the exponent */ int nsd; /* Number of significant digits returned */ | < > < | < | < | > | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | #define etSPACESIZE (sizeof(spaces)-1) int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ etByte flag_exp; /* True to force display of the exponent */ int nsd; /* Number of significant digits returned */ count = length = 0; bufpt = 0; for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ int amt; bufpt = (char *)fmt; amt = 1; while( (c=(*++fmt))!='%' && c!=0 ) amt++; blob_append(pBlob,bufpt,amt); count += amt; if( c==0 ) break; } if( (c=(*++fmt))==0 ){ errorflag = 1; blob_append(pBlob,"%",1); count++; break; } |
︙ | ︙ | |||
410 411 412 413 414 415 416 | }else{ flag_longlong = 0; } }else{ flag_long = flag_longlong = 0; } /* Fetch the info entry for the field */ | | > > | | | | < < > | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | }else{ flag_longlong = 0; } }else{ flag_long = flag_longlong = 0; } /* Fetch the info entry for the field */ infop = 0; xtype = etERROR; for(idx=0; idx<etNINFO; idx++){ if( c==fmtinfo[idx].fmttype ){ infop = &fmtinfo[idx]; xtype = infop->type; break; } } zExtra = 0; /* Limit the precision to prevent overflowing buf[] during conversion */ if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ precision = etBUFSIZE-40; } |
︙ | ︙ | |||
706 707 708 709 710 711 712 | int limit = flag_alternateform ? va_arg(ap,int) : -1; bufpt = va_arg(ap,char*); if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ zExtra = bufpt; }else if( xtype==etSTRINGID ){ | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | int limit = flag_alternateform ? va_arg(ap,int) : -1; bufpt = va_arg(ap,char*); if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ zExtra = bufpt; }else if( xtype==etSTRINGID ){ precision = hashDigits(flag_altform2); } length = StrNLen32(bufpt, limit); if( precision>=0 && precision<length ) length = precision; break; } case etBLOB: { int limit = flag_alternateform ? va_arg(ap, int) : -1; |
︙ | ︙ | |||
812 813 814 815 816 817 818 | char *zMem = va_arg(ap,char*); if( zMem==0 ) zMem = ""; zExtra = bufpt = fossilize(zMem, limit); length = strlen(bufpt); if( precision>=0 && precision<length ) length = precision; break; } | < < < < < < < < < < < < < < < < < < < < | | | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | char *zMem = va_arg(ap,char*); if( zMem==0 ) zMem = ""; zExtra = bufpt = fossilize(zMem, limit); length = strlen(bufpt); if( precision>=0 && precision<length ) length = precision; break; } case etWIKISTR: { int limit = flag_alternateform ? va_arg(ap,int) : -1; char *zWiki = va_arg(ap, char*); Blob wiki; blob_init(&wiki, zWiki, limit); wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2)); blob_reset(&wiki); length = width = 0; break; } case etERROR: buf[0] = '%'; buf[1] = c; errorflag = 0; idx = 1+(c!=0); blob_append(pBlob,"%",idx); count += idx; if( c==0 ) fmt--; break; }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do ** the output. */ if( !flag_leftjustify ){ register int nspace; nspace = width-length; if( nspace>0 ){ count += nspace; while( nspace>=etSPACESIZE ){ blob_append(pBlob,spaces,etSPACESIZE); nspace -= etSPACESIZE; } if( nspace>0 ) blob_append(pBlob,spaces,nspace); } } if( length>0 ){ blob_append(pBlob,bufpt,length); count += length; } if( flag_leftjustify ){ register int nspace; nspace = width-length; if( nspace>0 ){ count += nspace; while( nspace>=etSPACESIZE ){ blob_append(pBlob,spaces,etSPACESIZE); nspace -= etSPACESIZE; } if( nspace>0 ) blob_append(pBlob,spaces,nspace); } } if( zExtra ){ |
︙ | ︙ | |||
956 957 958 959 960 961 962 | ** On windows, transform the output into the current terminal encoding ** if the output is going to the screen. If output is redirected into ** a file, no translation occurs. Switch output mode to binary to ** properly process line-endings, make sure to switch the mode back to ** text when done. ** No translation ever occurs on unix. */ | | > | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 | ** On windows, transform the output into the current terminal encoding ** if the output is going to the screen. If output is redirected into ** a file, no translation occurs. Switch output mode to binary to ** properly process line-endings, make sure to switch the mode back to ** text when done. ** No translation ever occurs on unix. */ void fossil_puts(const char *z, int toStdErr){ FILE* out = (toStdErr ? stderr : stdout); int n = (int)strlen(z); if( n==0 ) return; assert( toStdErr==0 || toStdErr==1 ); if( toStdErr==0 ) stdoutAtBOL = (z[n-1]=='\n'); #if defined(_WIN32) if( fossil_utf8_to_console(z, n, toStdErr) >= 0 ){ return; } |
︙ | ︙ | |||
981 982 983 984 985 986 987 | /* ** Force the standard output cursor to move to the beginning ** of a line, if it is not there already. */ int fossil_force_newline(void){ if( g.cgiOutput==0 && stdoutAtBOL==0 ){ | | | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 | /* ** Force the standard output cursor to move to the beginning ** of a line, if it is not there already. */ int fossil_force_newline(void){ if( g.cgiOutput==0 && stdoutAtBOL==0 ){ fossil_puts("\n", 0); return 1; } return 0; } /* ** Indicate that the cursor has moved to the start of a line by means |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | */ void fossil_print(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); if( g.cgiOutput ){ cgi_vprintf(zFormat, ap); }else{ | > | > > < < < < < < < | < < < < | < < < < < < < | | | | | | | < | < < < < < < | < < < < < < | | | | < | | < < < < | < | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | */ void fossil_print(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); if( g.cgiOutput ){ cgi_vprintf(zFormat, ap); }else{ Blob b = empty_blob; vxprintf(&b, zFormat, ap); fossil_puts(blob_str(&b), 0); blob_reset(&b); } va_end(ap); } /* ** Print a trace message on standard error. */ void fossil_trace(const char *zFormat, ...){ va_list ap; Blob b; va_start(ap, zFormat); b = empty_blob; vxprintf(&b, zFormat, ap); fossil_puts(blob_str(&b), 1); blob_reset(&b); va_end(ap); } /* ** Write a message to the error log, if the error log filename is ** defined. */ void fossil_errorlog(const char *zFormat, ...){ struct tm *pNow; time_t now; FILE *out; const char *z; int i; va_list ap; static const char *const azEnv[] = { "HTTP_HOST", "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_NAME" }; if( g.zErrlog==0 ) return; if( g.zErrlog[0]=='-' && g.zErrlog[1]==0 ){ out = stderr; }else{ out = fossil_fopen(g.zErrlog, "a"); if( out==0 ) return; } now = time(0); pNow = gmtime(&now); fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n", pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday+1, pNow->tm_hour, pNow->tm_min, pNow->tm_sec); va_start(ap, zFormat); vfprintf(out, zFormat, ap); fprintf(out, "\n"); va_end(ap); for(i=0; i<count(azEnv); i++){ char *p; if( (p = fossil_getenv(azEnv[i]))!=0 && p[0]!=0 ){ fprintf(out, "%s=%s\n", azEnv[i], p); fossil_path_free(p); }else if( (z = P(azEnv[i]))!=0 && z[0]!=0 ){ fprintf(out, "%s=%s\n", azEnv[i], z); } } fclose(out); } /* ** The following variable becomes true while processing a fatal error ** or a panic. If additional "recursive-fatal" errors occur while ** shutting down, the recursive errors are silently ignored. */ static int mainInFatalError = 0; /* ** Write error message output */ static int fossil_print_error(int rc, const char *z){ #ifdef FOSSIL_ENABLE_JSON if( g.json.isJsonMode ){ json_err( 0, z, 1 ); if( g.isHTTP ){ rc = 0 /* avoid HTTP 500 */; } } else #endif if( g.cgiOutput==1 && g.db ){ g.cgiOutput = 2; cgi_reset_content(); cgi_set_content_type("text/html"); style_header("Bad Request"); @ <p class="generalError">%h(z)</p> cgi_set_status(400, "Bad Request"); style_footer(); cgi_reply(); }else if( !g.fQuiet ){ fossil_force_newline(); fossil_trace("%s\n", z); } return rc; } /* ** Print an error message, rollback all databases, and quit. These ** routines never return. ** ** The only different between fossil_fatal() and fossil_panic() is that ** fossil_panic() makes an entry in the error log whereas fossil_fatal() ** does not. If there is not error log, then both routines work the ** same. Hence, the routines are interchangable for commands and only ** make a difference with processing web pages. ** ** Use fossil_fatal() for malformed inputs that should be reported back ** to the user, but which do not represent a configuration problem or bug. ** ** Use fossil_panic() for any kind of error that should be brought to the ** attention of the system administrator. */ NORETURN void fossil_panic(const char *zFormat, ...){ va_list ap; int rc = 1; char z[1000]; static int once = 0; |
︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 | } fossil_errorlog("panic: %s", z); rc = fossil_print_error(rc, z); abort(); exit(rc); } NORETURN void fossil_fatal(const char *zFormat, ...){ | < < < | | 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 | } fossil_errorlog("panic: %s", z); rc = fossil_print_error(rc, z); abort(); exit(rc); } NORETURN void fossil_fatal(const char *zFormat, ...){ char *z; int rc = 1; va_list ap; mainInFatalError = 1; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); rc = fossil_print_error(rc, z); fossil_free(z); db_force_rollback(); |
︙ | ︙ | |||
1235 1236 1237 1238 1239 1240 1241 | char *z; va_list ap; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); fossil_errorlog("warning: %s", z); #ifdef FOSSIL_ENABLE_JSON | | < < < < < < < | 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 | char *z; va_list ap; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); fossil_errorlog("warning: %s", z); #ifdef FOSSIL_ENABLE_JSON if(g.json.isJsonMode){ json_warn( FSL_JSON_W_UNKNOWN, "%s", z ); }else #endif { if( g.cgiOutput==1 ){ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z); }else{ fossil_force_newline(); fossil_trace("%s\n", z); } } free(z); |
︙ | ︙ |
Changes to src/publish.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** "unpublished" commands. */ #include "config.h" #include "publish.h" #include <assert.h> /* | | | | | 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 | ** "unpublished" commands. */ #include "config.h" #include "publish.h" #include <assert.h> /* ** COMMAND: unpublished ** ** Usage: %fossil unpublished ?OPTIONS? ** ** Show a list of unpublished or "private" artifacts. Unpublished artifacts ** will never push and hence will not be shared with collaborators. ** ** By default, this command only shows unpublished check-ins. To show ** all unpublished artifacts, use the --all command-line option. ** ** OPTIONS: ** --all Show all artifacts, not just check-ins */ void unpublished_cmd(void){ int bAll = find_option("all",0,0)!=0; db_find_and_open_repository(0,0); verify_all_options(); if( bAll ){ describe_artifacts_to_stdout("IN private", 0); }else{ describe_artifacts_to_stdout( "IN (SELECT rid FROM private CROSS JOIN event" " WHERE private.rid=event.objid" " AND event.type='ci')", 0); } } /* ** COMMAND: publish ** ** Usage: %fossil publish ?--only? TAGS... ** ** Cause artifacts identified by TAGS... to be published (made non-private). ** This can be used (for example) to convert a private branch into a public ** branch, or to publish a bundle that was imported privately. ** |
︙ | ︙ |
Changes to src/purge.c.
1 2 3 4 5 6 | /* ** Copyright (c) 2014 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* ** Copyright (c) 2014 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ |
︙ | ︙ | |||
447 448 449 450 451 452 453 | ** COMMAND: purge* ** ** The purge command removes content from a repository and stores that content ** in a "graveyard". The graveyard exists so that content can be recovered ** using the "fossil purge undo" command. The "fossil purge obliterate" ** command empties the graveyard, making the content unrecoverable. ** | | | | | | | | | | | | | | | | | > > > > > > > > > > > | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | ** COMMAND: purge* ** ** The purge command removes content from a repository and stores that content ** in a "graveyard". The graveyard exists so that content can be recovered ** using the "fossil purge undo" command. The "fossil purge obliterate" ** command empties the graveyard, making the content unrecoverable. ** ** ==== WARNING: This command can potentially destroy historical data and ==== ** ==== leave your repository in a goofy state. Know what you are doing! ==== ** ==== Make a backup of your repository before using this command! ==== ** ** ==== FURTHER WARNING: This command is a work-in-progress and may yet ==== ** ==== contain bugs. ==== ** ** fossil purge artifacts UUID... ?OPTIONS? ** ** Move arbitrary artifacts identified by the UUID list into the ** graveyard. ** ** fossil purge cat UUID... ** ** Write the content of one or more artifacts in the graveyard onto ** standard output. ** ** fossil purge checkins TAGS... ?OPTIONS? ** ** Move the check-ins or branches identified by TAGS and all of ** their descendants out of the repository and into the graveyard. ** If TAGS includes a branch name then it means all the check-ins ** on the most recent occurrence of that branch. ** ** fossil purge files NAME ... ?OPTIONS? ** ** Move all instances of files called NAME into the graveyard. ** NAME should be the name of the file relative to the root of the ** repository. If NAME is a directory, then all files within that ** directory are moved. ** ** fossil purge list|ls ?-l? ** ** Show the graveyard of prior purges. The -l option gives more ** detail in the output. ** ** fossil purge obliterate ID... ?--force? ** ** Remove one or more purge events from the graveyard. Once a purge ** event is obliterated, it can no longer be undone. The --force ** option suppresses the confirmation prompt. ** ** fossil purge tickets NAME ... ?OPTIONS? ** ** TBD... ** ** fossil purge undo ID ** ** Restore the content previously removed by purge ID. ** ** fossil purge wiki NAME ... ?OPTIONS? ** ** TBD... ** ** COMMON OPTIONS: ** ** --explain Make no changes, but show what would happen. ** --dry-run An alias for --explain ** ** SUMMARY: ** fossil purge artifacts UUID.. [OPTIONS] ** fossil purge cat UUID... ** fossil purge checkins TAGS... [OPTIONS] ** fossil purge files FILENAME... [OPTIONS] ** fossil purge list ** fossil purge obliterate ID... ** fossil purge tickets NAME... [OPTIONS] ** fossil purge undo ID ** fossil purge wiki NAME... [OPTIONS] */ void purge_cmd(void){ int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY; const char *zSubcmd; int n; int i; Stmt q; |
︙ | ︙ | |||
534 535 536 537 538 539 540 | } describe_artifacts_to_stdout("IN ok", 0); purge_artifact_list("ok", "", purgeFlags); db_end_transaction(0); }else if( strncmp(zSubcmd, "cat", n)==0 ){ int i, piid; Blob content; | | | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | } describe_artifacts_to_stdout("IN ok", 0); purge_artifact_list("ok", "", purgeFlags); db_end_transaction(0); }else if( strncmp(zSubcmd, "cat", n)==0 ){ int i, piid; Blob content; if( g.argc<4 ) usage("cat UUID..."); for(i=3; i<g.argc; i++){ piid = db_int(0, "SELECT piid FROM purgeitem WHERE uuid LIKE '%q%%'", g.argv[i]); if( piid==0 ) fossil_fatal("no such item: %s", g.argv[3]); purge_extract_item(piid, &content); blob_write_to_file(&content, "-"); blob_reset(&content); |
︙ | ︙ | |||
558 559 560 561 562 563 564 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); for(i=3; i<g.argc; i++){ int r = name_to_typed_rid(g.argv[i], "br"); compute_descendants(r, 1000000000); } vid = db_lget_int("checkout",0); if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){ | | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); for(i=3; i<g.argc; i++){ int r = name_to_typed_rid(g.argv[i], "br"); compute_descendants(r, 1000000000); } vid = db_lget_int("checkout",0); if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){ fossil_fatal("cannot purge the current checkout"); } find_checkin_associates("ok", 1); purge_artifact_list("ok", "", purgeFlags); db_end_transaction(0); }else if( strncmp(zSubcmd, "files", n)==0 ){ verify_all_options(); db_begin_transaction(); |
︙ | ︙ |
Changes to src/rebuild.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | ); db_end_transaction(0); } /* Add the user.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "user", "mtime") ){ | < < < < | 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 | ); db_end_transaction(0); } /* Add the user.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "user", "mtime") ){ db_multi_exec( "CREATE TEMP TABLE temp_user AS SELECT * FROM user;" "DROP TABLE user;" "CREATE TABLE user(\n" " uid INTEGER PRIMARY KEY,\n" " login TEXT UNIQUE,\n" " pw TEXT,\n" " cap TEXT,\n" " cookie TEXT,\n" " ipaddr TEXT,\n" " cexpire DATETIME,\n" " info TEXT,\n" " mtime DATE,\n" " photo BLOB\n" ");" "INSERT OR IGNORE INTO user" " SELECT uid, login, pw, cap, cookie," " ipaddr, cexpire, info, now(), photo FROM temp_user;" "DROP TABLE temp_user;" ); } /* Add the config.mtime column if it is missing. (2011-04-27) */ if( !db_table_has_column("repository", "config", "mtime") ){ db_multi_exec( "ALTER TABLE config ADD COLUMN mtime INTEGER;" "UPDATE config SET mtime=now();" ); } /* Add the shun.mtime and shun.scom columns if they are missing. ** (2011-04-27) */ if( !db_table_has_column("repository", "shun", "mtime") ){ db_multi_exec( |
︙ | ︙ | |||
146 147 148 149 150 151 152 | /* ** Update the repository schema for Fossil version 2.0. (2017-02-28) ** (1) Change the CHECK constraint on BLOB.UUID so that the length ** is greater than or equal to 40, not exactly equal to 40. */ void rebuild_schema_update_2_0(void){ | | < < | < | | | | < < < < < < < < < < | 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 | /* ** Update the repository schema for Fossil version 2.0. (2017-02-28) ** (1) Change the CHECK constraint on BLOB.UUID so that the length ** is greater than or equal to 40, not exactly equal to 40. */ void rebuild_schema_update_2_0(void){ char *z = db_text(0, "SELECT sql FROM repository.sqlite_master" " WHERE name='blob'"); if( z ){ /* Search for: length(uuid)==40 ** 0123456789 12345 */ int i; for(i=10; z[i]; i++){ if( z[i]=='=' && strncmp(&z[i-6],"(uuid)==40",10)==0 ){ z[i] = '>'; db_multi_exec( "PRAGMA writable_schema=ON;" "UPDATE repository.sqlite_master SET sql=%Q WHERE name LIKE 'blob';" "PRAGMA writable_schema=OFF;", z ); break; } } fossil_free(z); } db_multi_exec( "CREATE VIEW IF NOT EXISTS " " repository.artifact(rid,rcvid,size,atype,srcid,hash,content) AS " " SELECT blob.rid,rcvid,size,1,srcid,uuid,content" " FROM blob LEFT JOIN delta ON (blob.rid=delta.rid);" ); } /* ** Variables used to store state information about an on-going "rebuild" ** or "deconstruct". */ static int totalSize; /* Total number of artifacts to process */ static int processCnt; /* Number processed so far */ static int ttyOutput; /* Do progress output */ static Bag bagDone; /* Bag of records rebuilt */ static char *zFNameFormat; /* Format string for filenames on deconstruct */ static int prefixLength; /* Length of directory prefix for deconstruct */ /* ** Draw the percent-complete message. ** The input is actually the permill complete. */ static void percent_complete(int permill){ static int lastOutput = -1; if( permill>lastOutput ){ fossil_print(" %d.%d%% complete...\r", permill/10, permill%10); fflush(stdout); lastOutput = permill; } } /* ** Called after each artifact is processed */ static void rebuild_step_done(int rid){ /* assert( bag_find(&bagDone, rid)==0 ); */ bag_insert(&bagDone, rid); |
︙ | ︙ | |||
254 255 256 257 258 259 260 | Blob copy; Blob *pUse; int nChild, i, cid; while( rid>0 ){ /* Fix up the "blob.size" field if needed. */ | | | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | Blob copy; Blob *pUse; int nChild, i, cid; while( rid>0 ){ /* Fix up the "blob.size" field if needed. */ if( size!=blob_size(pBase) ){ db_multi_exec( "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid ); } /* Find all children of artifact rid */ db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); |
︙ | ︙ | |||
289 290 291 292 293 294 295 | manifest_crosslink(rid, pUse, MC_NONE); }else{ /* We are doing "fossil deconstruct" */ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); char *zFile = mprintf(zFNameFormat /*works-like:"%s:%s"*/, zUuid, zUuid+prefixLength); blob_write_to_file(pUse,zFile); | < < < < < < < < < < < | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | manifest_crosslink(rid, pUse, MC_NONE); }else{ /* We are doing "fossil deconstruct" */ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); char *zFile = mprintf(zFNameFormat /*works-like:"%s:%s"*/, zUuid, zUuid+prefixLength); blob_write_to_file(pUse,zFile); free(zFile); free(zUuid); blob_reset(pUse); } assert( blob_is_reset(pUse) ); rebuild_step_done(rid); |
︙ | ︙ | |||
366 367 368 369 370 371 372 373 | /* ** Core function to rebuild the information in the derived tables of a ** fossil repository from the blobs. This function is shared between ** 'rebuild_database' ('rebuild') and 'reconstruct_cmd' ** ('reconstruct'), both of which have to regenerate this information ** from scratch. */ | > > > > > | | | < | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | /* ** Core function to rebuild the information in the derived tables of a ** fossil repository from the blobs. This function is shared between ** 'rebuild_database' ('rebuild') and 'reconstruct_cmd' ** ('reconstruct'), both of which have to regenerate this information ** from scratch. ** ** If the randomize parameter is true, then the BLOBs are deliberately ** extracted in a random order. This feature is used to test the ** ability of fossil to accept records in any order and still ** construct a sane repository. */ int rebuild_db(int randomize, int doOut, int doClustering){ Stmt s, q; int errCnt = 0; int incrSize; Blob sql; bag_init(&bagDone); ttyOutput = doOut; processCnt = 0; if (ttyOutput && !g.fQuiet) { percent_complete(0); } alert_triggers_disable(); rebuild_update_schema(); blob_init(&sql, 0, 0); db_prepare(&q, "SELECT name FROM sqlite_master /*scan*/" " WHERE type='table'" " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias'," "'config','shun','private','reportfmt'," "'concealed','accesslog','modreq'," "'purgeevent','purgeitem','unversioned'," "'subscriber','pending_alert','alert_bounce')" " AND name NOT GLOB 'sqlite_*'" " AND name NOT GLOB 'fx_*'" ); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0)); } db_finalize(&q); |
︙ | ︙ | |||
471 472 473 474 475 476 477 478 479 480 481 | percent_complete((processCnt*1000)/totalSize); } if( doClustering ) create_cluster(); if( ttyOutput && !g.fQuiet && totalSize>0 ){ processCnt += incrSize; percent_complete((processCnt*1000)/totalSize); } if(!g.fQuiet && ttyOutput ){ percent_complete(1000); fossil_print("\n"); } | > < | < | < < < | < < < < | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | percent_complete((processCnt*1000)/totalSize); } if( doClustering ) create_cluster(); if( ttyOutput && !g.fQuiet && totalSize>0 ){ processCnt += incrSize; percent_complete((processCnt*1000)/totalSize); } alert_triggers_enable(); if(!g.fQuiet && ttyOutput ){ percent_complete(1000); fossil_print("\n"); } return errCnt; } /* ** Number of neighbors to search */ #define N_NEIGHBOR 5 /* ** Attempt to convert more full-text blobs into delta-blobs for ** storage efficiency. */ void extra_deltification(void){ Stmt q; int aPrev[N_NEIGHBOR]; int nPrev; int rid; int prevfnid, fnid; db_begin_transaction(); /* Look for manifests that have not been deltaed and try to make them ** children of one of the 5 chronologically subsequent check-ins */ db_prepare(&q, "SELECT rid FROM event, blob" " WHERE blob.rid=event.objid" " AND event.type='ci'" " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)" " ORDER BY event.mtime DESC" ); nPrev = 0; while( db_step(&q)==SQLITE_ROW ){ rid = db_column_int(&q, 0); if( nPrev>0 ){ content_deltify(rid, aPrev, nPrev, 0); } if( nPrev<N_NEIGHBOR ){ aPrev[nPrev++] = rid; }else{ int i; for(i=0; i<N_NEIGHBOR-1; i++) aPrev[i] = aPrev[i+1]; aPrev[N_NEIGHBOR-1] = rid; |
︙ | ︙ | |||
549 550 551 552 553 554 555 | prevfnid = 0; while( db_step(&q)==SQLITE_ROW ){ rid = db_column_int(&q, 0); fnid = db_column_int(&q, 1); if( fnid!=prevfnid ) nPrev = 0; prevfnid = fnid; if( nPrev>0 ){ | | < < < < < < | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | prevfnid = 0; while( db_step(&q)==SQLITE_ROW ){ rid = db_column_int(&q, 0); fnid = db_column_int(&q, 1); if( fnid!=prevfnid ) nPrev = 0; prevfnid = fnid; if( nPrev>0 ){ content_deltify(rid, aPrev, nPrev, 0); } if( nPrev<N_NEIGHBOR ){ aPrev[nPrev++] = rid; }else{ int i; for(i=0; i<N_NEIGHBOR-1; i++) aPrev[i] = aPrev[i+1]; aPrev[N_NEIGHBOR-1] = rid; } } db_finalize(&q); db_end_transaction(0); } /* Reconstruct the private table. The private table contains the rid ** of every manifest that is tagged with "private" and every file that ** is not used by a manifest that is not private. */ |
︙ | ︙ | |||
589 590 591 592 593 594 595 | " EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;" "INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;" "DROP TABLE private_ckin;", TAG_PRIVATE ); fix_private_blob_dependencies(0); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > > > > > | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | " EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;" "INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;" "DROP TABLE private_ckin;", TAG_PRIVATE ); fix_private_blob_dependencies(0); } /* ** COMMAND: rebuild ** ** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS? ** ** Reconstruct the named repository database from the core ** records. Run this command after updating the fossil ** executable in a way that changes the database schema. ** ** Options: ** --analyze Run ANALYZE on the database after rebuilding ** --cluster Compute clusters for unclustered artifacts ** --compress Strive to make the database as small as possible ** --compress-only Skip the rebuilding step. Do --compress only ** --deanalyze Remove ANALYZE tables from the database ** --force Force the rebuild to complete even if errors are seen ** --ifneeded Only do the rebuild if it would change the schema version ** --index Always add in the full-text search index ** --noverify Skip the verification of changes to the BLOB table ** --noindex Always omit the full-text search index ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2) ** --quiet Only show output if there are errors ** --randomize Scan artifacts in a random order ** --stats Show artifact statistics after rebuilding ** --vacuum Run VACUUM on the database after rebuilding ** --wal Set Write-Ahead-Log journalling mode on the database ** ** See also: deconstruct, reconstruct */ void rebuild_database(void){ int forceFlag; int randomizeFlag; int errCnt = 0; int omitVerify; int doClustering; const char *zPagesize; int newPagesize = 0; int activateWal; int runVacuum; int runDeanalyze; int runAnalyze; int runCompress; int showStats; int runReindex; int optNoIndex; int optIndex; int optIfNeeded; int compressOnlyFlag; omitVerify = find_option("noverify",0,0)!=0; forceFlag = find_option("force","f",0)!=0; randomizeFlag = find_option("randomize", 0, 0)!=0; doClustering = find_option("cluster", 0, 0)!=0; runVacuum = find_option("vacuum",0,0)!=0; runDeanalyze = find_option("deanalyze",0,0)!=0; runAnalyze = find_option("analyze",0,0)!=0; runCompress = find_option("compress",0,0)!=0; zPagesize = find_option("pagesize",0,1); showStats = find_option("stats",0,0)!=0; optIndex = find_option("index",0,0)!=0; optNoIndex = find_option("noindex",0,0)!=0; optIfNeeded = find_option("ifneeded",0,0)!=0; compressOnlyFlag = find_option("compress-only",0,0)!=0; if( compressOnlyFlag ) runCompress = runVacuum = 1; if( zPagesize ){ newPagesize = atoi(zPagesize); if( newPagesize<512 || newPagesize>65536 || (newPagesize&(newPagesize-1))!=0 ){ fossil_fatal("page size must be a power of two between 512 and 65536"); } |
︙ | ︙ | |||
728 729 730 731 732 733 734 | return; } /* We should be done with options.. */ verify_all_options(); db_begin_transaction(); | < | < < | < < < < < < | < < < < | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | return; } /* We should be done with options.. */ verify_all_options(); db_begin_transaction(); if( !compressOnlyFlag ){ search_drop_index(); ttyOutput = 1; errCnt = rebuild_db(randomizeFlag, 1, doClustering); reconstruct_private_table(); } db_multi_exec( "REPLACE INTO config(name,value,mtime) VALUES('content-schema',%Q,now());" "REPLACE INTO config(name,value,mtime) VALUES('aux-schema',%Q,now());" "REPLACE INTO config(name,value,mtime) VALUES('rebuilt',%Q,now());", CONTENT_SCHEMA, AUX_SCHEMA_MAX, get_version() ); if( errCnt && !forceFlag ){ fossil_print( "%d errors. Rolling back changes. Use --force to force a commit.\n", errCnt ); db_end_transaction(1); }else{ if( runCompress ){ fossil_print("Extra delta compression... "); fflush(stdout); extra_deltification(); runVacuum = 1; } if( omitVerify ) verify_cancel(); db_end_transaction(0); if( runCompress ) fossil_print("done\n"); db_close(0); db_open_repository(g.zRepositoryName); if( newPagesize ){ db_multi_exec("PRAGMA page_size=%d", newPagesize); runVacuum = 1; } if( runDeanalyze ){ |
︙ | ︙ | |||
794 795 796 797 798 799 800 | fossil_print("done\n"); } if( activateWal ){ db_multi_exec("PRAGMA journal_mode=WAL;"); } } if( runReindex ) search_rebuild_index(); | < | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 | fossil_print("done\n"); } if( activateWal ){ db_multi_exec("PRAGMA journal_mode=WAL;"); } } if( runReindex ) search_rebuild_index(); if( showStats ){ static const struct { int idx; const char *zLabel; } aStat[] = { { CFTYPE_ANY, "Artifacts:" }, { CFTYPE_MANIFEST, "Manifests:" }, { CFTYPE_CLUSTER, "Clusters:" }, { CFTYPE_CONTROL, "Tags:" }, { CFTYPE_WIKI, "Wikis:" }, |
︙ | ︙ | |||
818 819 820 821 822 823 824 | if( k>0 ) subtotal += g.parseCnt[k]; } fossil_print("%-15s %6d\n", "Other:", g.parseCnt[CFTYPE_ANY] - subtotal); } } /* | | | | < < < < < < < < < | | < | < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | if( k>0 ) subtotal += g.parseCnt[k]; } fossil_print("%-15s %6d\n", "Other:", g.parseCnt[CFTYPE_ANY] - subtotal); } } /* ** COMMAND: test-detach ** ** Usage: %fossil test-detach ?REPOSITORY? ** ** Change the project-code and make other changes in order to prevent ** the repository from ever again pushing or pulling to other ** repositories. Used to create a "test" repository for development ** testing by cloning a working project repository. */ void test_detach_cmd(void){ db_find_and_open_repository(0, 2); db_begin_transaction(); db_multi_exec( "DELETE FROM config WHERE name='last-sync-url';" "UPDATE config SET value=lower(hex(randomblob(20)))" " WHERE name='project-code';" "UPDATE config SET value='detached-' || value" " WHERE name='project-name' AND value NOT GLOB 'detached-*';" ); db_end_transaction(0); } /* ** COMMAND: test-create-clusters ** ** Create clusters for all unclustered artifacts if the number of unclustered ** artifacts exceeds the current clustering threshold. |
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | ** This command permanently deletes the scrubbed information. THE EFFECTS ** OF THIS COMMAND ARE IRREVERSIBLE. USE WITH CAUTION! ** ** The user is prompted to confirm the scrub unless the --force option ** is used. ** ** Options: | | | | | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 | ** This command permanently deletes the scrubbed information. THE EFFECTS ** OF THIS COMMAND ARE IRREVERSIBLE. USE WITH CAUTION! ** ** The user is prompted to confirm the scrub unless the --force option ** is used. ** ** Options: ** --force do not prompt for confirmation ** --private only private branches are removed from the repository ** --verily scrub real thoroughly (see above) */ void scrub_cmd(void){ int bVerily = find_option("verily",0,0)!=0; int bForce = find_option("force", "f", 0)!=0; int privateOnly = find_option("private",0,0)!=0; int bNeedRebuild = 0; db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | } db_begin_transaction(); if( privateOnly || bVerily ){ bNeedRebuild = db_exists("SELECT 1 FROM private"); delete_private_content(); } if( !privateOnly ){ | < < | < < < < < < < < < > | < < | | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | } db_begin_transaction(); if( privateOnly || bVerily ){ bNeedRebuild = db_exists("SELECT 1 FROM private"); delete_private_content(); } if( !privateOnly ){ db_multi_exec( "UPDATE user SET pw='';" "DELETE FROM config WHERE name GLOB 'last-sync-*';" "DELETE FROM config WHERE name GLOB 'peer-*';" "DELETE FROM config WHERE name GLOB 'login-group-*';" "DELETE FROM config WHERE name GLOB 'skin:*';" "DELETE FROM config WHERE name GLOB 'subrepo:*';" ); if( bVerily ){ db_multi_exec( "DELETE FROM concealed;\n" "UPDATE rcvfrom SET ipaddr='unknown';\n" "DROP TABLE IF EXISTS accesslog;\n" "UPDATE user SET photo=NULL, info='';\n" "DROP TABLE IF EXISTS purgeevent;\n" "DROP TABLE IF EXISTS purgeitem;\n" "DROP TABLE IF EXISTS admin_log;\n" "DROP TABLE IF EXISTS vcache;\n" ); } } if( !bNeedRebuild ){ db_end_transaction(0); db_multi_exec("VACUUM;"); }else{ rebuild_db(0, 1, 0); db_end_transaction(0); } } /* ** Recursively read all files from the directory zPath and install ** every file read as a new artifact in the repository. */ void recon_read_dir(char *zPath){ DIR *d; struct dirent *pEntry; Blob aContent; /* content of the just read artifact */ static int nFileRead = 0; void *zUnicodePath; char *zUtf8Name; zUnicodePath = fossil_utf8_to_path(zPath, 1); d = opendir(zUnicodePath); if( d ){ while( (pEntry=readdir(d))!=0 ){ Blob path; char *zSubpath; |
︙ | ︙ | |||
1157 1158 1159 1160 1161 1162 1163 | if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) ? (file_isdir(zSubpath, ExtFILE)==1) : (pEntry->d_type==DT_DIR) ) #else if( file_isdir(zSubpath, ExtFILE)==1 ) #endif { recon_read_dir(zSubpath); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | | | < < < < < < < | 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 | if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) ? (file_isdir(zSubpath, ExtFILE)==1) : (pEntry->d_type==DT_DIR) ) #else if( file_isdir(zSubpath, ExtFILE)==1 ) #endif { recon_read_dir(zSubpath); }else{ blob_init(&path, 0, 0); blob_appendf(&path, "%s", zSubpath); if( blob_read_from_file(&aContent, blob_str(&path), ExtFILE)==-1 ){ fossil_fatal("some unknown error occurred while reading \"%s\"", blob_str(&path)); } content_put(&aContent); blob_reset(&path); blob_reset(&aContent); fossil_print("\r%d", ++nFileRead); fflush(stdout); } free(zSubpath); } closedir(d); }else { fossil_fatal("encountered error %d while trying to open \"%s\".", errno, g.argv[3]); } fossil_path_free(zUnicodePath); } /* ** COMMAND: reconstruct* ** ** Usage: %fossil reconstruct FILENAME DIRECTORY ** ** This command studies the artifacts (files) in DIRECTORY and ** reconstructs the fossil record from them. It places the new ** fossil repository in FILENAME. Subdirectories are read, files ** with leading '.' in the filename are ignored. ** ** See also: deconstruct, rebuild */ void reconstruct_cmd(void) { char *zPassword; if( g.argc!=4 ){ usage("FILENAME DIRECTORY"); } if( file_isdir(g.argv[3], ExtFILE)!=1 ){ fossil_print("\"%s\" is not a directory\n\n", g.argv[3]); usage("FILENAME DIRECTORY"); } |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | db_begin_transaction(); db_initial_setup(0, 0, 0); fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); recon_read_dir(g.argv[3]); fossil_print("\nBuilding the Fossil repository...\n"); | | < < < < < < < < | < < > | | | | | | | < < | | > | < < > < < < < | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | db_begin_transaction(); db_initial_setup(0, 0, 0); fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); recon_read_dir(g.argv[3]); fossil_print("\nBuilding the Fossil repository...\n"); rebuild_db(0, 1, 1); reconstruct_private_table(); /* Skip the verify_before_commit() step on a reconstruct. Most artifacts ** will have been changed and verification therefore takes a really, really ** long time. */ verify_cancel(); db_end_transaction(0); fossil_print("project-id: %s\n", db_get("project-code", 0)); fossil_print("server-id: %s\n", db_get("server-code", 0)); zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); } /* ** COMMAND: deconstruct* ** ** Usage %fossil deconstruct ?OPTIONS? DESTINATION ** ** ** This command exports all artifacts of a given repository and ** writes all artifacts to the file system. The DESTINATION directory ** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where ** AABBBBBBBBB.. is the 40+ character artifact ID, AA the first 2 characters. ** If -L|--prefixlength is given, the length (default 2) of the directory ** prefix can be set to 0,1,..,9 characters. ** ** Options: ** -R|--repository REPOSITORY deconstruct given REPOSITORY ** -L|--prefixlength N set the length of the names of the DESTINATION ** subdirectories to N ** --private Include private artifacts. ** ** See also: rebuild, reconstruct */ void deconstruct_cmd(void){ const char *zDestDir; const char *zPrefixOpt; Stmt s; int privateFlag; /* get and check prefix length argument and build format string */ zPrefixOpt=find_option("prefixlength","L",1); if( !zPrefixOpt ){ prefixLength = 2; }else{ if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){ prefixLength = (int)(*zPrefixOpt-'0'); }else{ fossil_fatal("N(%s) is not a valid prefix length!",zPrefixOpt); } } /* open repository and open query for all artifacts */ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); privateFlag = find_option("private",0,0)!=0; verify_all_options(); /* check number of arguments */ if( g.argc!=3 ){ usage ("?OPTIONS? DESTINATION"); } /* get and check argument destination directory */ zDestDir = g.argv[g.argc-1]; |
︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 | */ #endif if( prefixLength ){ zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); }else{ zFNameFormat = mprintf("%s/%%s",zDestDir); } | < | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 | */ #endif if( prefixLength ){ zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); }else{ zFNameFormat = mprintf("%s/%%s",zDestDir); } bag_init(&bagDone); ttyOutput = 1; processCnt = 0; if (!g.fQuiet) { fossil_print("0 (0%%)...\r"); fflush(stdout); |
︙ | ︙ | |||
1511 1512 1513 1514 1515 1516 1517 | Blob content; content_get(rid, &content); rebuild_step(rid, size, &content); } } } db_finalize(&s); | < < < < < < < < | 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | Blob content; content_get(rid, &content); rebuild_step(rid, size, &content); } } } db_finalize(&s); if(!g.fQuiet && ttyOutput ){ fossil_print("\n"); } /* free filename format string */ free(zFNameFormat); zFNameFormat = 0; } |
Changes to src/regexp.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file was adapted from the test_regexp.c file in SQLite3. That ** file is in the public domain. ** ** See ../www/grep.md for details of the algorithm and RE dialect. */ #include "config.h" #include "regexp.h" /* The end-of-input character */ #define RE_EOF 0 /* End of input */ |
︙ | ︙ | |||
121 122 123 124 125 126 127 | }; #endif /* Add a state to the given state set if it is not already there */ static void re_add_state(ReStateSet *pSet, int newState){ unsigned i; for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return; | | | | | 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 | }; #endif /* Add a state to the given state set if it is not already there */ static void re_add_state(ReStateSet *pSet, int newState){ unsigned i; for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return; pSet->aState[pSet->nState++] = newState; } /* Extract the next unicode character from *pzIn and return it. Advance ** *pzIn to the first byte past the end of the character returned. To ** be clear: this routine converts utf8 to unicode. This routine is ** optimized for the common case where the next character is a single byte. */ static unsigned re_next_char(ReInput *p){ unsigned c; if( p->i>=p->mx ) return 0; c = p->z[p->i++]; if( c>=0x80 ){ if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); if( c<0x80 ) c = 0xfffd; }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 ){ c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); p->i += 2; if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) | (p->z[p->i+2]&0x3f); p->i += 3; if( c<=0xffff || c>0x10ffff ) c = 0xfffd; }else{ c = 0xfffd; } } return c; } static unsigned re_next_char_nocase(ReInput *p){ unsigned c = re_next_char(p); return unicode_fold(c,1); } /* Return true if c is a perl "word" character: [A-Za-z0-9_] */ static int re_word_char(int c){ return unicode_isalnum(c) || c=='_'; } |
︙ | ︙ | |||
190 191 192 193 194 195 196 | int c = RE_EOF+1; int cPrev = 0; int rc = 0; ReInput in; in.z = zIn; in.i = 0; | | | | 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 | int c = RE_EOF+1; int cPrev = 0; int rc = 0; ReInput in; in.z = zIn; in.i = 0; in.mx = nIn>=0 ? nIn : strlen((const char*)zIn); /* Look for the initial prefix match, if there is one. */ if( pRe->nInit ){ unsigned char x = pRe->zInit[0]; while( in.i+pRe->nInit<=in.mx && (zIn[in.i]!=x || strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) ){ in.i++; } if( in.i+pRe->nInit>in.mx ) return 0; } if( pRe->nState<=count(aSpace)*2 ){ pToFree = 0; aStateSet[0].aState = aSpace; }else{ pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState ); if( pToFree==0 ) return -1; aStateSet[0].aState = pToFree; } |
︙ | ︙ | |||
231 232 233 234 235 236 237 | int x = pThis->aState[i]; switch( pRe->aOp[x] ){ case RE_OP_MATCH: { if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); break; } case RE_OP_ANY: { | | | | | | 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 | int x = pThis->aState[i]; switch( pRe->aOp[x] ){ case RE_OP_MATCH: { if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); break; } case RE_OP_ANY: { re_add_state(pNext, x+1); break; } case RE_OP_WORD: { if( re_word_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTWORD: { if( !re_word_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_DIGIT: { if( re_digit_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTDIGIT: { if( !re_digit_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_SPACE: { if( re_space_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTSPACE: { if( !re_space_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_BOUNDARY: { if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); break; } case RE_OP_ANYSTAR: { |
︙ | ︙ | |||
280 281 282 283 284 285 286 | re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } | | < < < | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } case RE_OP_CC_INC: case RE_OP_CC_EXC: { int j = 1; int n = pRe->aArg[x]; int hit = 0; for(j=1; j>0 && j<n; j++){ if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){ if( pRe->aArg[x+j]==c ){ hit = 1; |
︙ | ︙ | |||
344 345 346 347 348 349 350 | int i; if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; for(i=p->nState; i>iBefore; i--){ p->aOp[i] = p->aOp[i-1]; p->aArg[i] = p->aArg[i-1]; } p->nState++; | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | int i; if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; for(i=p->nState; i>iBefore; i--){ p->aOp[i] = p->aOp[i-1]; p->aArg[i] = p->aArg[i-1]; } p->nState++; p->aOp[iBefore] = op; p->aArg[iBefore] = arg; return iBefore; } /* Append a new opcode and argument to the end of the RE under construction. */ static int re_append(ReCompiled *p, int op, int arg){ |
︙ | ︙ | |||
633 634 635 636 637 638 639 | if( zIn[0]=='^' ){ zIn++; }else{ re_append(pRe, RE_OP_ANYSTAR, 0); } pRe->sIn.z = (unsigned char*)zIn; pRe->sIn.i = 0; | | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | if( zIn[0]=='^' ){ zIn++; }else{ re_append(pRe, RE_OP_ANYSTAR, 0); } pRe->sIn.z = (unsigned char*)zIn; pRe->sIn.i = 0; pRe->sIn.mx = strlen(zIn); zErr = re_subcompile_re(pRe); if( zErr ){ re_free(pRe); return zErr; } if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ re_append(pRe, RE_OP_MATCH, RE_EOF); |
︙ | ︙ | |||
659 660 661 662 663 664 665 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ | | | | | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ if( pRe->aOp[0]==RE_OP_ANYSTAR ){ for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ unsigned x = pRe->aArg[i]; if( x<=127 ){ pRe->zInit[j++] = x; }else if( x<=0xfff ){ pRe->zInit[j++] = 0xc0 | (x>>6); pRe->zInit[j++] = 0x80 | (x&0x3f); }else if( x<=0xffff ){ pRe->zInit[j++] = 0xd0 | (x>>12); pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); pRe->zInit[j++] = 0x80 | (x&0x3f); }else{ break; } } if( j>0 && pRe->zInit[j-1]==0 ) j--; |
︙ | ︙ | |||
699 700 701 702 703 704 705 | int argc, sqlite3_value **argv ){ ReCompiled *pRe; /* Compiled regular expression */ const char *zPattern; /* The regular expression */ const unsigned char *zStr;/* String being searched */ const char *zErr; /* Compile error message */ | < < | < | < < < | > > > > > > > < | | < < < < < < < | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | int argc, sqlite3_value **argv ){ ReCompiled *pRe; /* Compiled regular expression */ const char *zPattern; /* The regular expression */ const unsigned char *zStr;/* String being searched */ const char *zErr; /* Compile error message */ pRe = sqlite3_get_auxdata(context, 0); if( pRe==0 ){ zPattern = (const char*)sqlite3_value_text(argv[0]); if( zPattern==0 ) return; zErr = re_compile(&pRe, zPattern, 0); if( zErr ){ sqlite3_result_error(context, zErr, -1); return; } if( pRe==0 ){ sqlite3_result_error_nomem(context); return; } sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); } zStr = (const unsigned char*)sqlite3_value_text(argv[1]); if( zStr!=0 ){ sqlite3_result_int(context, re_match(pRe, zStr, -1)); } } /* ** Invoke this routine in order to install the REGEXP function in an ** SQLite database connection. ** ** Use: ** ** sqlite3_auto_extension(sqlite3_add_regexp_func); ** ** to cause this extension to be automatically loaded into each new ** database connection. */ int re_add_sql_func(sqlite3 *db){ return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, re_sql_func, 0, 0); } /* ** Run a "grep" over a single file read from disk. */ static void grep_file(ReCompiled *pRe, const char *zFile, FILE *in){ int ln = 0; |
︙ | ︙ | |||
765 766 767 768 769 770 771 | } } /* ** Flags for grep_buffer() */ #define GREP_EXISTS 0x001 /* If any match, print only the name and stop */ | < > | < < | < < < > | 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | } } /* ** Flags for grep_buffer() */ #define GREP_EXISTS 0x001 /* If any match, print only the name and stop */ /* ** Run a "grep" over a text file */ static int grep_buffer( ReCompiled *pRe, const char *zName, const char *z, u32 flags ){ int i, j, n, ln, cnt; for(i=j=ln=cnt=0; z[i]; i=j+1){ for(j=i; z[j] && z[j]!='\n'; j++){} n = j - i; if( z[j]=='\n' ) j++; ln++; if( re_match(pRe, (const unsigned char*)(z+i), j-i) ){ cnt++; if( flags & GREP_EXISTS ){ fossil_print("%s\n", zName); break; } fossil_print("%s:%d:%.*s\n", zName, ln, n, z+i); } } return cnt; } /* ** COMMAND: test-grep ** ** Usage: %fossil test-grep REGEXP [FILE...] ** ** Run a regular expression match over the named disk files, or against ** standard input if no disk files are named on the command-line. ** ** Options: ** ** -i|--ignore-case Ignore case */ void re_test_grep(void){ ReCompiled *pRe; const char *zErr; int ignoreCase = find_option("ignore-case","i",0)!=0; if( g.argc<3 ){ |
︙ | ︙ | |||
838 839 840 841 842 843 844 | } re_free(pRe); } /* ** COMMAND: grep ** | | | | < < < < < | < < > | | < < < < < | < < < < < < < < < | < < < < < < < < < < < | < < < < | | | | > | < < < < < < < < < < < < | | < < < | < | | | < | | | > | | < < < < < < < < < | < | < < < < < < < < < < < < < < | < < < < < < | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | } re_free(pRe); } /* ** COMMAND: grep ** ** Usage: %fossil grep [OPTIONS] PATTERN FILENAME ** ** Attempt to match the given POSIX extended regular expression PATTERN ** over all historic versions of FILENAME. For details of the supported ** RE dialect, see https://fossil-scm.org/fossil/doc/trunk/www/grep.md ** ** Options: ** ** -i|--ignore-case Ignore case ** -l|--files-with-matches List only checkin ID for versions that match ** -v|--verbose Show each file as it is analyzed */ void re_grep_cmd(void){ u32 flags = 0; int bVerbose = 0; ReCompiled *pRe; const char *zErr; int ignoreCase = 0; Blob fullName; if( find_option("ignore-case","i",0)!=0 ) ignoreCase = 1; if( find_option("files-with-matches","l",0)!=0 ) flags |= GREP_EXISTS; if( find_option("verbose","v",0)!=0 ) bVerbose = 1; db_find_and_open_repository(0, 0); verify_all_options(); if( g.argc<4 ){ usage("REGEXP FILENAME"); } zErr = re_compile(&pRe, g.argv[2], ignoreCase); if( zErr ) fossil_fatal("%s", zErr); if( file_tree_name(g.argv[3], &fullName, 0, 0) ){ int fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", blob_str(&fullName)); if( fnid ){ Stmt q; add_content_sql_commands(g.db); db_prepare(&q, "SELECT content(ux), substr(ux,1,10) FROM (" " SELECT blob.uuid AS ux, min(event.mtime) AS mx" " FROM mlink, blob, event" " WHERE mlink.mid=event.objid" " AND mlink.fid=blob.rid" " AND mlink.fnid=%d" " GROUP BY blob.uuid" ") ORDER BY mx DESC;", fnid ); while( db_step(&q)==SQLITE_ROW ){ if( bVerbose ) fossil_print("%s:\n", db_column_text(&q,1)); grep_buffer(pRe, db_column_text(&q,1), db_column_text(&q,0), flags); } db_finalize(&q); } } } |
Deleted src/repolist.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/report.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | /* Forward references to static routines */ static void report_format_hints(void); #ifndef SQLITE_RECURSIVE # define SQLITE_RECURSIVE 33 #endif | < < < < < < < < | | | > | | | | < < < | | | 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 | /* Forward references to static routines */ static void report_format_hints(void); #ifndef SQLITE_RECURSIVE # define SQLITE_RECURSIVE 33 #endif /* ** WEBPAGE: reportlist ** ** Main menu for Tickets. */ void view_list(void){ const char *zScript; Blob ril; /* Report Item List */ Stmt q; int rn = 0; int cnt = 0; login_check_credentials(); if( !g.perm.RdTkt && !g.perm.NewTkt ){ login_needed(g.anon.RdTkt || g.anon.NewTkt); return; } style_header("Ticket Main Menu"); ticket_standard_submenu(T_ALL_BUT(T_REPLIST)); if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST<br />\n", -1); zScript = ticket_reportlist_code(); if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT<br />\n", -1); blob_zero(&ril); ticket_init(); db_prepare(&q, "SELECT rn, title, owner FROM reportfmt ORDER BY title"); while( db_step(&q)==SQLITE_ROW ){ const char *zTitle = db_column_text(&q, 1); const char *zOwner = db_column_text(&q, 2); if( zTitle[0] =='_' && !g.perm.TktFmt ){ continue; } rn = db_column_int(&q, 0); cnt++; blob_appendf(&ril, "<li>"); if( zTitle[0] == '_' ){ blob_appendf(&ril, "%s", zTitle); } else { blob_appendf(&ril, "%z%h</a>", href("%R/rptview?rn=%d", rn), zTitle); } blob_appendf(&ril, " "); if( g.perm.Write && zOwner && zOwner[0] ){ blob_appendf(&ril, "(by <i>%h</i>) ", zOwner); } if( g.perm.TktFmt ){ blob_appendf(&ril, "[%zcopy</a>] ", href("%R/rptedit?rn=%d©=1", rn)); } if( g.perm.Admin || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0) ){ blob_appendf(&ril, "[%zedit</a>]", href("%R/rptedit?rn=%d", rn)); } if( g.perm.TktFmt ){ blob_appendf(&ril, "[%zsql</a>]", href("%R/rptsql?rn=%d", rn)); } blob_appendf(&ril, "</li>\n"); } db_finalize(&q); Th_Store("report_items", blob_str(&ril)); Th_Render(zScript); blob_reset(&ril); if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1); style_footer(); } /* ** Remove whitespace from both ends of a string. */ char *trim_string(const char *zOrig){ int i; |
︙ | ︙ | |||
169 170 171 172 173 174 175 | /*********************************************************************/ /* ** This is the SQLite authorizer callback used to make sure that the ** SQL statements entered by users do not try to do anything untoward. ** If anything suspicious is tried, set *(char**)pError to an error ** message obtained from malloc. | < < < | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | /*********************************************************************/ /* ** This is the SQLite authorizer callback used to make sure that the ** SQL statements entered by users do not try to do anything untoward. ** If anything suspicious is tried, set *(char**)pError to an error ** message obtained from malloc. */ static int report_query_authorizer( void *pError, int code, const char *zArg1, const char *zArg2, const char *zArg3, |
︙ | ︙ | |||
194 195 196 197 198 199 200 | case SQLITE_SELECT: case SQLITE_RECURSIVE: case SQLITE_FUNCTION: { break; } case SQLITE_READ: { static const char *const azAllowed[] = { | | > < < < > < < | < < | < < < < < < > | < < < < < < | < | < < < < | < < < < < < < < < < < < | < < < | | | 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 | case SQLITE_SELECT: case SQLITE_RECURSIVE: case SQLITE_FUNCTION: { break; } case SQLITE_READ: { static const char *const azAllowed[] = { "ticket", "ticketchng", "blob", "filename", "mlink", "plink", "event", "tag", "tagxref", "unversioned", }; int i; if( fossil_strncmp(zArg1, "fx_", 3)==0 ){ break; } for(i=0; i<count(azAllowed); i++){ if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break; } if( i>=count(azAllowed) ){ *(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1); rc = SQLITE_DENY; }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){ rc = SQLITE_IGNORE; } break; } default: { *(char**)pError = mprintf("only SELECT statements are allowed"); rc = SQLITE_DENY; break; } } return rc; } /* ** Activate the query authorizer */ void report_restrict_sql(char **pzErr){ sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr); sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000); } void report_unrestrict_sql(void){ sqlite3_set_authorizer(g.db, 0, 0); } /* ** Check the given SQL to see if is a valid query that does not ** attempt to do anything dangerous. Return 0 on success and a ** pointer to an error message string (obtained from malloc) if |
︙ | ︙ | |||
333 334 335 336 337 338 339 | sqlite3_finalize(pStmt); } report_unrestrict_sql(); return zErr; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | | | < | < < < < | | | | | < < < < < | < < < < | > | | | | < < < | | < < | < | | < | < < < < < < < < | < < < < | < < < < < < < < < < < < < | | | | | | | < < < | < < < | < < < < < < < < < < | | | | | | | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | sqlite3_finalize(pStmt); } report_unrestrict_sql(); return zErr; } /* ** WEBPAGE: rptsql ** URL: /rptsql?rn=N ** ** Display the SQL query used to generate a ticket report. The rn=N ** query parameter identifies the specific report number to be displayed. */ void view_see_sql(void){ int rn; const char *zTitle; const char *zSQL; const char *zOwner; const char *zClrKey; Stmt q; login_check_credentials(); if( !g.perm.TktFmt ){ login_needed(g.anon.TktFmt); return; } rn = atoi(PD("rn","0")); db_prepare(&q, "SELECT title, sqlcode, owner, cols " "FROM reportfmt WHERE rn=%d",rn); style_header("SQL For Report Format Number %d", rn); if( db_step(&q)!=SQLITE_ROW ){ @ <p>Unknown report number: %d(rn)</p> style_footer(); db_finalize(&q); return; } zTitle = db_column_text(&q, 0); zSQL = db_column_text(&q, 1); zOwner = db_column_text(&q, 2); zClrKey = db_column_text(&q, 3); @ <table cellpadding=0 cellspacing=0 border=0> @ <tr><td valign="top" align="right">Title:</td><td width=15></td> @ <td colspan="3">%h(zTitle)</td></tr> @ <tr><td valign="top" align="right">Owner:</td><td></td> @ <td colspan="3">%h(zOwner)</td></tr> @ <tr><td valign="top" align="right">SQL:</td><td></td> @ <td valign="top"><pre> @ %h(zSQL) @ </pre></td> @ <td width=15></td><td valign="top"> output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3"); @ </td> @ </tr></table> report_format_hints(); style_footer(); db_finalize(&q); } /* ** WEBPAGE: rptnew ** WEBPAGE: rptedit ** ** Create (/rptnew) or edit (/rptedit) a ticket report format. ** Query parameters: ** ** rn=N Ticket report number. (required) ** t=TITLE Title of the report format ** w=USER Owner of the report format ** s=SQL SQL text used to implement the report ** k=KEY Color key */ void view_edit(void){ int rn; const char *zTitle; const char *z; const char *zOwner; const char *zClrKey; char *zSQL; char *zErr = 0; login_check_credentials(); if( !g.perm.TktFmt ){ login_needed(g.anon.TktFmt); return; } /*view_add_functions(0);*/ rn = atoi(PD("rn","0")); zTitle = P("t"); zOwner = PD("w",g.zLogin); z = P("s"); zSQL = z ? trim_string(z) : 0; zClrKey = trim_string(PD("k","")); if( rn>0 && P("del2") ){ login_verify_csrf_secret(); db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn); cgi_redirect("reportlist"); return; }else if( rn>0 && P("del1") ){ zTitle = db_text(0, "SELECT title FROM reportfmt " "WHERE rn=%d", rn); if( zTitle==0 ) cgi_redirect("reportlist"); style_header("Are You Sure?"); @ <form action="rptedit" method="post"> @ <p>You are about to delete all traces of the report @ <strong>%h(zTitle)</strong> from @ the database. This is an irreversible operation. All records @ related to this report will be removed and cannot be recovered.</p> @ @ <input type="hidden" name="rn" value="%d(rn)"> login_insert_csrf_secret(); @ <input type="submit" name="del2" value="Delete The Report"> @ <input type="submit" name="can" value="Cancel"> @ </form> style_footer(); return; }else if( P("can") ){ /* user cancelled */ cgi_redirect("reportlist"); return; } if( zTitle && zSQL ){ if( zSQL[0]==0 ){ zErr = "Please supply an SQL query statement"; }else if( (zTitle = trim_string(zTitle))[0]==0 ){ zErr = "Please supply a title"; }else{ zErr = verify_sql_statement(zSQL); } if( zErr==0 && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", zTitle, rn) ){ zErr = mprintf("There is already another report named \"%h\"", zTitle); } if( zErr==0 ){ login_verify_csrf_secret(); if( rn>0 ){ db_multi_exec("UPDATE reportfmt SET title=%Q, sqlcode=%Q," " owner=%Q, cols=%Q, mtime=now() WHERE rn=%d", zTitle, zSQL, zOwner, zClrKey, rn); }else{ db_multi_exec("INSERT INTO reportfmt(title,sqlcode,owner,cols,mtime) " "VALUES(%Q,%Q,%Q,%Q,now())", zTitle, zSQL, zOwner, zClrKey); rn = db_last_insert_rowid(); } cgi_redirect(mprintf("rptview?rn=%d", rn)); return; } }else if( rn==0 ){ zTitle = ""; zSQL = ticket_report_template(); zClrKey = ticket_key_template(); }else{ Stmt q; db_prepare(&q, "SELECT title, sqlcode, owner, cols " "FROM reportfmt WHERE rn=%d",rn); if( db_step(&q)==SQLITE_ROW ){ zTitle = db_column_malloc(&q, 0); zSQL = db_column_malloc(&q, 1); zOwner = db_column_malloc(&q, 2); zClrKey = db_column_malloc(&q, 3); } db_finalize(&q); if( P("copy") ){ rn = 0; zTitle = mprintf("Copy Of %s", zTitle); zOwner = g.zLogin; } } if( zOwner==0 ) zOwner = g.zLogin; style_submenu_element("Cancel", "reportlist"); if( rn>0 ){ style_submenu_element("Delete", "rptedit?rn=%d&del1=1", rn); } style_header("%s", rn>0 ? "Edit Report Format":"Create New Report Format"); if( zErr ){ @ <blockquote class="reportError">%h(zErr)</blockquote> } @ <form action="rptedit" method="post"><div> @ <input type="hidden" name="rn" value="%d(rn)" /> @ <p>Report Title:<br /> @ <input type="text" name="t" value="%h(zTitle)" size="60" /></p> @ <p>Enter a complete SQL query statement against the "TICKET" table:<br /> @ <textarea name="s" rows="20" cols="80">%h(zSQL)</textarea> @ </p> login_insert_csrf_secret(); if( g.perm.Admin ){ @ <p>Report owner: @ <input type="text" name="w" size="20" value="%h(zOwner)" /> @ </p> } else { @ <input type="hidden" name="w" value="%h(zOwner)" /> } @ <p>Enter an optional color key in the following box. (If blank, no @ color key is displayed.) Each line contains the text for a single @ entry in the key. The first token of each line is the background @ color for that line.<br /> @ <textarea name="k" rows="8" cols="50">%h(zClrKey)</textarea> @ </p> if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){ @ <p>This report format is owned by %h(zOwner). You are not allowed @ to change it.</p> @ </form> report_format_hints(); style_footer(); return; } @ <input type="submit" value="Apply Changes" /> if( rn>0 ){ @ <input type="submit" value="Delete This Report" name="del1" /> } @ </div></form> report_format_hints(); style_footer(); } /* ** Output a bunch of text that provides information about report ** formats */ static void report_format_hints(void){ char *zSchema; zSchema = db_text(0,"SELECT sql FROM sqlite_master WHERE name='ticket'"); if( zSchema==0 ){ zSchema = db_text(0,"SELECT sql FROM repository.sqlite_master" " WHERE name='ticket'"); } @ <hr /><h3>TICKET Schema</h3> @ <blockquote><pre> @ %h(zSchema) @ </pre></blockquote> @ <h3>Notes</h3> @ <ul> @ <li><p>The SQL must consist of a single SELECT statement</p></li> @ @ <li><p>If a column of the result set is named "#" then that column @ is assumed to hold a ticket number. A hyperlink will be created from |
︙ | ︙ | |||
808 809 810 811 812 813 814 | void *pUser, /* Pointer to output state */ int nArg, /* Number of columns in this result row */ const char **azArg, /* Text of data in all columns */ const char **azName /* Names of the columns */ ){ struct GenerateHTML *pState = (struct GenerateHTML*)pUser; int i; | | | | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 | void *pUser, /* Pointer to output state */ int nArg, /* Number of columns in this result row */ const char **azArg, /* Text of data in all columns */ const char **azName /* Names of the columns */ ){ struct GenerateHTML *pState = (struct GenerateHTML*)pUser; int i; const char *zTid; /* Ticket UUID. (value of column named '#') */ const char *zBg = 0; /* Use this background color */ /* Do initialization */ if( pState->nCount==0 ){ /* Turn off the authorizer. It is no longer doing anything since the ** query has already been prepared. */ sqlite3_set_authorizer(g.db, 0, 0); /* Figure out the number of columns, the column that determines background ** color, and whether or not this row of data is represented by multiple ** rows in the table. */ pState->nCol = 0; pState->isMultirow = 0; |
︙ | ︙ | |||
846 847 848 849 850 851 852 | pState->wikiFlags = WIKI_NOBADLINKS; pState->zWikiStart = ""; pState->zWikiEnd = ""; if( P("plaintext") ){ pState->wikiFlags |= WIKI_LINKSONLY; pState->zWikiStart = "<pre class='verbatim'>"; pState->zWikiEnd = "</pre>"; | | | | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | pState->wikiFlags = WIKI_NOBADLINKS; pState->zWikiStart = ""; pState->zWikiEnd = ""; if( P("plaintext") ){ pState->wikiFlags |= WIKI_LINKSONLY; pState->zWikiStart = "<pre class='verbatim'>"; pState->zWikiEnd = "</pre>"; style_submenu_element("Formatted", "%R/rptview?rn=%d", pState->rn); }else{ style_submenu_element("Plaintext", "%R/rptview?rn=%d&plaintext", pState->rn); } }else{ pState->nCol++; } } } |
︙ | ︙ | |||
926 927 928 929 930 931 932 | blob_init(&content, zData, -1); wiki_convert(&content, 0, pState->wikiFlags); blob_reset(&content); @ %s(pState->zWikiEnd) } }else if( azName[i][0]=='#' ){ zTid = zData; | | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | blob_init(&content, zData, -1); wiki_convert(&content, 0, pState->wikiFlags); blob_reset(&content); @ %s(pState->zWikiEnd) } }else if( azName[i][0]=='#' ){ zTid = zData; @ <td valign="top">%z(href("%R/tktview?name=%h",zData))%h(zData)</a></td> }else if( zData[0]==0 ){ @ <td valign="top"> </td> }else{ @ <td valign="top"> @ %h(zData) @ </td> } |
︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 | ** ** Generate a report. The rn query parameter is the report number ** corresponding to REPORTFMT.RN. If the tablist query parameter exists, ** then the output consists of lines of tab-separated fields instead of ** an HTML table. */ void rptview_page(void){ | < < < < < < < < < < < < < < < < | < > < < < | < | < | < < < < < < < < < | < < < < < < < < < < < < < | | | | | | | | | | | < < < < < < < < < | < | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | ** ** Generate a report. The rn query parameter is the report number ** corresponding to REPORTFMT.RN. If the tablist query parameter exists, ** then the output consists of lines of tab-separated fields instead of ** an HTML table. */ void rptview_page(void){ int count = 0; int rn, rc; char *zSql; char *zTitle; char *zOwner; char *zClrKey; int tabs; Stmt q; char *zErr1 = 0; char *zErr2 = 0; login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; } tabs = P("tablist")!=0; db_prepare(&q, "SELECT title, sqlcode, owner, cols, rn FROM reportfmt WHERE rn=%d", atoi(PD("rn","0"))); rc = db_step(&q); if( rc!=SQLITE_ROW ){ db_finalize(&q); db_prepare(&q, "SELECT title, sqlcode, owner, cols, rn FROM reportfmt WHERE title GLOB %Q", P("title")); rc = db_step(&q); } if( rc!=SQLITE_ROW ){ db_finalize(&q); cgi_redirect("reportlist"); return; } zTitle = db_column_malloc(&q, 0); zSql = db_column_malloc(&q, 1); zOwner = db_column_malloc(&q, 2); zClrKey = db_column_malloc(&q, 3); rn = db_column_int(&q,4); db_finalize(&q); if( P("order_by") ){ /* ** If the user wants to do a column sort, wrap the query into a sub ** query and then sort the results. This is a whole lot easier than ** trying to insert an ORDER BY into the query itself, especially ** if the query is already ordered. */ int nField = atoi(P("order_by")); if( nField > 0 ){ const char* zDir = PD("order_dir",""); zDir = !strcmp("ASC",zDir) ? "ASC" : "DESC"; zSql = mprintf("SELECT * FROM (%s) ORDER BY %d %s", zSql, nField, zDir); } } count = 0; if( !tabs ){ struct GenerateHTML sState = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; db_multi_exec("PRAGMA empty_result_callbacks=ON"); style_submenu_element("Raw", "rptview?tablist=1&%h", PD("QUERY_STRING","")); if( g.perm.Admin || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ style_submenu_element("Edit", "rptedit?rn=%d", rn); } if( g.perm.TktFmt ){ style_submenu_element("SQL", "rptsql?rn=%d",rn); } if( g.perm.NewTkt ){ style_submenu_element("New Ticket", "%s/tktnew", g.zTop); } style_header("%s", zTitle); output_color_key(zClrKey, 1, "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\""); @ <table border="1" cellpadding="2" cellspacing="0" class="report sortable" @ data-column-types='' data-init-sort='0'> sState.rn = rn; sState.nCount = 0; report_restrict_sql(&zErr1); db_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2); report_unrestrict_sql(); @ </tbody></table> if( zErr1 ){ @ <p class="reportError">Error: %h(zErr1)</p> }else if( zErr2 ){ @ <p class="reportError">Error: %h(zErr2)</p> } style_table_sorter(); style_footer(); }else{ report_restrict_sql(&zErr1); db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2); report_unrestrict_sql(); cgi_set_content_type("text/plain"); } } |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | Stmt q; char *zSql; char *zErr1 = 0; char *zErr2 = 0; int count = 0; int rn; | | < | 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | Stmt q; char *zSql; char *zErr1 = 0; char *zErr2 = 0; int count = 0; int rn; if( !zRep || !strcmp(zRep,zFullTicketRptRn) || !strcmp(zRep,zFullTicketRptTitle) ){ zSql = "SELECT * FROM ticket"; }else{ rn = atoi(zRep); if( rn ){ db_prepare(&q, "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn); }else{ |
︙ | ︙ |
Changes to src/rss.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "config.h" #include <time.h> #include "rss.h" #include <assert.h> /* ** WEBPAGE: timeline.rss | | | | < | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include "config.h" #include <time.h> #include "rss.h" #include <assert.h> /* ** WEBPAGE: timeline.rss ** URL: /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME ** ** Produce an RSS feed of the timeline. ** ** TYPE may be: all, ci (show check-ins only), t (show tickets only), ** w (show wiki only). ** ** LIMIT is the number of items to show. ** ** tkt=UUID filters for only those events for the specified ticket. tag=TAG ** filters for a tag, and wiki=NAME for a wiki page. Only one may be used. ** ** In addition, name=FILENAME filters for a specific file. This may be ** combined with one of the other filters (useful for looking at a specific ** branch). */ |
︙ | ︙ | |||
55 56 57 58 59 60 61 | int nLimit = atoi(PD("n","20")); int nTagId; const char zSQL1[] = @ SELECT @ blob.rid, @ uuid, @ event.mtime, | < | < > > | | | | < > | | > | | > > | | > | < | 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 | int nLimit = atoi(PD("n","20")); int nTagId; const char zSQL1[] = @ SELECT @ blob.rid, @ uuid, @ event.mtime, @ coalesce(ecomment,comment), @ coalesce(euser,user), @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim), @ (SELECT count(*) FROM plink WHERE cid=blob.rid), @ (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0) AS tags @ FROM event, blob @ WHERE blob.rid=event.objid ; login_check_credentials(); if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ return; } blob_zero(&bSQL); blob_append( &bSQL, zSQL1, -1 ); if( zType[0]!='a' ){ if( zType[0]=='c' && !g.perm.Read ) zType = "x"; if( zType[0]=='w' && !g.perm.RdWiki ) zType = "x"; if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x"; blob_append_sql(&bSQL, " AND event.type=%Q", zType); }else{ if( !g.perm.Read ){ if( g.perm.RdTkt && g.perm.RdWiki ){ blob_append(&bSQL, " AND event.type!='ci'", -1); }else if( g.perm.RdTkt ){ blob_append(&bSQL, " AND event.type=='t'", -1); }else{ blob_append(&bSQL, " AND event.type=='w'", -1); } }else if( !g.perm.RdWiki ){ if( g.perm.RdTkt ){ blob_append(&bSQL, " AND event.type!='w'", -1); }else{ blob_append(&bSQL, " AND event.type=='ci'", -1); } }else if( !g.perm.RdTkt ){ assert( !g.perm.RdTkt && g.perm.Read && g.perm.RdWiki ); blob_append(&bSQL, " AND event.type!='t'", -1); } } if( zTicketUuid ){ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", zTicketUuid); if ( nTagId==0 ){ nTagId = -1; |
︙ | ︙ | |||
129 130 131 132 133 134 135 | }else if( nTagId!=0 ){ blob_append_sql(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); } if( zFilename ){ blob_append_sql(&bSQL, | | < | | | | 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 | }else if( nTagId!=0 ){ blob_append_sql(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); } if( zFilename ){ blob_append_sql(&bSQL, " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", zFilename, filename_collation() ); } blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); cgi_set_content_type("application/rss+xml"); zProjectName = db_get("project-name", 0); if( zProjectName==0 ){ zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s", g.zBaseURL); } zProjectDescr = db_get("project-description", 0); if( zProjectDescr==0 ){ zProjectDescr = zProjectName; } zPubDate = cgi_rfc822_datestamp(time(NULL)); |
︙ | ︙ | |||
164 165 166 167 168 169 170 | @ <pubDate>%s(zPubDate)</pubDate> @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> free(zPubDate); db_prepare(&q, "%s", blob_sql_text(&bSQL)); blob_reset( &bSQL ); while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){ const char *zId = db_column_text(&q, 1); | < | | | | < | | | | | | < < < < < < < < | 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 | @ <pubDate>%s(zPubDate)</pubDate> @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> free(zPubDate); db_prepare(&q, "%s", blob_sql_text(&bSQL)); blob_reset( &bSQL ); while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){ const char *zId = db_column_text(&q, 1); const char *zCom = db_column_text(&q, 3); const char *zAuthor = db_column_text(&q, 4); char *zPrefix = ""; char *zSuffix = 0; char *zDate; int nChild = db_column_int(&q, 5); int nParent = db_column_int(&q, 6); const char *zTagList = db_column_text(&q, 7); time_t ts; if( zTagList && zTagList[0]==0 ) zTagList = 0; ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0); zDate = cgi_rfc822_datestamp(ts); if( nParent>1 && nChild>1 ){ zPrefix = "*MERGE/FORK* "; }else if( nParent>1 ){ zPrefix = "*MERGE* "; }else if( nChild>1 ){ zPrefix = "*FORK* "; } if( zTagList ){ zSuffix = mprintf(" (tags: %s)", zTagList); } @ <item> |
︙ | ︙ | |||
228 229 230 231 232 233 234 | /* ** COMMAND: rss* ** ** Usage: %fossil rss ?OPTIONS? ** ** The CLI variant of the /timeline.rss page, this produces an RSS | | | | | > | > | | > > | | | | > | | | | 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 256 257 258 259 260 261 262 263 264 265 266 | /* ** COMMAND: rss* ** ** Usage: %fossil rss ?OPTIONS? ** ** The CLI variant of the /timeline.rss page, this produces an RSS ** feed of the timeline to stdout. Options: ** ** -type|y FLAG ** may be: all (default), ci (show check-ins only), t (show tickets only), ** w (show wiki only). ** ** -limit|n LIMIT ** The maximum number of items to show. ** ** -tkt UUID ** Filters for only those events for the specified ticket. ** ** -tag TAG ** filters for a tag ** ** -wiki NAME ** Filters on a specific wiki page. ** ** Only one of -tkt, -tag, or -wiki may be used. ** ** -name FILENAME ** filters for a specific file. This may be combined with one of the other ** filters (useful for looking at a specific branch). ** ** -url STRING ** Sets the RSS feed's root URL to the given string. The default is ** "URL-PLACEHOLDER" (without quotes). */ void cmd_timeline_rss(void){ Stmt q; int nLine=0; char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; Blob bSQL; const char *zType = find_option("type","y",1); /* Type of events. All if NULL */ const char *zTicketUuid = find_option("tkt",NULL,1); const char *zTag = find_option("tag",NULL,1); const char *zFilename = find_option("name",NULL,1); const char *zWiki = find_option("wiki",NULL,1); const char *zLimit = find_option("limit", "n",1); const char *zBaseURL = find_option("url", NULL, 1); int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" ); |
︙ | ︙ | |||
330 331 332 333 334 335 336 | }else if( nTagId!=0 ){ blob_append_sql(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); } if( zFilename ){ blob_append_sql(&bSQL, | | < | | | < | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | }else if( nTagId!=0 ){ blob_append_sql(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); } if( zFilename ){ blob_append_sql(&bSQL, " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", zFilename, filename_collation() ); } blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); zProjectName = db_get("project-name", 0); if( zProjectName==0 ){ zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s", zBaseURL); } zProjectDescr = db_get("project-description", 0); if( zProjectDescr==0 ){ zProjectDescr = zProjectName; } zPubDate = cgi_rfc822_datestamp(time(NULL)); fossil_print("<?xml version=\"1.0\"?>"); fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">"); fossil_print("<channel>\n"); fossil_print("<title>%h</title>\n", zProjectName); fossil_print("<link>%s</link>\n", zBaseURL); fossil_print("<description>%h</description>\n", zProjectDescr); fossil_print("<pubDate>%s</pubDate>\n", zPubDate); fossil_print("<generator>Fossil version %s %s</generator>\n", MANIFEST_VERSION, MANIFEST_DATE); |
︙ | ︙ |
Added src/sbsdiff.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* The javascript in this file was added by Joel Bruick on 2013-07-06, ** originally as in-line javascript. It does some kind of setup for ** side-by-side diff display, but I'm not really sure what. */ (function(){ var SCROLL_LEN = 25; function initSbsDiff(diff){ var txtCols = diff.querySelectorAll('.difftxtcol'); var txtPres = diff.querySelectorAll('.difftxtcol pre'); var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth); for(var i=0; i<2; i++){ txtPres[i].style.width = width + 'px'; txtCols[i].onscroll = function(e){ txtCols[0].scrollLeft = txtCols[1].scrollLeft = this.scrollLeft; }; } diff.tabIndex = 0; diff.onkeydown = function(e){ e = e || event; var len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode]; if( !len ) return; txtCols[0].scrollLeft += len; return false; }; } var diffs = document.querySelectorAll('.sbsdiffcols'); for(var i=0; i<diffs.length; i++){ initSbsDiff(diffs[i]); } }()) |
Changes to src/schema.c.
1 2 3 4 5 6 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ |
︙ | ︙ | |||
124 125 126 127 128 129 130 | @ pw TEXT, -- password @ cap TEXT, -- Capabilities of this user @ cookie TEXT, -- WWW login cookie @ ipaddr TEXT, -- IP address for which cookie is valid @ cexpire DATETIME, -- Time when cookie expires @ info TEXT, -- contact information @ mtime DATE, -- last change. seconds since 1970 | | < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | @ pw TEXT, -- password @ cap TEXT, -- Capabilities of this user @ cookie TEXT, -- WWW login cookie @ ipaddr TEXT, -- IP address for which cookie is valid @ cexpire DATETIME, -- Time when cookie expires @ info TEXT, -- contact information @ mtime DATE, -- last change. seconds since 1970 @ photo BLOB -- JPEG image of this user @ ); @ @ -- The config table holds miscellanous information about the repository. @ -- in the form of name-value pairs. @ -- @ CREATE TABLE config( @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry |
︙ | ︙ | |||
158 159 160 161 162 163 164 | @ scom TEXT -- Optional text explaining why the shun occurred @ ); @ @ -- Artifacts that should not be pushed are stored in the "private" @ -- table. Private artifacts are omitted from the "unclustered" and @ -- "unsent" tables. @ -- | < < < < < < | < | 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 | @ scom TEXT -- Optional text explaining why the shun occurred @ ); @ @ -- Artifacts that should not be pushed are stored in the "private" @ -- table. Private artifacts are omitted from the "unclustered" and @ -- "unsent" tables. @ -- @ CREATE TABLE private(rid INTEGER PRIMARY KEY); @ @ -- An entry in this table describes a database query that generates a @ -- table of tickets. @ -- @ CREATE TABLE reportfmt( @ rn INTEGER PRIMARY KEY, -- Report number @ owner TEXT, -- Owner of this report format (not used) @ title TEXT UNIQUE, -- Title of this report @ mtime DATE, -- Last modified. seconds since 1970 @ cols TEXT, -- A color-key specification @ sqlcode TEXT -- An SQL SELECT statement for this report @ ); @ @ -- Some ticket content (such as the originators email address or contact @ -- information) needs to be obscured to protect privacy. This is achieved @ -- by storing an SHA1 hash of the content. For display, the hash is @ -- mapped back into the original text using this table. @ -- |
︙ | ︙ | |||
266 267 268 269 270 271 272 | @ -- @ CREATE TABLE mlink( @ mid INTEGER, -- Check-in that contains fid @ fid INTEGER, -- New file content. 0 if deleted @ pmid INTEGER, -- Check-in that contains pid @ pid INTEGER, -- Prev file content. 0 if new. -1 merge @ fnid INTEGER REFERENCES filename, -- Name of the file | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | @ -- @ CREATE TABLE mlink( @ mid INTEGER, -- Check-in that contains fid @ fid INTEGER, -- New file content. 0 if deleted @ pmid INTEGER, -- Check-in that contains pid @ pid INTEGER, -- Prev file content. 0 if new. -1 merge @ fnid INTEGER REFERENCES filename, -- Name of the file @ pfnid INTEGER REFERENCES filename, -- Previous name. 0 if unchanged @ mperm INTEGER, -- File permissions. 1==exec @ isaux BOOLEAN DEFAULT 0 -- TRUE if pmid is the primary @ ); @ CREATE INDEX mlink_i1 ON mlink(mid); @ CREATE INDEX mlink_i2 ON mlink(fnid); @ CREATE INDEX mlink_i3 ON mlink(fid); @ CREATE INDEX mlink_i4 ON mlink(pid); |
︙ | ︙ | |||
321 322 323 324 325 326 327 | @ comment TEXT, -- Comment describing the event @ brief TEXT, -- Short comment when tagid already seen @ omtime DATETIME -- Original unchanged date+time, or NULL @ ); @ CREATE INDEX event_i1 ON event(mtime); @ @ -- A record of phantoms. A phantom is a record for which we know the | | | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | @ comment TEXT, -- Comment describing the event @ brief TEXT, -- Short comment when tagid already seen @ omtime DATETIME -- Original unchanged date+time, or NULL @ ); @ CREATE INDEX event_i1 ON event(mtime); @ @ -- A record of phantoms. A phantom is a record for which we know the @ -- UUID but we do not (yet) know the file content. @ -- @ CREATE TABLE phantom( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ @ -- A record of orphaned delta-manifests. An orphan is a delta-manifest @ -- for which we have content, but its baseline-manifest is a phantom. @ -- We have to track all orphan maniftests so that when the baseline arrives, @ -- we know to process the orphaned deltas. @ CREATE TABLE orphan( @ rid INTEGER PRIMARY KEY, -- Delta manifest with a phantom baseline @ baseline INTEGER -- Phantom baseline of this orphan @ ); @ CREATE INDEX orphan_baseline ON orphan(baseline); @ |
︙ | ︙ | |||
358 359 360 361 362 363 364 | @ -- used to reduce push operations to a single HTTP request in the @ -- common case when one repository only talks to a single server. @ -- @ CREATE TABLE unsent( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ | | | | | | < | < | < | | | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | @ -- used to reduce push operations to a single HTTP request in the @ -- common case when one repository only talks to a single server. @ -- @ CREATE TABLE unsent( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ @ -- Each baseline or manifest can have one or more tags. A tag @ -- is defined by a row in the next table. @ -- @ -- Wiki pages are tagged with "wiki-NAME" where NAME is the name of @ -- the wiki page. Tickets changes are tagged with "ticket-UUID" where @ -- UUID is the indentifier of the ticket. Tags used to assign symbolic @ -- names to baselines are branches are of the form "sym-NAME" where @ -- NAME is the symbolic name. @ -- @ CREATE TABLE tag( @ tagid INTEGER PRIMARY KEY, -- Numeric tag ID @ tagname TEXT UNIQUE -- Tag name. @ ); @ INSERT INTO tag VALUES(1, 'bgcolor'); -- TAG_BGCOLOR @ INSERT INTO tag VALUES(2, 'comment'); -- TAG_COMMENT @ INSERT INTO tag VALUES(3, 'user'); -- TAG_USER @ INSERT INTO tag VALUES(4, 'date'); -- TAG_DATE @ INSERT INTO tag VALUES(5, 'hidden'); -- TAG_HIDDEN @ INSERT INTO tag VALUES(6, 'private'); -- TAG_PRIVATE @ INSERT INTO tag VALUES(7, 'cluster'); -- TAG_CLUSTER @ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH @ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED @ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT @ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE @ @ -- Assignments of tags to baselines. Note that we allow tags to @ -- have values assigned to them. So we are not really dealing with @ -- tags here. These are really properties. But we are going to @ -- keep calling them tags because in many cases the value is ignored. @ -- @ CREATE TABLE tagxref( @ tagid INTEGER REFERENCES tag, -- The tag that added or removed @ tagtype INTEGER, -- 0:-,cancel 1:+,single 2:*,propagate @ srcid INTEGER REFERENCES blob, -- Artifact of tag. 0 for propagated tags @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag @ value TEXT, -- Value of the tag. Might be NULL. @ mtime TIMESTAMP, -- Time of addition or removal. Julian day @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to @ UNIQUE(rid, tagid) @ ); @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); @ @ -- When a hyperlink occurs from one artifact to another (for example @ -- when a check-in comment refers to a ticket) an entry is made in @ -- the following table for that hyperlink. This table is used to @ -- facilitate the display of "back links". @ -- @ CREATE TABLE backlink( @ target TEXT, -- Where the hyperlink points to @ srctype INT, -- 0: check-in 1: ticket 2: wiki @ srcid INT, -- rid for check-in or wiki. tkt_id for ticket. @ mtime TIMESTAMP, -- time that the hyperlink was added. Julian day. @ UNIQUE(target, srctype, srcid) @ ); @ CREATE INDEX backlink_src ON backlink(srcid, srctype); @ @ -- Each attachment is an entry in the following table. Only @ -- the most recent attachment (identified by the D card) is saved. @ -- @ CREATE TABLE attachment( @ attachid INTEGER PRIMARY KEY, -- Local id for this attachment @ isLatest BOOLEAN DEFAULT 0, -- True if this is the one to use @ mtime TIMESTAMP, -- Last changed. Julian day. @ src TEXT, -- UUID of the attachment. NULL to delete @ target TEXT, -- Object attached to. Wikiname or Tkt UUID @ filename TEXT, -- Filename for the attachment @ comment TEXT, -- Comment associated with this attachment @ user TEXT -- Name of user adding attachment @ ); @ CREATE INDEX attachment_idx1 ON attachment(target, filename, mtime); @ CREATE INDEX attachment_idx2 ON attachment(src); @ |
︙ | ︙ | |||
461 462 463 464 465 466 467 | @ comment TEXT @ ); @ CREATE TABLE ticketchng( @ -- Do not change any column that begins with tkt_ @ tkt_id INTEGER REFERENCES ticket, @ tkt_rid INTEGER REFERENCES blob, @ tkt_mtime DATE, | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | @ comment TEXT @ ); @ CREATE TABLE ticketchng( @ -- Do not change any column that begins with tkt_ @ tkt_id INTEGER REFERENCES ticket, @ tkt_rid INTEGER REFERENCES blob, @ tkt_mtime DATE, @ -- Add as many fields as required below this line @ login TEXT, @ username TEXT, @ mimetype TEXT, @ icomment TEXT @ ); @ CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime); ; /* ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ |
︙ | ︙ | |||
523 524 525 526 527 528 529 | # define TAG_PARENT 10 /* Change to parentage on a check-in */ # define TAG_NOTE 11 /* Extra text appended to a check-in comment */ #endif /* ** The schema for the local FOSSIL database file found at the root ** of every check-out. This database contains the complete state of | | | | | | | | | | > > | | < < < < < < < < < < < | < | < | < < < | < < < < < | < | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | # define TAG_PARENT 10 /* Change to parentage on a check-in */ # define TAG_NOTE 11 /* Extra text appended to a check-in comment */ #endif /* ** The schema for the local FOSSIL database file found at the root ** of every check-out. This database contains the complete state of ** the checkout. */ const char zLocalSchema[] = @ -- The VVAR table holds miscellanous information about the local database @ -- in the form of name-value pairs. This is similar to the VAR table @ -- table in the repository except that this table holds information that @ -- is specific to the local checkout. @ -- @ -- Important Variables: @ -- @ -- repository Full pathname of the repository database @ -- user-id Userid to use @ -- @ CREATE TABLE vvar( @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry @ value CLOB, -- Content of the named parameter @ CHECK( typeof(name)='text' AND length(name)>=1 ) @ ); @ @ -- Each entry in the vfile table represents a single file in the @ -- current checkout. @ -- @ -- The file.rid field is 0 for files or folders that have been @ -- added but not yet committed. @ -- @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have @ -- been edited or which have been subjected to a 3-way merge. @ -- Vfile.chnged is 2 if the file has been replaced from a different @ -- version by the merge and 3 if the file has been added by a merge. @ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been @ -- done by an --integrate merge. The difference between vfile.chnged==3|5 @ -- and a regular add is that with vfile.chnged==3|5 we know that the @ -- current version of the file is already in the repository. @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ isexe BOOLEAN, -- True if file should be executable @ islink BOOLEAN, -- True if file should be symlink @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root @ origname TEXT, -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); @ @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another @ -- record, there is an entry in this table with (id,merge) where @ -- merge is the RECORD table entry that the file merged against. @ -- An id of 0 or <-3 here means the version record itself. When @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a @ -- backout merge and id==(-4) is a integrate merge. @ @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record @ UNIQUE(id, merge) @ ); @ @ -- Identifier for this file type. @ -- The integer is the same as 'FSLC'. @ PRAGMA application_id=252006674; ; /* ** The following table holds information about forum posts. It ** is created on-demand whenever the manifest parser encounters ** a forum-post artifact. */ |
︙ | ︙ |
Changes to src/scroll.js.
|
| | | | 1 2 | /* Cause the the page to scroll so that the #scrollToMe is visible */ document.getElementById('scrollToMe').scrollIntoView(true); |
Changes to src/search.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement a search functions | | < | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement a search functions ** against timeline comments, check-in content, wiki pages, and/or tickets. ** ** The search can be either a per-query "grep"-like search that scans ** the entire corpus. Or it can use the FTS4 or FTS5 search engine of ** SQLite. The choice is a administrator configuration option. ** ** The first option is referred to as "full-scan search". The second ** option is called "indexed search". ** ** The code in this file is ordered approximately as follows: ** ** (1) The full-scan search engine |
︙ | ︙ | |||
330 331 332 333 334 335 336 | /* ** COMMAND: test-match ** ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... ** ** Run the full-scan search algorithm using SEARCHSTRING against ** the text of the files listed. Output matches and snippets. | < < < < < < < | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | /* ** COMMAND: test-match ** ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... ** ** Run the full-scan search algorithm using SEARCHSTRING against ** the text of the files listed. Output matches and snippets. */ void test_match_cmd(void){ Search *p; int i; Blob x; int score; char *zDoc; |
︙ | ︙ | |||
378 379 380 381 382 383 384 | ** ** search_init(PATTERN,BEGIN,END,GAP,FLAGS) ** ** All arguments are optional. PATTERN is the search pattern. If it ** is omitted, then the global search pattern is reset. BEGIN and END ** and GAP are the strings used to construct snippets. FLAGS is an ** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC, | | < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | ** ** search_init(PATTERN,BEGIN,END,GAP,FLAGS) ** ** All arguments are optional. PATTERN is the search pattern. If it ** is omitted, then the global search pattern is reset. BEGIN and END ** and GAP are the strings used to construct snippets. FLAGS is an ** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC, ** SRCH_TKT, or SRCH_ALL bits to determine what is to be searched. */ static void search_init_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zPattern = 0; |
︙ | ︙ | |||
414 415 416 417 418 419 420 | } } /* search_match(TEXT, TEXT, ....) ** ** Using the full-scan search engine created by the most recent call ** to search_init(), match the input the TEXT arguments. | | | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | } } /* search_match(TEXT, TEXT, ....) ** ** Using the full-scan search engine created by the most recent call ** to search_init(), match the input the TEXT arguments. ** Remember the results global full-scan search object. ** Return non-zero on a match and zero on a miss. */ static void search_match_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ |
︙ | ︙ | |||
537 538 539 540 541 542 543 | /* ** Register the various SQL functions (defined above) needed to implement ** full-scan search. */ void search_sql_setup(sqlite3 *db){ static int once = 0; | < | | | | | | | | | < < < < < > | < < | < < | > > < < | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 | /* ** Register the various SQL functions (defined above) needed to implement ** full-scan search. */ void search_sql_setup(sqlite3 *db){ static int once = 0; if( once++ ) return; sqlite3_create_function(db, "search_match", -1, SQLITE_UTF8, 0, search_match_sqlfunc, 0, 0); sqlite3_create_function(db, "search_score", 0, SQLITE_UTF8, 0, search_score_sqlfunc, 0, 0); sqlite3_create_function(db, "search_snippet", 0, SQLITE_UTF8, 0, search_snippet_sqlfunc, 0, 0); sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0, search_init_sqlfunc, 0, 0); sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0, search_stext_sqlfunc, 0, 0); sqlite3_create_function(db, "title", 3, SQLITE_UTF8, 0, search_title_sqlfunc, 0, 0); sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0, search_body_sqlfunc, 0, 0); sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0, search_urlencode_sqlfunc, 0, 0); } /* ** Testing the search function. ** ** COMMAND: search* ** ** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern... ** ** Search for timeline entries matching all words provided on the ** command line. Whole-word matches scope more highly than partial ** matches. ** ** Outputs, by default, some top-N fraction of the results. The -all ** option can be used to output all matches, regardless of their search ** score. The -limit option can be used to limit the number of entries ** returned. The -width option can be used to set the output width used ** when printing matches. ** ** Options: ** ** -a|--all Output all matches, not just best matches. ** -n|--limit N Limit output to N matches. ** -W|--width WIDTH Set display width to WIDTH columns, 0 for ** unlimited. Defaults the terminal's width. */ void search_cmd(void){ Blob pattern; int i; Blob sql = empty_blob; Stmt q; int iBest; char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop off the end of the results. */ const char *zLimit = find_option("limit","n",1); const char *zWidth = find_option("width","W",1); int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching lines/entries to list */ int width; if( zWidth ){ width = atoi(zWidth); if( (width!=0) && (width<=20) ){ fossil_fatal("-W|--width value must be >20 or 0"); } }else{ width = -1; } db_find_and_open_repository(0, 0); if( g.argc<3 ) return; blob_init(&pattern, g.argv[2], -1); for(i=3; i<g.argc; i++){ blob_appendf(&pattern, " %s", g.argv[i]); } (void)search_init(blob_str(&pattern),"*","*","...",SRCHFLG_STATIC); blob_reset(&pattern); search_sql_setup(g.db); db_multi_exec( "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);" "CREATE INDEX srch_idx1 ON srch(x);" "INSERT INTO srch(rid,uuid,date,comment,x)" " SELECT blob.rid, uuid, datetime(event.mtime,toLocal())," " coalesce(ecomment,comment)," " search_score()" " FROM event, blob" " WHERE blob.rid=event.objid" " AND search_match(coalesce(ecomment,comment));" ); iBest = db_int(0, "SELECT max(x) FROM srch"); blob_append(&sql, "SELECT rid, uuid, date, comment, 0, 0 FROM srch " "WHERE 1 ", -1); if(!fAll){ blob_append_sql(&sql,"AND x>%d ", iBest/3); } blob_append(&sql, "ORDER BY x DESC, date DESC ", -1); db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); print_timeline(&q, nLimit, width, 0); db_finalize(&q); } #if INTERFACE /* What to search for */ #define SRCH_CKIN 0x0001 /* Search over check-in comments */ #define SRCH_DOC 0x0002 /* Search over embedded documents */ #define SRCH_TKT 0x0004 /* Search over tickets */ #define SRCH_WIKI 0x0008 /* Search over wiki */ #define SRCH_TECHNOTE 0x0010 /* Search over tech notes */ #define SRCH_FORUM 0x0020 /* Search over forum messages */ #define SRCH_ALL 0x003f /* Search over everything */ #endif /* ** Remove bits from srchFlags which are disallowed by either the ** current server configuration or by user permissions. */ unsigned int search_restrict(unsigned int srchFlags){ static unsigned int knownGood = 0; static unsigned int knownBad = 0; static const struct { unsigned m; const char *zKey; } aSetng[] = { { SRCH_CKIN, "search-ci" }, { SRCH_DOC, "search-doc" }, |
︙ | ︙ | |||
782 783 784 785 786 787 788 | ** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine ** fills the X table with search results using a full-scan search. ** ** The companion indexed search routine is search_indexed(). */ | | | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | ** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine ** fills the X table with search results using a full-scan search. ** ** The companion indexed search routine is search_indexed(). */ static void search_fullscan( const char *zPattern, /* The query pattern */ unsigned int srchFlags /* What to search over */ ){ search_init(zPattern, "<mark>", "</mark>", " ... ", SRCHFLG_STATIC|SRCHFLG_HTML); if( (srchFlags & SRCH_DOC)!=0 ){ char *zDocGlob = db_get("doc-glob",""); |
︙ | ︙ | |||
990 991 992 993 994 995 996 | ** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine ** fills the X table with search results using FTS indexed search. ** ** The companion full-scan search routine is search_fullscan(). */ | | < < < | < < < < < < < < < < < < < < < < | | | < | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | ** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine ** fills the X table with search results using FTS indexed search. ** ** The companion full-scan search routine is search_fullscan(). */ static void search_indexed( const char *zPattern, /* The query pattern */ unsigned int srchFlags /* What to search over */ ){ Blob sql; if( srchFlags==0 ) return; sqlite3_create_function(g.db, "rank", 1, SQLITE_UTF8, 0, search_rank_sqlfunc, 0, 0); blob_init(&sql, 0, 0); blob_appendf(&sql, "INSERT INTO x(label,url,score,id,date,snip) " " SELECT ftsdocs.label," " ftsdocs.url," " rank(matchinfo(ftsidx,'pcsx'))," " ftsdocs.type || ftsdocs.rid," " datetime(ftsdocs.mtime)," " snippet(ftsidx,'<mark>','</mark>',' ... ',-1,35)" " FROM ftsidx CROSS JOIN ftsdocs" " WHERE ftsidx MATCH %Q" " AND ftsdocs.rowid=ftsidx.docid", zPattern ); if( srchFlags!=SRCH_ALL ){ const char *zSep = " AND ("; static const struct { unsigned m; char c; } aMask[] = { { SRCH_CKIN, 'c' }, { SRCH_DOC, 'd' }, { SRCH_TKT, 't' }, { SRCH_WIKI, 'w' }, |
︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 | int search_run_and_output( const char *zPattern, /* The query pattern */ unsigned int srchFlags, /* What to search over */ int fDebug /* Extra debugging output */ ){ Stmt q; int nRow = 0; | < < < < | < | < < < < < | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 | int search_run_and_output( const char *zPattern, /* The query pattern */ unsigned int srchFlags, /* What to search over */ int fDebug /* Extra debugging output */ ){ Stmt q; int nRow = 0; srchFlags = search_restrict(srchFlags); if( srchFlags==0 ) return 0; search_sql_setup(g.db); add_content_sql_commands(g.db); db_multi_exec( "CREATE TEMP TABLE x(label,url,score,id,date,snip);" ); if( !search_index_exists() ){ search_fullscan(zPattern, srchFlags); /* Full-scan search */ }else{ search_update_index(srchFlags); /* Update the index, if necessary */ search_indexed(zPattern, srchFlags); /* Indexed search */ } db_prepare(&q, "SELECT url, snip, label, score, id" " FROM x" " ORDER BY score DESC, date DESC;"); while( db_step(&q)==SQLITE_ROW ){ const char *zUrl = db_column_text(&q, 0); const char *zSnippet = db_column_text(&q, 1); const char *zLabel = db_column_text(&q, 2); if( nRow==0 ){ @ <ol> } nRow++; @ <li><p><a href='%R%s(zUrl)'>%h(zLabel)</a> if( fDebug ){ @ (%e(db_column_double(&q,3)), %s(db_column_text(&q,4)) } @ <br /><span class='snippet'>%z(cleanSnippet(zSnippet))</span></li> } db_finalize(&q); if( nRow ){ @ </ol> } return nRow; } |
︙ | ︙ | |||
1231 1232 1233 1234 1235 1236 1237 | if( zClass ){ @ <div class='searchForm searchForm%s(zClass)'> }else{ @ <div class='searchForm'> } @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> if( (mFlags & 0x01)!=0 && (srchFlags & (srchFlags-1))!=0 ){ | | | 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 | if( zClass ){ @ <div class='searchForm searchForm%s(zClass)'> }else{ @ <div class='searchForm'> } @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> if( (mFlags & 0x01)!=0 && (srchFlags & (srchFlags-1))!=0 ){ static const struct { char *z; char *zNm; unsigned m; } aY[] = { { "all", "All", SRCH_ALL }, { "c", "Check-ins", SRCH_CKIN }, { "d", "Docs", SRCH_DOC }, { "t", "Tickets", SRCH_TKT }, { "w", "Wiki", SRCH_WIKI }, { "e", "Tech Notes", SRCH_TECHNOTE }, { "f", "Forum", SRCH_FORUM }, |
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 | ** t -> tickets ** w -> wiki ** e -> tech notes ** f -> forum ** all -> everything */ void search_page(void){ | < | < | < < < < < < | < < < < < < | | | | | | | | | | < | < | > | > | > > > | < > | > | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | ** t -> tickets ** w -> wiki ** e -> tech notes ** f -> forum ** all -> everything */ void search_page(void){ login_check_credentials(); style_header("Search"); search_screen(SRCH_ALL, 1); style_footer(); } /* ** This is a helper function for search_stext(). Writing into pOut ** the search text obtained from pIn according to zMimetype. ** ** The title of the document is the first line of text. All subsequent ** lines are the body. If the document has no title, the first line ** is blank. */ static void get_stext_by_mimetype( Blob *pIn, const char *zMimetype, Blob *pOut ){ Blob html, title; blob_init(&html, 0, 0); blob_init(&title, 0, 0); if( zMimetype==0 ) zMimetype = "text/plain"; if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){ Blob tail; blob_init(&tail, 0, 0); if( wiki_find_title(pIn, &title, &tail) ){ blob_appendf(pOut, "%s\n", blob_str(&title)); wiki_convert(&tail, &html, 0); blob_reset(&tail); }else{ blob_append(pOut, "\n", 1); wiki_convert(pIn, &html, 0); } html_to_plaintext(blob_str(&html), pOut); }else if( fossil_strcmp(zMimetype,"text/x-markdown")==0 ){ markdown_to_html(pIn, &title, &html); if( blob_size(&title) ){ blob_appendf(pOut, "%s\n", blob_str(&title)); }else{ blob_append(pOut, "\n", 1); } html_to_plaintext(blob_str(&html), pOut); }else if( fossil_strcmp(zMimetype,"text/html")==0 ){ if( doc_is_embedded_html(pIn, &title) ){ blob_appendf(pOut, "%s\n", blob_str(&title)); } html_to_plaintext(blob_str(pIn), pOut); }else{ blob_append(pOut, "\n", 1); blob_append(pOut, blob_buffer(pIn), blob_size(pIn)); } blob_reset(&html); blob_reset(&title); } /* |
︙ | ︙ | |||
1394 1395 1396 1397 1398 1399 1400 | if( fossil_strcmp(zMime,"text/plain")==0 ) zMime = 0; }else if( zMime==0 || eType!=SQLITE_TEXT ){ blob_appendf(pAccum, "%s: %s |\n", zColName, db_column_text(pQuery,i)); }else{ Blob txt; blob_init(&txt, db_column_text(pQuery,i), -1); blob_appendf(pAccum, "%s: ", zColName); | | | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | if( fossil_strcmp(zMime,"text/plain")==0 ) zMime = 0; }else if( zMime==0 || eType!=SQLITE_TEXT ){ blob_appendf(pAccum, "%s: %s |\n", zColName, db_column_text(pQuery,i)); }else{ Blob txt; blob_init(&txt, db_column_text(pQuery,i), -1); blob_appendf(pAccum, "%s: ", zColName); get_stext_by_mimetype(&txt, zMime, pAccum); blob_append(pAccum, " |", 2); blob_reset(&txt); } } } |
︙ | ︙ | |||
1433 1434 1435 1436 1437 1438 1439 | ){ blob_init(pOut, 0, 0); switch( cType ){ case 'd': { /* Documents */ Blob doc; content_get(rid, &doc); blob_to_utf8_no_bom(&doc, 0); | | | 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 | ){ blob_init(pOut, 0, 0); switch( cType ){ case 'd': { /* Documents */ Blob doc; content_get(rid, &doc); blob_to_utf8_no_bom(&doc, 0); get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut); blob_reset(&doc); break; } case 'f': /* Forum messages */ case 'e': /* Tech Notes */ case 'w': { /* Wiki */ Manifest *pWiki = manifest_get(rid, |
︙ | ︙ | |||
1455 1456 1457 1458 1459 1460 1461 | blob_appendf(&wiki, "<h1>%h</h1>\n", pWiki->zThreadTitle); } blob_appendf(&wiki, "From %s:\n\n%s", pWiki->zUser, pWiki->zWiki); }else{ blob_init(&wiki, pWiki->zWiki, -1); } get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype), | | | 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 | blob_appendf(&wiki, "<h1>%h</h1>\n", pWiki->zThreadTitle); } blob_appendf(&wiki, "From %s:\n\n%s", pWiki->zUser, pWiki->zWiki); }else{ blob_init(&wiki, pWiki->zWiki, -1); } get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype), pOut); blob_reset(&wiki); manifest_destroy(pWiki); break; } case 'c': { /* Check-in Comments */ static Stmt q; static int isPlainText = -1; |
︙ | ︙ | |||
1485 1486 1487 1488 1489 1490 1491 | blob_append(pOut, "\n", 1); if( isPlainText ){ db_column_blob(&q, 0, pOut); }else{ Blob x; blob_init(&x,0,0); db_column_blob(&q, 0, &x); | | | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | blob_append(pOut, "\n", 1); if( isPlainText ){ db_column_blob(&q, 0, pOut); }else{ Blob x; blob_init(&x,0,0); db_column_blob(&q, 0, &x); get_stext_by_mimetype(&x, "text/x-fossil-wiki", pOut); blob_reset(&x); } } db_reset(&q); break; } case 't': { /* Tickets */ |
︙ | ︙ | |||
1596 1597 1598 1599 1600 1601 1602 | */ void test_convert_stext(void){ Blob in, out; db_find_and_open_repository(0,0); if( g.argc!=4 ) usage("FILENAME MIMETYPE"); blob_read_from_file(&in, g.argv[2], ExtFILE); blob_init(&out, 0, 0); | | < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 | */ void test_convert_stext(void){ Blob in, out; db_find_and_open_repository(0,0); if( g.argc!=4 ) usage("FILENAME MIMETYPE"); blob_read_from_file(&in, g.argv[2], ExtFILE); blob_init(&out, 0, 0); get_stext_by_mimetype(&in, g.argv[3], &out); fossil_print("%s\n",blob_str(&out)); blob_reset(&in); blob_reset(&out); } /* The schema for the full-text index */ static const char zFtsSchema[] = @ -- One entry for each possible search result @ CREATE TABLE IF NOT EXISTS repository.ftsdocs( @ rowid INTEGER PRIMARY KEY, -- Maps to the ftsidx.docid @ type CHAR(1), -- Type of document @ rid INTEGER, -- BLOB.RID or TAG.TAGID for the document @ name TEXT, -- Additional document description @ idxed BOOLEAN, -- True if currently in the index @ label TEXT, -- Label to print on search results @ url TEXT, -- URL to access this document @ mtime DATE, -- Date when document created @ bx TEXT, -- Temporary "body" content cache @ UNIQUE(type,rid) @ ); @ CREATE INDEX repository.ftsdocIdxed ON ftsdocs(type,rid,name) WHERE idxed==0; @ CREATE INDEX repository.ftsdocName ON ftsdocs(name) WHERE type='w'; @ CREATE VIEW IF NOT EXISTS repository.ftscontent AS @ SELECT rowid, type, rid, name, idxed, label, url, mtime, @ title(type,rid,name) AS 'title', body(type,rid,name) AS 'body' @ FROM ftsdocs; @ CREATE VIRTUAL TABLE IF NOT EXISTS repository.ftsidx @ USING fts4(content="ftscontent", title, body%s); ; static const char zFtsDrop[] = @ DROP TABLE IF EXISTS repository.ftsidx; @ DROP VIEW IF EXISTS repository.ftscontent; @ DROP TABLE IF EXISTS repository.ftsdocs; ; /* ** Create or drop the tables associated with a full-text index. */ static int searchIdxExists = -1; void search_create_index(void){ int useStemmer = db_get_boolean("search-stemmer",0); const char *zExtra = useStemmer ? ",tokenize=porter" : ""; search_sql_setup(g.db); db_multi_exec(zFtsSchema/*works-like:"%s"*/, zExtra/*safe-for-%s*/); searchIdxExists = 1; } void search_drop_index(void){ db_multi_exec(zFtsDrop/*works-like:""*/); searchIdxExists = 0; } /* ** Return true if the full-text search index exists */ int search_index_exists(void){ if( searchIdxExists<0 ){ searchIdxExists = db_table_exists("repository","ftsdocs"); } return searchIdxExists; } /* ** Fill the FTSDOCS table with unindexed entries for everything ** in the repository. This uses INSERT OR IGNORE so entries already ** in FTSDOCS are unchanged. */ void search_fill_index(void){ if( !search_index_exists() ) return; |
︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 | /* ** The document described by cType,rid,zName is about to be added or ** updated. If the document has already been indexed, then unindex it ** now while we still have access to the old content. Add the document ** to the queue of documents that need to be indexed or reindexed. */ void search_doc_touch(char cType, int rid, const char *zName){ | | | | | 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 | /* ** The document described by cType,rid,zName is about to be added or ** updated. If the document has already been indexed, then unindex it ** now while we still have access to the old content. Add the document ** to the queue of documents that need to be indexed or reindexed. */ void search_doc_touch(char cType, int rid, const char *zName){ if( search_index_exists() ){ char zType[2]; zType[0] = cType; zType[1] = 0; search_sql_setup(g.db); db_multi_exec( "DELETE FROM ftsidx WHERE docid IN" " (SELECT rowid FROM ftsdocs WHERE type=%Q AND rid=%d AND idxed)", zType, rid ); db_multi_exec( "REPLACE INTO ftsdocs(type,rid,name,idxed)" " VALUES(%Q,%d,%Q,0)", zType, rid, zName ); if( cType=='w' || cType=='e' ){ db_multi_exec( "DELETE FROM ftsidx WHERE docid IN" " (SELECT rowid FROM ftsdocs WHERE type='%c' AND name=%Q AND idxed)", cType, zName ); db_multi_exec( "DELETE FROM ftsdocs WHERE type='%c' AND name=%Q AND rid!=%d", cType, zName, rid ); |
︙ | ︙ | |||
1870 1871 1872 1873 1874 1875 1876 | "INSERT OR IGNORE INTO current_docs(rid, name)" " SELECT blob.rid, foci.filename FROM foci, blob" " WHERE foci.checkinID=%d AND blob.uuid=foci.uuid" " AND %z", ckid, glob_expr("foci.filename", db_get("doc-glob","")) ); db_multi_exec( | | | | | 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 | "INSERT OR IGNORE INTO current_docs(rid, name)" " SELECT blob.rid, foci.filename FROM foci, blob" " WHERE foci.checkinID=%d AND blob.uuid=foci.uuid" " AND %z", ckid, glob_expr("foci.filename", db_get("doc-glob","")) ); db_multi_exec( "DELETE FROM ftsidx WHERE docid IN" " (SELECT rowid FROM ftsdocs WHERE type='d'" " AND rid NOT IN (SELECT rid FROM current_docs))" ); db_multi_exec( "DELETE FROM ftsdocs WHERE type='d'" " AND rid NOT IN (SELECT rid FROM current_docs)" ); db_multi_exec( "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)" " SELECT 'd', rid, name, 0," " title('d',rid,name)," " body('d',rid,name)," " printf('/doc/%T/%%s',urlencode(name))," " %.17g" " FROM current_docs", zDocBr, rTime ); db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed" ); db_multi_exec( "UPDATE ftsdocs SET" " idxed=1," " bx=NULL," " label='Document: '||label" " WHERE type='d' AND NOT idxed" ); } /* ** Deal with all of the unindexed 'c' terms in FTSDOCS */ static void search_update_checkin_index(void){ db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, '', body('c',rid,NULL) FROM ftsdocs" " WHERE type='c' AND NOT idxed;" ); db_multi_exec( "UPDATE ftsdocs SET idxed=1, name=NULL," " (label,url,mtime) = " " (SELECT printf('Check-in [%%.16s] on %%s',blob.uuid," |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 | } /* ** Deal with all of the unindexed 't' terms in FTSDOCS */ static void search_update_ticket_index(void){ db_multi_exec( | | | 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 | } /* ** Deal with all of the unindexed 't' terms in FTSDOCS */ static void search_update_ticket_index(void){ db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, title('t',rid,NULL), body('t',rid,NULL) FROM ftsdocs" " WHERE type='t' AND NOT idxed;" ); if( db_changes()==0 ) return; db_multi_exec( "UPDATE ftsdocs SET idxed=1, name=NULL," " (label,url,mtime) =" |
︙ | ︙ | |||
1952 1953 1954 1955 1956 1957 1958 | } /* ** Deal with all of the unindexed 'w' terms in FTSDOCS */ static void search_update_wiki_index(void){ db_multi_exec( | | | 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 | } /* ** Deal with all of the unindexed 'w' terms in FTSDOCS */ static void search_update_wiki_index(void){ db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, title('w',rid,NULL),body('w',rid,NULL) FROM ftsdocs" " WHERE type='w' AND NOT idxed;" ); if( db_changes()==0 ) return; db_multi_exec( "UPDATE ftsdocs SET idxed=1," " (name,label,url,mtime) = " |
︙ | ︙ | |||
1974 1975 1976 1977 1978 1979 1980 | } /* ** Deal with all of the unindexed 'f' terms in FTSDOCS */ static void search_update_forum_index(void){ db_multi_exec( | | | 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | } /* ** Deal with all of the unindexed 'f' terms in FTSDOCS */ static void search_update_forum_index(void){ db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, title('f',rid,NULL),body('f',rid,NULL) FROM ftsdocs" " WHERE type='f' AND NOT idxed;" ); if( db_changes()==0 ) return; db_multi_exec( "UPDATE ftsdocs SET idxed=1, name=NULL," " (label,url,mtime) = " |
︙ | ︙ | |||
1997 1998 1999 2000 2001 2002 2003 | } /* ** Deal with all of the unindexed 'e' terms in FTSDOCS */ static void search_update_technote_index(void){ db_multi_exec( | | | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | } /* ** Deal with all of the unindexed 'e' terms in FTSDOCS */ static void search_update_technote_index(void){ db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, title('e',rid,NULL),body('e',rid,NULL) FROM ftsdocs" " WHERE type='e' AND NOT idxed;" ); if( db_changes()==0 ) return; db_multi_exec( "UPDATE ftsdocs SET idxed=1," " (name,label,url,mtime) = " |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | ** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the ** index. */ void search_update_index(unsigned int srchFlags){ if( !search_index_exists() ) return; if( !db_exists("SELECT 1 FROM ftsdocs WHERE NOT idxed") ) return; search_sql_setup(g.db); | < < | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 | ** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the ** index. */ void search_update_index(unsigned int srchFlags){ if( !search_index_exists() ) return; if( !db_exists("SELECT 1 FROM ftsdocs WHERE NOT idxed") ) return; search_sql_setup(g.db); if( srchFlags & (SRCH_CKIN|SRCH_DOC) ){ search_update_doc_index(); search_update_checkin_index(); } if( srchFlags & SRCH_TKT ){ search_update_ticket_index(); } if( srchFlags & SRCH_WIKI ){ search_update_wiki_index(); } if( srchFlags & SRCH_TECHNOTE ){ search_update_technote_index(); } if( srchFlags & SRCH_FORUM ){ search_update_forum_index(); } } /* ** Construct, prepopulate, and then update the full-text index. */ void search_rebuild_index(void){ fossil_print("rebuilding the search index..."); |
︙ | ︙ | |||
2070 2071 2072 2073 2074 2075 2076 | ** of the repository. Subcommands: ** ** reindex Rebuild the search index. This is a no-op if ** index search is disabled ** ** index (on|off) Turn the search index on or off ** | | | < | | < < | | < < < | | < < < < | 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 | ** of the repository. Subcommands: ** ** reindex Rebuild the search index. This is a no-op if ** index search is disabled ** ** index (on|off) Turn the search index on or off ** ** enable cdtwe Enable various kinds of search. c=Check-ins, ** d=Documents, t=Tickets, w=Wiki, e=Tech Notes. ** ** disable cdtwe Disable various kinds of search ** ** stemmer (on|off) Turn the Porter stemmer on or off for indexed ** search. (Unindexed search is never stemmed.) ** ** The current search settings are displayed after any changes are applied. ** Run this command with no arguments to simply see the settings. */ void fts_config_cmd(void){ static const struct { int iCmd; const char *z; } aCmd[] = { { 1, "reindex" }, { 2, "index" }, { 3, "disable" }, { 4, "enable" }, { 5, "stemmer" }, }; static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = { { "search-ci", "check-in search:", "c" }, { "search-doc", "document search:", "d" }, { "search-tkt", "ticket search:", "t" }, { "search-wiki", "wiki search:", "w" }, { "search-technote", "tech note search:", "e" }, { "search-forum", "forum search:", "f" }, }; |
︙ | ︙ | |||
2122 2123 2124 2125 2126 2127 2128 | for(i=0; i<count(aCmd); i++){ if( fossil_strncmp(aCmd[i].z, zSubCmd, n)==0 ) break; } if( i>=count(aCmd) ){ Blob all; blob_init(&all,0,0); for(i=0; i<count(aCmd); i++) blob_appendf(&all, " %s", aCmd[i].z); | | | 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 | for(i=0; i<count(aCmd); i++){ if( fossil_strncmp(aCmd[i].z, zSubCmd, n)==0 ) break; } if( i>=count(aCmd) ){ Blob all; blob_init(&all,0,0); for(i=0; i<count(aCmd); i++) blob_appendf(&all, " %s", aCmd[i].z); fossil_fatal("unknown \"%s\" - should be on of:%s", zSubCmd, blob_str(&all)); return; } iCmd = aCmd[i].iCmd; } g.perm.Read = 1; g.perm.RdTkt = 1; |
︙ | ︙ | |||
2147 2148 2149 2150 2151 2152 2153 | /* Adjust search settings */ if( iCmd==3 || iCmd==4 ){ const char *zCtrl; if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd)); zCtrl = g.argv[3]; for(j=0; j<count(aSetng); j++){ if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){ | | > | < | < < | < < < < < | | | | < < < < < < | < < < | < | < < < < < < | < < < < < < < < < < < < < < | < < < < < < < < < | < | | | | < | | < < < < | < < | < < < < < < < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | /* Adjust search settings */ if( iCmd==3 || iCmd==4 ){ const char *zCtrl; if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd)); zCtrl = g.argv[3]; for(j=0; j<count(aSetng); j++){ if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){ db_set_int(aSetng[j].zSetting, iCmd-3, 0); } } } if( iCmd==5 ){ if( g.argc<4 ) usage("porter ON/OFF"); db_set_int("search-stemmer", is_truth(g.argv[3]), 0); } /* destroy or rebuild the index, if requested */ if( iAction>=1 ){ search_drop_index(); } if( iAction>=2 ){ search_rebuild_index(); } /* Always show the status before ending */ for(i=0; i<count(aSetng); i++){ fossil_print("%-17s %s\n", aSetng[i].zName, db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off"); } fossil_print("%-17s %s\n", "Porter stemmer:", db_get_boolean("search-stemmer",0) ? "on" : "off"); if( search_index_exists() ){ fossil_print("%-17s enabled\n", "full-text index:"); fossil_print("%-17s %d\n", "documents:", db_int(0, "SELECT count(*) FROM ftsdocs")); }else{ fossil_print("%-17s disabled\n", "full-text index:"); } db_end_transaction(0); } /* ** WEBPAGE: test-ftsdocs ** ** Show a table of all documents currently in the search index. */ void search_data_page(void){ Stmt q; const char *zId = P("id"); const char *zType = P("y"); const char *zIdxed = P("ixed"); int id; int cnt = 0; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } if( !search_index_exists() ){ @ <p>Indexed search is disabled style_footer(); return; } if( zId!=0 && (id = atoi(zId))>0 ){ /* Show information about a single ftsdocs entry */ style_header("Information about ftsdoc entry %d", id); db_prepare(&q, "SELECT type||rid, name, idxed, label, url, datetime(mtime)" " FROM ftsdocs WHERE rowid=%d", id ); if( db_step(&q)==SQLITE_ROW ){ const char *zUrl = db_column_text(&q,4); @ <table border=0> @ <tr><td align='right'>rowid:<td> <td>%d(id) @ <tr><td align='right'>id:<td><td>%s(db_column_text(&q,0)) @ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1)) @ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2)) @ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3)) @ <tr><td align='right'>url:<td><td> @ <a href='%R%s(zUrl)'>%h(zUrl)</a> @ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5)) @ </table> } db_finalize(&q); style_footer(); return; } if( zType!=0 && zType[0]!=0 && zType[1]==0 && zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0 ){ int ixed = zIdxed[0]=='1'; style_header("List of '%c' documents that are%s indexed", zType[0], ixed ? "" : " not"); db_prepare(&q, "SELECT rowid, type||rid ||' '|| coalesce(label,'')" " FROM ftsdocs WHERE type='%c' AND %s idxed", zType[0], ixed ? "" : "NOT" ); @ <ul> while( db_step(&q)==SQLITE_ROW ){ @ <li> <a href='test-ftsdocs?id=%d(db_column_int(&q,0))'> @ %h(db_column_text(&q,1))</a> } @ </ul> db_finalize(&q); style_footer(); return; } style_header("Summary of ftsdocs"); db_prepare(&q, "SELECT type, idxed, count(*) FROM ftsdocs" " GROUP BY 1, 2 ORDER BY 3 DESC" ); @ <table border=1 cellpadding=3 cellspacing=0> @ <thead> @ <tr><th>Type<th>Indexed?<th>Count<th>Link @ </thead> @ <tbody> while( db_step(&q)==SQLITE_ROW ){ const char *zType = db_column_text(&q,0); int idxed = db_column_int(&q,1); int n = db_column_int(&q,2); @ <tr><td>%h(zType)<td>%d(idxed) @ <td>%d(n) @ <td><a href='test-ftsdocs?y=%s(zType)&ixed=%d(idxed)'>listing</a> @ </tr> cnt += n; } @ </tbody><tfooter> @ <tr><th>Total<th><th>%d(cnt)<th> @ </tfooter> @ </table> style_footer(); } |
Changes to src/security_audit.c.
︙ | ︙ | |||
30 31 32 33 34 35 36 | while( zTest[0] ){ if( strchr(zCap, zTest[0]) ) return 1; zTest++; } return 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < | < < | < < < < < < < < < < < < < < | < < < < < < < < < < < | < < | | | | | | | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | > < < < < < < < < < < < < < < < < < < | < < | < | > | < | 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 | while( zTest[0] ){ if( strchr(zCap, zTest[0]) ) return 1; zTest++; } return 0; } /* ** WEBPAGE: secaudit0 ** ** Run a security audit of the current Fossil setup. ** This page requires administrator access */ void secaudit0_page(void){ const char *zAnonCap; /* Capabilities of user "anonymous" and "nobody" */ const char *zPubPages; /* GLOB pattern for public pages */ char *z; int n; login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } style_header("Security Audit"); @ <ol> /* Step 1: Determine if the repository is public or private. "Public" ** means that any anonymous user on the internet can access all content. ** "Private" repos require (non-anonymous) login to access all content, ** though some content may be accessible anonymously. */ zAnonCap = db_text("", "SELECT fullcap(NULL)"); zPubPages = db_get("public-pages",0); if( hasAnyCap(zAnonCap,"as") ){ @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because @ it grants administrator privileges to anonymous users. You @ should <a href="takeitprivate">take this repository private</a> @ immediately! Or, at least remove the Setup and Admin privileges @ for users "anonymous" and "login" on the @ <a href="setup_ulist">User Configuration</a> page. }else if( hasAnyCap(zAnonCap,"y") ){ @ <li><p>This repository is <big><b>INSECURE</b></big> because @ it allows anonymous users to push unversioned files. @ <p>Fix this by <a href="takeitprivate">taking the repository private</a> @ or by removing the "y" permission from users "anonymous" and @ "nobody" on the <a href="setup_ulist">User Configuration</a> page. }else if( hasAnyCap(zAnonCap,"goz") ){ @ <li><p>This repository is <big><b>PUBLIC</b></big>. All @ checked-in content can be accessed by anonymous users. @ <a href="takeitprivate">Take it private</a>.<p> }else if( !hasAnyCap(zAnonCap, "jrwy234567") && (zPubPages==0 || zPubPages[0]==0) ){ @ <li><p>This repository is <big><b>Completely PRIVATE</b></big>. @ A valid login and password is required to access any content. }else{ @ <li><p>This repository is <big><b>Mostly PRIVATE</b></big>. @ A valid login and password is usually required, however some @ content can be accessed anonymously: @ <ul> if( hasAnyCap(zAnonCap,"j") ){ @ <li> Wiki pages } if( hasAnyCap(zAnonCap,"r") ){ @ <li> Tickets } if( hasAnyCap(zAnonCap,"234567") ){ @ <li> Forum posts } if( zPubPages && zPubPages[0] ){ Glob *pGlob = glob_create(zPubPages); int i; @ <li> URLs that match any of these GLOB patterns: @ <ul> for(i=0; i<pGlob->nPattern; i++){ @ <li> %h(pGlob->azPattern[i]) } @ </ul> } @ </ul> if( zPubPages && zPubPages[0] ){ @ <p>Change GLOB patterns exceptions using the "Public pages" setting @ on the <a href="setup_access">Access Settings</a> page.</p> } } /* Make sure the HTTPS is required for login, so that the password ** does not go across the internet in the clear. */ if( db_get_boolean("redirect-to-https",0)==0 ){ @ <li><p><b>WARNING:</b> @ Login passwords can be sent over an unencrypted connection. @ <p>Fix this by activating the "Redirect to HTTPS on the Login page" @ setting on the <a href="setup_access">Access Control</a> page. } /* Anonymous users should not be able to harvest email addresses ** from tickets. */ if( hasAnyCap(zAnonCap, "e") ){ @ <li><p><b>WARNING:</b> @ Anonymous users can view email addresses and other personally @ identifiable information on tickets. @ <p>Fix this by removing the "Email" privilege @ (<a href="setup_ucap_list">capability "e"</a>) from users @ "anonymous" and "nobody" on the @ <a href="setup_ulist">User Configuration</a> page. } /* Anonymous users probably should not be allowed to push content ** to the repository. */ if( hasAnyCap(zAnonCap, "i") ){ @ <li><p><b>WARNING:</b> @ Anonymous users can push new check-ins into the repository. @ <p>Fix this by removing the "Check-in" privilege @ (<a href="setup_ucap_list">capability</a> "i") from users @ "anonymous" and "nobody" on the @ <a href="setup_ulist">User Configuration</a> page. } /* Anonymous users probably should not be allowed act as moderators ** for wiki or tickets. */ if( hasAnyCap(zAnonCap, "lq5") ){ @ <li><p><b>WARNING:</b> @ Anonymous users can act as moderators for wiki, tickets, or @ forum posts. This defeats the whole purpose of moderation. @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum" @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5") @ from users "anonymous" and "nobody" @ on the <a href="setup_ulist">User Configuration</a> page. } /* Anonymous users probably should not be allowed to delete ** wiki or tickets. */ if( hasAnyCap(zAnonCap, "d") ){ @ <li><p><b>WARNING:</b> @ Anonymous users can delete wiki and tickets. @ <p>Fix this by removing the "Delete" @ privilege from users "anonymous" and "nobody" on the @ <a href="setup_ulist">User Configuration</a> page. } /* If anonymous users are allowed to create new Wiki, then ** wiki moderation should be activated to pervent spam. */ if( hasAnyCap(zAnonCap, "fk") ){ if( db_get_boolean("modreq-wiki",0)==0 ){ |
︙ | ︙ | |||
458 459 460 461 462 463 464 | @ <li><p> @ Users with administrator privilege are: %s(z) fossil_free(z); if( n>3 ){ @ <li><p><b>WARNING:</b> @ Administrator privilege is granted to @ <a href='setup_ulist?with=as'>%d(n) users</a>. | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | @ <li><p> @ Users with administrator privilege are: %s(z) fossil_free(z); if( n>3 ){ @ <li><p><b>WARNING:</b> @ Administrator privilege is granted to @ <a href='setup_ulist?with=as'>%d(n) users</a>. @ Ideally, administator privilege ('s' or 'a') should only @ be granted to one or two users. } } /* The push-unversioned privilege should only be provided to ** specific individuals, not to entire classes of people. ** And no too many people should have this privilege. |
︙ | ︙ | |||
500 501 502 503 504 505 506 | @ The "Write-Unver" privilege ('y') is granted to an excessive @ number of users (%d(n)). @ Ideally, the Write-Unver privilege should only @ be granted to one or two users. } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | < | | | | | | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | < < < < < < < < < < < < < < < < < < < < < | | < | < < < > > > > > > | > > > > > > > | | < | < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | @ The "Write-Unver" privilege ('y') is granted to an excessive @ number of users (%d(n)). @ Ideally, the Write-Unver privilege should only @ be granted to one or two users. } } /* Notify if REMOTE_USER or HTTP_AUTHENTICATION is used for login. */ if( db_get_boolean("remote_user_ok", 0) ){ @ <li><p> @ This repository trusts that the REMOTE_USER environment variable set @ up by the webserver contains the name of an authenticated user. @ Fossil's built-in authentication mechanism is bypassed. @ <p>Fix this by deactivating the "Allow REMOTE_USER authentication" @ checkbox on the <a href="setup_access">Access Control</a> page. } if( db_get_boolean("http_authentication_ok", 0) ){ @ <li><p> @ This repository trusts that the HTTP_AUTHENITICATION environment @ variable set up by the webserver contains the name of an @ authenticated user. @ Fossil's built-in authentication mechanism is bypassed. @ <p>Fix this by deactivating the "Allow HTTP_AUTHENTICATION authentication" @ checkbox on the <a href="setup_access">Access Control</a> page. } /* Logging should be turned on */ if( db_get_boolean("access-log",0)==0 ){ @ <li><p> @ The <a href="access_log">User Log</a> is disabled. The user log @ keeps a record of successful and unsucessful login attempts and is @ useful for security monitoring. } if( db_get_boolean("admin-log",0)==0 ){ @ <li><p> @ The <a href="admin_log">Administrative Log</a> is disabled. @ The administrative log provides a record of configuration changes @ and is useful for security monitoring. } #if !defined(_WIN32) && !defined(FOSSIL_OMIT_LOAD_AVERAGE) /* Make sure that the load-average limiter is armed and working */ if( load_average()==0.0 ){ @ <li><p> @ Unable to get the system load average. This can prevent Fossil @ from throttling expensive operations during peak demand. @ <p>If running in a chroot jail on Linux, verify that the /proc @ filesystem is mounted within the jail, so that the load average @ can be obtained from the /proc/loadavg file. }else { double r = atof(db_get("max-loadavg", "0")); if( r<=0.0 ){ @ <li><p> @ Load average limiting is turned off. This can cause the server @ to bog down if many requests for expensive services (such as @ large diffs or tarballs) arrive at about the same time. @ <p>To fix this, set the "Server Load Average Limit" on the @ <a href="setup_access">Access Control</a> page to approximately @ the number of available cores on your server, or maybe just a little @ less. }else if( r>=8.0 ){ @ <li><p> @ The "Server Load Average Limit" on the @ <a href="setup_access">Access Control</a> page is set to %g(r), @ which seems high. Is this server really a %d((int)r)-core machine? } } #endif if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){ @ <li><p> @ The server error log is disabled. @ To set up an error log: @ <ul> @ <li>If running from CGI, make an entry "errorlog: <i>FILENAME</i>" @ in the CGI script. @ <li>If running the "fossil server" or "fossil http" commands, @ add the "--errorlog <i>FILENAME</i>" command-line option. @ </ul> }else{ FILE *pTest = fossil_fopen(g.zErrlog,"a"); if( pTest==0 ){ @ <li><p> @ <b>Error:</b> @ There is an error log at "%h(g.zErrlog)" but that file is not @ writable and so no logging will occur. }else{ fclose(pTest); @ <li><p> @ The error log at "<a href='%R/errorlog'>%h(g.zErrlog)</a>" that is @ %,lld(file_size(g.zErrlog, ExtFILE)) bytes in size. } } @ <li><p> User capability summary: capability_summary(); if( alert_enabled() ){ @ <li><p> Email alert configuration summary: @ <table class="label-value"> stats_for_email(); @ </table> }else{ @ <li><p> Email alerts are disabled } @ </ol> style_footer(); } /* ** WEBPAGE: takeitprivate ** ** Disable anonymous access to this website */ void takeitprivate_page(void){ login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } if( P("cancel") ){ /* User pressed the cancel button. Go back */ cgi_redirect("secaudit0"); } if( P("apply") ){ db_multi_exec( "UPDATE user SET cap=''" " WHERE login IN ('nobody','anonymous');" "DELETE FROM config WHERE name='public-pages';" ); cgi_redirect("secaudit0"); } style_header("Make This Website Private"); @ <p>Click the "Make It Private" button below to disable all @ anonymous access to this repository. A valid login and password @ will be required to access this repository after clicking that @ button.</p> @ @ <p>Click the "Cancel" button to leave things as they are.</p> @ @ <form action="%s(g.zPath)" method="post"> @ <input type="submit" name="apply" value="Make It Private"> @ <input type="submit" name="cancel" value="Cancel"> @ </form> style_footer(); } /* ** The maximum number of bytes of log to show */ #define MXSHOWLOG 50000 /* ** WEBPAGE: errorlog ** ** Show the content of the error log. Only the administrator can view ** this page. */ void errorlog_page(void){ i64 szFile; FILE *in; char z[10000]; login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } style_header("Server Error Log"); style_submenu_element("Test", "%R/test-warning"); style_submenu_element("Refresh", "%R/errorlog"); if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){ @ <p>To create a server error log: @ <ol> @ <li><p> @ If the server is running as CGI, then create a line in the CGI file @ like this: @ <blockquote><pre> @ errorlog: <i>FILENAME</i> @ </pre></blockquote> @ <li><p> @ If the server is running using one of @ the "fossil http" or "fossil server" commands then add @ a command-line option "--errorlog <i>FILENAME</i>" to that @ command. @ </ol> style_footer(); return; } if( P("truncate1") && cgi_csrf_safe(1) ){ fclose(fopen(g.zErrlog,"w")); } if( P("download") ){ Blob log; blob_read_from_file(&log, g.zErrlog, ExtFILE); cgi_set_content_type("text/plain"); cgi_set_content(&log); return; } szFile = file_size(g.zErrlog, ExtFILE); if( P("truncate") ){ @ <form action="%R/errorlog" method="POST"> @ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log: @ <input type="submit" name="truncate1" value="Confirm"> @ <input type="submit" name="cancel" value="Cancel"> @ </form> style_footer(); return; } @ <p>The server error log at "%h(g.zErrlog)" is %,lld(szFile) bytes in size. style_submenu_element("Download", "%R/errorlog?download"); style_submenu_element("Truncate", "%R/errorlog?truncate"); in = fossil_fopen(g.zErrlog, "rb"); if( in==0 ){ @ <p class='generalError'>Unable top open that file for reading!</p> style_footer(); return; } if( szFile>MXSHOWLOG && P("all")==0 ){ @ <form action="%R/errorlog" method="POST"> @ <p>Only the last %,d(MXSHOWLOG) bytes are shown. @ <input type="submit" name="all" value="Show All"> @ </form> fseek(in, -MXSHOWLOG, SEEK_END); } @ <hr> @ <pre> while( fgets(z, sizeof(z), in) ){ @ %h(z)\ } fclose(in); @ </pre> style_footer(); } |
Changes to src/setup.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | ** Increment the "cfgcnt" variable, so that ETags will know that ** the configuration has changed. */ void setup_incr_cfgcnt(void){ static int once = 1; if( once ){ once = 0; | < < | | < < < | < < | 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 | ** Increment the "cfgcnt" variable, so that ETags will know that ** the configuration has changed. */ void setup_incr_cfgcnt(void){ static int once = 1; if( once ){ once = 0; db_multi_exec("UPDATE config SET value=value+1 WHERE name='cfgcnt'"); if( db_changes()==0 ){ db_multi_exec("INSERT INTO config(name,value) VALUES('cfgcnt',1)"); } } } /* ** Output a single entry for a menu generated using an HTML table. ** If zLink is not NULL or an empty string, then it is the page that ** the menu entry will hyperlink to. If zLink is NULL or "", then ** the menu entry has no hyperlink - it is disabled. */ void setup_menu_entry( const char *zTitle, const char *zLink, const char *zDesc ){ @ <tr><td valign="top" align="right"> if( zLink && zLink[0] ){ @ <a href="%s(zLink)">%h(zTitle)</a> }else{ @ %h(zTitle) } @ </td><td width="5"></td><td valign="top">%h(zDesc)</td></tr> } /* ** WEBPAGE: setup ** ** Main menu for the administrative pages. Requires Admin privileges. */ void setup_page(void){ login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); } style_header("Server Administration"); /* Make sure the header contains <base href="...">. Issue a warning ** if it does not. */ if( !cgi_header_contains("<base href=") ){ @ <p class="generalError"><b>Configuration Error:</b> Please add @ <tt><base href="$secureurl/$current_page"></tt> after |
︙ | ︙ | |||
100 101 102 103 104 105 106 | @ by SQLite will be poorly seeded.</p> } #endif @ <table border="0" cellspacing="3"> setup_menu_entry("Users", "setup_ulist", "Grant privileges to individual users."); | < | | | | < < < < | | < < | | | | | < < < < < < < < < < | | > > | | < | < | | < > > | > > | > > < | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < | < | | | | | | | < | < < | > | | | | | | < < | < | | | | | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | | | | < | < < | | > | < | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | @ by SQLite will be poorly seeded.</p> } #endif @ <table border="0" cellspacing="3"> setup_menu_entry("Users", "setup_ulist", "Grant privileges to individual users."); setup_menu_entry("Access", "setup_access", "Control access settings."); setup_menu_entry("Configuration", "setup_config", "Configure the WWW components of the repository"); setup_menu_entry("Security-Audit", "secaudit0", "Analyze the current configuration for security problems"); setup_menu_entry("Settings", "setup_settings", "Web interface to the \"fossil settings\" command"); setup_menu_entry("Timeline", "setup_timeline", "Timeline display preferences"); setup_menu_entry("Login-Group", "setup_login_group", "Manage single sign-on between this repository and others" " on the same server"); setup_menu_entry("Tickets", "tktsetup", "Configure the trouble-ticketing system for this repository"); setup_menu_entry("Search","srchsetup", "Configure the built-in search engine"); setup_menu_entry("URL Aliases", "waliassetup", "Configure URL aliases"); setup_menu_entry("Notification", "setup_notification", "Automatic notifications of changes via outbound email"); setup_menu_entry("Email-Server", "setup_smtp", "Activate and configure the built-in email server"); setup_menu_entry("Transfers", "xfersetup", "Configure the transfer system for this repository"); setup_menu_entry("Skins", "setup_skin", "Select and/or modify the web interface \"skins\""); setup_menu_entry("Moderation", "setup_modreq", "Enable/Disable requiring moderator approval of Wiki and/or Ticket" " changes and attachments."); setup_menu_entry("Ad-Unit", "setup_adunit", "Edit HTML text for an ad unit inserted after the menu bar"); setup_menu_entry("URLs & Checkouts", "urllist", "Show URLs used to access this repo and known check-outs"); setup_menu_entry("Web-Cache", "cachestat", "View the status of the expensive-page cache"); setup_menu_entry("Logo", "setup_logo", "Change the logo and background images for the server"); setup_menu_entry("Shunned", "shun", "Show artifacts that are shunned by this repository"); setup_menu_entry("Artifact Receipts Log", "rcvfromlist", "A record of received artifacts and their sources"); setup_menu_entry("User Log", "access_log", "A record of login attempts"); setup_menu_entry("Administrative Log", "admin_log", "View the admin_log entries"); setup_menu_entry("Error Log", "errorlog", "View the Fossil server error log"); setup_menu_entry("Unversioned Files", "uvlist?byage=1", "Show all unversioned files held"); setup_menu_entry("Stats", "stat", "Repository Status Reports"); setup_menu_entry("Sitemap", "sitemap", "Links to miscellaneous pages"); setup_menu_entry("SQL", "admin_sql", "Enter raw SQL commands"); setup_menu_entry("TH1", "admin_th1", "Enter raw TH1 commands"); @ </table> style_footer(); } /* ** Generate a checkbox for an attribute. */ void onoff_attribute( const char *zLabel, /* The text label on the checkbox */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQParm, /* The query parameter */ int dfltVal, /* Default value if VAR table entry does not exist */ int disabled /* 1 if disabled */ ){ const char *zQ = P(zQParm); int iVal = db_get_boolean(zVar, dfltVal); if( zQ==0 && !disabled && P("submit") ){ zQ = "off"; } if( zQ ){ int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); if( iQ!=iVal ){ login_verify_csrf_secret(); db_set(zVar, iQ ? "1" : "0", 0); admin_log("Set option [%q] to [%q].", zVar, iQ ? "on" : "off"); iVal = iQ; } } @ <label><input type="checkbox" name="%s(zQParm)" if( iVal ){ @ checked="checked" } if( disabled ){ @ disabled="disabled" } @ /> <b>%s(zLabel)</b></label> } /* ** Generate an entry box for an attribute. */ void entry_attribute( const char *zLabel, /* The text label on the entry box */ int width, /* Width of the entry box */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQParm, /* The query parameter */ const char *zDflt, /* Default value if VAR table entry does not exist */ int disabled /* 1 if disabled */ ){ const char *zVal = db_get(zVar, zDflt); const char *zQ = P(zQParm); if( zQ && fossil_strcmp(zQ,zVal)!=0 ){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); db_set(zVar, zQ, 0); admin_log("Set entry_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); zVal = zQ; } @ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" \ @ size="%d(width)" \ if( disabled ){ @ disabled="disabled" \ } @ /> <b>%s(zLabel)</b> } /* ** Generate a text box for an attribute. */ const char *textarea_attribute( const char *zLabel, /* The text label on the textarea */ int rows, /* Rows in the textarea */ int cols, /* Columns in the textarea */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQP, /* The query parameter */ const char *zDflt, /* Default value if VAR table entry does not exist */ int disabled /* 1 if the textarea should not be editable */ ){ const char *z = db_get(zVar, zDflt); const char *zQ = P(zQP); if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); db_set(zVar, zQ, 0); admin_log("Set textarea_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); z = zQ; } if( rows>0 && cols>0 ){ @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" if( disabled ){ @ disabled="disabled" } @ cols="%d(cols)">%h(z)</textarea> if( zLabel && *zLabel ){ @ <span class="textareaLabel">%s(zLabel)</span> } } return z; } /* ** Generate a text box for an attribute. */ void multiple_choice_attribute( const char *zLabel, /* The text label on the menu */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQP, /* The query parameter */ const char *zDflt, /* Default value if VAR table entry does not exist */ int nChoice, /* Number of choices */ const char *const *azChoice /* Choices. 2 per choice: (VAR value, Display) */ ){ const char *z = db_get(zVar, zDflt); const char *zQ = P(zQP); int i; if( zQ && fossil_strcmp(zQ,z)!=0){ const int nZQ = (int)strlen(zQ); login_verify_csrf_secret(); db_set(zVar, zQ, 0); admin_log("Set multiple_choice_attribute %Q to: %.*s%s", zVar, 20, zQ, (nZQ>20 ? "..." : "")); z = zQ; } @ <select size="1" name="%s(zQP)" id="id%s(zQP)"> for(i=0; i<nChoice*2; i+=2){ const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : ""; @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option> } @ </select> <b>%h(zLabel)</b> } /* ** WEBPAGE: setup_access ** ** The access-control settings page. Requires Admin privileges. */ void setup_access(void){ login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Access Control Settings"); db_begin_transaction(); @ <form action="%s(g.zTop)/setup_access" method="post"><div> login_insert_csrf_secret(); @ <input type="submit" name="submit" value="Apply Changes" /></p> @ <hr /> onoff_attribute("Redirect to HTTPS on the Login page", "redirect-to-https", "redirhttps", 0, 0); @ <p>When selected, force the use of HTTPS for the Login page. @ <p>Details: When enabled, this option causes the $secureurl TH1 @ variable is set to an "https:" variant of $baseurl. Otherwise, @ $secureurl is just an alias for $baseurl. Also when enabled, the @ Login page redirects to https if accessed via http. @ (Property: "redirhttps") @ <hr /> onoff_attribute("Require password for local access", "localauth", "localauth", 0, 0); @ <p>When enabled, the password sign-in is always required for @ web access. When disabled, unrestricted web access from 127.0.0.1 @ is allowed for the <a href="%R/help/ui">fossil ui</a> command or @ from the <a href="%R/help/server">fossil server</a>, @ <a href="%R/help/http">fossil http</a> commands when the |
︙ | ︙ | |||
547 548 549 550 551 552 553 | @ <a href="%R/help/server">fossil http</a> commands @ without the "--localauth" option. @ <li> The server is started from CGI without the "localauth" keyword @ in the CGI script. @ </ol> @ (Property: "localauth") @ | | | < < < < < < < < < | | | > > > > > > > > > | | < | > > > | > > > > > > > > > > > | > > > > > > > > > > | > > | > > | > | | | < < < | | | | < < < < | < < < < < < < < | < < < < < < < < < | < < < < < < < | < < < < < < < < | | | | | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | @ <a href="%R/help/server">fossil http</a> commands @ without the "--localauth" option. @ <li> The server is started from CGI without the "localauth" keyword @ in the CGI script. @ </ol> @ (Property: "localauth") @ @ <hr /> onoff_attribute("Enable /test_env", "test_env_enable", "test_env_enable", 0, 0); @ <p>When enabled, the %h(g.zBaseURL)/test_env URL is available to all @ users. When disabled (the default) only users Admin and Setup can visit @ the /test_env page. @ (Property: "test_env_enable") @ </p> @ @ <hr /> onoff_attribute("Allow REMOTE_USER authentication", "remote_user_ok", "remote_user_ok", 0, 0); @ <p>When enabled, if the REMOTE_USER environment variable is set to the @ login name of a valid user and no other login credentials are available, @ then the REMOTE_USER is accepted as an authenticated user. @ (Property: "remote_user_ok") @ </p> @ @ <hr /> onoff_attribute("Allow HTTP_AUTHENTICATION authentication", "http_authentication_ok", "http_authentication_ok", 0, 0); @ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment @ variable or the "Authentication:" HTTP header to find the username and @ password. This is another way of supporting Basic Authenitication. @ (Property: "http_authentication_ok") @ </p> @ @ <hr /> entry_attribute("IP address terms used in login cookie", 3, "ip-prefix-terms", "ipt", "2", 0); @ <p>The number of octets of of the IP address used in the login cookie. @ Set to zero to omit the IP address from the login cookie. A value of @ 2 is recommended. @ (Property: "ip-prefix-terms") @ </p> @ @ <hr /> entry_attribute("Login expiration time", 6, "cookie-expire", "cex", "8766", 0); @ <p>The number of hours for which a login is valid. This must be a @ positive number. The default is 8766 hours which is approximately equal @ to a year. @ (Property: "cookie-expire")</p> @ <hr /> entry_attribute("Download packet limit", 10, "max-download", "mxdwn", "5000000", 0); @ <p>Fossil tries to limit out-bound sync, clone, and pull packets @ to this many bytes, uncompressed. If the client requires more data @ than this, then the client will issue multiple HTTP requests. @ Values below 1 million are not recommended. 5 million is a @ reasonable number. (Property: "max-download")</p> @ <hr /> entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt", "30", 0); @ <p>Fossil tries to spend less than this many seconds gathering @ the out-bound data of sync, clone, and pull packets. @ If the client request takes longer, a partial reply is given similar @ to the download packet limit. 30s is a reasonable default. @ (Property: "max-download-time")</p> @ <hr /> entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg", "0.0", 0); @ <p>Some expensive operations (such as computing tarballs, zip archives, @ or annotation/blame pages) are prohibited if the load average on the host @ computer is too large. Set the threshold for disallowing expensive @ computations here. Set this to 0.0 to disable the load average limit. @ This limit is only enforced on Unix servers. On Linux systems, @ access to the /proc virtual filesystem is required, which means this limit @ might not work inside a chroot() jail. @ (Property: "max-loadavg")</p> @ <hr /> onoff_attribute( "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", "auto-hyperlink", "autohyperlink", 1, 0); @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users, @ including user "nobody", as long as @ <ol><li>the User-Agent string in the @ HTTP header indicates that the request is coming from an actual human @ being, and @ <li>the user agent is able to @ run Javascript in order to set the href= attribute of hyperlinks, and @ <li>mouse movement is detected (optional - see the checkbox below), and @ <li>a number of milliseconds have passed since the page loaded.</ol> @ @ <p>This setting is designed to give easy access to humans while @ keeping out robots and spiders. @ You do not normally want a robot to walk your entire repository because @ if it does, your server will end up computing diffs and annotations for @ every historical version of every file and creating ZIPs and tarballs of @ every historical check-in, which can use a lot of CPU and bandwidth @ even for relatively small projects.</p> @ @ <p>Additional parameters that control this behavior:</p> @ <blockquote> onoff_attribute("Require mouse movement before enabling hyperlinks", "auto-hyperlink-mouseover", "ahmo", 0, 0); @ <br /> entry_attribute("Delay in milliseconds before enabling hyperlinks", 5, "auto-hyperlink-delay", "ah-delay", "50", 0); @ </blockquote> @ <p>For maximum robot defense, the "require mouse movement" should @ be turned on and the "Delay" should be at least 50 milliseconds.</p> @ (Properties: "auto-hyperlink", @ "auto-hyperlink-mouseover", and "auto-hyperlink-delay")</p> @ <hr /> onoff_attribute("Require a CAPTCHA if not logged in", "require-captcha", "reqcapt", 1, 0); @ <p>Require a CAPTCHA for edit operations (appending, creating, or @ editing wiki or tickets or adding attachments to wiki or tickets) @ for users who are not logged in. (Property: "require-captcha")</p> @ <hr /> entry_attribute("Public pages", 30, "public-pages", "pubpage", "", 0); @ <p>A comma-separated list of glob patterns for pages that are accessible @ without needing a login and using the privileges given by the @ "Default privileges" setting below. Example use case: Set this field @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the @ latest version of the embedded documentation in the www/ folder without @ allowing them to see the rest of the source code. @ (Property: "public-pages") @ </p> @ <hr /> onoff_attribute("Allow users to register themselves", "self-register", "selfregister", 0, 0); @ <p>Allow users to register themselves through the HTTP UI. @ The registration form always requires filling in a CAPTCHA @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone @ can register under any user name. This option is useful for public projects @ where you do not want everyone in any ticket discussion to be named @ "Anonymous". (Property: "self-register")</p> @ <hr /> entry_attribute("Default privileges", 10, "default-perms", "defaultperms", "u", 0); @ <p>Permissions given to users that... <ul><li>register themselves using @ the self-registration procedure (if enabled), or <li>access "public" @ pages identified by the public-pages glob pattern above, or <li> @ are users newly created by the administrator.</ul> @ <p>Recommended value: "u" for Reader. @ <a href="%R/setup_ucap_list">Capability Key</a>. @ (Property: "default-perms") @ </p> @ <hr /> onoff_attribute("Show javascript button to fill in CAPTCHA", "auto-captcha", "autocaptcha", 0, 0); @ <p>When enabled, a button appears on the login screen for user @ "anonymous" that will automatically fill in the CAPTCHA password. @ This is less secure than forcing the user to do it manually, but is @ probably secure enough and it is certainly more convenient for @ anonymous users. (Property: "auto-captcha")</p> @ <hr /> @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ </div></form> db_end_transaction(0); style_footer(); } /* ** WEBPAGE: setup_login_group ** ** Change how the current repository participates in a login ** group. |
︙ | ︙ | |||
750 751 752 753 754 755 756 | login_needed(0); return; } file_canonical_name(g.zRepositoryName, &fullName, 0); zSelfRepo = fossil_strdup(blob_str(&fullName)); blob_reset(&fullName); if( P("join")!=0 ){ | | < | | < < | | < | | | < | < | | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | login_needed(0); return; } file_canonical_name(g.zRepositoryName, &fullName, 0); zSelfRepo = fossil_strdup(blob_str(&fullName)); blob_reset(&fullName); if( P("join")!=0 ){ login_group_join(zRepo, zLogin, zPw, zNewName, &zErrMsg); }else if( P("leave") ){ login_group_leave(&zErrMsg); } style_header("Login Group Configuration"); if( zErrMsg ){ @ <p class="generalError">%s(zErrMsg)</p> } zGroup = login_group_name(); if( zGroup==0 ){ @ <p>This repository (in the file named "%h(zSelfRepo)") @ is not currently part of any login-group. @ To join a login group, fill out the form below.</p> @ @ <form action="%s(g.zTop)/setup_login_group" method="post"><div> login_insert_csrf_secret(); @ <blockquote><table border="0"> @ @ <tr><th align="right">Repository filename in group to join:</th> @ <td width="5"></td><td> @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr> @ @ <tr><th align="right">Login on the above repo:</th> @ <td width="5"></td><td> @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr> @ @ <tr><th align="right">Password:</th> @ <td width="5"></td><td> @ <input type="password" size="20" name="pw"></td></tr> @ @ <tr><th align="right">Name of login-group:</th> @ <td width="5"></td><td> @ <input type="text" size="30" value="%h(zNewName)" name="newname"> @ (only used if creating a new login-group).</td></tr> @ @ <tr><td colspan="3" align="center"> @ <input type="submit" value="Join" name="join"></td></tr> @ </table></blockquote></div></form> }else{ Stmt q; |
︙ | ︙ | |||
821 822 823 824 825 826 827 | n++; @ <tr><td align="right">%d(n).</td><td width="4"> @ <td>%h(zTitle)<td width="10"><td>%h(zRepo)</tr> } db_finalize(&q); @ </table> @ | | > > > | | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | n++; @ <tr><td align="right">%d(n).</td><td width="4"> @ <td>%h(zTitle)<td width="10"><td>%h(zRepo)</tr> } db_finalize(&q); @ </table> @ @ <p><form action="%s(g.zTop)/setup_login_group" method="post"><div> login_insert_csrf_secret(); @ To leave this login group press @ <input type="submit" value="Leave Login Group" name="leave"> @ </form></p> @ <br />For best results, use the same number of <a href="setup_access#ipt"> @ IP octets</a> in the login cookie across all repositories in the @ same Login Group. @ <hr /><h2>Implementation Details</h2> @ <p>The following are fields from the CONFIG table related to login-groups, @ provided here for instructional and debugging purposes:</p> @ <table border='1' class='sortable' data-column-types='ttt' \ @ data-init-sort='1'> @ <thead><tr> @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr> @ </thead><tbody> |
︙ | ︙ | |||
848 849 850 851 852 853 854 | @ <td>%h(db_column_text(&q,1))</td> @ <td>%h(db_column_text(&q,2))</td></tr> } db_finalize(&q); @ </tbody></table> style_table_sorter(); } | | | < | | | | | | < | | < < < < < < < < | < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | | | | | < | > | > | | < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | < < < < < < < < < < < | | | > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < > > | < < < < | > | | < < < < < < | < < | < | < < < < | < < | < < < < < < < < < < < | < < < < < < < < | < < < < < < < < < < | < | | < < < < < < < < < < < < < < < < | | < < < < < | > > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | | | < < < < < | | | | | | | | | | | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 | @ <td>%h(db_column_text(&q,1))</td> @ <td>%h(db_column_text(&q,2))</td></tr> } db_finalize(&q); @ </tbody></table> style_table_sorter(); } style_footer(); } /* ** WEBPAGE: setup_timeline ** ** Edit administrative settings controlling the display of ** timelines. */ void setup_timeline(void){ double tmDiff; char zTmDiff[20]; static const char *const azTimeFormats[] = { "0", "HH:MM", "1", "HH:MM:SS", "2", "YYYY-MM-DD HH:MM", "3", "YYMMDD HH:MM", "4", "(off)" }; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Timeline Display Preferences"); db_begin_transaction(); @ <form action="%s(g.zTop)/setup_timeline" method="post"><div> login_insert_csrf_secret(); @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ <hr /> onoff_attribute("Allow block-markup in timeline", "timeline-block-markup", "tbm", 0, 0); @ <p>In timeline displays, check-in comments can be displayed with or @ without block markup such as paragraphs, tables, etc. @ (Property: "timeline-block-markup")</p> @ <hr /> onoff_attribute("Plaintext comments on timelines", "timeline-plaintext", "tpt", 0, 0); @ <p>In timeline displays, check-in comments are displayed literally, @ without any wiki or HTML interpretation. Use CSS to change @ display formatting features such as fonts and line-wrapping behavior. @ (Property: "timeline-plaintext")</p> @ <hr /> onoff_attribute("Truncate comment at first blank line", "timeline-truncate-at-blank", "ttb", 0, 0); @ <p>In timeline displays, check-in comments are displayed only through @ the first blank line. (Property: "timeline-truncate-at-blank")</p> @ <hr /> onoff_attribute("Use Universal Coordinated Time (UTC)", "timeline-utc", "utc", 1, 0); @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or @ Zulu) instead of in local time. On this server, local time is currently tmDiff = db_double(0.0, "SELECT julianday('now')"); tmDiff = db_double(0.0, "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0", tmDiff, tmDiff); sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff); if( strcmp(zTmDiff, "0.0")==0 ){ @ the same as UTC and so this setting will make no difference in @ the display.</p> }else if( tmDiff<0.0 ){ sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", -tmDiff); @ %s(zTmDiff) hours behind UTC.</p> }else{ @ %s(zTmDiff) hours ahead of UTC.</p> } @ <p>(Property: "timeline-utc") @ <hr /> multiple_choice_attribute("Per-Item Time Format", "timeline-date-format", "tdf", "0", count(azTimeFormats)/2, azTimeFormats); @ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown @ in a separate box (using CSS class "timelineDate") whenever the date @ changes. With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats, @ the complete date and time is shown on every timeline entry using the @ CSS class "timelineTime". (Property: "timeline-date-format")</p> @ <hr /> entry_attribute("Max timeline comment length", 6, "timeline-max-comment", "tmc", "0", 0); @ <p>The maximum length of a comment to be displayed in a timeline. @ "0" there is no length limit. @ (Property: "timeline-max-comment")</p> @ <hr /> @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ </div></form> db_end_transaction(0); style_footer(); } /* ** WEBPAGE: setup_settings ** ** Change or view miscellaneous settings. Part of the ** Admin pages requiring Admin privileges. */ void setup_settings(void){ int nSetting; int i; Setting const *pSet; const Setting *aSetting = setting_info(&nSetting); login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Settings"); if(!g.repositoryOpen){ /* Provide read-only access to versioned settings, but only if no repo file was explicitly provided. */ db_open_local(0); } db_begin_transaction(); @ <p>Settings marked with (v) are "versionable" and will be overridden @ by the contents of managed files named @ "<tt>.fossil-settings/</tt><i>SETTING-NAME</i>". @ If the file for a versionable setting exists, the value cannot be @ changed on this screen.</p><hr /><p> @ @ <form action="%s(g.zTop)/setup_settings" method="post"><div> @ <table border="0"><tr><td valign="top"> login_insert_csrf_secret(); for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){ if( pSet->width==0 ){ int hasVersionableValue = pSet->versionable && (db_get_versioned(pSet->name, NULL)!=0); onoff_attribute("", pSet->name, pSet->var!=0 ? pSet->var : pSet->name, is_truth(pSet->def), hasVersionableValue); @ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a> if( pSet->versionable ){ @ (v)<br /> } else { @ <br /> } } } @ <br /><input type="submit" name="submit" value="Apply Changes" /> @ </td><td style="width:50px;"></td><td valign="top"> for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){ if( pSet->width!=0 && !pSet->forceTextArea ){ int hasVersionableValue = pSet->versionable && (db_get_versioned(pSet->name, NULL)!=0); entry_attribute("", /*pSet->width*/ 25, pSet->name, pSet->var!=0 ? pSet->var : pSet->name, (char*)pSet->def, hasVersionableValue); @ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a> if( pSet->versionable ){ @ (v)<br /> } else { @ <br /> } } } @ </td><td style="width:50px;"></td><td valign="top"> for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){ if( pSet->width!=0 && pSet->forceTextArea ){ int hasVersionableValue = db_get_versioned(pSet->name, NULL)!=0; @ <a href='%R/help?cmd=%s(pSet->name)'>%s(pSet->name)</a> if( pSet->versionable ){ @ (v)<br /> } else { @ <br /> } textarea_attribute("", /*rows*/ 2, /*cols*/ 35, pSet->name, pSet->var!=0 ? pSet->var : pSet->name, (char*)pSet->def, hasVersionableValue); @<br /> } } @ </td></tr></table> @ </div></form> db_end_transaction(0); style_footer(); } /* ** WEBPAGE: setup_config ** ** The "Admin/Configuration" page. Requires Admin privilege. */ void setup_config(void){ login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("WWW Configuration"); db_begin_transaction(); @ <form action="%s(g.zTop)/setup_config" method="post"><div> login_insert_csrf_secret(); @ <input type="submit" name="submit" value="Apply Changes" /></p> @ <hr /> entry_attribute("Project Name", 60, "project-name", "pn", "", 0); @ <p>A brief project name so visitors know what this site is about. @ The project name will also be used as the RSS feed title. @ (Property: "project-name") @ </p> @ <hr /> textarea_attribute("Project Description", 3, 80, "project-description", "pd", "", 0); @ <p>Describe your project. This will be used in page headers for search @ engines as well as a short RSS description. @ (Property: "project-description")</p> @ <hr /> entry_attribute("Tarball and ZIP-archive Prefix", 20, "short-project-name", "spn", "", 0); @ <p>This is used as a prefix on the names of generated tarballs and @ ZIP archive. For best results, keep this prefix brief and avoid special @ characters such as "/" and "\". @ If no tarball prefix is specified, then the full Project Name above is used. @ (Property: "short-project-name") @ </p> @ <hr /> entry_attribute("Download Tag", 20, "download-tag", "dlt", "trunk", 0); @ <p>The <a href='%R/download'>/download</a> page is designed to provide @ a convenient place for newbies @ to download a ZIP archive or a tarball of the project. By default, @ the latest trunk check-in is downloaded. Change this tag to something @ else (ex: release) to alter the behavior of the /download page. @ (Property: "download-tag") @ </p> @ <hr /> onoff_attribute("Enable WYSIWYG Wiki Editing", "wysiwyg-wiki", "wysiwyg-wiki", 0, 0); @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages. @ The WYSIWYG editor generates HTML instead of markup, which makes @ subsequent manual editing more difficult. @ (Property: "wysiwyg-wiki")</p> @ <hr /> entry_attribute("Index Page", 60, "index-page", "idxpg", "/home", 0); @ <p>Enter the pathname of the page to display when the "Home" menu @ option is selected and when no pathname is @ specified in the URL. For example, if you visit the url:</p> @ @ <blockquote><p>%h(g.zBaseURL)</p></blockquote> @ @ <p>And you have specified an index page of "/home" the above will @ automatically redirect to:</p> @ @ <blockquote><p>%h(g.zBaseURL)/home</p></blockquote> @ @ <p>The default "/home" page displays a Wiki page with the same name @ as the Project Name specified above. Some sites prefer to redirect @ to a documentation page (ex: "/doc/tip/index.wiki") or to "/timeline".</p> @ @ <p>Note: To avoid a redirect loop or other problems, this entry must @ begin with "/" and it must specify a valid page. For example, @ "<b>/home</b>" will work but "<b>home</b>" will not, since it omits the @ leading "/".</p> @ <p>(Property: "index-page") @ <hr> @ <p>Extra links to appear on the <a href="%R/sitemap">/sitemap</a> page. @ Often these are filled in with links like @ "/doc/trunk/doc/<i>filename</i>.md" so that they refer to @ embedded documentation, or like "/wiki/<i>pagename</i>" to refer @ to wiki pages. @ Leave blank to omit. @ <p> entry_attribute("Documentation Index", 40, "sitemap-docidx", "smdocidx", "", 0); @ (Property: sitemap-docidx)<br> entry_attribute("Download", 40, "sitemap-download", "smdownload", "", 0); @ (Property: sitemap-download)<br> entry_attribute("License", 40, "sitemap-license", "smlicense", "", 0); @ (Property: sitemap-license)<br> entry_attribute("Contact", 40, "sitemap-contact", "smcontact", "", 0); @ (Property: sitemap-contact) @ <hr /> onoff_attribute("Use HTML as wiki markup language", "wiki-use-html", "wiki-use-html", 0, 0); @ <p>Use HTML as the wiki markup language. Wiki links will still be parsed @ but all other wiki formatting will be ignored. This option is helpful @ if you have chosen to use a rich HTML editor for wiki markup such as @ TinyMCE.</p> @ <p><strong>CAUTION:</strong> when @ enabling, <i>all</i> HTML tags and attributes are accepted in the wiki. @ No sanitization is done. This means that it is very possible for malicious @ users to inject dangerous HTML, CSS and JavaScript code into your wiki.</p> @ <p>This should <strong>only</strong> be enabled when wiki editing is limited @ to trusted users. It should <strong>not</strong> be used on a publicly @ editable wiki.</p> @ (Property: "wiki-use-html") @ <hr /> @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ </div></form> db_end_transaction(0); style_footer(); } /* ** WEBPAGE: setup_modreq ** ** Admin page for setting up moderation of tickets and wiki. */ void setup_modreq(void){ login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Moderator For Wiki And Tickets"); db_begin_transaction(); @ <form action="%R/setup_modreq" method="post"><div> login_insert_csrf_secret(); @ <hr /> onoff_attribute("Moderate ticket changes", "modreq-tkt", "modreq-tkt", 0, 0); @ <p>When enabled, any change to tickets is subject to the approval @ by a ticket moderator - a user with the "q" or Mod-Tkt privilege. @ Ticket changes enter the system and are shown locally, but are not @ synced until they are approved. The moderator has the option to @ delete the change rather than approve it. Ticket changes made by @ a user who has the Mod-Tkt privilege are never subject to @ moderation. (Property: "modreq-tkt") @ @ <hr /> onoff_attribute("Moderate wiki changes", "modreq-wiki", "modreq-wiki", 0, 0); @ <p>When enabled, any change to wiki is subject to the approval @ by a wiki moderator - a user with the "l" or Mod-Wiki privilege. @ Wiki changes enter the system and are shown locally, but are not @ synced until they are approved. The moderator has the option to @ delete the change rather than approve it. Wiki changes made by @ a user who has the Mod-Wiki privilege are never subject to @ moderation. (Property: "modreq-wiki") @ </p> @ <hr /> @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ </div></form> db_end_transaction(0); style_footer(); } /* ** WEBPAGE: setup_adunit ** ** Administrative page for configuring and controlling ad units ** and how they are displayed. */ void setup_adunit(void){ login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } db_begin_transaction(); if( P("clear")!=0 && cgi_csrf_safe(1) ){ db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'"); cgi_replace_parameter("adunit",""); } style_header("Edit Ad Unit"); @ <form action="%s(g.zTop)/setup_adunit" method="post"><div> login_insert_csrf_secret(); @ <b>Banner Ad-Unit:</b><br /> textarea_attribute("", 6, 80, "adunit", "adunit", "", 0); @ <br /> @ <b>Right-Column Ad-Unit:</b><br /> textarea_attribute("", 6, 80, "adunit-right", "adright", "", 0); @ <br /> onoff_attribute("Omit ads to administrator", "adunit-omit-if-admin", "oia", 0, 0); @ <br /> onoff_attribute("Omit ads to logged-in users", "adunit-omit-if-user", "oiu", 0, 0); @ <br /> onoff_attribute("Temporarily disable all ads", "adunit-disable", "oall", 0, 0); @ <br /> @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="clear" value="Delete Ad-Unit" /> @ </div></form> @ <hr /> @ <b>Ad-Unit Notes:</b><ul> @ <li>Leave both Ad-Units blank to disable all advertising. @ <li>The "Banner Ad-Unit" is used for wide pages. @ <li>The "Right-Column Ad-Unit" is used on pages with tall, narrow content. @ <li>If the "Right-Column Ad-Unit" is blank, the "Banner Ad-Unit" is @ used on all pages. @ <li>Properties: "adunit", "adunit-right", "adunit-omit-if-admin", and |
︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 | @ width: 600px; @ height: 90px; @ border: 1px solid #f11; @ background-color: #fcc; @ '>Demo Ad</div> @ </pre></blockquote> @ </li> | | | < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < | | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 | @ width: 600px; @ height: 90px; @ border: 1px solid #f11; @ background-color: #fcc; @ '>Demo Ad</div> @ </pre></blockquote> @ </li> style_footer(); db_end_transaction(0); } /* ** WEBPAGE: setup_logo ** ** Administrative page for changing the logo image. */ void setup_logo(void){ const char *zLogoMtime = db_get_mtime("logo-image", 0, 0); const char *zLogoMime = db_get("logo-mimetype","image/gif"); const char *aLogoImg = P("logoim"); int szLogoImg = atoi(PD("logoim:bytes","0")); const char *zBgMtime = db_get_mtime("background-image", 0, 0); const char *zBgMime = db_get("background-mimetype","image/gif"); const char *aBgImg = P("bgim"); int szBgImg = atoi(PD("bgim:bytes","0")); if( szLogoImg>0 ){ zLogoMime = PD("logoim:mimetype","image/gif"); } if( szBgImg>0 ){ zBgMime = PD("bgim:mimetype","image/gif"); } login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } db_begin_transaction(); if( !cgi_csrf_safe(1) ){ /* Allow no state changes if not safe from CSRF */ }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){ Blob img; Stmt ins; blob_init(&img, aLogoImg, szLogoImg); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" " VALUES('logo-image',:bytes,now())" ); db_bind_blob(&ins, ":bytes", &img); db_step(&ins); db_finalize(&ins); db_multi_exec( "REPLACE INTO config(name,value,mtime) VALUES('logo-mimetype',%Q,now())", zLogoMime ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("clrlogo")!=0 ){ db_multi_exec( "DELETE FROM config WHERE name IN " "('logo-image','logo-mimetype')" ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("setbg")!=0 && zBgMime && zBgMime[0] && szBgImg>0 ){ Blob img; Stmt ins; blob_init(&img, aBgImg, szBgImg); db_prepare(&ins, "REPLACE INTO config(name,value,mtime)" " VALUES('background-image',:bytes,now())" ); db_bind_blob(&ins, ":bytes", &img); db_step(&ins); db_finalize(&ins); db_multi_exec( "REPLACE INTO config(name,value,mtime)" " VALUES('background-mimetype',%Q,now())", zBgMime ); db_end_transaction(0); cgi_redirect("setup_logo"); }else if( P("clrbg")!=0 ){ db_multi_exec( "DELETE FROM config WHERE name IN " "('background-image','background-mimetype')" ); db_end_transaction(0); cgi_redirect("setup_logo"); } style_header("Edit Project Logo And Background"); @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b> @ and looks like this:</p> @ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" \ @ alt="logo" border="1" /> @ </p></blockquote> @ @ <form action="%s(g.zTop)/setup_logo" method="post" @ enctype="multipart/form-data"><div> @ <p>The logo is accessible to all users at this URL: @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>. @ The logo may or may not appear on each @ page depending on the <a href="setup_skinedit?w=0">CSS</a> and @ <a href="setup_skinedit?w=2">header setup</a>. @ To change the logo image, use the following form:</p> login_insert_csrf_secret(); @ Logo Image file: @ <input type="file" name="logoim" size="60" accept="image/*" /> @ <p align="center"> @ <input type="submit" name="setlogo" value="Change Logo" /> @ <input type="submit" name="clrlogo" value="Revert To Default" /></p> @ <p>(Properties: "logo-image" and "logo-mimetype") @ </div></form> @ <hr /> @ @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> @ and looks like this:</p> @ <blockquote><p><img src="%s(g.zTop)/background/%z(zBgMtime)" \ @ alt="background" border=1 /> @ </p></blockquote> @ @ <form action="%s(g.zTop)/setup_logo" method="post" @ enctype="multipart/form-data"><div> @ <p>The background image is accessible to all users at this URL: @ <a href="%s(g.zBaseURL)/background">%s(g.zBaseURL)/background</a>. @ The background image may or may not appear on each @ page depending on the <a href="setup_skinedit?w=0">CSS</a> and @ <a href="setup_skinedit?w=2">header setup</a>. @ To change the background image, use the following form:</p> login_insert_csrf_secret(); @ Background image file: @ <input type="file" name="bgim" size="60" accept="image/*" /> @ <p align="center"> @ <input type="submit" name="setbg" value="Change Background" /> @ <input type="submit" name="clrbg" value="Revert To Default" /></p> @ </div></form> @ <p>(Properties: "background-image" and "background-mimetype") @ <hr /> @ @ <p><span class="note">Note:</span> Your browser has probably cached these @ images, so you may need to press the Reload button before changes will @ take effect. </p> style_footer(); db_end_transaction(0); } /* ** Prevent the RAW SQL feature from being used to ATTACH a different ** database and query it. ** |
︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 | } /* ** WEBPAGE: admin_sql ** ** Run raw SQL commands against the database file using the web interface. | | | < | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 | } /* ** WEBPAGE: admin_sql ** ** Run raw SQL commands against the database file using the web interface. ** Requires Admin privileges. */ void sql_page(void){ const char *zQ; int go = P("go")!=0; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } add_content_sql_commands(g.db); zQ = cgi_csrf_safe(1) ? P("q") : 0; style_header("Raw SQL Commands"); @ <p><b>Caution:</b> There are no restrictions on the SQL that can be @ run by this page. You can do serious and irrepairable damage to the @ repository. Proceed with extreme caution.</p> @ #if 0 @ <p>Only the first statement in the entry box will be run. |
︙ | ︙ | |||
1866 1867 1868 1869 1870 1871 1872 | " ELSE '...' END AS value,\n" " datetime(mtime, 'unixepoch') AS mtime\n" "FROM config\n" "-- ORDER BY mtime DESC; -- optional"; go = 1; } @ | | | | | | > > | | > < | | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 | " ELSE '...' END AS value,\n" " datetime(mtime, 'unixepoch') AS mtime\n" "FROM config\n" "-- ORDER BY mtime DESC; -- optional"; go = 1; } @ @ <form method="post" action="%s(g.zTop)/admin_sql"> login_insert_csrf_secret(); @ SQL:<br /> @ <textarea name="q" rows="8" cols="80">%h(zQ)</textarea><br /> @ <input type="submit" name="go" value="Run SQL"> @ <input type="submit" name="schema" value="Show Schema"> @ <input type="submit" name="tablelist" value="List Tables"> @ <input type="submit" name="configtab" value="CONFIG Table Query"> @ </form> if( P("schema") ){ zQ = sqlite3_mprintf( "SELECT sql FROM repository.sqlite_master" " WHERE sql IS NOT NULL ORDER BY name"); go = 1; }else if( P("tablelist") ){ zQ = sqlite3_mprintf( "SELECT name FROM repository.sqlite_master WHERE type='table'" " ORDER BY name"); go = 1; } if( go ){ sqlite3_stmt *pStmt; int rc; const char *zTail; int nCol; int nRow = 0; int i; @ <hr /> login_verify_csrf_secret(); sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0); rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); if( rc!=SQLITE_OK ){ @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> sqlite3_finalize(pStmt); }else if( pStmt==0 ){ /* No-op */ }else if( (nCol = sqlite3_column_count(pStmt))==0 ){ sqlite3_step(pStmt); rc = sqlite3_finalize(pStmt); if( rc ){ @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> } }else{ @ <table border=1> while( sqlite3_step(pStmt)==SQLITE_ROW ){ if( nRow==0 ){ @ <tr> for(i=0; i<nCol; i++){ @ <th>%h(sqlite3_column_name(pStmt, i))</th> } @ </tr> |
︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 | } @ </tr> } sqlite3_finalize(pStmt); @ </table> } } | | < | > | | | | > | | < < | | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 | } @ </tr> } sqlite3_finalize(pStmt); @ </table> } } style_footer(); } /* ** WEBPAGE: admin_th1 ** ** Run raw TH1 commands using the web interface. If Tcl integration was ** enabled at compile-time and the "tcl" setting is enabled, Tcl commands ** may be run as well. Requires Admin privilege. */ void th1_page(void){ const char *zQ = P("q"); int go = P("go")!=0; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Raw TH1 Commands"); @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be @ run by this page. If Tcl integration was enabled at compile-time and @ the "tcl" setting is enabled, Tcl commands may be run as well.</p> @ @ <form method="post" action="%s(g.zTop)/admin_th1"> login_insert_csrf_secret(); @ TH1:<br /> @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br /> @ <input type="submit" name="go" value="Run TH1"> @ </form> if( go ){ const char *zR; int rc; int n; @ <hr /> login_verify_csrf_secret(); rc = Th_Eval(g.interp, 0, zQ, -1); zR = Th_GetResult(g.interp, &n); if( rc==TH_OK ){ @ <pre class="th1result">%h(zR)</pre> }else{ @ <pre class="th1error">%h(zR)</pre> } } style_footer(); } /* ** WEBPAGE: admin_log ** ** Shows the contents of the admin_log table, which is only created if ** the admin-log setting is enabled. Requires Admin or Setup ('a' or ** 's') permissions. */ void page_admin_log(){ Stmt stLog; int limit; /* How many entries to show */ int ofst; /* Offset to the first entry */ int fLogEnabled; int counter = 0; login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } style_header("Admin Log"); create_admin_log_table(); limit = atoi(PD("n","200")); ofst = atoi(PD("x","0")); fLogEnabled = db_get_boolean("admin-log", 0); @ <div>Admin logging is %s(fLogEnabled?"on":"off"). @ (Change this on the <a href="setup_settings">settings</a> page.)</div> if( ofst>0 ){ int prevx = ofst - limit; if( prevx<0 ) prevx = 0; @ <p><a href="admin_log?n=%d(limit)&x=%d(prevx)">[Newer]</a></p> } db_prepare(&stLog, "SELECT datetime(time,'unixepoch'), who, page, what " "FROM admin_log " "ORDER BY time DESC"); style_table_sorter(); @ <table class="sortable adminLogTable" width="100%%" \ @ data-column-types='Tttx' data-init-sort='1'> @ <thead> @ <th>Time</th> @ <th>User</th> @ <th>Page</th> |
︙ | ︙ | |||
2061 2062 2063 2064 2065 2066 2067 | @ </tr> } db_finalize(&stLog); @ </tbody></table> if( counter>ofst+limit ){ @ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p> } | | < < < < < < < < < < < < < < < < | < | | | | | | | | | | | | < < < < < < < < < | | < < < > < | < > | | | 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 | @ </tr> } db_finalize(&stLog); @ </tbody></table> if( counter>ofst+limit ){ @ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p> } style_footer(); } /* ** WEBPAGE: srchsetup ** ** Configure the search engine. Requires Admin privilege. */ void page_srchsetup(){ login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } style_header("Search Configuration"); @ <form action="%s(g.zTop)/srchsetup" method="post"><div> login_insert_csrf_secret(); @ <div style="text-align:center;font-weight:bold;"> @ Server-specific settings that affect the @ <a href="%R/search">/search</a> webpage. @ </div> @ <hr /> textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0); @ <p>The "Document Glob List" is a comma- or newline-separated list @ of GLOB expressions that identify all documents within the source @ tree that are to be searched when "Document Search" is enabled. @ Some examples: @ <table border=0 cellpadding=2 align=center> @ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;"> @ <td>Search all wiki, HTML, Markdown, and Text files</tr> @ <tr><td>doc/*.md,*/README.txt,README.txt<td> @ <td>Search all Markdown files in the doc/ subfolder and all README.txt @ files.</tr> @ <tr><td>*<td><td>Search all checked-in files</tr> @ <tr><td><i>(blank)</i><td> @ <td>Search nothing. (Disables document search).</tr> @ </table> @ <hr /> entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0); @ <p>When searching documents, use the versions of the files found at the @ type of the "Document Branch" branch. Recommended value: "trunk". @ Document search is disabled if blank. @ <hr /> onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0); @ <br /> onoff_attribute("Search Documents", "search-doc", "sd", 0, 0); @ <br /> onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0); @ <br /> onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0); @ <br /> onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0); @ <br /> onoff_attribute("Search Forum", "search-forum", "sf", 0, 0); @ <hr /> @ <p><input type="submit" name="submit" value="Apply Changes" /></p> @ <hr /> if( P("fts0") ){ search_drop_index(); }else if( P("fts1") ){ search_drop_index(); search_create_index(); search_fill_index(); search_update_index(search_restrict(SRCH_ALL)); } if( search_index_exists() ){ @ <p>Currently using an SQLite FTS4 search index. This makes search @ run faster, especially on large repositories, but takes up space.</p> onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index"> @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index"> }else{ @ <p>The SQLite FTS4 search index is disabled. All searching will be @ a full-text scan. This usually works fine, but can be slow for @ larger repositories.</p> onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); @ <p><input type="submit" name="fts1" value="Create A Full-Text Index"> } @ </div></form> style_footer(); } /* ** A URL Alias originally called zOldName is now zNewName/zValue. ** Write SQL to make this change into pSql. ** ** If zNewName or zValue is an empty string, then delete the entry. ** ** If zOldName is an empty string, create a new entry. */ static void setup_update_url_alias( Blob *pSql, const char *zOldName, const char *zNewName, const char *zValue ){ if( !cgi_csrf_safe(1) ) return; if( zNewName[0]==0 || zValue[0]==0 ){ if( zOldName[0] ){ blob_append_sql(pSql, "DELETE FROM config WHERE name='walias:%q';\n", zOldName); } return; |
︙ | ︙ | |||
2224 2225 2226 2227 2228 2229 2230 | ** Configure the URL aliases */ void page_waliassetup(){ Stmt q; int cnt = 0; Blob namelist; login_check_credentials(); | | < | > < < | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 | ** Configure the URL aliases */ void page_waliassetup(){ Stmt q; int cnt = 0; Blob namelist; login_check_credentials(); if( !g.perm.Setup && !g.perm.Admin ){ login_needed(0); return; } style_header("URL Alias Configuration"); if( P("submit")!=0 ){ Blob token; Blob sql; const char *zNewName; const char *zValue; char zCnt[10]; login_verify_csrf_secret(); blob_init(&namelist, PD("namelist",""), -1); blob_init(&sql, 0, 0); while( blob_token(&namelist, &token) ){ const char *zOldName = blob_str(&token); sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt); zNewName = PD(zCnt, ""); sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt); zValue = PD(zCnt, ""); setup_update_url_alias(&sql, zOldName, zNewName, zValue); cnt++; blob_reset(&token); } sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt); zNewName = PD(zCnt,""); sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt); zValue = PD(zCnt,""); setup_update_url_alias(&sql, "", zNewName, zValue); db_multi_exec("%s", blob_sql_text(&sql)); blob_reset(&sql); blob_reset(&namelist); cnt = 0; } db_prepare(&q, "SELECT substr(name,8), value FROM config WHERE name GLOB 'walias:/*'" " UNION ALL SELECT '', ''" ); @ <form action="%s(g.zTop)/waliassetup" method="post"><div> login_insert_csrf_secret(); @ <table border=0 cellpadding=5> @ <tr><th>Alias<th>URI That The Alias Maps Into blob_init(&namelist, 0, 0); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zValue = db_column_text(&q, 1); |
︙ | ︙ | |||
2327 2328 2329 2330 2331 2332 2333 | @ </ul> @ @ <p>To delete an entry from the alias table, change its name or value to an @ empty string and press "Apply Changes". @ @ <p>To add a new alias, fill in the name and value in the bottom row @ of the table above and press "Apply Changes". | | | 1688 1689 1690 1691 1692 1693 1694 1695 1696 | @ </ul> @ @ <p>To delete an entry from the alias table, change its name or value to an @ empty string and press "Apply Changes". @ @ <p>To add a new alias, fill in the name and value in the bottom row @ of the table above and press "Apply Changes". style_footer(); } |
Changes to src/setupuser.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Setup pages associated with user management. The code in this ** file was formerly part of the "setup.c" module, but has been broken ** out into its own module to improve maintainability. | < < < < < < < < < < | | 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 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Setup pages associated with user management. The code in this ** file was formerly part of the "setup.c" module, but has been broken ** out into its own module to improve maintainability. */ #include "config.h" #include <assert.h> #include "setupuser.h" /* ** WEBPAGE: setup_ulist ** ** Show a list of users. Clicking on any user jumps to the edit ** screen for that user. Requires Admin privileges. ** ** Query parameters: ** ** with=CAP Only show users that have one or more capabilities in CAP. */ void setup_ulist(void){ Stmt s; double rNow; const char *zWith = P("with"); login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } style_submenu_element("Add", "setup_uedit"); style_submenu_element("Log", "access_log"); style_submenu_element("Help", "setup_ulist_notes"); style_header("User List"); if( zWith==0 || zWith[0]==0 ){ @ <table border=1 cellpadding=2 cellspacing=0 class='userTable'> @ <thead><tr> @ <th>Category @ <th>Capabilities (<a href='%R/setup_ucap_list'>key</a>) @ <th>Info <th>Last Change</tr></thead> @ <tbody> db_prepare(&s, |
︙ | ︙ | |||
99 100 101 102 103 104 105 | @ </tr> } db_finalize(&s); @ </tbody></table> @ <div class='section'>Users</div> }else{ style_submenu_element("All Users", "setup_ulist"); | < < < | | | | | | < < < < | | < < < < < < < < < < < < < < < | | | < < < < < < < | < < < < < < < < < | < | 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 | @ </tr> } db_finalize(&s); @ </tbody></table> @ <div class='section'>Users</div> }else{ style_submenu_element("All Users", "setup_ulist"); if( zWith[1]==0 ){ @ <div class='section'>Users with capability "%h(zWith)"</div> }else{ @ <div class='section'>Users with any capability in "%h(zWith)"</div> } } @ <table border=1 cellpadding=2 cellspacing=0 class='userTable sortable' \ @ data-column-types='ktxTTK' data-init-sort='2'> @ <thead><tr> @ <th>Login Name<th>Caps<th>Info<th>Date<th>Expire<th>Last Login</tr></thead> @ <tbody> db_multi_exec( "CREATE TEMP TABLE lastAccess(uname TEXT PRIMARY KEY, atime REAL)" "WITHOUT ROWID;" ); if( db_table_exists("repository","accesslog") ){ db_multi_exec( "INSERT INTO lastAccess(uname, atime)" " SELECT uname, max(mtime) FROM (" " SELECT uname, mtime FROM accesslog WHERE success" " UNION ALL" " SELECT login AS uname, rcvfrom.mtime AS mtime" " FROM rcvfrom JOIN user USING(uid))" " GROUP BY 1;" ); } if( zWith && zWith[0] ){ zWith = mprintf(" AND fullcap(cap) GLOB '*[%q]*'", zWith); }else{ zWith = ""; } db_prepare(&s, "SELECT uid, login, cap, info, date(mtime,'unixepoch')," " lower(login) AS sortkey, " " CASE WHEN info LIKE '%%expires 20%%'" " THEN substr(info,instr(lower(info),'expires')+8,10)" " END AS exp," "atime" " FROM user LEFT JOIN lastAccess ON login=uname" " WHERE login NOT IN ('anonymous','nobody','developer','reader') %s" " ORDER BY sortkey", zWith/*safe-for-%s*/ ); rNow = db_double(0.0, "SELECT julianday('now');"); while( db_step(&s)==SQLITE_ROW ){ int uid = db_column_int(&s, 0); const char *zLogin = db_column_text(&s, 1); const char *zCap = db_column_text(&s, 2); const char *zInfo = db_column_text(&s, 3); const char *zDate = db_column_text(&s, 4); const char *zSortKey = db_column_text(&s,5); const char *zExp = db_column_text(&s,6); double rATime = db_column_double(&s,7); char *zAge = 0; if( rATime>0.0 ){ zAge = human_readable_age(rNow - rATime); } @ <tr> @ <td data-sortkey='%h(zSortKey)'>\ @ <a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a> @ <td>%h(zCap) @ <td>%h(zInfo) @ <td>%h(zDate?zDate:"") @ <td>%h(zExp?zExp:"") @ <td data-sortkey='%f(rATime)' style='white-space:nowrap'>%s(zAge?zAge:"") @ </tr> fossil_free(zAge); } @ </tbody></table> db_finalize(&s); style_table_sorter(); style_footer(); } /* ** WEBPAGE: setup_ulist_notes ** ** A documentation page showing notes about user configuration. This ** information used to be a side-bar on the user list page, but has been ** factored out for improved presentation. */ void setup_ulist_notes(void){ style_header("User Configuration Notes"); @ <h1>User Configuration Notes:</h1> @ <ol> @ <li><p> @ Every user, logged in or not, inherits the privileges of @ <span class="usertype">nobody</span>. @ </p></li> |
︙ | ︙ | |||
254 255 256 257 258 259 260 | @ <span class="usertype">nobody</span>. @ </p></li> @ @ <li><p>The permission flags are as follows:</p> capabilities_table(CAPCLASS_ALL); @ </li> @ </ol> | | < | | 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 | @ <span class="usertype">nobody</span>. @ </p></li> @ @ <li><p>The permission flags are as follows:</p> capabilities_table(CAPCLASS_ALL); @ </li> @ </ol> style_footer(); } /* ** WEBPAGE: setup_ucap_list ** ** A documentation page showing the meaning of the various user capabilities ** code letters. */ void setup_ucap_list(void){ style_header("User Capability Codes"); @ <h1>All capabilities</h1> capabilities_table(CAPCLASS_ALL); @ <h1>Capabilities associated with checked-in content</h1> capabilities_table(CAPCLASS_CODE); @ <h1>Capabilities associated with data transfer and sync</h1> capabilities_table(CAPCLASS_DATA); @ <h1>Capabilities associated with the forum</h1> capabilities_table(CAPCLASS_FORUM); @ <h1>Capabilities associated with tickets</h1> capabilities_table(CAPCLASS_TKT); @ <h1>Capabilities associated with wiki</h1> capabilities_table(CAPCLASS_WIKI); @ <h1>Administrative capabilities</h1> capabilities_table(CAPCLASS_SUPER); @ <h1>Miscellaneous capabilities</h1> capabilities_table(CAPCLASS_OTHER); style_footer(); } /* ** Return true if zPw is a valid password string. A valid ** password string is: ** ** (1) A zero-length string, or |
︙ | ︙ | |||
340 341 342 343 344 345 346 | if( P("can") ){ /* User pressed the cancel button */ cgi_redirect(cgi_referer("setup_ulist")); return; } /* Check for requests to delete the user */ | | < < < < < < < < < < < < | | | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | if( P("can") ){ /* User pressed the cancel button */ cgi_redirect(cgi_referer("setup_ulist")); return; } /* Check for requests to delete the user */ if( P("delete") && cgi_csrf_safe(1) ){ int n; if( P("verifydelete") ){ /* Verified delete user request */ db_multi_exec("DELETE FROM user WHERE uid=%d", uid); cgi_redirect(cgi_referer("setup_ulist")); return; } n = db_int(0, "SELECT count(*) FROM event" " WHERE user=%Q AND objid NOT IN private", P("login")); if( n==0 ){ zDeleteVerify = mprintf("Check this box and press \"Delete User\" again"); }else{ zDeleteVerify = mprintf( "User \"%s\" has %d or more artifacts in the block-chain. " "Delete anyhow?", P("login")/*safe-for-%s*/, n); } } /* If we have all the necessary information, write the new or ** modified user record. After writing the user record, redirect ** to the page that displays a list of users. */ if( !cgi_all("login","info","pw","apply") ){ /* need all of the above properties to make a change. Since one or ** more are missing, no-op */ }else if( higherUser ){ /* An Admin (a) user cannot edit a Superuser (s) */ }else if( zDeleteVerify!=0 ){ /* Need to verify a delete request */ }else if( !cgi_csrf_safe(1) ){ /* This might be a cross-site request forgery, so ignore it */ }else{ /* We have all the information we need to make the change to the user */ char c; char zCap[70], zNm[4]; zNm[0] = 'a'; zNm[2] = 0; for(i=0, c='a'; c<='z'; c++){ zNm[1] = c; a[c&0x7f] = (c!='s' || g.perm.Setup) && P(zNm)!=0; if( a[c&0x7f] ) zCap[i++] = c; } for(c='0'; c<='9'; c++){ zNm[1] = c; a[c&0x7f] = P(zNm)!=0; if( a[c&0x7f] ) zCap[i++] = c; } |
︙ | ︙ | |||
418 419 420 421 422 423 424 | if( strlen(zLogin)==0 ){ const char *zRef = cgi_referer("setup_ulist"); style_header("User Creation Error"); @ <span class="loginError">Empty login not allowed.</span> @ @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> @ [Bummer]</a></p> | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | if( strlen(zLogin)==0 ){ const char *zRef = cgi_referer("setup_ulist"); style_header("User Creation Error"); @ <span class="loginError">Empty login not allowed.</span> @ @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> @ [Bummer]</a></p> style_footer(); return; } if( isValidPwString(zPw) ){ zPw = sha1_shared_secret(zPw, zLogin, 0); }else{ zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid); } zOldLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid); if( db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d",zLogin,uid) ){ const char *zRef = cgi_referer("setup_ulist"); style_header("User Creation Error"); @ <span class="loginError">Login "%h(zLogin)" is already used by @ a different user.</span> @ @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> @ [Bummer]</a></p> style_footer(); return; } login_verify_csrf_secret(); db_multi_exec( "REPLACE INTO user(uid,login,info,pw,cap,mtime) " "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())", uid, zLogin, P("info"), zPw, zCap ); setup_incr_cfgcnt(); admin_log( "Updated user [%q] with capabilities [%q].", zLogin, zCap ); if( atoi(PD("all","0"))>0 ){ Blob sql; char *zErr = 0; blob_zero(&sql); if( zOldLogin==0 ){ blob_appendf(&sql, "INSERT INTO user(login)" " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);", zLogin, zLogin ); zOldLogin = zLogin; } blob_appendf(&sql, "UPDATE user SET login=%Q," " pw=coalesce(shared_secret(%Q,%Q," "(SELECT value FROM config WHERE name='project-code')),pw)," " info=%Q," " cap=%Q," " mtime=now()" " WHERE login=%Q;", zLogin, P("pw"), zLogin, P("info"), zCap, zOldLogin ); login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr); blob_reset(&sql); admin_log( "Updated user [%q] in all login groups " "with capabilities [%q].", zLogin, zCap ); if( zErr ){ const char *zRef = cgi_referer("setup_ulist"); style_header("User Change Error"); admin_log( "Error updating user '%q': %s'.", zLogin, zErr ); @ <span class="loginError">%h(zErr)</span> @ @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> @ [Bummer]</a></p> style_footer(); return; } } cgi_redirect(cgi_referer("setup_ulist")); return; } |
︙ | ︙ | |||
584 585 586 587 588 589 590 | } /* Begin generating the page */ style_submenu_element("Cancel", "%s", cgi_referer("setup_ulist")); if( uid ){ style_header("Edit User %h", zLogin); | < | < < | < | < | < | < | < < < < < < < < < | | < | | | | | < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < | < < | < | | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | } /* Begin generating the page */ style_submenu_element("Cancel", "%s", cgi_referer("setup_ulist")); if( uid ){ style_header("Edit User %h", zLogin); style_submenu_element("Access Log", "%R/access_log?u=%t", zLogin); }else{ style_header("Add A New User"); } @ <div class="ueditCapBox"> @ <form action="%s(g.zPath)" method="post"><div> login_insert_csrf_secret(); if( login_is_special(zLogin) ){ @ <input type="hidden" name="login" value="%s(zLogin)"> @ <input type="hidden" name="info" value=""> @ <input type="hidden" name="pw" value="*"> } @ <input type="hidden" name="referer" value="%h(cgi_referer("setup_ulist"))"> @ <table width="100%%"> @ <tr> @ <td class="usetupEditLabel">User ID:</td> if( uid ){ @ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td> }else{ @ <td>(new user)<input type="hidden" name="id" value="0" /></td> } @ </tr> @ <tr> @ <td class="usetupEditLabel">Login:</td> if( login_is_special(zLogin) ){ @ <td><b>%h(zLogin)</b></td> }else{ @ <td><input type="text" name="login" value="%h(zLogin)" /></td> @ </tr> @ <tr> @ <td class="usetupEditLabel">Contact Info:</td> @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td> } @ </tr> @ <tr> @ <td class="usetupEditLabel">Capabilities:</td> @ <td width="100%%"> #define B(x) inherit[x] @ <div class="columns" style="column-width:13em;"> @ <ul style="list-style-type: none;"> if( g.perm.Setup ){ @ <li><label><input type="checkbox" name="as"%s(oa['s']) /> @ Setup%s(B('s'))</label> } @ <li><label><input type="checkbox" name="aa"%s(oa['a']) /> @ Admin%s(B('a'))</label> @ <li><label><input type="checkbox" name="au"%s(oa['u']) /> @ Reader%s(B('u'))</label> @ <li><label><input type="checkbox" name="av"%s(oa['v']) /> @ Developer%s(B('v'))</label> @ <li><label><input type="checkbox" name="ad"%s(oa['d']) /> @ Delete%s(B('d'))</label> @ <li><label><input type="checkbox" name="ae"%s(oa['e']) /> @ View-PII%s(B('e'))</label> @ <li><label><input type="checkbox" name="ap"%s(oa['p']) /> @ Password%s(B('p'))</label> @ <li><label><input type="checkbox" name="ai"%s(oa['i']) /> @ Check-In%s(B('i'))</label> @ <li><label><input type="checkbox" name="ao"%s(oa['o']) /> @ Check-Out%s(B('o'))</label> @ <li><label><input type="checkbox" name="ah"%s(oa['h']) /> @ Hyperlinks%s(B('h'))</label> @ <li><label><input type="checkbox" name="ab"%s(oa['b']) /> @ Attachments%s(B('b'))</label> @ <li><label><input type="checkbox" name="ag"%s(oa['g']) /> @ Clone%s(B('g'))</label> @ <li><label><input type="checkbox" name="aj"%s(oa['j']) /> @ Read Wiki%s(B('j'))</label> @ <li><label><input type="checkbox" name="af"%s(oa['f']) /> @ New Wiki%s(B('f'))</label> @ <li><label><input type="checkbox" name="am"%s(oa['m']) /> @ Append Wiki%s(B('m'))</label> @ <li><label><input type="checkbox" name="ak"%s(oa['k']) /> @ Write Wiki%s(B('k'))</label> @ <li><label><input type="checkbox" name="al"%s(oa['l']) /> @ Moderate Wiki%s(B('l'))</label> @ <li><label><input type="checkbox" name="ar"%s(oa['r']) /> @ Read Ticket%s(B('r'))</label> @ <li><label><input type="checkbox" name="an"%s(oa['n']) /> @ New Tickets%s(B('n'))</label> @ <li><label><input type="checkbox" name="ac"%s(oa['c']) /> @ Append To Ticket%s(B('c'))</label> @ <li><label><input type="checkbox" name="aw"%s(oa['w']) /> @ Write Tickets%s(B('w'))</label> @ <li><label><input type="checkbox" name="aq"%s(oa['q']) /> @ Moderate Tickets%s(B('q'))</label> @ <li><label><input type="checkbox" name="at"%s(oa['t']) /> @ Ticket Report%s(B('t'))</label> @ <li><label><input type="checkbox" name="ax"%s(oa['x']) /> @ Private%s(B('x'))</label> @ <li><label><input type="checkbox" name="ay"%s(oa['y']) /> @ Write Unversioned%s(B('y'))</label> @ <li><label><input type="checkbox" name="az"%s(oa['z']) /> @ Download Zip%s(B('z'))</label> @ <li><label><input type="checkbox" name="a2"%s(oa['2']) /> @ Read Forum%s(B('2'))</label> @ <li><label><input type="checkbox" name="a3"%s(oa['3']) /> @ Write Forum%s(B('3'))</label> @ <li><label><input type="checkbox" name="a4"%s(oa['4']) /> @ WriteTrusted Forum%s(B('4'))</label> @ <li><label><input type="checkbox" name="a5"%s(oa['5']) /> @ Moderate Forum%s(B('5'))</label> @ <li><label><input type="checkbox" name="a6"%s(oa['6']) /> @ Supervise Forum%s(B('6'))</label> @ <li><label><input type="checkbox" name="a7"%s(oa['7']) /> @ Email Alerts%s(B('7'))</label> @ <li><label><input type="checkbox" name="aA"%s(oa['A']) /> @ Send Announcements%s(B('A'))</label> @ <li><label><input type="checkbox" name="aD"%s(oa['D']) /> @ Enable Debug%s(B('D'))</label> @ </ul></div> @ </td> @ </tr> @ <tr> @ <td class="usetupEditLabel">Selected Cap:</td> @ <td> @ <span id="usetupEditCapability">(missing JS?)</span> @ <a href="%R/setup_ucap_list">(key)</a> @ </td> @ </tr> if( !login_is_special(zLogin) ){ @ <tr> @ <td align="right">Password:</td> if( zPw[0] ){ /* Obscure the password for all users */ @ <td><input type="password" name="pw" value="**********" /></td> }else{ /* Show an empty password as an empty input field */ @ <td><input type="password" name="pw" value="" /></td> } @ </tr> } zGroup = login_group_name(); if( zGroup ){ @ <tr> @ <td valign="top" align="right">Scope:</td> @ <td valign="top"> @ <input type="radio" name="all" checked value="0"> @ Apply changes to this repository only.<br /> @ <input type="radio" name="all" value="1"> @ Apply changes to all repositories in the "<b>%h(zGroup)</b>" @ login group.</td></tr> } if( !higherUser ){ if( zDeleteVerify ){ @ <tr> |
︙ | ︙ | |||
774 775 776 777 778 779 780 | } @ <input type="submit" name="can" value="Cancel"></td> @ </tr> } @ </table> @ </div></form> @ </div> | | | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 | } @ <input type="submit" name="can" value="Cancel"></td> @ </tr> } @ </table> @ </div></form> @ </div> style_load_one_js_file("useredit.js"); @ <hr> @ <h1>Notes On Privileges And Capabilities:</h1> @ <ul> if( higherUser ){ @ <li><p class="missingPriv"> @ User %h(zLogin) has Setup privileges and you only have Admin privileges @ so you are not permitted to make changes to %h(zLogin). |
︙ | ︙ | |||
808 809 810 811 812 813 814 | @ subscript suffix @ indicates the privileges of <span class="usertype">anonymous</span> that @ are inherited by all logged-in users. @ </p></li> @ @ <li><p> @ The "<span class="ueditInheritDeveloper"><sub>D</sub></span>" | | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | @ subscript suffix @ indicates the privileges of <span class="usertype">anonymous</span> that @ are inherited by all logged-in users. @ </p></li> @ @ <li><p> @ The "<span class="ueditInheritDeveloper"><sub>D</sub></span>" @ subscript suffix indicates the privileges of @ <span class="usertype">developer</span> that @ are inherited by all users with the @ <span class="capability">Developer</span> privilege. @ </p></li> @ @ <li><p> @ The "<span class="ueditInheritReader"><sub>R</sub></span>" subscript suffix |
︙ | ︙ | |||
935 936 937 938 939 940 941 | @ <span class="usertype">developer</span> @ user. Similarly, the <span class="usertype">reader</span> user is a @ template for users who are allowed more access than @ <span class="usertype">anonymous</span>, @ but less than a <span class="usertype">developer</span>. @ </p></li> @ </ul> | | | 821 822 823 824 825 826 827 828 829 | @ <span class="usertype">developer</span> @ user. Similarly, the <span class="usertype">reader</span> user is a @ template for users who are allowed more access than @ <span class="usertype">anonymous</span>, @ but less than a <span class="usertype">developer</span>. @ </p></li> @ </ul> style_footer(); } |
Changes to src/sha1.c.
︙ | ︙ | |||
30 31 32 33 34 35 36 | ** ** Downloaded on 2017-03-01 then repackaged to work with Fossil ** and makeheaders. */ #if FOSSIL_HARDENED_SHA1 #if INTERFACE | | < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ** ** Downloaded on 2017-03-01 then repackaged to work with Fossil ** and makeheaders. */ #if FOSSIL_HARDENED_SHA1 #if INTERFACE typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); struct SHA1_CTX { uint64_t total; uint32_t ihv[5]; unsigned char buffer[64]; int bigendian; int found_collision; int safe_hash; |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* | > > > > > > > > > > > > > > > > > > > | 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 | /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #endif #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* |
︙ | ︙ | |||
275 276 277 278 279 280 281 | *zBuf++ = zEncode[(*digest>>4)&0xf]; *zBuf++ = zEncode[*digest++ & 0xf]; } *zBuf = '\0'; } /* | | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | *zBuf++ = zEncode[(*digest>>4)&0xf]; *zBuf++ = zEncode[*digest++ & 0xf]; } *zBuf = '\0'; } /* ** The state of a incremental SHA1 checksum computation. Only one ** such computation can be underway at a time, of course. */ static SHA1Context incrCtx; static int incrInit = 0; /* ** Add more text to the incremental SHA1 checksum. |
︙ | ︙ | |||
392 393 394 395 396 397 398 | } blob_resize(pCksum, 40); SHA1Final(zResult, &ctx); DigestToBase16(zResult, blob_buffer(pCksum)); return 0; } | < < < < < < < < < < < < < | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | } blob_resize(pCksum, 40); SHA1Final(zResult, &ctx); DigestToBase16(zResult, blob_buffer(pCksum)); return 0; } /* ** Compute the SHA1 checksum of a zero-terminated string. The ** result is held in memory obtained from mprintf(). */ char *sha1sum(const char *zIn){ SHA1Context ctx; unsigned char zResult[20]; |
︙ | ︙ | |||
513 514 515 516 517 518 519 | /* ** COMMAND: sha1sum* ** ** Usage: %fossil sha1sum FILE... ** ** Compute an SHA1 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. | < > | | | | < < | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | /* ** COMMAND: sha1sum* ** ** Usage: %fossil sha1sum FILE... ** ** Compute an SHA1 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. ** Options: ** ** -h, --dereference If FILE is a symbolic link, compute the hash ** on the object that the link points to. Normally, ** the hash is over the name of the object that ** the link points to. */ void sha1sum_test(void){ int i; Blob in; Blob cksum; int eFType = SymFILE; if( find_option("dereference","h",0)!=0 ){ |
︙ | ︙ |
Changes to src/sha1hard.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | void sha1_message_expansion(uint32_t W[80]); void sha1_compression(uint32_t ihv[5], const uint32_t m[16]); void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]); void sha1_compression_states(uint32_t ihv[5], const uint32_t W[80], uint32_t states[80][5]); extern sha1_recompression_type sha1_recompression_step[80]; typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); typedef struct { | | | | | | | | | | | | | | | | | 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 | void sha1_message_expansion(uint32_t W[80]); void sha1_compression(uint32_t ihv[5], const uint32_t m[16]); void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]); void sha1_compression_states(uint32_t ihv[5], const uint32_t W[80], uint32_t states[80][5]); extern sha1_recompression_type sha1_recompression_step[80]; typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); typedef struct { uint64_t total; uint32_t ihv[5]; unsigned char buffer[64]; int bigendian; int found_collision; int safe_hash; int detect_coll; int ubc_check; int reduced_round_coll; collision_block_callback callback; uint32_t ihv1[5]; uint32_t ihv2[5]; uint32_t m1[80]; uint32_t m2[80]; uint32_t states[80][5]; } SHA1_CTX; /******************** File: lib/ubc_check.c **************************/ /*** * Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com> * Distributed under the MIT Software License. * See accompanying file LICENSE.txt or copy at |
︙ | ︙ |
Changes to src/sha3.c.
︙ | ︙ | |||
414 415 416 417 418 419 420 | static void SHA3Update( SHA3Context *p, const unsigned char *aData, unsigned int nData ){ unsigned int i = 0; #if SHA3_BYTEORDER==1234 | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | static void SHA3Update( SHA3Context *p, const unsigned char *aData, unsigned int nData ){ unsigned int i = 0; #if SHA3_BYTEORDER==1234 if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ for(; i+7<nData; i+=8){ p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; p->nLoaded += 8; if( p->nLoaded>=p->nRate ){ KeccakF1600Step(p); p->nLoaded = 0; } |
︙ | ︙ | |||
482 483 484 485 486 487 488 | *zBuf++ = zEncode[(*digest>>4)&0xf]; *zBuf++ = zEncode[*digest++ & 0xf]; } *zBuf = '\0'; } /* | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | *zBuf++ = zEncode[(*digest>>4)&0xf]; *zBuf++ = zEncode[*digest++ & 0xf]; } *zBuf = '\0'; } /* ** The state of a incremental SHA3 checksum computation. Only one ** such computation can be underway at a time, of course. */ static SHA3Context incrCtx; static int incrInit = 0; /* ** Initialize a new global SHA3 hash. |
︙ | ︙ | |||
626 627 628 629 630 631 632 633 634 635 636 637 638 | ** Compute an SHA3 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. ** ** To be clear: The official NIST FIPS-202 implementation of SHA3 ** with the added 01 padding is used, not the original Keccak submission. ** ** Options: ** --224 Compute a SHA3-224 hash ** --256 Compute a SHA3-256 hash (the default) ** --384 Compute a SHA3-384 hash ** --512 Compute a SHA3-512 hash ** --size N An N-bit hash. N must be a multiple of 32 between ** 128 and 512. | > | < < | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | ** Compute an SHA3 checksum of all files named on the command-line. ** If a file is named "-" then take its content from standard input. ** ** To be clear: The official NIST FIPS-202 implementation of SHA3 ** with the added 01 padding is used, not the original Keccak submission. ** ** Options: ** ** --224 Compute a SHA3-224 hash ** --256 Compute a SHA3-256 hash (the default) ** --384 Compute a SHA3-384 hash ** --512 Compute a SHA3-512 hash ** --size N An N-bit hash. N must be a multiple of 32 between ** 128 and 512. ** -h, --dereference If FILE is a symbolic link, compute the hash on ** the object pointed to, not on the link itself. */ void sha3sum_test(void){ int i; Blob in; Blob cksum; int iSize = 256; int eFType = SymFILE; if( find_option("dereference","h",0) ) eFType = ExtFILE; if( find_option("224",0,0)!=0 ) iSize = 224; else if( find_option("256",0,0)!=0 ) iSize = 256; else if( find_option("384",0,0)!=0 ) iSize = 384; |
︙ | ︙ | |||
662 663 664 665 666 667 668 669 670 671 | } iSize = n; } } verify_all_options(); for(i=2; i<g.argc; i++){ if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){ blob_read_from_channel(&in, stdin, -1); sha3sum_blob(&in, iSize, &cksum); | > > | < | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | } iSize = n; } } verify_all_options(); for(i=2; i<g.argc; i++){ blob_init(&cksum, "************** not found ***************", -1); if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){ blob_read_from_channel(&in, stdin, -1); sha3sum_blob(&in, iSize, &cksum); }else{ sha3sum_file(g.argv[i], eFType, iSize, &cksum); } fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]); blob_reset(&cksum); } } |
Added src/shell.c.
more than 10,000 changes
Changes to src/shun.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | void shun_page(void){ Stmt q; int cnt = 0; const char *zUuid = P("uuid"); const char *zShun = P("shun"); const char *zAccept = P("accept"); const char *zRcvid = P("rcvid"); | < | | 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 | void shun_page(void){ Stmt q; int cnt = 0; const char *zUuid = P("uuid"); const char *zShun = P("shun"); const char *zAccept = P("accept"); const char *zRcvid = P("rcvid"); int nRcvid = 0; int numRows = 3; char *zCanonical = 0; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } if( P("rebuild") ){ db_close(1); db_open_repository(g.zRepositoryName); db_begin_transaction(); rebuild_db(0, 0, 0); admin_log("Rebuilt database."); db_end_transaction(0); } if( zUuid ){ char *p; int i = 0; int j = 0; |
︙ | ︙ | |||
84 85 86 87 88 89 90 | } i++; } zCanonical[j+1] = zCanonical[j] = 0; p = zCanonical; while( *p ){ int nUuid = strlen(p); | | | > | | | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < | < | < | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | } i++; } zCanonical[j+1] = zCanonical[j] = 0; p = zCanonical; while( *p ){ int nUuid = strlen(p); if( !hname_validate(p, nUuid) ){ @ <p class="generalError">Error: Bad artifact IDs.</p> fossil_free(zCanonical); zCanonical = 0; break; }else{ canonical16(p, nUuid); p += nUuid+1; } } zUuid = zCanonical; } style_header("Shunned Artifacts"); if( zUuid && P("sub") ){ const char *p = zUuid; int allExist = 1; login_verify_csrf_secret(); while( *p ){ db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p); if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){ allExist = 0; } admin_log("Unshunned %Q", p); p += strlen(p)+1; } if( allExist ){ @ <p class="noMoreShun">Artifact(s)<br /> for( p = zUuid ; *p ; p += strlen(p)+1 ){ @ <a href="%R/artifact/%s(p)">%s(p)</a><br /> } @ are no longer being shunned.</p> }else{ @ <p class="noMoreShun">Artifact(s)<br /> for( p = zUuid ; *p ; p += strlen(p)+1 ){ @ %s(p)<br /> } @ will no longer be shunned. But they may not exist in the repository. @ It may be necessary to rebuild the repository using the @ <b>fossil rebuild</b> command-line before the artifact content @ can pulled in from other repositories.</p> } } if( zUuid && P("add") ){ const char *p = zUuid; int rid, tagid; login_verify_csrf_secret(); while( *p ){ db_multi_exec( "INSERT OR IGNORE INTO shun(uuid,mtime)" " VALUES(%Q, now())", p); db_multi_exec("DELETE FROM attachment WHERE src=%Q", p); rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", p); if( rid ){ db_multi_exec("DELETE FROM event WHERE objid=%d", rid); } tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", p); if( tagid ){ db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p); db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); } admin_log("Shunned %Q", p); p += strlen(p)+1; } @ <p class="shunned">Artifact(s)<br /> for( p = zUuid ; *p ; p += strlen(p)+1 ){ @ <a href="%R/artifact/%s(p)">%s(p)</a><br /> } @ have been shunned. They will no longer be pushed. @ They will be removed from the repository the next time the repository @ is rebuilt using the <b>fossil rebuild</b> command-line</p> } if( zRcvid ){ nRcvid = atoi(zRcvid); numRows = db_int(0, "SELECT min(count(), 10) FROM blob WHERE rcvid=%d", nRcvid); } @ <p>A shunned artifact will not be pushed nor accepted in a pull and the @ artifact content will be purged from the repository the next time the @ repository is rebuilt. A list of shunned artifacts can be seen at the @ bottom of this page.</p> @ @ <a name="addshun"></a> @ <p>To shun artifacts, enter their artifact hashes (the 40- or @ 64-character lowercase hexadecimal hash of the artifact content) in the @ following box and press the "Shun" button. This will cause the artifacts @ to be removed from the repository and will prevent the artifacts from being @ readded to the repository by subsequent sync operation.</p> @ @ <p>Note that you must enter the full 40- or 64-character artifact hashes, @ not an abbreviation or a symbolic tag.</p> @ @ <p>Warning: Shunning should only be used to remove inappropriate content @ from the repository. Inappropriate content includes such things as @ spam added to Wiki, files that violate copyright or patent agreements, @ or artifacts that by design or accident interfere with the processing @ of the repository. Do not shun artifacts merely to remove them from @ sight - set the "hidden" tag on such artifacts instead.</p> @ @ <blockquote> @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid"> if( zShun ){ if( strlen(zShun) ){ @ %h(zShun) }else if( nRcvid ){ db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid); while( db_step(&q)==SQLITE_ROW ){ @ %s(db_column_text(&q, 0)) } db_finalize(&q); } } @ </textarea> @ <input type="submit" name="add" value="Shun" /> @ </div></form> @ </blockquote> @ @ <a name="delshun"></a> @ <p>Enter the UUIDs of previously shunned artifacts to cause them to be @ accepted again in the repository. The artifacts content is not @ restored because the content is unknown. The only change is that @ the formerly shunned artifacts will be accepted on subsequent sync @ operations.</p> @ @ <blockquote> @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid"> if( zAccept ){ if( strlen(zAccept) ){ @ %h(zAccept) }else if( nRcvid ){ db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid); while( db_step(&q)==SQLITE_ROW ){ @ %s(db_column_text(&q, 0)) } db_finalize(&q); } } @ </textarea> @ <input type="submit" name="sub" value="Accept" /> @ </div></form> @ </blockquote> @ @ <p>Press the Rebuild button below to rebuild the repository. The @ content of newly shunned artifacts is not purged until the repository @ is rebuilt. On larger repositories, the rebuild may take minute or @ two, so be patient after pressing the button.</p> @ @ <blockquote> @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <input type="submit" name="rebuild" value="Rebuild" /> @ </div></form> @ </blockquote> @ @ <hr /><p>Shunned Artifacts:</p> @ <blockquote><p> db_prepare(&q, "SELECT uuid, EXISTS(SELECT 1 FROM blob WHERE blob.uuid=shun.uuid)" " FROM shun ORDER BY uuid"); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); int stillExists = db_column_int(&q, 1); cnt++; if( stillExists ){ @ <b><a href="%R/artifact/%s(zUuid)">%s(zUuid)</a></b><br /> }else{ @ <b>%s(zUuid)</b><br /> } } if( cnt==0 ){ @ <i>no artifacts are shunned on this server</i> } db_finalize(&q); @ </p></blockquote> style_footer(); fossil_free(zCanonical); } /* ** Remove from the BLOB table all artifacts that are in the SHUN table. */ void shun_artifacts(void){ |
︙ | ︙ | |||
372 373 374 375 376 377 378 | login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } style_header("Artifact Receipts"); | < | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } style_header("Artifact Receipts"); if( showAll ){ ofst = 0; }else{ style_submenu_element("All", "rcvfromlist?all=1"); } if( ofst>0 ){ style_submenu_element("Newer", "rcvfromlist?ofst=%d", |
︙ | ︙ | |||
438 439 440 441 442 443 444 | while( db_step(&q)==SQLITE_ROW ){ int rcvid = db_column_int(&q, 0); const char *zUser = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); const char *zIpAddr = db_column_text(&q, 3); int usesSha1 = db_column_int(&q, 5)!=0; int usesSha3 = db_column_int(&q, 6)!=0; | | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | while( db_step(&q)==SQLITE_ROW ){ int rcvid = db_column_int(&q, 0); const char *zUser = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); const char *zIpAddr = db_column_text(&q, 3); int usesSha1 = db_column_int(&q, 5)!=0; int usesSha3 = db_column_int(&q, 6)!=0; static const char *zHashType[] = { "", "sha1", "sha3", "both" }; const char *zHash = zHashType[usesSha1+usesSha3*2]; if( cnt==perScreen && !showAll ){ style_submenu_element("Older", "rcvfromlist?ofst=%d", ofst+perScreen); }else{ cnt++; @ <tr> if( db_column_int(&q,4) ){ |
︙ | ︙ | |||
460 461 462 463 464 465 466 | @ <td style="padding-right: 15px;text-align: left;">%s(zHash)</td> @ <td style="text-align: left;">%s(zIpAddr)</td> @ </tr> } } db_finalize(&q); @ </table> | | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | @ <td style="padding-right: 15px;text-align: left;">%s(zHash)</td> @ <td style="text-align: left;">%s(zIpAddr)</td> @ </tr> } } db_finalize(&q); @ </table> style_footer(); } /* ** WEBPAGE: rcvfrom ** ** Show a single RCVFROM table entry identified by the rcvid= query ** parameters. Requires Admin privilege. |
︙ | ︙ | |||
535 536 537 538 539 540 541 | if( zDesc==0 ) zDesc = ""; if( cnt==0 ){ @ <tr><th valign="top" align="right">Artifacts:</th> @ <td valign="top"> } cnt++; @ <a href="%R/info/%s(zUuid)">%s(zUuid)</a> | | | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | if( zDesc==0 ) zDesc = ""; if( cnt==0 ){ @ <tr><th valign="top" align="right">Artifacts:</th> @ <td valign="top"> } cnt++; @ <a href="%R/info/%s(zUuid)">%s(zUuid)</a> @ %h(zDesc) (size: %d(size))<br /> } if( cnt>0 ){ @ <p> if( db_exists( "SELECT 1 FROM blob WHERE rcvid=%d AND" " NOT EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) ){ |
︙ | ︙ | |||
585 586 587 588 589 590 591 | int isDeleted = zHash==0; if( cnt==0 ){ @ <tr><th valign="top" align="right">Unversioned Files:</th> @ <td valign="top"> } cnt++; if( isDeleted ){ | | | | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | int isDeleted = zHash==0; if( cnt==0 ){ @ <tr><th valign="top" align="right">Unversioned Files:</th> @ <td valign="top"> } cnt++; if( isDeleted ){ @ %h(zName) (deleted)<br /> }else{ @ <a href="%R/uv/%h(zName)">%h(zName)</a> (size: %d(size))<br /> } } if( cnt>0 ){ @ <p><form action='%R/rcvfrom'> @ <input type="hidden" name="rcvid" value='%d(rcvid)'> @ <input type="hidden" name="uvdelete" value="1"> if( PB("uvdelete") ){ @ <input type="hidden" name="confirmdelete" value="1"> @ <input type="submit" value="Confirm Deletion of These Files"> }else{ @ <input type="submit" value="Delete These Unversioned Files"> } @ </form> @ </td></tr> } } @ </table> db_finalize(&q); style_footer(); } |
Changes to src/sitemap.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | /* ** WEBPAGE: sitemap ** ** List some of the web pages offered by the Fossil web engine. This ** page is intended as a supplement to the menu bar on the main screen. ** That is, this page is designed to hold links that are omitted from ** the main menu due to lack of space. | < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < > | > > < < < | | < < > > | < > | > > > > > | | | > > > | < < < < | | < > < | < < < < < < < < < < < < < < < < < | < < | < < < > > | < < < < < | < < < < < < < < < | < < < > | | < < | < < < < < < < < < < < < > | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | /* ** WEBPAGE: sitemap ** ** List some of the web pages offered by the Fossil web engine. This ** page is intended as a supplement to the menu bar on the main screen. ** That is, this page is designed to hold links that are omitted from ** the main menu due to lack of space. */ void sitemap_page(void){ int srchFlags; int inSublist = 0; int i; int isPopup = 0; /* This is an XMLHttpRequest() for /sitemap */ const struct { const char *zTitle; const char *zProperty; } aExtra[] = { { "Documentation", "sitemap-docidx" }, { "Download", "sitemap-download" }, { "License", "sitemap-license" }, { "Contact", "sitemap-contact" }, }; login_check_credentials(); if( P("popup")!=0 && cgi_csrf_safe(0) ){ /* If this is a POST from the same origin with the popup=1 parameter, ** then disable anti-robot defenses */ isPopup = 1; g.perm.Hyperlink = 1; g.javascriptHyperlink = 0; } srchFlags = search_restrict(SRCH_ALL); if( !isPopup ){ style_header("Site Map"); style_adunit_config(ADUNIT_RIGHT_OK); } @ <ul id="sitemap" class="columns" style="column-width:20em"> @ <li>%z(href("%R/home"))Home Page</a> for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){ char *z = db_get(aExtra[i].zProperty,0); if( z==0 || z[0]==0 ) continue; if( !inSublist ){ @ <ul> inSublist = 1; } if( z[0]=='/' ){ @ <li>%z(href("%R%s",z))%s(aExtra[i].zTitle)</a></li> }else{ @ <li>%z(href("%s",z))%s(aExtra[i].zTitle)</a></li> } } if( srchFlags & SRCH_DOC ){ if( !inSublist ){ @ <ul> inSublist = 1; } @ <li>%z(href("%R/docsrch"))Documentation Search</a></li> } if( inSublist ){ @ </ul> inSublist = 0; } @ </li> if( g.perm.Read ){ @ <li>%z(href("%R/tree"))File Browser</a> @ <ul> @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view, @ Trunk Check-in</a></li> @ <li>%z(href("%R/tree?type=flat"))Flat-view</a></li> @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li> @ <li>%z(href("%R/uvlist"))Unversioned Files</a> @ </ul> } if( g.perm.Read ){ @ <li>%z(href("%R/timeline"))Project Timeline</a> @ <ul> @ <li>%z(href("%R/reports"))Activity Reports</a></li> @ <li>%z(href("%R/timeline?n=all&namechng"))File name changes</a></li> @ <li>%z(href("%R/timeline?n=all&forks"))Forks</a></li> @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10 @ check-ins</a></li> @ </ul> @ </li> } if( g.perm.Read ){ @ <li>%z(href("%R/brlist"))Branches</a> @ <ul> @ <li>%z(href("%R/taglist"))Tags</a></li> @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li> @ </ul> @ </li> } if( srchFlags ){ @ <li>%z(href("%R/search"))Search</a></li> } if( g.perm.RdForum ){ @ <li>%z(href("%R/forum"))Forum</a> @ <ul> @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li> @ </ul> @ </li> } if( g.perm.RdTkt ){ @ <li>%z(href("%R/reportlist"))Tickets</a> @ <ul> if( srchFlags & SRCH_TKT ){ @ <li>%z(href("%R/tktsrch"))Ticket Search</a></li> } @ <li>%z(href("%R/timeline?y=t"))Recent activity</a></li> @ <li>%z(href("%R/attachlist"))List of Attachments</a></li> @ </ul> @ </li> } if( g.perm.RdWiki ){ @ <li>%z(href("%R/wikihelp"))Wiki</a> @ <ul> if( srchFlags & SRCH_WIKI ){ @ <li>%z(href("%R/wikisrch"))Wiki Search</a></li> } @ <li>%z(href("%R/wcontent"))List of Wiki Pages</a></li> @ <li>%z(href("%R/timeline?y=w"))Recent activity</a></li> @ <li>%z(href("%R/wiki?name=Sandbox"))Sandbox</a></li> @ <li>%z(href("%R/attachlist"))List of Attachments</a></li> @ </ul> @ </li> } if( !g.zLogin ){ @ <li>%z(href("%R/login"))Login</a> if( login_self_register_available(0) ){ @ <ul> @ <li>%z(href("%R/register"))Create a new account</a></li> inSublist = 1; } }else { @ <li>%z(href("%R/logout"))Logout</a> if( g.perm.Password ){ @ <ul> @ <li>%z(href("%R/logout"))Change Password</a></li> inSublist = 1; } } if( alert_enabled() && g.perm.EmailAlert ){ if( !inSublist ){ inSublist = 1; @ <ul> } if( login_is_individual() ){ @ <li>%z(href("%R/alerts"))Email Alerts</a></li> }else{ @ <li>%z(href("%R/subscribe"))Subscribe to Email Alerts</a></li> } } if( inSublist ){ @ </ul> inSublist = 0; } @ </li> if( g.perm.Read ){ @ <li>%z(href("%R/stat"))Repository Status</a> @ <ul> @ <li>%z(href("%R/hash-collisions"))Collisions on hash prefixes</a></li> if( g.perm.Admin ){ @ <li>%z(href("%R/urllist"))List of URLs used to access @ this repository</a></li> } @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li> @ <li>%z(href("%R/timewarps"))List of "Timewarp" Check-ins</a></li> @ </ul> @ </li> } @ <li>Help @ <ul> @ <li>%z(href("%R/wiki_rules"))Wiki Formatting Rules</a></li> @ <li>%z(href("%R/md_rules"))Markdown Formatting Rules</a></li> @ <li>%z(href("%R/help"))List of All Commands and Web Pages</a></li> @ <li>%z(href("%R/test-all-help"))All "help" text on a single page</a></li> @ <li>%z(href("%R/mimetype_list"))Filename suffix to mimetype map</a></li> @ </ul></li> if( g.perm.Admin ){ @ <li>%z(href("%R/setup"))Administration Pages</a> @ <ul> @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li> @ <li>%z(href("%R/admin_log"))Admin log</a></li> @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li> @ </ul></li> } @ <li>Test Pages @ <ul> if( g.perm.Admin || db_get_boolean("test_env_enable",0) ){ @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li> } if( g.perm.Read ){ @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li> } @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic @ colors assigned to branch names</a> @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li> @ </ul></li> @ </ul> if( !isPopup ){ style_footer(); } } |
Changes to src/skins.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** Implementation of the Setup page for "skins". */ #include "config.h" #include <assert.h> #include "skins.h" | < < < < < < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** Implementation of the Setup page for "skins". */ #include "config.h" #include <assert.h> #include "skins.h" /* ** An array of available built-in skins. ** ** To add new built-in skins: ** ** 1. Pick a name for the new skin. (Here we use "xyzzy"). ** |
︙ | ︙ | |||
45 46 47 48 49 50 51 | */ static struct BuiltinSkin { const char *zDesc; /* Description of this skin */ const char *zLabel; /* The directory under skins/ holding this skin */ char *zSQL; /* Filled in at run-time with SQL to insert this skin */ } aBuiltinSkin[] = { { "Default", "default", 0 }, | < < > | | | | > | > | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < | < < < < < < < < < < < < < < < < | < | 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 | */ static struct BuiltinSkin { const char *zDesc; /* Description of this skin */ const char *zLabel; /* The directory under skins/ holding this skin */ char *zSQL; /* Filled in at run-time with SQL to insert this skin */ } aBuiltinSkin[] = { { "Default", "default", 0 }, { "Blitz", "blitz", 0 }, { "Blitz, No Logo", "blitz_no_logo", 0 }, { "Bootstrap", "bootstrap", 0 }, { "Xekri", "xekri", 0 }, { "Original", "original", 0 }, { "Enhanced Original", "enhanced1", 0 }, { "Shadow boxes & Rounded Corners", "rounded1", 0 }, { "Eagle", "eagle", 0 }, { "Black & White, Menu on Left", "black_and_white", 0 }, { "Plain Gray, No Logo", "plain_gray", 0 }, { "Khaki, No Logo", "khaki", 0 }, { "Ardoise", "ardoise", 0 }, }; /* ** A skin consists of five "files" named here: */ static const char *azSkinFile[] = { "css", "header", "footer", "details", "js" }; /* ** Alternative skins can be specified in the CGI script or by options ** on the "http", "ui", and "server" commands. The alternative skin ** name must be one of the aBuiltinSkin[].zLabel names. If there is ** a match, that alternative is used. ** ** The following static variable holds the name of the alternative skin, ** or NULL if the skin should be as configured. */ static struct BuiltinSkin *pAltSkin = 0; static char *zAltSkinDir = 0; static int iDraftSkin = 0; /* ** Skin details are a set of key/value pairs that define display ** attributes of the skin that cannot be easily specified using CSS ** or that need to be known on the server-side. ** ** The following array holds the value for all known skin details. */ static struct SkinDetail { const char *zName; /* Name of the detail */ const char *zValue; /* Value of the detail */ } aSkinDetail[] = { { "timeline-arrowheads", "1" }, { "timeline-circle-nodes", "0" }, { "timeline-color-graph-lines", "0" }, { "white-foreground", "0" }, }; /* ** Invoke this routine to set the alternative skin. Return NULL if the ** alternative was successfully installed. Return a string listing all ** available skins if zName does not match an available skin. Memory ** for the returned string comes from fossil_malloc() and should be freed ** by the caller. ** ** If the alternative skin name contains one or more '/' characters, then ** it is assumed to be a directory on disk that holds override css.txt, ** footer.txt, and header.txt. This mode can be used for interactive ** development of new skins. */ char *skin_use_alternative(const char *zName){ int i; Blob err = BLOB_INITIALIZER; if( strchr(zName, '/')!=0 ){ zAltSkinDir = fossil_strdup(zName); return 0; } if( sqlite3_strglob("draft[1-9]", zName)==0 ){ skin_use_draft(zName[5] - '0'); return 0; } for(i=0; i<count(aBuiltinSkin); i++){ if( fossil_strcmp(aBuiltinSkin[i].zLabel, zName)==0 ){ pAltSkin = &aBuiltinSkin[i]; return 0; } } blob_appendf(&err, "available skins: %s", aBuiltinSkin[0].zLabel); for(i=1; i<count(aBuiltinSkin); i++){ blob_append(&err, " ", 1); blob_append(&err, aBuiltinSkin[i].zLabel, -1); } return blob_str(&err); } /* ** Look for the --skin command-line option and process it. Or ** call fossil_fatal() if an unknown skin is specified. */ void skin_override(void){ const char *zSkin = find_option("skin",0,1); if( zSkin ){ char *zErr = skin_use_alternative(zSkin); if( zErr ) fossil_fatal("%s", zErr); } } /* ** Use one of the draft skins. */ void skin_use_draft(int i){ iDraftSkin = i; } /* ** The following routines return the various components of the skin ** that should be used for the current run. ** ** zWhat is one of: "css", "header", "footer", "details", "js" |
︙ | ︙ | |||
263 264 265 266 267 268 269 | Blob x; blob_read_from_file(&x, z, ExtFILE); fossil_free(z); return blob_str(&x); } fossil_free(z); } | < < < < < < < < < < < < < < < < | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | Blob x; blob_read_from_file(&x, z, ExtFILE); fossil_free(z); return blob_str(&x); } fossil_free(z); } if( pAltSkin ){ z = mprintf("skins/%s/%s.txt", pAltSkin->zLabel, zWhat); zOut = builtin_text(z); fossil_free(z); }else{ zOut = db_get(zWhat, 0); if( zOut==0 ){ z = mprintf("skins/default/%s.txt", zWhat); zOut = builtin_text(z); fossil_free(z); } } return zOut; } /* ** Return the command-line option used to set the skin, or return NULL |
︙ | ︙ | |||
388 389 390 391 392 393 394 | /* ** Return an identifier that is (probably) different for every skin ** but that is (probably) the same if the skin is unchanged. This ** identifier can be attached to resource URLs to force reloading when ** the resources change but allow the resources to be read from cache ** as long as they are unchanged. | < < < < < | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | /* ** Return an identifier that is (probably) different for every skin ** but that is (probably) the same if the skin is unchanged. This ** identifier can be attached to resource URLs to force reloading when ** the resources change but allow the resources to be read from cache ** as long as they are unchanged. */ unsigned int skin_id(const char *zResource){ unsigned int h = 0; if( zAltSkinDir ){ h = skin_hash(0, zAltSkinDir); }else if( pAltSkin ){ h = skin_hash(0, pAltSkin->zLabel); }else{ char *zMTime = db_get_mtime(zResource, 0, 0); h = skin_hash(0, zMTime); fossil_free(zMTime); } h = skin_hash(h, MANIFEST_UUID); return h; } /* ** For a skin named zSkinName, compute the name of the CONFIG table ** entry where that skin is stored and return it. ** |
︙ | ︙ | |||
467 468 469 470 471 472 473 | z = db_get(azSkinFile[i], 0); if( z==0 ){ zLabel = mprintf("skins/default/%s.txt", azSkinFile[i]); z = builtin_text(zLabel); fossil_free(zLabel); } } | < < < | | < < < | | < < < < < < < < < < < < > < < < < | < < | | | | | | | < < < < < | | < < < < < < < < < | < < < < < < < < < < < | < < | | | | | | | | | | | < | | | | | < | | < < < < < | < < < < | < < < < < < | < < | | > > > | | < < < < | | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | > | > > > | | | > > > > > > > > > > | > | < < < | < | | | | | | < | < | | < | < < < < < < < < | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | z = db_get(azSkinFile[i], 0); if( z==0 ){ zLabel = mprintf("skins/default/%s.txt", azSkinFile[i]); z = builtin_text(zLabel); fossil_free(zLabel); } } blob_appendf(&val, "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now());\n", azSkinFile[i], z ); } return blob_str(&val); } /* ** Respond to a Rename button press. Return TRUE if a dialog was painted. ** Return FALSE to continue with the main Skins page. */ static int skinRename(void){ const char *zOldName; const char *zNewName; int ex = 0; if( P("rename")==0 ) return 0; zOldName = P("sn"); zNewName = P("newname"); if( zOldName==0 ) return 0; if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){ if( zNewName==0 ) zNewName = zOldName; style_header("Rename A Skin"); if( ex ){ @ <p><span class="generalError">There is already another skin @ named "%h(zNewName)". Choose a different name.</span></p> } @ <form action="%s(g.zTop)/setup_skin_admin" method="post"><div> @ <table border="0"><tr> @ <tr><td align="right">Current name:<td align="left"><b>%h(zOldName)</b> @ <tr><td align="right">New name:<td align="left"> @ <input type="text" size="35" name="newname" value="%h(zNewName)"> @ <tr><td><td> @ <input type="hidden" name="sn" value="%h(zOldName)"> @ <input type="submit" name="rename" value="Rename"> @ <input type="submit" name="canren" value="Cancel"> @ </table> login_insert_csrf_secret(); @ </div></form> style_footer(); return 1; } db_multi_exec( "UPDATE config SET name='skin:%q' WHERE name='skin:%q';", zNewName, zOldName ); return 0; } /* ** Respond to a Save button press. Return TRUE if a dialog was painted. ** Return FALSE to continue with the main Skins page. */ static int skinSave(const char *zCurrent){ const char *zNewName; int ex = 0; if( P("save")==0 ) return 0; zNewName = P("svname"); if( zNewName && zNewName[0]!=0 ){ } if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){ if( zNewName==0 ) zNewName = ""; style_header("Save Current Skin"); if( ex ){ @ <p><span class="generalError">There is already another skin @ named "%h(zNewName)". Choose a different name.</span></p> } @ <form action="%s(g.zTop)/setup_skin_admin" method="post"><div> @ <table border="0"><tr> @ <tr><td align="right">Name for this skin:<td align="left"> @ <input type="text" size="35" name="svname" value="%h(zNewName)"> @ <tr><td><td> @ <input type="submit" name="save" value="Save"> @ <input type="submit" name="cansave" value="Cancel"> @ </table> login_insert_csrf_secret(); @ </div></form> style_footer(); return 1; } db_multi_exec( "INSERT OR IGNORE INTO config(name, value, mtime)" "VALUES('skin:%q',%Q,now())", zNewName, zCurrent ); return 0; } /* ** WEBPAGE: setup_skin_admin ** ** Administrative actions on skins. For administrators only. */ void setup_skin_admin(void){ const char *z; char *zName; char *zErr = 0; const char *zCurrent = 0; /* Current skin */ int i; /* Loop counter */ Stmt q; int seenCurrent = 0; int once; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } db_begin_transaction(); zCurrent = getSkin(0); for(i=0; i<count(aBuiltinSkin); i++){ aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel); } if( cgi_csrf_safe(1) ){ /* Process requests to delete a user-defined skin */ if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){ style_header("Confirm Custom Skin Delete"); @ <form action="%s(g.zTop)/setup_skin_admin" method="post"><div> @ <p>Deletion of a custom skin is a permanent action that cannot @ be undone. Please confirm that this is what you want to do:</p> @ <input type="hidden" name="sn" value="%h(P("sn"))" /> @ <input type="submit" name="del2" value="Confirm - Delete The Skin" /> @ <input type="submit" name="cancel" value="Cancel - Do Not Delete" /> login_insert_csrf_secret(); @ </div></form> style_footer(); db_end_transaction(1); return; } if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){ db_multi_exec("DELETE FROM config WHERE name=%Q", zName); } if( P("draftdel")!=0 ){ const char *zDraft = P("name"); if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ db_multi_exec("DELETE FROM config WHERE name GLOB '%q-*'", zDraft); } } if( skinRename() || skinSave(zCurrent) ){ db_end_transaction(0); return; } /* The user pressed one of the "Install" buttons. */ if( P("load") && (z = P("sn"))!=0 && z[0] ){ int seen = 0; /* Check to see if the current skin is already saved. If it is, there ** is no need to create a backup */ zCurrent = getSkin(0); for(i=0; i<count(aBuiltinSkin); i++){ if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ seen = 1; break; } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); if( !seen ){ db_multi_exec( "INSERT INTO config(name,value,mtime) VALUES(" " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," " %Q,now())", zCurrent ); } } seen = 0; for(i=0; i<count(aBuiltinSkin); i++){ if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){ seen = 1; zCurrent = aBuiltinSkin[i].zSQL; db_multi_exec("%s", zCurrent/*safe-for-%s*/); break; } } if( !seen ){ zName = skinVarName(z,0); zCurrent = db_get(zName, 0); db_multi_exec("%s", zCurrent/*safe-for-%s*/); } } } style_header("Skins"); if( zErr ){ @ <p style="color:red">%h(zErr)</p> } @ <table border="0"> @ <tr><td colspan=4><h2>Built-in Skins:</h2></td></th> for(i=0; i<count(aBuiltinSkin); i++){ z = aBuiltinSkin[i].zDesc; @ <tr><td>%d(i+1).<td>%h(z)<td> <td> if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ @ (Currently In Use) seenCurrent = 1; }else{ @ <form action="%s(g.zTop)/setup_skin_admin" method="post"> @ <input type="hidden" name="sn" value="%h(z)" /> @ <input type="submit" name="load" value="Install" /> if( pAltSkin==&aBuiltinSkin[i] ){ @ (Current override) } @ </form> } @ </tr> } db_prepare(&q, "SELECT substr(name, 6), value FROM config" " WHERE name GLOB 'skin:*'" " ORDER BY name" ); once = 1; while( db_step(&q)==SQLITE_ROW ){ const char *zN = db_column_text(&q, 0); const char *zV = db_column_text(&q, 1); i++; if( once ){ once = 0; @ <tr><td colspan=4><h2>Skins saved as "skin:*' entries \ @ in the CONFIG table:</h2></td></tr> } @ <tr><td>%d(i).<td>%h(zN)<td> <td> @ <form action="%s(g.zTop)/setup_skin_admin" method="post"> if( fossil_strcmp(zV, zCurrent)==0 ){ @ (Currently In Use) seenCurrent = 1; }else{ @ <input type="submit" name="load" value="Install"> @ <input type="submit" name="del1" value="Delete"> } @ <input type="submit" name="rename" value="Rename"> @ <input type="hidden" name="sn" value="%h(zN)"> @ </form></tr> } db_finalize(&q); if( !seenCurrent ){ i++; @ <tr><td colspan=4><h2>Current skin in css/header/footer/details entries \ @ in the CONFIG table:</h2></td></tr> @ <tr><td>%d(i).<td><i>Current</i><td> <td> @ <form action="%s(g.zTop)/setup_skin_admin" method="post"> @ <input type="submit" name="save" value="Backup"> @ </form> } db_prepare(&q, "SELECT DISTINCT substr(name, 1, 6) FROM config" " WHERE name GLOB 'draft[1-9]-*'" " ORDER BY name" ); once = 1; while( db_step(&q)==SQLITE_ROW ){ const char *zN = db_column_text(&q, 0); i++; if( once ){ once = 0; @ <tr><td colspan=4><h2>Draft skins stored as "draft[1-9]-*' entries \ @ in the CONFIG table:</h2></td></tr> } @ <tr><td>%d(i).<td>%h(zN)<td> <td> @ <form action="%s(g.zTop)/setup_skin_admin" method="post"> @ <input type="submit" name="draftdel" value="Delete"> @ <input type="hidden" name="name" value="%h(zN)"> @ </form></tr> } db_finalize(&q); @ </table> style_footer(); db_end_transaction(0); } /* ** Generate HTML for a <select> that lists all the available skin names, ** except for zExcept if zExcept!=NULL. */ static void skin_emit_skin_selector( const char *zVarName, /* Variable name for the <select> */ const char *zDefault, /* The default value, if not NULL */ const char *zExcept /* Omit this skin if not NULL */ ){ int i; @ <select size='1' name='%s(zVarName)'> if( fossil_strcmp(zExcept, "current")!=0 ){ @ <option value='current'>Currently In Use</option> } for(i=0; i<count(aBuiltinSkin); i++){ const char *zName = aBuiltinSkin[i].zLabel; if( fossil_strcmp(zName, zExcept)==0 ) continue; if( fossil_strcmp(zDefault, zName)==0 ){ @ <option value='%s(zName)' selected>\ @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> }else{ @ <option value='%s(zName)'>\ @ %h(aBuiltinSkin[i].zDesc) (built-in)</option> } } for(i=1; i<=9; i++){ char zName[20]; sqlite3_snprintf(sizeof(zName), zName, "draft%d", i); if( fossil_strcmp(zName, zExcept)==0 ) continue; if( fossil_strcmp(zDefault, zName)==0 ){ @ <option value='%s(zName)' selected>%s(zName)</option> }else{ @ <option value='%s(zName)'>%s(zName)</option> } } @ </select> } /* ** Return the text of one of the skin files. */ static const char *skin_file_content(const char *zLabel, const char *zFile){ const char *zResult; if( fossil_strcmp(zLabel, "current")==0 ){ zResult = db_get(zFile, ""); }else if( sqlite3_strglob("draft[1-9]", zLabel)==0 ){ zResult = db_get_mprintf("", "%s-%s", zLabel, zFile); }else{ while( 1 ){ char *zKey = mprintf("skins/%s/%s.txt", zLabel, zFile); zResult = builtin_text(zKey); fossil_free(zKey); if( zResult!=0 || fossil_strcmp(zLabel,"default")==0 ) break; } } return zResult; } /* ** WEBPAGE: setup_skinedit ** ** Edit aspects of a skin determined by the w= query parameter. ** Requires Setup privileges. ** ** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details, 4=js ** sk=NUM -- the draft skin number */ void setup_skinedit(void){ static const struct sSkinAddr { const char *zFile; |
︙ | ︙ | |||
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 | /* 4 */ { "js", "JavaScript", "Script", }, }; const char *zBasis; /* The baseline file */ const char *zOrig; /* Original content prior to editing */ const char *zContent; /* Content after editing */ const char *zDflt; /* Default content */ char *zDraft; /* Which draft: "draft%d" */ char *zTitle; /* Title of this page */ const char *zFile; /* One of "css", "footer", "header", "details" */ int iSkin; /* draft number. 1..9 */ int ii; /* Index in aSkinAttr[] of this file */ int j; /* Loop counter */ int isRevert = 0; /* True if Revert-to-Baseline was pressed */ login_check_credentials(); /* Figure out which skin we are editing */ iSkin = atoi(PD("sk","1")); if( iSkin<1 || iSkin>9 ) iSkin = 1; /* Check that the user is authorized to edit this skin. */ | > | | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | /* 4 */ { "js", "JavaScript", "Script", }, }; const char *zBasis; /* The baseline file */ const char *zOrig; /* Original content prior to editing */ const char *zContent; /* Content after editing */ const char *zDflt; /* Default content */ char *zDraft; /* Which draft: "draft%d" */ char *zKey; /* CONFIG table key name: "draft%d-%s" */ char *zTitle; /* Title of this page */ const char *zFile; /* One of "css", "footer", "header", "details" */ int iSkin; /* draft number. 1..9 */ int ii; /* Index in aSkinAttr[] of this file */ int j; /* Loop counter */ int isRevert = 0; /* True if Revert-to-Baseline was pressed */ login_check_credentials(); /* Figure out which skin we are editing */ iSkin = atoi(PD("sk","1")); if( iSkin<1 || iSkin>9 ) iSkin = 1; /* Check that the user is authorized to edit this skin. */ if( !g.perm.Setup ){ char *zAllowedEditors = ""; Glob *pAllowedEditors; int isMatch = 0; if( login_is_individual() ){ zAllowedEditors = db_get_mprintf("", "draft%d-users", iSkin); } if( zAllowedEditors[0] ){ |
︙ | ︙ | |||
982 983 984 985 986 987 988 989 990 991 | } /* figure out which file is to be edited */ ii = atoi(PD("w","0")); if( ii<0 || ii>count(aSkinAttr) ) ii = 0; zFile = aSkinAttr[ii].zFile; zDraft = mprintf("draft%d", iSkin); zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin); zBasis = PD("basis","current"); zDflt = skin_file_content(zBasis, zFile); | > | | < | | < < | | | | | | | > < < < | < | | < | > | | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | } /* figure out which file is to be edited */ ii = atoi(PD("w","0")); if( ii<0 || ii>count(aSkinAttr) ) ii = 0; zFile = aSkinAttr[ii].zFile; zDraft = mprintf("draft%d", iSkin); zKey = mprintf("draft%d-%s", iSkin, zFile); zTitle = mprintf("%s for Draft%d", aSkinAttr[ii].zTitle, iSkin); zBasis = PD("basis","current"); zDflt = skin_file_content(zBasis, zFile); zOrig = db_get(zKey, zDflt); zContent = PD(zFile,zOrig); if( P("revert")!=0 && cgi_csrf_safe(0) ){ zContent = zDflt; isRevert = 1; } db_begin_transaction(); style_header("%s", zTitle); for(j=0; j<count(aSkinAttr); j++){ style_submenu_element(aSkinAttr[j].zSubmenu, "%R/setup_skinedit?w=%d&basis=%h&sk=%d",j,zBasis,iSkin); } @ <form action="%s(g.zTop)/setup_skinedit" method="post"><div> login_insert_csrf_secret(); @ <input type='hidden' name='w' value='%d(ii)'> @ <input type='hidden' name='sk' value='%d(iSkin)'> @ <h2>Edit %s(zTitle):</h2> if( P("submit") && cgi_csrf_safe(0) && strcmp(zOrig,zContent)!=0 ){ db_set(zKey, zContent, 0); } @ <textarea name="%s(zFile)" rows="10" cols="80">\ @ %h(zContent)</textarea> @ <br /> @ <input type="submit" name="submit" value="Apply Changes" /> if( isRevert ){ @ ← Press to complete reversion to "%s(zBasis)" }else if( fossil_strcmp(zContent,zDflt)!=0 ){ @ <input type="submit" name="revert" value='Revert To "%s(zBasis)"' /> } @ <hr /> @ Baseline: \ skin_emit_skin_selector("basis", zBasis, zDraft); @ <input type="submit" name="diff" value="Unified Diff" /> @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" /> if( P("diff")!=0 || P("sbsdiff")!=0 ){ u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR; Blob from, to, out; if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE; blob_init(&to, zContent, -1); blob_init(&from, skin_file_content(zBasis, zFile), -1); blob_zero(&out); if( diffFlags & DIFF_SIDEBYSIDE ){ text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG); @ %s(blob_str(&out)) }else{ text_diff(&from, &to, &out, 0, diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG); @ <pre class="udiff"> @ %s(blob_str(&out)) @ </pre> } blob_reset(&from); blob_reset(&to); blob_reset(&out); } @ </div></form> style_footer(); db_end_transaction(0); } /* ** Try to initialize draft skin iSkin to the built-in or preexisting ** skin named by zTemplate. */ |
︙ | ︙ | |||
1089 1090 1091 1092 1093 1094 1095 | } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); } if( !seen ){ | < < | < | < | | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | } } if( !seen ){ seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" " AND value=%Q", zCurrent); } if( !seen ){ db_multi_exec( "INSERT INTO config(name,value,mtime) VALUES(" " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," " %Q,now())", zCurrent ); } /* Publish draft iSkin */ for(i=0; i<count(azSkinFile); i++){ char *zNew = db_get_mprintf("", "draft%d-%s", iSkin, azSkinFile[i]); db_set(azSkinFile[i], zNew, 0); } } /* ** WEBPAGE: setup_skin ** ** Generate a page showing the steps needed to customize a skin. */ void setup_skin(void){ int i; /* Loop counter */ int iSkin; /* Which draft skin is being edited */ int isSetup; /* True for an administrator */ int isEditor; /* Others authorized to make edits */ char *zAllowedEditors; /* Who may edit the draft skin */ char *zBase; /* Base URL for draft under test */ static const char *azTestPages[] = { "home", "timeline", "dir?ci=tip", "dir?ci=tip&type=tree", "brlist", "info/trunk", }; |
︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 | */ login_check_credentials(); if( !login_is_individual() ){ login_needed(0); return; } zAllowedEditors = db_get_mprintf("", "draft%d-users", iSkin); | | | 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 | */ login_check_credentials(); if( !login_is_individual() ){ login_needed(0); return; } zAllowedEditors = db_get_mprintf("", "draft%d-users", iSkin); if( g.perm.Setup ){ isSetup = isEditor = 1; }else{ Glob *pAllowedEditors; isSetup = isEditor = 0; if( zAllowedEditors[0] ){ pAllowedEditors = glob_create(zAllowedEditors); isEditor = glob_match(pAllowedEditors, g.zLogin); |
︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 | } /* Publish the draft skin */ if( P("pub7")!=0 && PB("pub7ck1") && PB("pub7ck2") ){ skin_publish(iSkin); } | < < < < | < < | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 | } /* Publish the draft skin */ if( P("pub7")!=0 && PB("pub7ck1") && PB("pub7ck2") ){ skin_publish(iSkin); } style_header("Customize Skin"); @ <p>Customize the look of this Fossil repository by making changes @ to the CSS, Header, Footer, and Detail Settings in one of nine "draft" @ configurations. Then, after verifying that all is working correctly, @ publish the draft to become the new main Skin.<p> @ @ <a name='step1'></a> @ <h1>Step 1: Identify Which Draft To Use</h1> @ @ <p>The main skin of Fossil cannot be edited directly. Instead, @ edits are made to one of nine draft skins. A draft skin can then @ be published to become the default skin. |
︙ | ︙ | |||
1200 1201 1202 1203 1204 1205 1206 | @ <option value='%d(i)' selected>draft%d(i)</option> }else{ @ <option value='%d(i)'>draft%d(i)</option> } } @ </select> @ </p> | < | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 | @ <option value='%d(i)' selected>draft%d(i)</option> }else{ @ <option value='%d(i)'>draft%d(i)</option> } } @ </select> @ </p> @ @ <a name='step2'></a> @ <h1>Step 2: Authenticate</h1> @ if( isSetup ){ @ <p>As an administrator, you can make any edits you like to this or @ any other skin. You can also authorize other users to edit this |
︙ | ︙ | |||
1237 1238 1239 1240 1241 1242 1243 | @ <a name='step3'></a> @ <h1>Step 3: Initialize The Draft</h1> @ if( !isEditor ){ @ <p>You are not allowed to initialize draft%d(iSkin). Contact @ the administrator for this repository for more information. }else{ | < | < | 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 | @ <a name='step3'></a> @ <h1>Step 3: Initialize The Draft</h1> @ if( !isEditor ){ @ <p>You are not allowed to initialize draft%d(iSkin). Contact @ the administrator for this repository for more information. }else{ @ <p>Initialize the draft%d(iSkin) skin to one of the built-in skins @ or a preexisting skin, to use as a baseline.</p> @ @ <form method='POST' action='%R/setup_skin#step4' id='f03'> @ <p class='skinInput'> @ <input type='hidden' name='sk' value='%d(iSkin)'> @ Initialize skin <b>draft%d(iSkin)</b> using skin_emit_skin_selector("initskin", "current", 0); @ <input type='submit' name='init3' value='Go'> @ </p> @ </form> } @ @ <a name='step4'></a> @ <h1>Step 4: Make Edits</h1> |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | @ <p>Repeat <a href='#step4'>step 4</a> and @ <a href='#step5'>step 5</a> as many times as necessary to create @ a production-ready skin. @ @ <a name='step7'></a> @ <h1>Step 7: Publish</h1> @ | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 | @ <p>Repeat <a href='#step4'>step 4</a> and @ <a href='#step5'>step 5</a> as many times as necessary to create @ a production-ready skin. @ @ <a name='step7'></a> @ <h1>Step 7: Publish</h1> @ if( !g.perm.Setup ){ @ <p>Only administrators are allowed to publish draft skins. Contact @ an administrator to get this "draft%d(iSkin)" skin published.</p> }else{ @ <p>When the draft%d(iSkin) skin is ready for production use, @ make it the default scan by clicking the acknowledgements and @ pressing the button below:</p> @ @ <form method='POST' action='%R/setup_skin#step7'> @ <p class='skinInput'> @ <input type='hidden' name='sk' value='%d(iSkin)'> @ <input type='checkbox' name='pub7ck1' value='yes'>\ @ Skin draft%d(iSkin) has been tested and found ready for production.<br> @ <input type='checkbox' name='pub7ck2' value='yes'>\ @ The current skin should be overwritten with draft%d(iSkin).<br> @ <input type='submit' name='pub7' value='Publish Draft%d(iSkin)'> @ </p></form> @ @ <p>You will probably need to press Reload on your browser after @ publishing the new skin.</p> } @ @ <a name='step8'></a> @ <h1>Step 8: Cleanup and Undo Actions</h1> @ if( !g.perm.Setup ){ @ <p>Administrators can optionally save or restore legacy skins, and/or @ undo a prior publish. }else{ @ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page @ for cleanup and recovery actions. } style_load_one_js_file("skin.js"); style_footer(); } |
Changes to src/smtp.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** Implementation of SMTP (Simple Mail Transport Protocol) according ** to RFC 5321. */ #include "config.h" #include "smtp.h" #include <assert.h> | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** ** Implementation of SMTP (Simple Mail Transport Protocol) according ** to RFC 5321. */ #include "config.h" #include "smtp.h" #include <assert.h> #if (HAVE_DN_EXPAND || HAVE___NS_NAME_UNCOMPRESS || HAVE_NS_NAME_UNCOMPRESS) && \ (HAVE_NS_PARSERR || HAVE___NS_PARSERR) && !defined(FOSSIL_OMIT_DNS) # include <sys/types.h> # include <netinet/in.h> # if defined(HAVE_BIND_RESOLV_H) # include <bind/resolv.h> # include <bind/arpa/nameser_compat.h> # else # include <arpa/nameser.h> |
︙ | ︙ | |||
114 115 116 117 118 119 120 | if( p->Data.MX.wPreference<iBestPriority ){ iBestPriority = p->Data.MX.wPreference; pBest = p->Data.MX.pNameExchange; } p = p->pNext; } if( pBest ){ | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | if( p->Data.MX.wPreference<iBestPriority ){ iBestPriority = p->Data.MX.wPreference; pBest = p->Data.MX.pNameExchange; } p = p->pNext; } if( pBest ){ pBest = fossil_strdup(pBest); } DnsRecordListFree(pDnsRecord, DnsFreeRecordListDeep); return pBest; #else return 0; #endif /* defined(FOSSIL_WINDOWS_STYLE_DNS) */ } |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 | ** Usage: %fossil test-smtp-probe DOMAIN [ME] ** ** Interact with the SMTP server for DOMAIN by setting up a connection ** and then immediately shutting it back down. Log all interaction ** on the console. Use ME as the domain name of the sender. ** ** Options: ** --direct Use DOMAIN directly without going through MX ** --port N Talk on TCP port N */ void test_smtp_probe(void){ SmtpSession *p; const char *zDomain; const char *zSelf; | > | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | ** Usage: %fossil test-smtp-probe DOMAIN [ME] ** ** Interact with the SMTP server for DOMAIN by setting up a connection ** and then immediately shutting it back down. Log all interaction ** on the console. Use ME as the domain name of the sender. ** ** Options: ** ** --direct Use DOMAIN directly without going through MX ** --port N Talk on TCP port N */ void test_smtp_probe(void){ SmtpSession *p; const char *zDomain; const char *zSelf; |
︙ | ︙ | |||
575 576 577 578 579 580 581 | }while( bMore ); if( iCode!=250 ) return 1; return 0; } /* ** The input is a base email address of the form "local@domain". | | < | > < < < | < < < < | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 | }while( bMore ); if( iCode!=250 ) return 1; return 0; } /* ** The input is a base email address of the form "local@domain". ** Return a pointer to just the "domain" part. */ static const char *domainOfAddr(const char *z){ while( z[0] && z[0]!='@' ) z++; if( z[0]==0 ) return 0; return z+1; } /* ** COMMAND: test-smtp-send ** ** Usage: %fossil test-smtp-send EMAIL FROM TO ... ** ** Use SMTP to send the email message contained in the file named EMAIL ** to the list of users TO. FROM is the sender of the email. ** ** Options: ** ** --direct Go directly to the TO domain. Bypass MX lookup ** --port N Use TCP port N instead of 25 ** --trace Show the SMTP conversation on the console */ void test_smtp_send(void){ SmtpSession *p; const char *zFrom; int nTo; const char *zToDomain; const char *zFromDomain; const char **azTo; int smtpPort = 25; const char *zPort; Blob body; u32 smtpFlags = SMTP_PORT; if( find_option("trace",0,0)!=0 ) smtpFlags |= SMTP_TRACE_STDOUT; if( find_option("direct",0,0)!=0 ) smtpFlags |= SMTP_DIRECT; zPort = find_option("port",0,1); if( zPort ) smtpPort = atoi(zPort); verify_all_options(); if( g.argc<5 ) usage("EMAIL FROM TO ..."); blob_read_from_file(&body, g.argv[2], ExtFILE); zFrom = g.argv[3]; nTo = g.argc-4; azTo = (const char**)g.argv+4; zFromDomain = domainOfAddr(zFrom); zToDomain = domainOfAddr(azTo[0]); p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort); if( p->zErr ){ fossil_fatal("%s", p->zErr); } fossil_print("Connection to \"%s\"\n", p->zHostname); smtp_client_startup(p); smtp_send_msg(p, zFrom, nTo, azTo, blob_str(&body)); smtp_client_quit(p); if( p->zErr ){ fossil_fatal("ERROR: %s\n", p->zErr); } smtp_session_free(p); blob_reset(&body); } /***************************************************************************** ** Server implementation *****************************************************************************/ /* ** Schema used by the email processing system. */ static const char zEmailSchema[] = @ -- bulk storage is in this table. This table can store either @ -- the body of email messages or transcripts of an smtp session. @ CREATE TABLE IF NOT EXISTS repository.emailblob( @ emailid INTEGER PRIMARY KEY AUTOINCREMENT, -- numeric idea for the entry @ enref INT, -- Number of references to this blob @ ets INT, -- Corresponding transcript, or NULL @ etime INT, -- insertion time, secs since 1970 @ esz INT, -- uncompressed content size @ etxt TEXT -- content of this entry @ ); @ @ -- One row for each mailbox entry. All users emails are stored in @ -- this same table. @ CREATE TABLE IF NOT EXISTS repository.emailbox( @ ebid INTEGER PRIMARY KEY, -- Unique id for each mailbox entry @ euser TEXT, -- User who received this email @ edate INT, -- Date received. Seconds since 1970 @ efrom TEXT, -- Who is the email from @ emsgid INT, -- Raw email text @ estate INT, -- 0: Unread, 1: read, 2: trash 3: sent @ esubject TEXT, -- Subject line for display @ etags TEXT -- zero or more tags @ ); @ @ -- Information on how to deliver incoming email. @ CREATE TABLE IF NOT EXISTS repository.emailroute( @ eaddr TEXT PRIMARY KEY, -- Email address @ epolicy TEXT -- How to handle email sent to this address @ ) WITHOUT ROWID; @ @ -- Outgoing email queue @ CREATE TABLE IF NOT EXISTS repository.emailoutq( @ edomain TEXT, -- Destination domain. (ex: "fossil-scm.org") @ efrom TEXT, -- Sender email address (envelope "from") @ eto TEXT, -- Recipient email address (envelope "to") @ emsgid INT, -- Message body in the emailblob table @ ectime INT, -- Time enqueued. Seconds since 1970 @ emtime INT, -- Time of last send attempt. Sec since 1970 @ ensend INT, -- Number of send attempts @ ets INT -- Transcript of last failed attempt @ ); @ @ -- Triggers to automatically keep the emailblob.enref field up to date @ -- as entries in the emailblob, emailbox, and emailoutq tables are @ -- deleted. @ CREATE TRIGGER IF NOT EXISTS repository.emailblob_d1 @ AFTER DELETE ON emailblob BEGIN @ UPDATE emailblob SET enref=enref-1 WHERE emailid=old.ets; @ END; @ CREATE TRIGGER IF NOT EXISTS repository.emailbox_d1 @ AFTER DELETE ON emailbox BEGIN @ UPDATE emailblob SET enref=enref-1 WHERE emailid=old.emsgid; @ END; @ CREATE TRIGGER IF NOT EXISTS repository.emailoutq_d1 @ AFTER DELETE ON emailoutq BEGIN @ UPDATE emailblob SET enref=enref-1 WHERE emailid IN (old.ets,old.emsgid); @ END; @ @ -- An index on the emailblob entries which are unreferenced. @ CREATE INDEX IF NOT EXISTS repository.emailblob_nref ON emailblob(enref) @ WHERE enref<=0; ; /* ** Code used to delete the email tables. */ static const char zEmailDrop[] = @ DROP TABLE IF EXISTS emailblob; @ DROP TABLE IF EXISTS emailbox; @ DROP TABLE IF EXISTS emailroute; @ DROP TABLE IF EXISTS emailqueue; ; #if INTERFACE /* ** Mailbox message states */ #define MSG_UNREAD 0 #define MSG_READ 1 #define MSG_TRASH 2 #endif /* INTERFACE */ /* ** Populate the schema of a database. ** ** eForce==0 Fast ** eForce==1 Run CREATE TABLE statements every time ** eForce==2 DROP then rerun CREATE TABLE */ void smtp_server_schema(int eForce){ if( eForce==2 ){ db_multi_exec(zEmailDrop/*works-like:""*/); } if( eForce==1 || !db_table_exists("repository","emailblob") ){ db_multi_exec(zEmailSchema/*works-like:""*/); } } /* ** WEBPAGE: setup_smtp ** ** Administrative page for configuring and controlling inbound email and ** output email queuing. This page is available to administrators ** only via the /Admin/EmailServer menu. */ void setup_smtp(void){ Stmt q; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } db_begin_transaction(); style_header("Email Server Setup"); if( db_table_exists("repository","emailroute") ){ style_submenu_element("emailblob table", "%R/emailblob"); style_submenu_element("emailoutq table", "%R/emailoutq"); db_prepare(&q, "SELECT eaddr, epolicy FROM emailroute ORDER BY 1"); }else{ db_prepare(&q, "SELECT null, null WHERE false"); } @ <h1>Email Routing Table</h1> @ <table class="emailroutetab" cellpadding="5" border="1" cellspacing="0"> @ <thead> @ <tr> @ <th>Email Address @ <th>Routing @ <th> @ </tr> @ </thead><tbody> while( db_step(&q)==SQLITE_ROW ){ const char *zEAddr = db_column_text(&q, 0); const char *zEPolicy = db_column_text(&q, 1); @ <tr> @ <td valign="top">%h(zEAddr)</td> @ <td valign="top"><span style="white-space:pre;">%h(zEPolicy)</span></td> @ <td valign="top"><form method="POST" action="%R/setup_smtp_route"> @ <input type="hidden" name="oaddr" value="%h(zEAddr)"> @ <input type="submit" value="Edit"> @ </form> } db_finalize(&q); @ <tr> @ <td colspan="3"> @ <form method="POST" action="%R/setup_smtp_route"> @ <input type="submit" value="New"> @ ← Add a new email address @ </form> @ </table> style_footer(); db_end_transaction(0); } /* ** WEBPAGE: setup_smtp_route ** ** Edit a single entry in the emailroute table. ** Query parameters: ** ** eaddr=ADDR ADDR is the email address as edited. ** ** oaddr=ADDR The original email address prior to editing. ** Omit to add a new address. ** ** epolicy=TXT The routing policy. */ void setup_smtp_route(void){ char *zEAddr = PT("eaddr"); /* new email address */ char *zEPolicy = PT("epolicy"); /* new routing policy */ char *zOAddr = PT("oaddr"); /* original email address */ char *zErr = 0; int iErr = 0; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } style_header("Email Route Editor"); if( P("edit") && cgi_csrf_safe(1) && zEAddr!=0 && zEPolicy!=0 ){ smtp_server_schema(0); if( (zOAddr==0 || fossil_strcmp(zEAddr,zOAddr)!=0) ){ /* New or changed email address */ if( db_exists("SELECT 1 FROM emailroute WHERE eaddr=%Q",zEAddr) ){ iErr = 1; zErr = mprintf("email address \"%h(zEAddr)\" already exists",zEAddr); goto smtp_route_edit; } if( zEPolicy[0]==0 ){ iErr = 2; zErr = mprintf("empty route"); goto smtp_route_edit; } } /* If the email address has changed, or if the new policy is blank, ** delete the old address and route information */ db_begin_transaction(); if( (zOAddr && fossil_strcmp(zEAddr,zOAddr)!=0) || zEPolicy[0]==0 ){ db_multi_exec("DELETE FROM emailroute WHERE eaddr=%Q", zOAddr); } if( zEPolicy[0] ){ /* Insert the new address and route */ db_multi_exec( "REPLACE INTO emailroute(eaddr,epolicy) VALUES(%Q,%Q)", zEAddr, zEPolicy ); } db_end_transaction(0); cgi_redirectf("%R/setup_smtp"); } if( P("cancel")!=0 ){ cgi_redirectf("%R/setup_smtp"); } smtp_route_edit: if( zEAddr==0 ) zEAddr = zOAddr; if( zEPolicy==0 && db_table_exists("repository","emailroute") ){ zEPolicy = db_text(0, "SELECT epolicy FROM emailroute WHERE eaddr=%Q", zEAddr); } if( zEPolicy==0 ) zEPolicy = ""; @ <form method="POST" action="%R/setup_smtp_route"> if( zOAddr ){ @ <input type="hidden" name="oaddr" value="%h(zOAddr)"> } @ <table class="label-value"> @ <tr> @ <th>Email Address:</th> @ <td><input type="text" size=30 name="eaddr" value="%h(zEAddr)"> if( iErr==1 ){ @ <td><span class="generalError">← %z(zErr)</span> } @ </tr> if( zOAddr && fossil_strcmp(zOAddr,zEAddr)!=0 ){ @ <tr> @ <th>Original Address:</th> @ <td>%h(zOAddr) @ </tr> } @ <tr> @ <th>Routing:</th> @ <td><textarea name="epolicy" rows="3" cols="40">%h(zEPolicy)</textarea> if( iErr==2 ){ @ <td valign="top"><span class="generalError">← %z(zErr)</span> } @ </tr> @ <tr> @ <td> @ <td><input type="submit" name="edit" value="Apply"> @ <input type="submit" name="cancel" value="Cancel"> @ </tr> @ </table> @ <hr> @ <h1>Instructions</h1> @ @ <p>The "Routing" field consists of zero or more lines where each @ line is an "action" followed by an "argument". Available actions: @ <ul> @ <li><p><b>forward</b> <i>email-address</i> @ <p>Forward the message to <i>email-address</i>. @ <li><p><b>mbox</b> <i>login-name</i> @ <p>Store the message in the local mailbox for the user @ with USER.LOGIN=<i>login-name</i>. @ </ul> @ @ <p>To delete a route → erase all text from the "Routing" field then @ press the "Apply" button. style_footer(); } #if LOCAL_INTERFACE /* ** State information for the server */ struct SmtpServer { sqlite3_int64 idTranscript; /* Transcript ID number */ sqlite3_int64 idMsg; /* Message ID number */ const char *zIpAddr; /* Remote IP address */ char *zEhlo; /* Client domain on the EHLO line */ char *zFrom; /* MAIL FROM: argument */ int nTo; /* Number of RCPT TO: lines seen */ struct SmtpTo { char *z; /* Address in each RCPT TO line */ int okRemote; /* zTo can be in another domain */ } *aTo; u32 srvrFlags; /* Control flags */ int nEts; /* Number of references to the transcript */ int nRef; /* Number of references to idMsg */ Blob msg; /* Content following DATA */ Blob transcript; /* Session transcript */ }; #define SMTPSRV_CLEAR_MSG 1 /* smtp_server_clear() last message only */ #define SMTPSRV_CLEAR_ALL 2 /* smtp_server_clear() everything */ #define SMTPSRV_LOG 0x001 /* Record a transcript of the interaction */ #define SMTPSRV_STDERR 0x002 /* Transcription written to stderr */ #define SMTPSRV_DRYRUN 0x004 /* Do not record anything in database */ #endif /* LOCAL_INTERFACE */ /* ** Clear the SmtpServer object. Deallocate resources. ** How much to clear depends on eHowMuch */ static void smtp_server_clear(SmtpServer *p, int eHowMuch){ int i; if( eHowMuch>=SMTPSRV_CLEAR_MSG ){ fossil_free(p->zFrom); p->zFrom = 0; for(i=0; i<p->nTo; i++) fossil_free(p->aTo[i].z); fossil_free(p->aTo); p->aTo = 0; p->nTo = 0; blob_reset(&p->msg); p->idMsg = 0; } if( eHowMuch>=SMTPSRV_CLEAR_ALL ){ blob_reset(&p->transcript); p->idTranscript = 0; fossil_free(p->zEhlo); p->zEhlo = 0; } } /* ** Turn raw memory into an SmtpServer object. */ static void smtp_server_init(SmtpServer *p){ memset(p, 0, sizeof(*p)); blob_init(&p->msg, 0, 0); blob_init(&p->transcript, 0, 0); } /* ** Append a new TO entry to the SmtpServer object. Do not do the ** append if the same entry is already on the list. ** ** The zAddr argument is obtained from fossil_malloc(). This ** routine assumes ownership of the allocation. */ static void smtp_append_to(SmtpServer *p, char *zAddr, int okRemote){ int i; for(i=0; zAddr[i]; i++){ zAddr[i] = fossil_tolower(zAddr[i]); } for(i=0; i<p->nTo; i++){ if( strcmp(zAddr, p->aTo[i].z)==0 ){ fossil_free(zAddr); if( p->aTo[i].okRemote==0 ) p->aTo[i].okRemote = okRemote; return; } } p->aTo = fossil_realloc(p->aTo, (p->nTo+1)*sizeof(p->aTo[0])); p->aTo[p->nTo].z = zAddr; p->aTo[p->nTo].okRemote = okRemote; p->nTo++; } /* ** Send a single line of output from the server to the client. */ static void smtp_server_send(SmtpServer *p, const char *zFormat, ...){ Blob b = empty_blob; va_list ap; char *z; int n; va_start(ap, zFormat); blob_vappendf(&b, zFormat, ap); va_end(ap); z = blob_buffer(&b); n = blob_size(&b); assert( n>=2 ); assert( z[n-1]=='\n' ); assert( z[n-2]=='\r' ); if( p->srvrFlags & SMTPSRV_LOG ){ blob_appendf(&p->transcript, "S: %.*s\n", n-2, z); } if( p->srvrFlags & SMTPSRV_STDERR ){ fprintf(stderr, "S: %.*s\n", n-2, z); } fwrite(z, n, 1, stdout); fflush(stdout); blob_reset(&b); } /* ** Read a single line from the client. */ static int smtp_server_gets(SmtpServer *p, char *aBuf, int nBuf){ int rc = fgets(aBuf, nBuf, stdin)!=0; if( rc ){ if( (p->srvrFlags & SMTPSRV_LOG)!=0 ){ blob_appendf(&p->transcript, "C: %s", aBuf); } if( (p->srvrFlags & SMTPSRV_STDERR)!=0 ){ fprintf(stderr, "C: %s", aBuf); } } return rc; } /* ** RFC-5321 requires certain content be prepended to an email header ** as that email is received. */ static void smtp_server_prepend_header_lines(SmtpServer *p){ blob_appendf(&p->msg, "Received: from %s by Fossil-smtp\r\n", p->zIpAddr); } /* ** Capture the incoming email data into the p->msg blob. Dequote ** lines of "..\r\n" into just ".\r\n". */ static void smtp_server_capture_data(SmtpServer *p, char *z, int n){ int nLine = 0; while( fgets(z, n, stdin) ){ if( strncmp(z, ".\r\n", 3)==0 || strncmp(z, ".\n",2)==0 ) break; nLine++; if( strncmp(z, "..\r\n", 4)==0 || strncmp(z, "..\n",3)==0 ){ memmove(z, z+1, 4); } blob_append(&p->msg, z, -1); } if( p->srvrFlags & SMTPSRV_LOG ){ blob_appendf(&p->transcript, "C: # %d lines, %d bytes of content\n", nLine, blob_size(&p->msg)); } if( p->srvrFlags & SMTPSRV_STDERR ){ fprintf(stderr, "C: # %d lines, %d bytes of content\n", nLine, blob_size(&p->msg)); } } /* ** Send an email to a single email addess that is registered with ** this system, according to the instructions in emailroute. If ** zAddr is not in the emailroute table, then this routine is a ** no-op. Or if zAddr has already been processed, then this ** routine is a no-op. */ static void smtp_server_send_one_user( SmtpServer *p, /* The current inbound email */ const char *zAddr, /* Who to forward this to */ int okRemote /* True if ok to foward to another domain */ ){ char *zPolicy; Blob policy, line, token, tail; zPolicy = db_text(0, "SELECT epolicy FROM emailroute WHERE eaddr=%Q", zAddr); if( zPolicy==0 ){ if( okRemote ){ int i; for(i=0; zAddr[i] && zAddr[i]!='@'; i++){} if( zAddr[i]=='@' && zAddr[i+1]!=0 ){ db_multi_exec( "INSERT INTO emailoutq(edomain,efrom,eto,emsgid,ectime," "emtime,ensend)" "VALUES(%Q,%Q,%Q,%lld,now(),0,0)", zAddr+i+1, p->zFrom, zAddr, p->idMsg ); p->nRef++; } } return; } blob_init(&policy, zPolicy, -1); while( blob_line(&policy, &line) ){ blob_trim(&line); blob_token(&line, &token); blob_tail(&line, &tail); if( blob_size(&tail)==0 ) continue; if( blob_eq_str(&token, "mbox", 4) ){ Blob subj; email_header_value(&p->msg, "subject", &subj); db_multi_exec( "INSERT INTO emailbox(euser,edate,efrom,emsgid,estate,esubject)" " VALUES(%Q,now(),%Q,%lld,0,%Q)", blob_str(&tail), p->zFrom, p->idMsg, blob_str(&subj) ); blob_reset(&subj); p->nRef++; } if( blob_eq_str(&token, "forward", 7) ){ smtp_append_to(p, fossil_strdup(blob_str(&tail)), 1); } blob_reset(&tail); } } /* ** The SmtpServer object contains a complete incoming email. ** Add this email to the database. */ static void smtp_server_route_incoming(SmtpServer *p, int bFinish){ Stmt s; int i; int nEtsStart = p->nEts; if( p->zFrom && p->nTo && blob_size(&p->msg) && (p->srvrFlags & SMTPSRV_DRYRUN)==0 ){ db_begin_write(); if( p->idTranscript==0 ) smtp_server_schema(0); p->nRef = 0; db_prepare(&s, "INSERT INTO emailblob(ets,etime,etxt,enref,esz)" " VALUES(:ets,now(),compress(:etxt),0,:esz)" ); p->nEts++; if( !bFinish && p->idTranscript==0 ){ db_bind_null(&s, ":ets"); db_bind_null(&s, ":etxt"); db_bind_null(&s, ":esz"); db_step(&s); db_reset(&s); p->idTranscript = db_last_insert_rowid(); }else if( bFinish ){ if( p->idTranscript ){ db_multi_exec( "UPDATE emailblob SET etxt=compress(%Q), enref=%d, esz=%d" " WHERE emailid=%lld", blob_str(&p->transcript), p->nEts, blob_size(&p->transcript), p->idTranscript); }else{ db_bind_null(&s, ":ets"); db_bind_str(&s, ":etxt", &p->transcript); db_bind_int(&s, ":esz", blob_size(&p->transcript)); db_step(&s); db_reset(&s); p->idTranscript = db_last_insert_rowid(); db_multi_exec( "UPDATE emailblob SET enref=%d WHERE emailid=%lld", p->nEts, p->idTranscript); } /* smtp_server_send(p, "221-Transcript id %lld nref %d\r\n", ** p->idTranscript, p->nEts); */ } db_bind_int64(&s, ":ets", p->idTranscript); db_bind_str(&s, ":etxt", &p->msg); db_bind_int(&s, ":esz", blob_size(&p->msg)); db_step(&s); db_finalize(&s); p->idMsg = db_last_insert_rowid(); /* make entries in emailbox and emailoutq */ for(i=0; i<p->nTo; i++){ int okRemote = p->aTo[i].okRemote; p->aTo[i].okRemote = 1; smtp_server_send_one_user(p, p->aTo[i].z, okRemote); } /* Fix up the emailblob.enref field of the email message body */ if( p->nRef ){ db_multi_exec( "UPDATE emailblob SET enref=%d WHERE emailid=%lld", p->nRef, p->idMsg ); }else{ db_multi_exec( "DELETE FROM emailblob WHERE emailid=%lld", p->idMsg ); p->nEts = nEtsStart; } /* Clean out legacy entries */ if( bFinish ){ db_multi_exec("DELETE FROM emailblob WHERE enref<=0"); } /* Finish the transaction after all changes are implemented */ db_commit_transaction(); } smtp_server_clear(p, SMTPSRV_CLEAR_MSG); } /* ** Remove stale content from the emailblob table. */ void smtp_cleanup(void){ if( db_table_exists("repository","emailblob") ){ db_begin_transaction(); db_multi_exec( "UPDATE emailblob SET ets=NULL WHERE enref<=0;" "DELETE FROM emailblob WHERE enref<=0;" ); db_end_transaction(0); } } /* ** COMMAND: test-emailblob-refcheck ** ** Usage: %fossil test-emailblob-refcheck [--repair] [--full] [--clean] ** ** Verify that the emailblob.enref field is correct. Report any errors. ** Use the --repair command to fix up the enref field. The --full option ** gives a full report showing the enref value on all entries in the ** emailblob table. If the --clean flags is used together with --repair, ** then emailblob table entires with enref==0 are removed. */ void test_refcheck_emailblob(void){ int doRepair; int fullReport; int doClean; Blob sql; Stmt q; int nErr = 0; db_find_and_open_repository(0, 0); fullReport = find_option("full",0,0)!=0; doRepair = find_option("repair",0,0)!=0; doClean = find_option("clean",0,0)!=0; verify_all_options(); if( !db_table_exists("repository","emailblob") ){ fossil_print("emailblob table is not configured - nothing to check\n"); return; } db_multi_exec( "CREATE TEMP TABLE refcnt(id INTEGER PRIMARY KEY, n);" "INSERT INTO refcnt SELECT ets, count(*) FROM (" " SELECT ets FROM emailblob" " UNION ALL" " SELECT emsgid FROM emailbox" " UNION ALL" " SELECT emsgid FROM emailoutq" ") WHERE ets IS NOT NULL GROUP BY 1;" "INSERT OR IGNORE INTO refcnt(id,n) SELECT emailid, 0 FROM emailblob;" ); if( doRepair ){ db_multi_exec( "UPDATE emailblob SET enref=(SELECT n FROM refcnt WHERE id=emailid)" ); if( doClean ){ smtp_cleanup(); } } blob_init(&sql, 0, 0); blob_append_sql(&sql, "SELECT a.emailid, a.enref, b.n" " FROM emailblob AS a JOIN refcnt AS b ON a.emailid=b.id" ); if( !fullReport ){ blob_append_sql(&sql, " WHERE a.enref!=b.n"); } db_prepare_blob(&q, &sql); blob_reset(&sql); while( db_step(&q)==SQLITE_ROW ){ sqlite3_int64 id = db_column_int64(&q,0); int n1 = db_column_int(&q, 1); int n2 = db_column_int(&q, 2); if( n1!=n2 ) nErr++; fossil_print("%12lld %4d %4d%s\n", id, n1, n2, n1!=n2 ? " ERROR" : ""); } db_finalize(&q); if( nErr ){ fossil_print("Number of incorrect emailblob.enref values: %d\n",nErr); } } /* ** COMMAND: smtpd* ** ** Usage: %fossil smtpd [OPTIONS] REPOSITORY ** ** Begin a SMTP conversation with a client using stdin/stdout. The ** received email is stored in REPOSITORY. ** ** Options: ** ** --dryrun Do not record any emails in the database ** ** --trace Print a transcript of the conversation on stderr ** for debugging and analysis ** ** --ipaddr ADDR The SMTP connection originates at ADDR. Or if ADDR ** is the name of an environment variable, the address ** is taken from that environment variable. */ void smtp_server(void){ char *zDbName; const char *zDomain; SmtpServer x; char z[5000]; smtp_server_init(&x); zDomain = find_option("domain",0,1); if( zDomain==0 ) zDomain = ""; x.srvrFlags = SMTPSRV_LOG; if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR; if( find_option("dryrun",0,0)!=0 ) x.srvrFlags |= SMTPSRV_DRYRUN; x.zIpAddr = find_option("ipaddr",0,1); if( x.zIpAddr ){ const char *zNew = fossil_getenv(x.zIpAddr); if( zNew && zNew[0] ) x.zIpAddr = zNew; } if( x.zIpAddr==0 ){ x.zIpAddr = cgi_remote_ip(0); if( x.zIpAddr==0 ) x.zIpAddr = "?.?.?.?"; } verify_all_options(); if( g.argc!=3 ) usage("DBNAME"); zDbName = g.argv[2]; zDbName = enter_chroot_jail(zDbName, 0); db_open_repository(zDbName); add_content_sql_commands(g.db); smtp_server_send(&x, "220 %s ESMTP https://fossil-scm.org/ %s\r\n", zDomain, MANIFEST_VERSION); while( smtp_server_gets(&x, z, sizeof(z)) ){ if( strncmp(z, "EHLO", 4)==0 && fossil_isspace(z[4]) ){ smtp_server_send(&x, "250 ok\r\n"); }else if( strncmp(z, "HELO", 4)==0 && fossil_isspace(z[4]) ){ smtp_server_send(&x, "250 ok\r\n"); }else if( strncmp(z, "MAIL FROM:<", 11)==0 ){ smtp_server_route_incoming(&x, 0); smtp_server_clear(&x, SMTPSRV_CLEAR_MSG); x.zFrom = email_copy_addr(z+11,'>'); if( x.zFrom==0 ){ smtp_server_send(&x, "500 unacceptable email address\r\n"); }else{ smtp_server_send(&x, "250 ok\r\n"); } }else if( strncmp(z, "RCPT TO:<", 9)==0 ){ char *zAddr; if( x.zFrom==0 ){ smtp_server_send(&x, "500 missing MAIL FROM\r\n"); continue; } zAddr = email_copy_addr(z+9, '>'); if( zAddr==0 ){ smtp_server_send(&x, "505 no such user\r\n"); continue; } smtp_append_to(&x, zAddr, 0); if( x.nTo>=100 ){ smtp_server_send(&x, "452 too many recipients\r\n"); continue; } smtp_server_send(&x, "250 ok\r\n"); }else if( strncmp(z, "DATA", 4)==0 && fossil_isspace(z[4]) ){ if( x.zFrom==0 || x.nTo==0 ){ smtp_server_send(&x, "500 missing RCPT TO\r\n"); continue; } smtp_server_send(&x, "354 ready\r\n"); smtp_server_prepend_header_lines(&x); smtp_server_capture_data(&x, z, sizeof(z)); smtp_server_send(&x, "250 ok\r\n"); }else if( strncmp(z, "QUIT", 4)==0 && fossil_isspace(z[4]) ){ smtp_server_route_incoming(&x, 1); smtp_server_send(&x, "221 closing connection\r\n"); break; }else { smtp_server_send(&x, "500 unknown command\r\n"); } } smtp_server_clear(&x, SMTPSRV_CLEAR_ALL); } /* ** Zero-terminate the argument. Return a pointer the start of the ** next argument, or to NULL if there are no more arguments. */ static char *pop3d_arg(char *z){ if( z[0]==0 || fossil_isspace(z[0]) ){ return 0; } z++; while( z[0] && !fossil_isspace(z[0]) ){ z++; } if( z[0]==0 ) return 0; z[0] = 0; z++; if( z[0]==0 || fossil_isspace(z[0]) ) return 0; return z; } /* ** Write formatted output back to the pop3 client, and also to the ** log file, if there is a log file. */ static void pop3_print(FILE *pLog, const char *zFormat, ...){ va_list ap; char zLine[500]; va_start(ap, zFormat); sqlite3_vsnprintf(sizeof(zLine),zLine,zFormat,ap); va_end(ap); printf("%s\r\n", zLine); fflush(stdout); if( pLog ) fprintf(pLog, "S: %s\n", zLine); } /* ** Try to log in for zUser and zPass. ** ** zUser can either point to a Fossil user name or to an email address ** found in the user table's info field, in angle brackets. */ static int pop3_login(const char *zUser, char *zPass){ return login_search_uid(&zUser, zPass) != 0; } /* ** COMMAND: pop3d* ** ** Usage: %fossil pop3d [OPTIONS] REPOSITORY ** ** Begin a POP3 conversation with a client using stdin/stdout using ** the mailboxes stored in REPOSITORY. ** ** If launched as root, the process first enters a chroot jail using ** the directory of REPOSITORY as root, then drops all privileges and ** assumes the user and group of REPOSITORY before reading any content ** off of the wire. ** ** --logdir DIR Each pop3d session creates a new logfile ** in the directory DIR and records a transcript ** of the session there. The logfile is opened ** before entering the chroot jail. */ void pop3d_command(void){ char *zDbName; char *zA1, *zA2, *zCmd, *z; int inAuth = 1; int i; FILE *pLog = 0; const char *zDir; Stmt q; char zIn[1000]; char zUser[100]; zDir = find_option("logdir",0,1); if( zDir ){ char *zFile = file_time_tempname(zDir, ".txt"); pLog = fossil_fopen(zFile, "w"); fossil_free(zFile); } verify_all_options(); if( g.argc!=3 ) usage("DBNAME"); zDbName = g.argv[2]; zDbName = enter_chroot_jail(zDbName, 0); db_open_repository(zDbName); add_content_sql_commands(g.db); pop3_print(pLog, "+OK POP3 server ready"); while( fgets(zIn, sizeof(zIn), stdin) ){ if( pLog ) fprintf(pLog, "C: %s", zIn); zCmd = zIn; zA1 = pop3d_arg(zCmd); zA2 = zA1 ? pop3d_arg(zA1) : 0; for(i=0; zCmd[i]; i++){ zCmd[i] = fossil_tolower(zCmd[i]); } if( strcmp(zCmd,"quit")==0 ){ if( !inAuth ){ db_multi_exec( "UPDATE emailbox SET estate=2" " WHERE estate<2 AND ebid IN (SELECT ebid FROM pop3 WHERE isDel);" ); } pop3_print(pLog, "+OK"); break; } if( strcmp(zCmd,"capa")==0 ){ static const char *azCap[] = { "TOP", "USER", "UIDL", }; int i; pop3_print(pLog, "+OK"); for(i=0; i<sizeof(azCap)/sizeof(azCap[0]); i++){ pop3_print(pLog, azCap[i]); } pop3_print(pLog, "."); continue; } if( inAuth ){ if( strcmp(zCmd,"user")==0 ){ if( zA1==0 || zA2!=0 ) goto cmd_error; sqlite3_snprintf(sizeof(zUser),zUser,"%s",zA1); goto cmd_ok; } if( strcmp(zCmd,"pass")==0 ){ if( zA1==0 || zA2!=0 ) goto cmd_error; if( pop3_login(zUser,zA1)==0 ){ goto cmd_error; }else{ inAuth = 0; db_multi_exec( "CREATE TEMP TABLE pop3(" " id INTEGER PRIMARY KEY," " emailid INT," " ebid INT," " isDel INT," " esz INT" ");" "INSERT INTO pop3(id,emailid,ebid,isDel,esz)" " SELECT NULL, emailid, ebid, 0, esz FROM emailblob, emailbox" " WHERE emailid=emsgid AND euser=%Q AND estate<=1" " ORDER BY edate;", zUser ); goto cmd_ok; } } /* Fossil cannot process APOP since the users clear-text password is ** unknown. */ goto cmd_error; }else{ if( strcmp(zCmd,"stat")==0 ){ db_prepare(&q, "SELECT count(*), sum(esz) FROM pop3 WHERE NOT isDel"); if( db_step(&q)==SQLITE_ROW ){ pop3_print(pLog, "+OK %d %d", db_column_int(&q,0), db_column_int(&q,1)); }else{ pop3_print(pLog,"-ERR"); } db_finalize(&q); continue; } if( strcmp(zCmd,"list")==0 ){ if( zA1 ){ db_prepare(&q, "SELECT id, esz FROM pop3" " WHERE id=%d AND NOT isDel", atoi(zA1)); if( db_step(&q)==SQLITE_ROW ){ pop3_print(pLog, "+OK %d %d", db_column_int(&q,0), db_column_int(&q,1)); }else{ pop3_print(pLog, "-ERR"); } }else{ pop3_print(pLog, "+OK"); db_prepare(&q, "SELECT id, esz FROM pop3 WHERE NOT isDel"); while( db_step(&q)==SQLITE_ROW ){ pop3_print(pLog, "%d %d", db_column_int(&q,0), db_column_int(&q,1)); } pop3_print(pLog, "."); } db_finalize(&q); continue; } if( strcmp(zCmd,"retr")==0 || strcmp(zCmd,"top")==0 ){ Blob all, line; int nLine = 0; int iLimit; int hdrPending = 1; if( zA1==0 ) goto cmd_error; iLimit = zA2 ? atoi(zA2) : 2147483647; if( iLimit<0 ) goto cmd_error; z = db_text(0, "SELECT decompress(emailblob.etxt) " " FROM emailblob, pop3" " WHERE emailblob.emailid=pop3.emailid" " AND pop3.id=%d AND NOT pop3.isDel", atoi(zA1)); if( z==0 ) goto cmd_error; pop3_print(pLog, "+OK"); blob_init(&all, z, -1); while( (hdrPending || iLimit>0) && blob_line(&all, &line) ){ char c = blob_buffer(&line)[0]; if( c=='.' ){ fputc('.', stdout); }else if( c=='\r' || c=='\n' ){ hdrPending = 0; } fwrite(blob_buffer(&line), 1, blob_size(&line), stdout); nLine++; if( !hdrPending ) iLimit--; } if( pLog ) fprintf(pLog, "S: # %d lines of content\n", nLine); pop3_print(pLog, "."); fossil_free(z); blob_reset(&all); blob_reset(&line); fflush(stdout); continue; } if( strcmp(zCmd,"dele")==0 ){ if( zA1==0 ) goto cmd_error; db_multi_exec("UPDATE pop3 SET isDel=1 WHERE id=%d",atoi(zA1)); goto cmd_ok; } if( strcmp(zCmd,"rset")==0 ){ db_multi_exec("UPDATE pop3 SET isDel=0"); goto cmd_ok; } if( strcmp(zCmd,"uidl")==0 ){ if( zA1 ){ db_prepare(&q, "SELECT id, emailid FROM pop3" " WHERE id=%d AND NOT isDel", atoi(zA1)); if( db_step(&q)==SQLITE_ROW ){ pop3_print(pLog, "+OK %d %d", db_column_int(&q,0), db_column_int(&q,1)); }else{ pop3_print(pLog,"-ERR"); } }else{ pop3_print(pLog, "+OK"); db_prepare(&q, "SELECT id, emailid FROM pop3 WHERE NOT isDel"); while( db_step(&q)==SQLITE_ROW ){ pop3_print(pLog, "%d %d", db_column_int(&q,0), db_column_int(&q,1)); } pop3_print(pLog, "."); } db_finalize(&q); continue; } if( strcmp(zCmd,"noop")==0 ){ goto cmd_ok; } /* Else, fall through into cmd_error */ } cmd_error: pop3_print(pLog, "-ERR"); continue; cmd_ok: pop3_print(pLog, "+OK"); continue; } if( pLog ) fclose(pLog); } |
Deleted src/sounds/0.wav.
cannot compute difference between binary files
Deleted src/sounds/1.wav.
cannot compute difference between binary files
Deleted src/sounds/2.wav.
cannot compute difference between binary files
Deleted src/sounds/3.wav.
cannot compute difference between binary files
Deleted src/sounds/4.wav.
cannot compute difference between binary files
Deleted src/sounds/5.wav.
cannot compute difference between binary files
Deleted src/sounds/6.wav.
cannot compute difference between binary files
Deleted src/sounds/7.wav.
cannot compute difference between binary files
Deleted src/sounds/8.wav.
cannot compute difference between binary files
Deleted src/sounds/9.wav.
cannot compute difference between binary files
Deleted src/sounds/README.md.
|
| < < < < < < < < < < < < < < |
Deleted src/sounds/a.wav.
cannot compute difference between binary files
Deleted src/sounds/b.wav.
cannot compute difference between binary files
Deleted src/sounds/c.wav.
cannot compute difference between binary files
Deleted src/sounds/d.wav.
cannot compute difference between binary files
Deleted src/sounds/e.wav.
cannot compute difference between binary files
Deleted src/sounds/f.wav.
cannot compute difference between binary files
Changes to src/sqlcmd.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** shell against the repository database. The command-line shell itself ** is a copy of the "shell.c" code from SQLite. This file contains logic ** to initialize the code in shell.c. */ #include "config.h" #include "sqlcmd.h" #include <stdlib.h> /* atexit() */ | > > > > | > > < < < < < | 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 | ** shell against the repository database. The command-line shell itself ** is a copy of the "shell.c" code from SQLite. This file contains logic ** to initialize the code in shell.c. */ #include "config.h" #include "sqlcmd.h" #include <stdlib.h> /* atexit() */ #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #ifndef _WIN32 # include "linenoise.h" #endif /* ** Implementation of the "content(X)" SQL function. Return the complete ** content of artifact identified by X as a blob. */ static void sqlcmd_content( sqlite3_context *context, int argc, |
︙ | ︙ | |||
81 82 83 84 85 86 87 | pOut[0] = nIn>>24 & 0xff; pOut[1] = nIn>>16 & 0xff; pOut[2] = nIn>>8 & 0xff; pOut[3] = nIn & 0xff; rc = compress(&pOut[4], &nOut, pIn, nIn); if( rc==Z_OK ){ sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free); | < < < | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | pOut[0] = nIn>>24 & 0xff; pOut[1] = nIn>>16 & 0xff; pOut[2] = nIn>>8 & 0xff; pOut[3] = nIn & 0xff; rc = compress(&pOut[4], &nOut, pIn, nIn); if( rc==Z_OK ){ sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free); }else{ sqlite3_free(pOut); sqlite3_result_error(context, "input cannot be zlib compressed", -1); } } /* |
︙ | ︙ | |||
107 108 109 110 111 112 113 | const unsigned char *pIn; unsigned char *pOut; unsigned int nIn; unsigned long int nOut; int rc; pIn = sqlite3_value_blob(argv[0]); | < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | const unsigned char *pIn; unsigned char *pOut; unsigned int nIn; unsigned long int nOut; int rc; pIn = sqlite3_value_blob(argv[0]); nIn = sqlite3_value_bytes(argv[0]); nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3]; pOut = sqlite3_malloc( nOut+1 ); rc = uncompress(pOut, &nOut, &pIn[4], nIn-4); if( rc==Z_OK ){ sqlite3_result_blob(context, pOut, nOut, sqlite3_free); }else{ sqlite3_free(pOut); sqlite3_result_error(context, "input is not zlib compressed", -1); } } /* ** Add the content(), compress(), and decompress() SQL functions to ** database connection db. */ int add_content_sql_commands(sqlite3 *db){ sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0, sqlcmd_content, 0, 0); sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0, sqlcmd_compress, 0, 0); sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0, sqlcmd_decompress, 0, 0); return SQLITE_OK; } /* ** This is the "automatic extension" initializer that runs right after ** the connection to the repository database is opened. Set up the ** database connection to be more useful to the human operator. */ static int sqlcmd_autoinit( sqlite3 *db, const char **pzErrMsg, const void *notUsed ){ add_content_sql_commands(db); db_add_aux_functions(db); re_add_sql_func(db); search_sql_setup(db); foci_register(db); g.repositoryOpen = 1; g.db = db; sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "repository"); db_maybe_set_encryption_key(db, g.zRepositoryName); if( g.zLocalDbName ){ char *zSql = sqlite3_mprintf("ATTACH %Q AS 'localdb' KEY ''", g.zLocalDbName); sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); } if( g.zConfigDbName ){ char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''", g.zConfigDbName); sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); } return SQLITE_OK; } /* ** atexit() handler that cleans up global state modified by this module. */ static void sqlcmd_atexit(void) { |
︙ | ︙ | |||
278 279 280 281 282 283 284 | sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit); } #if USE_SEE /* ** This routine is called by the patched sqlite3 command-line shell in order ** to load the encryption key for the open Fossil database. The memory that | | > | | > | | | 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 | sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit); } #if USE_SEE /* ** This routine is called by the patched sqlite3 command-line shell in order ** to load the encryption key for the open Fossil database. The memory that ** is pointed to by the value placed in pzKey must be obtained from SQLite. */ void fossil_key(const char **pzKey, int *pnKey){ char *zSavedKey = db_get_saved_encryption_key(); char *zKey; size_t savedKeySize = db_get_saved_encryption_key_size(); size_t nByte; if( zSavedKey==0 || savedKeySize==0 ) return; nByte = savedKeySize * sizeof(char); zKey = sqlite3_malloc( (int)nByte ); if( zKey ){ memcpy(zKey, zSavedKey, nByte); *pzKey = zKey; if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){ *pnKey = (int)strlen(zKey); }else{ *pnKey = -1; } }else{ fossil_panic("failed to allocate %u bytes for key", nByte); } } #endif /* ** This routine closes the Fossil databases and/or invalidates the global ** state variables that keep track of them. |
︙ | ︙ | |||
319 320 321 322 323 324 325 | /* ** COMMAND: sql ** COMMAND: sqlite3* ** ** Usage: %fossil sql ?OPTIONS? ** | | | | > > | > > > > | < > | < < < < < < > | < | | < < < < | < < < | < < < < < | | < < | < < | < < < < < | < < < < < < < < < < < < < < < < < | < | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | /* ** COMMAND: sql ** COMMAND: sqlite3* ** ** Usage: %fossil sql ?OPTIONS? ** ** Run the standalone sqlite3 command-line shell on DATABASE with SHELL_OPTS. ** If DATABASE is omitted, then the repository that serves the working ** directory is opened. See https://www.sqlite.org/cli.html for additional ** information. ** ** Options: ** ** --no-repository Skip opening the repository database. ** ** -R REPOSITORY Use REPOSITORY as the repository database ** ** WARNING: Careless use of this command can corrupt a Fossil repository ** in ways that are unrecoverable. Be sure you know what you are doing before ** running any SQL commands that modify the repository database. ** ** The following extensions to the usual SQLite commands are provided: ** ** content(X) Return the content of artifact X. X can be an ** artifact hash or prefix or a tag. ** ** compress(X) Compress text X. ** ** decompress(X) Decompress text X. Undoes the work of ** compress(X). ** ** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID) ** found in check-in X (another BLOB.RID value). ** ** symbolic_name_to_rid(X) Return the BLOB.RID corresponding to symbolic ** name X. ** ** now() Return the number of seconds since 1970. ** ** REGEXP The REGEXP operator works, unlike in ** standard SQLite. ** ** files_of_checkin(X) A table-valued function that returns info on ** all files contained in check-in X. Example: ** SELECT * FROM files_of_checkin('trunk'); */ void cmd_sqlite3(void){ int noRepository; const char *zConfigDb; extern int sqlite3_shell(int, char**); #ifdef FOSSIL_ENABLE_TH1_HOOKS g.fNoThHook = 1; #endif noRepository = find_option("no-repository", 0, 0)!=0; if( !noRepository ){ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); } db_open_config(1,0); zConfigDb = g.zConfigDbName; fossil_close(1, noRepository); sqlite3_shutdown(); #ifndef _WIN32 linenoiseSetMultiLine(1); #endif atexit(sqlcmd_atexit); g.zConfigDbName = zConfigDb; g.argv[1] = "-quote"; sqlite3_shell(g.argc, g.argv); sqlite3_cancel_auto_extension((void(*)(void))sqlcmd_autoinit); fossil_close(0, noRepository); } |
Added src/sqlite3.c.
more than 10,000 changes
Added src/sqlite3.h.
more than 10,000 changes
Changes to src/stash.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "config.h" #include "stash.h" #include <assert.h> /* ** SQL code to implement the tables needed by the stash. | < < < < < < < < < < < < < | < > < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | #include "config.h" #include "stash.h" #include <assert.h> /* ** SQL code to implement the tables needed by the stash. */ static const char zStashInit[] = @ CREATE TABLE IF NOT EXISTS localdb.stash( @ stashid INTEGER PRIMARY KEY, -- Unique stash identifier @ vid INTEGER, -- The baseline checkout for this stash @ comment TEXT, -- Comment for this stash. Or NULL @ ctime TIMESTAMP -- When the stash was created @ ); @ CREATE TABLE IF NOT EXISTS localdb.stashfile( @ stashid INTEGER REFERENCES stash, -- Stash that contains this file @ rid INTEGER, -- Baseline content in BLOB table or 0. @ isAdded BOOLEAN, -- True if this is an added file @ isRemoved BOOLEAN, -- True if this file is deleted @ isExec BOOLEAN, -- True if file is executable @ isLink BOOLEAN, -- True if file is a symlink @ origname TEXT, -- Original filename @ newname TEXT, -- New name for file at next check-in @ delta BLOB, -- Delta from baseline. Content if rid=0 @ PRIMARY KEY(newname, stashid) @ ); @ INSERT OR IGNORE INTO vvar(name, value) VALUES('stash-next', 1); ; /* ** Add zFName to the stash given by stashid. zFName might be the name of a ** file or a directory. If a directory, add all changed files contained ** within that directory. */ static void stash_add_file_or_dir(int stashid, int vid, const char *zFName){ char *zFile; /* Normalized filename */ |
︙ | ︙ | |||
188 189 190 191 192 193 194 | " OR pathname=%Q OR origname=%Q)", zTreename, zTreename, zTreename, zTreename ); } db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); db_prepare(&ins, | | | | < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | " OR pathname=%Q OR origname=%Q)", zTreename, zTreename, zTreename, zTreename ); } db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); db_prepare(&ins, "INSERT INTO stashfile(stashid, rid, isAdded, isRemoved, isExec, isLink," "origname, newname, delta)" "VALUES(%d,:rid,:isadd,:isrm,:isexe,:islink,:orig,:new,:content)", stashid ); while( db_step(&q)==SQLITE_ROW ){ int deleted = db_column_int(&q, 0); int rid = db_column_int(&q, 3); const char *zName = db_column_text(&q, 4); const char *zOrig = db_column_text(&q, 5); |
︙ | ︙ | |||
254 255 256 257 258 259 260 | ** ** If files are named on the command-line, then only stash the named ** files. */ static int stash_create(void){ const char *zComment; /* Comment to add to the stash */ int stashid; /* ID of the new stash */ | | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | ** ** If files are named on the command-line, then only stash the named ** files. */ static int stash_create(void){ const char *zComment; /* Comment to add to the stash */ int stashid; /* ID of the new stash */ int vid; /* Current checkout */ zComment = find_option("comment", "m", 1); verify_all_options(); if( zComment==0 ){ Blob prompt; /* Prompt for stash comment */ Blob comment; /* User comment reply */ #if defined(_WIN32) || defined(__CYGWIN__) |
︙ | ︙ | |||
283 284 285 286 287 288 289 | zComment = blob_str(&comment); } stashid = db_lget_int("stash-next", 1); db_lset_int("stash-next", stashid+1); vid = db_lget_int("checkout", 0); vfile_check_signature(vid, 0); db_multi_exec( | | | | | | < < | | | 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 | zComment = blob_str(&comment); } stashid = db_lget_int("stash-next", 1); db_lset_int("stash-next", stashid+1); vid = db_lget_int("checkout", 0); vfile_check_signature(vid, 0); db_multi_exec( "INSERT INTO stash(stashid,vid,comment,ctime)" "VALUES(%d,%d,%Q,julianday('now'))", stashid, vid, zComment ); if( g.argc>3 ){ int i; for(i=3; i<g.argc; i++){ stash_add_file_or_dir(stashid, vid, g.argv[i]); } }else{ stash_add_file_or_dir(stashid, vid, g.zLocalRoot); } return stashid; } /* ** Apply a stash to the current checkout. */ static void stash_apply(int stashid, int nConflict){ int vid; Stmt q; db_prepare(&q, "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile WHERE stashid=%d", stashid ); vid = db_lget_int("checkout",0); db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); int isRemoved = db_column_int(&q, 1); |
︙ | ︙ | |||
334 335 336 337 338 339 340 | db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew); db_ephemeral_blob(&q, 6, &delta); blob_write_to_file(&delta, zNPath); file_setexe(zNPath, isExec); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); file_delete(zOPath); | < < | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew); db_ephemeral_blob(&q, 6, &delta); blob_write_to_file(&delta, zNPath); file_setexe(zNPath, isExec); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); file_delete(zOPath); }else{ Blob a, b, out, disk; int isNewLink = file_islink(zOPath); db_ephemeral_blob(&q, 6, &delta); blob_read_from_file(&disk, zOPath, RepoFILE); content_get(rid, &a); blob_delta_apply(&a, &delta, &b); |
︙ | ︙ | |||
361 362 363 364 365 366 367 | }else{ int rc; if( isLink || isNewLink ){ rc = -1; blob_zero(&b); /* because we reset it later */ fossil_print("***** Cannot merge symlink %s\n", zNew); }else{ | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | }else{ int rc; if( isLink || isNewLink ){ rc = -1; blob_zero(&b); /* because we reset it later */ fossil_print("***** Cannot merge symlink %s\n", zNew); }else{ rc = merge_3way(&a, zOPath, &b, &out, 0); blob_write_to_file(&out, zNPath); blob_reset(&out); file_setexe(zNPath, isExec); } if( rc ){ fossil_print("CONFLICT %s\n", zNew); nConflict++; |
︙ | ︙ | |||
402 403 404 405 406 407 408 409 | } /* ** Show the diffs associate with a single stash. */ static void stash_diff( int stashid, /* The stash entry to diff */ int fBaseline, /* Diff against original baseline check-in if true */ | > > > | < < | < < | | > < | < | > > | > | < | > > | > > | | | > > | > < > > | | | < | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | } /* ** Show the diffs associate with a single stash. */ static void stash_diff( int stashid, /* The stash entry to diff */ const char *zDiffCmd, /* Command used for diffing */ const char *zBinGlob, /* GLOB pattern to determine binary files */ int fBaseline, /* Diff against original baseline check-in if true */ int fIncludeBinary, /* Do diffs against binary files */ u64 diffFlags /* Other diff flags */ ){ Stmt q; Blob empty; blob_zero(&empty); db_prepare(&q, "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile WHERE stashid=%d", stashid ); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); int isRemoved = db_column_int(&q, 1); int isLink = db_column_int(&q, 3); int isBin1, isBin2; const char *zOrig = db_column_text(&q, 4); const char *zNew = db_column_text(&q, 5); char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); Blob a, b; if( rid==0 ){ db_ephemeral_blob(&q, 6, &a); fossil_print("ADDED %s\n", zNew); diff_print_index(zNew, diffFlags); isBin1 = 0; isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); diff_print_index(zNew, diffFlags); isBin2 = 0; if( fBaseline ){ content_get(rid, &a); isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); }else{ } }else{ Blob delta; int isOrigLink = file_islink(zOPath); db_ephemeral_blob(&q, 6, &delta); fossil_print("CHANGED %s\n", zNew); if( !isOrigLink != !isLink ){ diff_print_index(zNew, diffFlags); diff_print_filenames(zOrig, zNew, diffFlags); printf(DIFF_CANNOT_COMPUTE_SYMLINK); }else{ content_get(rid, &a); blob_delta_apply(&a, &delta, &b); isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); if( fBaseline ){ diff_file_mem(&a, &b, isBin1, isBin2, zNew, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); }else{ /*Diff with file on disk using fSwapDiff=1 to show the diff in the same direction as if fBaseline=1.*/ diff_file(&b, isBin2, zOPath, zNew, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 1); } blob_reset(&a); blob_reset(&b); } blob_reset(&delta); } } db_finalize(&q); } /* ** Drop the indicated stash */ static void stash_drop(int stashid){ db_multi_exec( |
︙ | ︙ | |||
505 506 507 508 509 510 511 | } /* ** COMMAND: stash ** ** Usage: %fossil stash SUBCOMMAND ARGS... ** | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | < < < | < < < < > < < < < < | | > | | | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | } /* ** COMMAND: stash ** ** Usage: %fossil stash SUBCOMMAND ARGS... ** ** fossil stash ** fossil stash save ?-m|--comment COMMENT? ?FILES...? ** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? ** ** Save the current changes in the working tree as a new stash. ** Then revert the changes back to the last check-in. If FILES ** are listed, then only stash and revert the named files. The ** "save" verb can be omitted if and only if there are no other ** arguments. The "snapshot" verb works the same as "save" but ** omits the revert, keeping the checkout unchanged. ** ** fossil stash list|ls ?-v|--verbose? ?-W|--width <num>? ** ** List all changes sets currently stashed. Show information about ** individual files in each changeset if -v or --verbose is used. ** ** fossil stash show|cat ?STASHID? ?DIFF-OPTIONS? ** fossil stash gshow|gcat ?STASHID? ?DIFF-OPTIONS? ** ** Show the contents of a stash as a diff against its baseline. ** With gshow and gcat, gdiff-command is used instead of internal ** diff logic. ** ** fossil stash pop ** fossil stash apply ?STASHID? ** ** Apply STASHID or the most recently create stash to the current ** working checkout. The "pop" command deletes that changeset from ** the stash after applying it but the "apply" command retains the ** changeset. ** ** fossil stash goto ?STASHID? ** ** Update to the baseline checkout for STASHID then apply the ** changes of STASHID. Keep STASHID so that it can be reused ** This command is undoable. ** ** fossil stash drop|rm ?STASHID? ?-a|--all? ** ** Forget everything about STASHID. Forget the whole stash if the ** -a|--all flag is used. Individual drops are undoable but -a|--all ** is not. ** ** fossil stash diff ?STASHID? ?DIFF-OPTIONS? ** fossil stash gdiff ?STASHID? ?DIFF-OPTIONS? ** ** Show diffs of the current working directory and what that ** directory would be if STASHID were applied. With gdiff, ** gdiff-command is used instead of internal diff logic. ** ** SUMMARY: ** fossil stash ** fossil stash save ?-m|--comment COMMENT? ?FILES...? ** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? ** fossil stash list|ls ?-v|--verbose? ?-W|--width <num>? ** fossil stash show|cat ?STASHID? ?DIFF-OPTIONS? ** fossil stash gshow|gcat ?STASHID? ?DIFF-OPTIONS? ** fossil stash pop ** fossil stash apply|goto ?STASHID? ** fossil stash drop|rm ?STASHID? ?-a|--all? ** fossil stash diff ?STASHID? ?DIFF-OPTIONS? ** fossil stash gdiff ?STASHID? ?DIFF-OPTIONS? */ void stash_cmd(void){ const char *zCmd; int nCmd; int stashid = 0; int rc; undo_capture_command_line(); db_must_be_within_tree(); db_open_config(0, 0); db_begin_transaction(); db_multi_exec(zStashInit /*works-like:""*/); rc = db_exists("SELECT 1 FROM sqlite_master" " WHERE name='stashfile'" " AND sql GLOB '* PRIMARY KEY(origname, stashid)*'"); if( rc!=0 ){ db_multi_exec( "CREATE TABLE localdb.stashfile_tmp AS SELECT * FROM stashfile;" "DROP TABLE stashfile;" ); db_multi_exec(zStashInit /*works-like:""*/); db_multi_exec( "INSERT INTO stashfile SELECT * FROM stashfile_tmp;" "DROP TABLE stashfile_tmp;" ); } if( g.argc<=2 ){ zCmd = "save"; }else{ zCmd = g.argv[2]; } nCmd = strlen(zCmd); if( memcmp(zCmd, "save", nCmd)==0 ){ stashid = stash_create(); undo_disable(); if( g.argc>=2 ){ int nFile = db_int(0, "SELECT count(*) FROM stashfile WHERE stashid=%d", stashid); char **newArgv = fossil_malloc( sizeof(char*)*(nFile+2) ); int i = 2; Stmt q; db_prepare(&q,"SELECT origname FROM stashfile WHERE stashid=%d", stashid); while( db_step(&q)==SQLITE_ROW ){ newArgv[i++] = mprintf("%s%s", g.zLocalRoot, db_column_text(&q, 0)); } db_finalize(&q); newArgv[0] = g.argv[0]; newArgv[1] = 0; g.argv = newArgv; g.argc = nFile+2; if( nFile==0 ) return; } g.argv[1] = "revert"; revert_cmd(); }else if( memcmp(zCmd, "snapshot", nCmd)==0 ){ stash_create(); }else if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){ Stmt q, q2; int n = 0, width; int verboseFlag = find_option("verbose","v",0)!=0; const char *zWidth = find_option("width","W",1); if( zWidth ){ width = atoi(zWidth); if( (width!=0) && (width<=46) ){ fossil_fatal("-W|--width value must be >46 or 0"); } }else{ width = -1; } if( !verboseFlag ){ verboseFlag = find_option("detail","l",0)!=0; /* deprecated */ } verify_all_options(); db_prepare(&q, "SELECT stashid, (SELECT uuid FROM blob WHERE rid=vid)," " comment, datetime(ctime) FROM stash" " ORDER BY ctime" ); if( verboseFlag ){ db_prepare(&q2, "SELECT isAdded, isRemoved, origname, newname" " FROM stashfile WHERE stashid=$id"); } while( db_step(&q)==SQLITE_ROW ){ int stashid = db_column_int(&q, 0); const char *zCom; n++; fossil_print("%5d: [%.14s] on %s\n", stashid, db_column_text(&q, 1), db_column_text(&q, 3) ); zCom = db_column_text(&q, 2); if( zCom && zCom[0] ){ fossil_print(" "); comment_print(zCom, 0, 7, width, g.comFmtFlags); } if( verboseFlag ){ db_bind_int(&q2, "$id", stashid); while( db_step(&q2)==SQLITE_ROW ){ int isAdded = db_column_int(&q2, 0); int isRemoved = db_column_int(&q2, 1); const char *zOrig = db_column_text(&q2, 2); |
︙ | ︙ | |||
671 672 673 674 675 676 677 | db_reset(&q2); } } db_finalize(&q); if( verboseFlag ) db_finalize(&q2); if( n==0 ) fossil_print("empty stash\n"); }else | | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | db_reset(&q2); } } db_finalize(&q); if( verboseFlag ) db_finalize(&q2); if( n==0 ) fossil_print("empty stash\n"); }else if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){ int allFlag = find_option("all", "a", 0)!=0; if( allFlag ){ Blob ans; char cReply; prompt_user("This action is not undoable. Continue (y/N)? ", &ans); cReply = blob_str(&ans)[0]; if( cReply=='y' || cReply=='Y' ){ |
︙ | ︙ | |||
697 698 699 700 701 702 703 | }else{ undo_begin(); undo_save_stash(0); stash_drop(stashid); undo_finish(); } }else | | < < < | | > > > > > | > | | < < < < < < < < < < < < < < < < | | < | | | | | | > > > | > > > | > > > > > > | > | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | }else{ undo_begin(); undo_save_stash(0); stash_drop(stashid); undo_finish(); } }else if( memcmp(zCmd, "pop", nCmd)==0 ){ if( g.argc>3 ) usage("pop"); stashid = stash_get_id(0); undo_begin(); stash_apply(stashid, 0); undo_save_stash(stashid); undo_finish(); stash_drop(stashid); }else if( memcmp(zCmd, "apply", nCmd)==0 ){ if( g.argc>4 ) usage("apply STASHID"); stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); undo_begin(); stash_apply(stashid, 0); undo_finish(); }else if( memcmp(zCmd, "goto", nCmd)==0 ){ int nConflict; int vid; if( g.argc>4 ) usage("apply STASHID"); stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); undo_begin(); vid = db_int(0, "SELECT vid FROM stash WHERE stashid=%d", stashid); nConflict = update_to(vid); stash_apply(stashid, nConflict); db_multi_exec("UPDATE vfile SET mtime=0 WHERE pathname IN " "(SELECT origname FROM stashfile WHERE stashid=%d)", stashid); undo_finish(); }else if( memcmp(zCmd, "diff", nCmd)==0 || memcmp(zCmd, "gdiff", nCmd)==0 || memcmp(zCmd, "show", nCmd)==0 || memcmp(zCmd, "gshow", nCmd)==0 || memcmp(zCmd, "cat", nCmd)==0 || memcmp(zCmd, "gcat", nCmd)==0 ){ const char *zDiffCmd = 0; const char *zBinGlob = 0; int fIncludeBinary = 0; int fBaseline = 0; u64 diffFlags; if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){ fBaseline = 1; } if( find_option("tk",0,0)!=0 ){ db_close(0); diff_tk(fBaseline ? "stash show" : "stash diff", 3); return; } if( find_option("internal","i",0)==0 ){ zDiffCmd = diff_command_external(zCmd[0]=='g'); } diffFlags = diff_options(); if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd)); if( zDiffCmd ){ zBinGlob = diff_get_binary_glob(); fIncludeBinary = diff_include_binary_files(); } stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, diffFlags); }else if( memcmp(zCmd, "help", nCmd)==0 ){ g.argv[1] = "help"; g.argv[2] = "stash"; g.argc = 3; help_cmd(); }else { usage("SUBCOMMAND ARGS..."); } db_end_transaction(0); } |
Changes to src/stat.c.
︙ | ︙ | |||
57 58 59 60 61 62 63 | /* ** Generate stats for the email notification subsystem. */ void stats_for_email(void){ const char *zDest = db_get("email-send-method",0); int nSub, nASub, nPend, nDPend; const char *zDir, *zDb, *zCmd, *zRelay; | < < < < < < < | 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 | /* ** Generate stats for the email notification subsystem. */ void stats_for_email(void){ const char *zDest = db_get("email-send-method",0); int nSub, nASub, nPend, nDPend; const char *zDir, *zDb, *zCmd, *zRelay; @ <tr><th>Outgoing Email:</th><td> if( fossil_strcmp(zDest,"pipe")==0 && (zCmd = db_get("email-send-command",0))!=0 ){ @ Piped to command "%h(zCmd)" }else if( fossil_strcmp(zDest,"db")==0 && (zDb = db_get("email-send-db",0))!=0 ){ sqlite3 *db; sqlite3_stmt *pStmt; int rc; @ Queued to database "%h(zDb)" rc = sqlite3_open(zDb, &db); if( rc==SQLITE_OK ){ rc = sqlite3_prepare_v2(db, "SELECT count(*) FROM email",-1,&pStmt,0); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ @ (%,d(sqlite3_column_int(pStmt,0)) messages, @ %,d(file_size(zDb,ExtFILE)) bytes) } sqlite3_finalize(pStmt); } sqlite3_close(db); }else if( fossil_strcmp(zDest,"dir")==0 && (zDir = db_get("email-send-dir",0))!=0 ){ @ Written to files in "%h(zDir)" @ (%,d(file_directory_size(zDir,0,1)) messages) |
︙ | ︙ | |||
109 110 111 112 113 114 115 | @ </td></tr> nPend = db_int(0,"SELECT count(*) FROM pending_alert WHERE NOT sentSep"); nDPend = db_int(0,"SELECT count(*) FROM pending_alert" " WHERE NOT sentDigest"); @ <tr><th>Pending Alerts:</th><td> @ %,d(nPend) normal, %,d(nDPend) digest @ </td></tr> | < < < | < < | < < < < < < < < < < < < < | 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 | @ </td></tr> nPend = db_int(0,"SELECT count(*) FROM pending_alert WHERE NOT sentSep"); nDPend = db_int(0,"SELECT count(*) FROM pending_alert" " WHERE NOT sentDigest"); @ <tr><th>Pending Alerts:</th><td> @ %,d(nPend) normal, %,d(nDPend) digest @ </td></tr> @ <tr><th>Subscribers:</th><td> nSub = db_int(0, "SELECT count(*) FROM subscriber"); nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified" " AND NOT sdonotcall AND length(ssub)>1"); @ %,d(nASub) active, %,d(nSub) total @ </td></tr> } /* ** WEBPAGE: stat ** ** Show statistics and global information about the repository. */ void stat_page(void){ i64 t, fsize; int n, m; int szMax, szAvg; int brief; const char *p; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } brief = P("brief")!=0; style_header("Repository Statistics"); style_adunit_config(ADUNIT_RIGHT_OK); if( g.perm.Admin ){ |
︙ | ︙ | |||
172 173 174 175 176 177 178 | } @ <table class="label-value"> fsize = file_size(g.zRepositoryName, ExtFILE); @ <tr><th>Repository Size:</th><td>%,lld(fsize) bytes</td> @ </td></tr> if( !brief ){ @ <tr><th>Number Of Artifacts:</th><td> | | | | | 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 | } @ <table class="label-value"> fsize = file_size(g.zRepositoryName, ExtFILE); @ <tr><th>Repository Size:</th><td>%,lld(fsize) bytes</td> @ </td></tr> if( !brief ){ @ <tr><th>Number Of Artifacts:</th><td> n = db_int(0, "SELECT count(*) FROM blob"); m = db_int(0, "SELECT count(*) FROM delta"); @ %.d(n) (%,d(n-m) fulltext and %,d(m) deltas) if( g.perm.Write ){ @ <a href='%R/artifact_stats'>Details</a> } @ </td></tr> if( n>0 ){ int a, b; Stmt q; @ <tr><th>Uncompressed Artifact Size:</th><td> db_prepare(&q, "SELECT total(size), avg(size), max(size)" " FROM blob WHERE size>0 /*scan*/"); db_step(&q); t = db_column_int64(&q, 0); szAvg = db_column_int(&q, 1); szMax = db_column_int(&q, 2); db_finalize(&q); @ %,d(szAvg) bytes average, %,d(szMax) bytes max, %,lld(t) total @ </td></tr> |
︙ | ︙ | |||
207 208 209 210 211 212 213 | @ %d(a):%d(b) @ </td></tr> } if( db_table_exists("repository","unversioned") ){ Stmt q; char zStored[100]; db_prepare(&q, | | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | @ %d(a):%d(b) @ </td></tr> } if( db_table_exists("repository","unversioned") ){ Stmt q; char zStored[100]; db_prepare(&q, "SELECT count(*), sum(sz), sum(length(content))" " FROM unversioned" " WHERE length(hash)>1" ); if( db_step(&q)==SQLITE_ROW && (n = db_column_int(&q,0))>0 ){ sqlite3_int64 iStored, pct; iStored = db_column_int64(&q,2); pct = (iStored*100 + fsize/2)/fsize; |
︙ | ︙ | |||
236 237 238 239 240 241 242 | @ %,d(n) @ </td></tr> @ <tr><th>Number Of Wiki Pages:</th><td> n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE +tagname GLOB 'wiki-*'"); @ %,d(n) @ </td></tr> | < < < < < < < < | < < < | < < < < < < < | | < < | | < | < < < < < | < < < < < < < < | 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 | @ %,d(n) @ </td></tr> @ <tr><th>Number Of Wiki Pages:</th><td> n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE +tagname GLOB 'wiki-*'"); @ %,d(n) @ </td></tr> @ <tr><th>Number Of Tickets:</th><td> n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE +tagname GLOB 'tkt-*'"); @ %,d(n) @ </td></tr> } @ <tr><th>Duration Of Project:</th><td> n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" " + 0.99"); @ %,d(n) days or approximately %.2f(n/365.2425) years. @ </td></tr> p = db_get("project-code", 0); if( p ){ @ <tr><th>Project ID:</th> @ <td>%h(p) %h(db_get("project-name",""))</td></tr> } p = db_get("parent-project-code", 0); if( p ){ @ <tr><th>Parent Project ID:</th> @ <td>%h(p) %h(db_get("parent-project-name",""))</td></tr> } /* @ <tr><th>Server ID:</th><td>%h(db_get("server-code",""))</td></tr> */ @ <tr><th>Fossil Version:</th><td> @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION) @ (%h(RELEASE_VERSION)) <a href='version?verbose'>(details)</a> @ </td></tr> @ <tr><th>SQLite Version:</th><td>%.19s(sqlite3_sourceid()) @ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion())) @ <a href='version?verbose'>(details)</a></td></tr> if( g.eHashPolicy!=HPOLICY_AUTO ){ @ <tr><th>Schema Version:</th><td>%h(g.zAuxSchema), @ %s(hpolicy_name())</td></tr> }else{ @ <tr><th>Schema Version:</th><td>%h(g.zAuxSchema)</td></tr> } @ <tr><th>Repository Rebuilt:</th><td> |
︙ | ︙ | |||
332 333 334 335 336 337 338 | @ <td>Last run: %z(backoffice_last_run())</td></tr> } if( g.perm.Admin && alert_enabled() ){ stats_for_email(); } @ </table> | | | | < > | | < < < < | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | @ <td>Last run: %z(backoffice_last_run())</td></tr> } if( g.perm.Admin && alert_enabled() ){ stats_for_email(); } @ </table> style_footer(); } /* ** COMMAND: dbstat* ** ** Usage: %fossil dbstat OPTIONS ** ** Shows statistics and global information about the repository. ** ** Options: ** ** --brief|-b Only show essential elements ** --db-check Run a PRAGMA quick_check on the repository database ** --omit-version-info Omit the SQLite and Fossil version information */ void dbstat_cmd(void){ i64 t, fsize; int n, m; int szMax, szAvg; int brief; int omitVers; /* Omit Fossil and SQLite version information */ int dbCheck; /* True for the --db-check option */ const int colWidth = -19 /* printf alignment/width for left column */; const char *p, *z; brief = find_option("brief", "b",0)!=0; omitVers = find_option("omit-version-info", 0, 0)!=0; dbCheck = find_option("db-check",0,0)!=0; db_find_and_open_repository(0,0); /* We should be done with options.. */ verify_all_options(); if( (z = db_get("project-name",0))!=0 || (z = db_get("short-project-name",0))!=0 ){ fossil_print("%*s%s\n", colWidth, "project-name:", z); } fsize = file_size(g.zRepositoryName, ExtFILE); fossil_print( "%*s%,lld bytes\n", colWidth, "repository-size:", fsize); if( !brief ){ n = db_int(0, "SELECT count(*) FROM blob"); m = db_int(0, "SELECT count(*) FROM delta"); fossil_print("%*s%,d (stored as %,d full text and %,d deltas)\n", colWidth, "artifact-count:", n, n-m, m); if( n>0 ){ int a, b; Stmt q; |
︙ | ︙ | |||
410 411 412 413 414 415 416 | a = t/fsize; fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b); } n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'"); fossil_print("%*s%,d\n", colWidth, "check-ins:", n); n = db_int(0, "SELECT count(*) FROM filename /*scan*/"); fossil_print("%*s%,d across all branches\n", colWidth, "files:", n); | | < < | < < < < < < < < < < < < | | | < | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | a = t/fsize; fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b); } n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'"); fossil_print("%*s%,d\n", colWidth, "check-ins:", n); n = db_int(0, "SELECT count(*) FROM filename /*scan*/"); fossil_print("%*s%,d across all branches\n", colWidth, "files:", n); n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE tagname GLOB 'wiki-*'"); m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='w'"); fossil_print("%*s%,d (%,d changes)\n", colWidth, "wiki-pages:", n, m); n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE tagname GLOB 'tkt-*'"); m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='t'"); fossil_print("%*s%,d (%,d changes)\n", colWidth, "tickets:", n, m); n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='e'"); fossil_print("%*s%,d\n", colWidth, "events:", n); n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='g'"); fossil_print("%*s%,d\n", colWidth, "tag-changes:", n); z = db_text(0, "SELECT datetime(mtime) || ' - about ' ||" " CAST(julianday('now') - mtime AS INTEGER)" " || ' days ago' FROM event " " ORDER BY mtime DESC LIMIT 1"); fossil_print("%*s%s\n", colWidth, "latest-change:", z); } n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" " + 0.99"); fossil_print("%*s%,d days or approximately %.2f years.\n", colWidth, "project-age:", n, n/365.2425); p = db_get("project-code", 0); if( p ){ fossil_print("%*s%s\n", colWidth, "project-id:", p); } #if 0 /* Server-id is not useful information any more */ fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0)); #endif fossil_print("%*s%s\n", colWidth, "schema-version:", g.zAuxSchema); if( !omitVers ){ |
︙ | ︙ | |||
475 476 477 478 479 480 481 | colWidth, "database-stats:", db_int(0, "PRAGMA repository.page_count"), db_int(0, "PRAGMA repository.page_size"), db_int(0, "PRAGMA repository.freelist_count"), db_text(0, "PRAGMA repository.encoding"), db_text(0, "PRAGMA repository.journal_mode")); if( dbCheck ){ | < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < | < < | | < < < < | > | < | < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < > | < < < < < < < < < < | | < | < < < < < < < | < < < < < < < | | < < < < < < < | | < > > | | | < | | < < < < < < < < < < < < < < < < < | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | colWidth, "database-stats:", db_int(0, "PRAGMA repository.page_count"), db_int(0, "PRAGMA repository.page_size"), db_int(0, "PRAGMA repository.freelist_count"), db_text(0, "PRAGMA repository.encoding"), db_text(0, "PRAGMA repository.journal_mode")); if( dbCheck ){ fossil_print("%*s%s\n", colWidth, "database-check:", db_text(0, "PRAGMA quick_check(1)")); } } /* ** WEBPAGE: urllist ** ** Show ways in which this repository has been accessed */ void urllist_page(void){ Stmt q; int cnt; int showAll = P("all")!=0; int nOmitted; sqlite3_int64 iNow; char *zRemote; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } style_header("URLs and Checkouts"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Stat", "stat"); style_submenu_element("Schema", "repo_schema"); iNow = db_int64(0, "SELECT strftime('%%s','now')"); @ <div class="section">URLs</div> @ <table border="0" width='100%%'> db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch'), mtime" " FROM config WHERE name GLOB 'baseurl:*' ORDER BY 3 DESC"); cnt = 0; nOmitted = 0; while( db_step(&q)==SQLITE_ROW ){ if( !showAll && db_column_int64(&q,2)<(iNow - 3600*24*30) && cnt>8 ){ nOmitted++; }else{ @ <tr><td width='100%%'>%h(db_column_text(&q,0))</td> @ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr> } cnt++; } db_finalize(&q); if( cnt==0 ){ @ <tr><td>(none)</td> }else if( nOmitted ){ @ <tr><td><a href="urllist?all"><i>Show %d(nOmitted) more...</i></a> } @ </table> @ <div class="section">Checkouts</div> @ <table border="0" width='100%%'> db_prepare(&q, "SELECT substr(name,7), datetime(mtime,'unixepoch')" " FROM config WHERE name GLOB 'ckout:*' ORDER BY 2 DESC"); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zPath = db_column_text(&q,0); if( vfile_top_of_checkout(zPath) ){ @ <tr><td width='100%%'>%h(zPath)</td> @ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr> } cnt++; } db_finalize(&q); if( cnt==0 ){ @ <tr><td>(none)</td> } @ </table> zRemote = db_text(0, "SELECT value FROM config WHERE name='last-sync-url'"); if( zRemote ){ @ <div class="section">Last Sync URL</div> if( sqlite3_strlike("http%", zRemote, 0)==0 ){ UrlData x; url_parse_local(zRemote, URL_OMIT_USER, &x); @ <p><a href='%h(x.canonical)'>%h(zRemote)</a> }else{ @ <p>%h(zRemote)</p> } @ </div> } style_footer(); } /* ** WEBPAGE: repo_schema ** ** Show the repository schema */ void repo_schema_page(void){ Stmt q; Blob sql; const char *zArg = P("n"); login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } style_header("Repository Schema"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Stat", "stat"); style_submenu_element("URLs", "urllist"); if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){ style_submenu_element("Table Sizes", "repo-tabsize"); } blob_init(&sql, "SELECT sql FROM repository.sqlite_master WHERE sql IS NOT NULL", -1); if( zArg ){ style_submenu_element("All", "repo_schema"); blob_appendf(&sql, " AND (tbl_name=%Q OR name=%Q)", zArg, zArg); } blob_appendf(&sql, " ORDER BY tbl_name, type<>'table', name"); db_prepare(&q, "%s", blob_str(&sql)/*safe-for-%s*/); blob_reset(&sql); |
︙ | ︙ | |||
773 774 775 776 777 778 779 | } @ </pre> db_finalize(&q); }else{ style_submenu_element("Stat1","repo_stat1"); } } | < < < < < < < | < < < < < < < < < < < < < < < < < | < < < < < | | < < < < | < < < < < < < < < < < | < < | | | | | | | | | | | | | | < | | | | | | | | | | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | } @ </pre> db_finalize(&q); }else{ style_submenu_element("Stat1","repo_stat1"); } } style_footer(); } /* ** WEBPAGE: repo_stat1 ** ** Show the sqlite_stat1 table for the repository schema */ void repo_stat1_page(void){ login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } style_header("Repository STAT1 Table"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Stat", "stat"); style_submenu_element("Schema", "repo_schema"); if( db_table_exists("repository","sqlite_stat1") ){ Stmt q; db_prepare(&q, "SELECT tbl, idx, stat FROM repository.sqlite_stat1" " ORDER BY tbl, idx"); @ <pre> while( db_step(&q)==SQLITE_ROW ){ const char *zTab = db_column_text(&q,0); const char *zIdx = db_column_text(&q,1); const char *zStat = db_column_text(&q,2); char *zUrl = href("%R/repo_schema?n=%t",zTab); @ INSERT INTO sqlite_stat1 VALUES('%z(zUrl)%h(zTab)</a>','%h(zIdx)','%h(zStat)'); } @ </pre> db_finalize(&q); } style_footer(); } /* ** WEBPAGE: repo-tabsize ** ** Show relative sizes of tables in the repository database. */ void repo_tabsize_page(void){ int nPageFree; sqlite3_int64 fsize; char zBuf[100]; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("Repository Table Sizes"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Stat", "stat"); if( g.perm.Admin ){ style_submenu_element("Schema", "repo_schema"); } db_multi_exec( "CREATE TEMP TABLE trans(name TEXT PRIMARY KEY,tabname TEXT)WITHOUT ROWID;" "INSERT INTO trans(name,tabname)" " SELECT name, tbl_name FROM repository.sqlite_master;" "CREATE TEMP TABLE piechart(amt REAL, label TEXT);" "INSERT INTO piechart(amt,label)" " SELECT count(*), " " coalesce((SELECT tabname FROM trans WHERE trans.name=dbstat.name),name)" " FROM dbstat('repository')" " GROUP BY 2 ORDER BY 2;" ); nPageFree = db_int(0, "PRAGMA repository.freelist_count"); if( nPageFree>0 ){ db_multi_exec( "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')", nPageFree ); } fsize = file_size(g.zRepositoryName, ExtFILE); approxSizeName(sizeof(zBuf), zBuf, fsize); @ <h2>Repository Size: %s(zBuf)</h2> @ <center><svg width='800' height='500'> piechart_render(800,500,PIE_OTHER|PIE_PERCENT); @ </svg></center> if( g.localOpen ){ db_multi_exec( "DELETE FROM trans;" "INSERT INTO trans(name,tabname)" " SELECT name, tbl_name FROM localdb.sqlite_master;" "DELETE FROM piechart;" "INSERT INTO piechart(amt,label)" " SELECT count(*), " " coalesce((SELECT tabname FROM trans WHERE trans.name=dbstat.name),name)" " FROM dbstat('localdb')" " GROUP BY 2 ORDER BY 2;" ); nPageFree = db_int(0, "PRAGMA localdb.freelist_count"); if( nPageFree>0 ){ db_multi_exec( "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')", nPageFree ); } fsize = file_size(g.zLocalDbName, ExtFILE); approxSizeName(sizeof(zBuf), zBuf, fsize); @ <h2>%h(file_tail(g.zLocalDbName)) Size: %s(zBuf)</h2> @ <center><svg width='800' height='500'> piechart_render(800,500,PIE_OTHER|PIE_PERCENT); @ </svg></center> } style_footer(); } /* ** Gather statistics on artifact types, counts, and sizes. ** ** Only populate the artstat.atype field if the bWithTypes parameter is true. */ static void gather_artifact_stats(int bWithTypes){ static const char zSql[] = @ CREATE TEMP TABLE artstat( @ id INTEGER PRIMARY KEY, -- Corresponds to BLOB.RID @ atype TEXT, -- 'data', 'manifest', 'tag', 'wiki', etc. @ isDelta BOOLEAN, -- true if stored as a delta @ szExp, -- expanded, uncompressed size @ szCmpr -- size as stored on disk @ ); @ INSERT INTO artstat(id,atype,isDelta,szExp,szCmpr) @ SELECT blob.rid, NULL, @ EXISTS(SELECT 1 FROM delta WHERE delta.rid=blob.rid), @ size, length(content) @ FROM blob @ WHERE content IS NOT NULL; ; static const char zSql2[] = @ UPDATE artstat SET atype='file' @ WHERE id IN (SELECT fid FROM mlink) @ AND atype IS NULL; @ UPDATE artstat SET atype='manifest' @ WHERE id IN (SELECT objid FROM event WHERE type='ci') AND atype IS NULL; @ UPDATE artstat SET atype='cluster' @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid=(SELECT tagid FROM tag @ WHERE tagname='cluster')); @ UPDATE artstat SET atype='ticket' @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid IN (SELECT tagid FROM tag @ WHERE tagname GLOB 'tkt-*')); @ UPDATE artstat SET atype='wiki' @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid IN (SELECT tagid FROM tag @ WHERE tagname GLOB 'wiki-*')); @ UPDATE artstat SET atype='technote' @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid IN (SELECT tagid FROM tag @ WHERE tagname GLOB 'event-*')); @ UPDATE artstat SET atype='attachment' @ WHERE atype IS NULL @ AND id IN (SELECT attachid FROM attachment UNION @ SELECT blob.rid FROM attachment JOIN blob ON uuid=src); @ UPDATE artstat SET atype='tag' @ WHERE atype IS NULL @ AND id IN (SELECT srcid FROM tagxref); @ UPDATE artstat SET atype='tag' @ WHERE atype IS NULL @ AND id IN (SELECT objid FROM event WHERE type='g'); @ UPDATE artstat SET atype='unused' WHERE atype IS NULL; ; db_multi_exec("%s", zSql/*safe-for-%s*/); if( bWithTypes ){ db_multi_exec("%s", zSql2/*safe-for-%s*/); } |
︙ | ︙ | |||
1037 1038 1039 1040 1041 1042 1043 | login_check_credentials(); /* These stats are expensive to compute. To disable them for ** user without check-in privileges, to prevent excessive usage by ** robots and random passers-by on the internet */ | | | < < < | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | login_check_credentials(); /* These stats are expensive to compute. To disable them for ** user without check-in privileges, to prevent excessive usage by ** robots and random passers-by on the internet */ if( !g.perm.Write ){ login_needed(g.anon.Admin); return; } style_header("Artifact Statistics"); style_submenu_element("Repository Stats", "stat"); style_submenu_element("Artifact List", "bloblist"); gather_artifact_stats(1); db_prepare(&q, "SELECT count(*), sum(isDelta), max(szCmpr)," |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 | mxCmpr = db_column_int(&q, 2); mxExp = db_column_int(&q, 3); sumCmpr = db_column_int64(&q, 4); sumExp = db_column_int64(&q, 5); db_finalize(&q); if( nTotal==0 ){ @ No artifacts in this repository! | | | | | | < < < | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 | mxCmpr = db_column_int(&q, 2); mxExp = db_column_int(&q, 3); sumCmpr = db_column_int64(&q, 4); sumExp = db_column_int64(&q, 5); db_finalize(&q); if( nTotal==0 ){ @ No artifacts in this repository! style_footer(); return; } avgCmpr = (double)sumCmpr/nTotal; avgExp = (double)sumExp/nTotal; db_prepare(&q, "SELECT szCmpr FROM artstat ORDER BY 1 DESC"); r = 0; n = 0; while( db_step(&q)==SQLITE_ROW ){ r += db_column_int(&q, 0); if( n50pct==0 && r>=sumCmpr/2 ) n50pct = n; if( n==(nTotal+99)/100 ) sz1pct = r; if( n==(nTotal+9)/10 ) sz10pct = r; if( n==(nTotal+4)/5 ) sz25pct = r; if( n==(nTotal+1)/2 ){ sz50pct = r; medCmpr = db_column_int(&q,0); } n++; } db_finalize(&q); @ <h1>Overall Artifact Size Statistics:</h1> @ <table class="label-value"> @ <tr><th>Number of artifacts:</th><td>%,d(nTotal)</td></tr> |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | r = db_double(0.0, "SELECT avg(szCmpr) FROM artstat WHERE NOT isDelta;"); med = db_int(0, "SELECT szCmpr FROM artstat WHERE NOT isDelta ORDER BY szCmpr" " LIMIT 1 OFFSET %d", nFull/2); @ <tr><th>Full-text artifact sizes:</th> @ <td>largest: %,d(mxCmpr), average: %,d((int)r), median: %,d(med)</td> @ </table> | | | 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | r = db_double(0.0, "SELECT avg(szCmpr) FROM artstat WHERE NOT isDelta;"); med = db_int(0, "SELECT szCmpr FROM artstat WHERE NOT isDelta ORDER BY szCmpr" " LIMIT 1 OFFSET %d", nFull/2); @ <tr><th>Full-text artifact sizes:</th> @ <td>largest: %,d(mxCmpr), average: %,d((int)r), median: %,d(med)</td> @ </table> @ <h1>Artifact size distribution facts:</h1> @ <ol> @ <li><p>The largest %.2f(n50pct*100.0/nTotal)%% of artifacts largest_n_artifacts(n50pct); @ use 50%% of the total artifact space. @ <li><p>The largest 1%% of artifacts largest_n_artifacts((nTotal+99)/100); @ use %lld(sz1pct*100/sumCmpr)%% of the total artifact space. |
︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | int nFull = nTotal - nDelta; sqlite3_int64 szCmpr = db_column_int64(&q, 3); sqlite3_int64 szExp = db_column_int64(&q, 4); @ <tr><td>%h(zType)</td> @ <td data-sortkey='%08x(nTotal)' align='right'>%,d(nTotal)</td> @ <td data-sortkey='%08x(nFull)' align='right'>%,d(nFull)</td> @ <td data-sortkey='%08x(nDelta)' align='right'>%,d(nDelta)</td> | | | | 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | int nFull = nTotal - nDelta; sqlite3_int64 szCmpr = db_column_int64(&q, 3); sqlite3_int64 szExp = db_column_int64(&q, 4); @ <tr><td>%h(zType)</td> @ <td data-sortkey='%08x(nTotal)' align='right'>%,d(nTotal)</td> @ <td data-sortkey='%08x(nFull)' align='right'>%,d(nFull)</td> @ <td data-sortkey='%08x(nDelta)' align='right'>%,d(nDelta)</td> @ <td data-sortkey='%016x(szCmpr)' align='right'>%,lld(szCmpr)</td> @ <td data-sortkey='%016x(szExp)' align='right'>%,lld(szExp)</td> } @ </tbody></table> db_finalize(&q); if( db_exists("SELECT 1 FROM artstat WHERE atype='unused'") ){ @ <h1>Unused Artifacts:</h1> db_prepare(&q, |
︙ | ︙ | |||
1214 1215 1216 1217 1218 1219 1220 | @ <td>%h(zDate)</td> @ <td>%z(href("%R/rcvfrom?rcvid=%d",iRcvid))%d(iRcvid)</a></td></tr> } @ </tbody></table></div> db_finalize(&q); } style_table_sorter(); | | | 920 921 922 923 924 925 926 927 928 | @ <td>%h(zDate)</td> @ <td>%z(href("%R/rcvfrom?rcvid=%d",iRcvid))%d(iRcvid)</a></td></tr> } @ </tbody></table></div> db_finalize(&q); } style_table_sorter(); style_footer(); } |
Changes to src/statrep.c.
︙ | ︙ | |||
48 49 50 51 52 53 54 | ** no 'y' is specified), "*" is assumed (that is also the default for ** invalid/unknown filter values). That 'y' filter is the one used for ** the event list. Note that a filter of "*" or "all" is equivalent to ** querying against the full event table. The view, however, adds an ** abstraction level to simplify the implementation code for the ** various /reports pages. ** | | < < < < < < < < < < < < < < < | 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 | ** no 'y' is specified), "*" is assumed (that is also the default for ** invalid/unknown filter values). That 'y' filter is the one used for ** the event list. Note that a filter of "*" or "all" is equivalent to ** querying against the full event table. The view, however, adds an ** abstraction level to simplify the implementation code for the ** various /reports pages. ** ** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of ** filter it applies, or '*' if no filter is applied (i.e. if "all" is ** used). */ static int stats_report_init_view(){ const char *zType = PD("type","*"); /* analog to /timeline?y=... */ const char *zRealType = NULL; /* normalized form of zType */ int rc = 0; /* result code */ char *zTimeSpan; /* Time span */ assert( !statsReportType && "Must not be called more than once." ); switch( (zType && *zType) ? *zType : 0 ){ case 'c': case 'C': zRealType = "ci"; rc = *zRealType; break; case 'e': case 'E': zRealType = "e"; rc = *zRealType; break; case 'g': case 'G': zRealType = "g"; rc = *zRealType; break; case 't': case 'T': zRealType = "t"; rc = *zRealType; break; |
︙ | ︙ | |||
111 112 113 114 115 116 117 | if( P("from")!=0 && P("to")!=0 ){ zTimeSpan = mprintf( " (event.mtime BETWEEN julianday(%Q) AND julianday(%Q))", P("from"), P("to")); }else{ zTimeSpan = " 1"; } | | < < < < < | < | | < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | | < | < > | < | | < < < < < < < < < | < < < < < | | 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 | if( P("from")!=0 && P("to")!=0 ){ zTimeSpan = mprintf( " (event.mtime BETWEEN julianday(%Q) AND julianday(%Q))", P("from"), P("to")); }else{ zTimeSpan = " 1"; } if(zRealType){ statsReportTimelineYFlag = zRealType; db_multi_exec("CREATE TEMP VIEW v_reports AS " "SELECT * FROM event WHERE (type GLOB %Q) AND %s", zRealType, zTimeSpan/*safe-for-%s*/); }else{ statsReportTimelineYFlag = "a"; db_multi_exec("CREATE TEMP VIEW v_reports AS " "SELECT * FROM event WHERE %s", zTimeSpan/*safe-for-%s*/); } return statsReportType = rc; } /* ** Returns a string suitable (for a given value of suitable) for ** use in a label with the header of the /reports pages, dependent ** on the 'type' flag. See stats_report_init_view(). ** The returned bytes are static. */ static const char *stats_report_label_for_type(){ assert( statsReportType && "Must call stats_report_init_view() first." ); switch( statsReportType ){ case 'c': return "check-ins"; case 'e': return "technotes"; case 'w': return "wiki changes"; case 't': return "ticket changes"; case 'g': return "tag changes"; default: return "all types"; } } /* ** Helper for stats_report_by_month_year(), which generates a list of ** week numbers. zTimeframe should be either a timeframe in the form YYYY ** or YYYY-MM. */ static void stats_report_output_week_links(const char *zTimeframe){ Stmt stWeek = empty_Stmt; char yearPart[5] = {0,0,0,0,0}; memcpy(yearPart, zTimeframe, 4); db_prepare(&stWeek, "SELECT DISTINCT strftime('%%W',mtime) AS wk, " "count(*) AS n, " "substr(date(mtime),1,%d) AS ym " "FROM v_reports " "WHERE ym=%Q AND mtime < current_timestamp " "GROUP BY wk ORDER BY wk", strlen(zTimeframe), zTimeframe); while( SQLITE_ROW == db_step(&stWeek) ){ const char *zWeek = db_column_text(&stWeek,0); const int nCount = db_column_int(&stWeek,1); cgi_printf("<a href='%R/timeline?" "yw=%t-%t&n=%d&y=%s'>%s</a>", yearPart, zWeek, nCount, statsReportTimelineYFlag, zWeek); } db_finalize(&stWeek); } /* ** Implements the "byyear" and "bymonth" reports for /reports. ** If includeMonth is true then it generates the "bymonth" report, ** else the "byyear" report. If zUserName is not NULL then the report is ** restricted to events created by the named user account. */ static void stats_report_by_month_year(char includeMonth, char includeWeeks, const char *zUserName){ Stmt query = empty_Stmt; int nRowNumber = 0; /* current TR number */ int nEventTotal = 0; /* Total event count */ int rowClass = 0; /* counter for alternating row colors */ const char *zTimeLabel = includeMonth ? "Year/Month" : "Year"; char zPrevYear[5] = {0}; /* For keeping track of when we change years while looping */ int nEventsPerYear = 0; /* Total event count for the current year */ char showYearTotal = 0; /* Flag telling us when to show the per-year event totals */ int nMaxEvents = 1; /* for calculating length of graph bars. */ int iterations = 0; /* number of weeks/months we iterate over */ Blob userFilter = empty_blob; /* Optional user=johndoe query string */ stats_report_init_view(); if( zUserName ){ blob_appendf(&userFilter, "user=%s", zUserName); } blob_reset(&userFilter); db_prepare(&query, "SELECT substr(date(mtime),1,%d) AS timeframe," " count(*) AS eventCount" " FROM v_reports" " WHERE ifnull(coalesce(euser,user,'')=%Q,1)" " GROUP BY timeframe" " ORDER BY timeframe DESC", includeMonth ? 7 : 4, zUserName); @ <h1>Timeline Events (%s(stats_report_label_for_type())) @ by year%s(includeMonth ? "/month" : "") if( zUserName ){ @ for user %h(zUserName) } @ </h1> @ <table border='0' cellpadding='2' cellspacing='0' \ if( !includeMonth ){ @ class='statistics-report-table-events sortable' \ @ data-column-types='tnx' data-init-sort='0'> style_table_sorter(); }else{ @ class='statistics-report-table-events'> } @ <thead> @ <th>%s(zTimeLabel)</th> @ <th>Events</th> @ <th width='90%%'><!-- relative commits graph --></th> @ </thead><tbody> /* Run the query twice. The first time we calculate the maximum number of events for a given row. Maybe someone with better SQL Fu can re-implement this with a single query. */ while( SQLITE_ROW == db_step(&query) ){ const int nCount = db_column_int(&query, 1); if(nCount>nMaxEvents){ nMaxEvents = nCount; } ++iterations; } db_reset(&query); while( SQLITE_ROW == db_step(&query) ){ const char *zTimeframe = db_column_text(&query, 0); const int nCount = db_column_int(&query, 1); int nSize = nCount ? (int)(100 * nCount / nMaxEvents) : 1; showYearTotal = 0; if(!nSize) nSize = 1; if(includeMonth){ /* For Month/year view, add a separator for each distinct year. */ if(!*zPrevYear || |
︙ | ︙ | |||
307 308 309 310 311 312 313 | zTimeframe, (char)statsReportType); if( zUserName ){ cgi_printf("&u=%t", zUserName); } cgi_printf("'>%s</a>", zTimeframe); } @ </td><td>%d(nCount)</td> | | < < < < < < < < < < < < < < < | | < | > > > > > > > > > > > | | > | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | zTimeframe, (char)statsReportType); if( zUserName ){ cgi_printf("&u=%t", zUserName); } cgi_printf("'>%s</a>", zTimeframe); } @ </td><td>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' @ style='width:%d(nSize)%%;'> </div> @ </td> @</tr> if(includeWeeks){ /* This part works fine for months but it terribly slow (4.5s on my PC), so it's only shown for by-year for now. Suggestions/patches for a better/faster layout are welcomed. */ @ <tr class='row%d(rowClass)'> @ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td> @ <td class='statistics-report-week-of-year-list'> stats_report_output_week_links(zTimeframe); @ </td></tr> } /* Potential improvement: calculate the min/max event counts and use percent-based graph bars. */ } db_finalize(&query); if(includeMonth && !showYearTotal && *zPrevYear){ /* Add final year total separator. */ rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <td></td> @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td> @</tr> } @ </tbody></table> if(nEventTotal){ const char *zAvgLabel = includeMonth ? "month" : "year"; int nAvg = iterations ? (nEventTotal/iterations) : 0; @ <br /><div>Total events: %d(nEventTotal) @ <br />Average per active %s(zAvgLabel): %d(nAvg) @ </div> } } /* ** Implements the "byuser" view for /reports. */ static void stats_report_by_user(){ Stmt query = empty_Stmt; int nRowNumber = 0; /* current TR number */ int nEventTotal = 0; /* Total event count */ int rowClass = 0; /* counter for alternating row colors */ int nMaxEvents = 1; /* max number of events for all rows. */ stats_report_init_view(); @ <h1>Timeline Events @ (%s(stats_report_label_for_type())) by User</h1> db_multi_exec( "CREATE TEMP VIEW piechart(amt,label) AS" " SELECT count(*), ifnull(euser,user) FROM v_reports" " GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;" ); if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){ @ <center><svg width=700 height=400> piechart_render(700, 400, PIE_OTHER|PIE_PERCENT); @ </svg></centre><hr /> } style_table_sorter(); @ <table class='statistics-report-table-events sortable' border='0' \ @ cellpadding='2' cellspacing='0' data-column-types='tkx' data-init-sort='2'> @ <thead><tr> @ <th>User</th> @ <th>Events</th> |
︙ | ︙ | |||
405 406 407 408 409 410 411 412 413 414 415 416 417 418 | char y = (char)statsReportType; int nSize = nCount ? (int)(100 * nCount / nMaxEvents) : 0; if(!nCount) continue /* arguable! Possible? */; else if(!nSize) nSize = 1; rowClass = ++nRowNumber % 2; @ <tr class='row%d(rowClass)'> @ <td> @ <a href="?view=bymonth&user=%h(zUser)&type=%c(y)">%h(zUser)</a> @ </td><td data-sortkey='%08x(-nCount)'>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' @ style='width:%d(nSize)%%;'> </div> | > | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | char y = (char)statsReportType; int nSize = nCount ? (int)(100 * nCount / nMaxEvents) : 0; if(!nCount) continue /* arguable! Possible? */; else if(!nSize) nSize = 1; rowClass = ++nRowNumber % 2; nEventTotal += nCount; @ <tr class='row%d(rowClass)'> @ <td> @ <a href="?view=bymonth&user=%h(zUser)&type=%c(y)">%h(zUser)</a> @ </td><td data-sortkey='%08x(-nCount)'>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' @ style='width:%d(nSize)%%;'> </div> |
︙ | ︙ | |||
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | /* ** Implements the "byweekday" view for /reports. If zUserName is not NULL then ** the report is restricted to events created by the named user account. */ static void stats_report_day_of_week(const char *zUserName){ Stmt query = empty_Stmt; int nRowNumber = 0; /* current TR number */ int rowClass = 0; /* counter for alternating row colors */ int nMaxEvents = 1; /* max number of events for all rows. */ static const char *const daysOfWeek[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; stats_report_init_view(); db_prepare(&query, "SELECT cast(strftime('%%w', mtime) AS INTEGER) dow," " COUNT(*) AS eventCount" " FROM v_reports" " WHERE ifnull(coalesce(euser,user,'')=%Q,1)" " GROUP BY dow ORDER BY dow", zUserName); @ <h1>Timeline Events (%h(stats_report_label_for_type())) by Day of the Week | > > > > > | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | /* ** Implements the "byweekday" view for /reports. If zUserName is not NULL then ** the report is restricted to events created by the named user account. */ static void stats_report_day_of_week(const char *zUserName){ Stmt query = empty_Stmt; int nRowNumber = 0; /* current TR number */ int nEventTotal = 0; /* Total event count */ int rowClass = 0; /* counter for alternating row colors */ int nMaxEvents = 1; /* max number of events for all rows. */ Blob userFilter = empty_blob; /* Optional user=johndoe query string */ static const char *const daysOfWeek[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; stats_report_init_view(); if( zUserName ){ blob_appendf(&userFilter, "user=%s", zUserName); } db_prepare(&query, "SELECT cast(strftime('%%w', mtime) AS INTEGER) dow," " COUNT(*) AS eventCount" " FROM v_reports" " WHERE ifnull(coalesce(euser,user,'')=%Q,1)" " GROUP BY dow ORDER BY dow", zUserName); @ <h1>Timeline Events (%h(stats_report_label_for_type())) by Day of the Week |
︙ | ︙ | |||
529 530 531 532 533 534 535 | " WHERE ifnull(coalesce(euser,user,'')=%Q,1)" " GROUP BY 2 ORDER BY cast(strftime('%%w', mtime) AS INT);" , zUserName ); if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){ @ <center><svg width=700 height=400> piechart_render(700, 400, PIE_OTHER|PIE_PERCENT); | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | " WHERE ifnull(coalesce(euser,user,'')=%Q,1)" " GROUP BY 2 ORDER BY cast(strftime('%%w', mtime) AS INT);" , zUserName ); if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){ @ <center><svg width=700 height=400> piechart_render(700, 400, PIE_OTHER|PIE_PERCENT); @ </svg></centre><hr /> } style_table_sorter(); @ <table class='statistics-report-table-events sortable' border='0' \ @ cellpadding='2' cellspacing='0' data-column-types='ntnx' data-init-sort='1'> @ <thead><tr> @ <th>DoW</th> @ <th>Day</th> |
︙ | ︙ | |||
556 557 558 559 560 561 562 563 564 565 566 567 | const int nCount = db_column_int(&query, 1); int nSize = nCount ? (int)(100 * nCount / nMaxEvents) : 0; if(!nCount) continue /* arguable! Possible? */; else if(!nSize) nSize = 1; rowClass = ++nRowNumber % 2; @<tr class='row%d(rowClass)'> @ <td>%d(dayNum)</td> @ <td>%s(daysOfWeek[dayNum])</td> @ <td>%d(nCount)</td> @ <td> | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | < < < < < < < | | | | | < < < < < < | | | < < < < < < < < < < < < < < < | | > | < | | | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | const int nCount = db_column_int(&query, 1); int nSize = nCount ? (int)(100 * nCount / nMaxEvents) : 0; if(!nCount) continue /* arguable! Possible? */; else if(!nSize) nSize = 1; rowClass = ++nRowNumber % 2; nEventTotal += nCount; @<tr class='row%d(rowClass)'> @ <td>%d(dayNum)</td> @ <td>%s(daysOfWeek[dayNum])</td> @ <td>%d(nCount)</td> @ <td> @ <div class='statistics-report-graph-line' @ style='width:%d(nSize)%%;'> </div> @ </td> @</tr> } @ </tbody></table> db_finalize(&query); } /* ** Helper for stats_report_by_month_year(), which generates a list of ** week numbers. zTimeframe should be either a timeframe in the form YYYY ** or YYYY-MM. If zUserName is not NULL then the report is restricted to events ** created by the named user account. */ static void stats_report_year_weeks(const char *zUserName){ const char *zYear = P("y"); /* Year for which report shown */ Stmt q; int nMaxEvents = 1; /* max number of events for all rows. */ int iterations = 0; /* # of active time periods. */ int rowCount = 0; int total = 0; stats_report_init_view(); style_submenu_sql("y", "Year:", "WITH RECURSIVE a(b) AS (" " SELECT substr(date('now'),1,4) UNION ALL" " SELECT b-1 FROM a" " WHERE b>0+(SELECT substr(date(min(mtime)),1,4) FROM event)" ") SELECT b, b FROM a ORDER BY b DESC"); if( zYear==0 || strlen(zYear)!=4 ){ zYear = db_text("1970","SELECT substr(date('now'),1,4);"); } cgi_printf("<br />"); db_prepare(&q, "SELECT DISTINCT strftime('%%W',mtime) AS wk, " " count(*) AS n " " FROM v_reports " " WHERE %Q=substr(date(mtime),1,4) " " AND mtime < current_timestamp " " AND ifnull(coalesce(euser,user,'')=%Q,1)" " GROUP BY wk ORDER BY wk DESC", zYear, zUserName); @ <h1>Timeline events (%h(stats_report_label_for_type())) @ for the calendar weeks of %h(zYear) if( zUserName ){ @ for user %h(zUserName) } @ </h1> style_table_sorter(); cgi_printf("<table class='statistics-report-table-events sortable' " "border='0' cellpadding='2' width='100%%' " "cellspacing='0' data-column-types='tnx' data-init-sort='0'>"); cgi_printf("<thead><tr>" "<th>Week</th>" "<th>Events</th>" "<th width='90%%'><!-- relative commits graph --></th>" "</tr></thead>" "<tbody>"); while( SQLITE_ROW == db_step(&q) ){ const int nCount = db_column_int(&q, 1); if(nCount>nMaxEvents){ nMaxEvents = nCount; } ++iterations; } db_reset(&q); while( SQLITE_ROW == db_step(&q) ){ const char *zWeek = db_column_text(&q,0); const int nCount = db_column_int(&q,1); int nSize = nCount ? (int)(100 * nCount / nMaxEvents) : 0; if(!nSize) nSize = 1; total += nCount; cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); cgi_printf("<td><a href='%R/timeline?yw=%t-%s&n=%d&y=%s", zYear, zWeek, nCount, statsReportTimelineYFlag); if( zUserName ){ cgi_printf("&u=%t",zUserName); } cgi_printf("'>%s</a></td>",zWeek); cgi_printf("<td>%d</td>",nCount); cgi_printf("<td>"); if(nCount){ cgi_printf("<div class='statistics-report-graph-line'" "style='width:%d%%;'> </div>", nSize); } cgi_printf("</td></tr>"); } db_finalize(&q); cgi_printf("</tbody></table>"); if(total){ int nAvg = iterations ? (total/iterations) : 0; cgi_printf("<br /><div>Total events: %d<br />" "Average per active week: %d</div>", total, nAvg); } } /* |
︙ | ︙ | |||
825 826 827 828 829 830 831 | #define RPT_BYFILE 1 #define RPT_BYMONTH 2 #define RPT_BYUSER 3 #define RPT_BYWEEK 4 #define RPT_BYWEEKDAY 5 #define RPT_BYYEAR 6 #define RPT_LASTCHNG 7 /* Last change made for each user */ | < | < < < < < < < < < | < < < < < < | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | #define RPT_BYFILE 1 #define RPT_BYMONTH 2 #define RPT_BYUSER 3 #define RPT_BYWEEK 4 #define RPT_BYWEEKDAY 5 #define RPT_BYYEAR 6 #define RPT_LASTCHNG 7 /* Last change made for each user */ #define RPT_NONE 0 /* None of the above */ /* ** WEBPAGE: reports ** ** Shows activity reports for the repository. ** ** Query Parameters: ** ** view=REPORT_NAME Valid values: bymonth, byyear, byuser ** user=NAME Restricts statistics to the given user ** type=TYPE Restricts the report to a specific event type: ** ci (check-in), w (wiki), t (ticket), g (tag) ** Defaulting to all event types. ** ** The view-specific query parameters include: ** ** view=byweek: ** ** y=YYYY The year to report (default is the server's |
︙ | ︙ | |||
881 882 883 884 885 886 887 | { "File Changes","byfile", RPT_BYFILE }, { "Last Change", "lastchng", RPT_LASTCHNG }, { "By Month", "bymonth", RPT_BYMONTH }, { "By User", "byuser", RPT_BYUSER }, { "By Week", "byweek", RPT_BYWEEK }, { "By Weekday", "byweekday", RPT_BYWEEKDAY }, { "By Year", "byyear", RPT_BYYEAR }, | < < < < | 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | { "File Changes","byfile", RPT_BYFILE }, { "Last Change", "lastchng", RPT_LASTCHNG }, { "By Month", "bymonth", RPT_BYMONTH }, { "By User", "byuser", RPT_BYUSER }, { "By Week", "byweek", RPT_BYWEEK }, { "By Weekday", "byweekday", RPT_BYWEEKDAY }, { "By Year", "byyear", RPT_BYYEAR }, }; static const char *const azType[] = { "a", "All Changes", "ci", "Check-ins", "g", "Tags", "e", "Tech Notes", "t", "Tickets", "w", "Wiki" }; login_check_credentials(); |
︙ | ︙ | |||
910 911 912 913 914 915 916 | } for(i=0; i<count(aViewType); i++){ if( fossil_strcmp(zView, aViewType[i].zVal)==0 ){ eType = aViewType[i].eType; break; } } | < | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | } for(i=0; i<count(aViewType); i++){ if( fossil_strcmp(zView, aViewType[i].zVal)==0 ){ eType = aViewType[i].eType; break; } } if( eType!=RPT_NONE ){ int nView = 0; /* Slots used in azView[] */ for(i=0; i<count(aViewType); i++){ azView[nView++] = aViewType[i].zVal; azView[nView++] = aViewType[i].zName; } if( eType!=RPT_BYFILE ){ |
︙ | ︙ | |||
935 936 937 938 939 940 941 | ); } } style_submenu_element("Stats", "%R/stat"); style_header("Activity Reports"); switch( eType ){ case RPT_BYYEAR: | | | < < < | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | ); } } style_submenu_element("Stats", "%R/stat"); style_header("Activity Reports"); switch( eType ){ case RPT_BYYEAR: stats_report_by_month_year(0, 0, zUserName); break; case RPT_BYMONTH: stats_report_by_month_year(1, 0, zUserName); break; case RPT_BYWEEK: stats_report_year_weeks(zUserName); break; default: case RPT_BYUSER: stats_report_by_user(); break; case RPT_BYWEEKDAY: stats_report_day_of_week(zUserName); break; case RPT_BYFILE: stats_report_by_file(zUserName); break; case RPT_LASTCHNG: stats_report_last_change(); break; } style_footer(); } |
Deleted src/style.admin_log.css.
|
| < < < < < < |
Changes to src/style.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 | ** style_submenu_element() ** style_submenu_entry() ** style_submenu_checkbox() ** style_submenu_binary() ** style_submenu_multichoice() ** style_submenu_sql() ** | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ** style_submenu_element() ** style_submenu_entry() ** style_submenu_checkbox() ** style_submenu_binary() ** style_submenu_multichoice() ** style_submenu_sql() ** ** prior to calling style_footer(). The style_footer() routine ** will generate the appropriate HTML text just below the main ** menu. */ static struct Submenu { const char *zLabel; /* Button label */ const char *zLink; /* Jump to this link when button is pressed */ } aSubmenu[30]; |
︙ | ︙ | |||
77 78 79 80 81 82 83 | static int sideboxUsed = 0; /* ** Ad-unit styles. */ static unsigned adUnitFlags = 0; | < < < < < < < < < < < | > > | | < < < < < < < < < < | | | | > > | < < > | | < < < < < < < < < < < < | < < | | 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 | static int sideboxUsed = 0; /* ** Ad-unit styles. */ static unsigned adUnitFlags = 0; /* ** Flags for various javascript files needed prior to </body> */ static int needHrefJs = 0; /* href.js */ static int needSortJs = 0; /* sorttable.js */ static int needGraphJs = 0; /* graph.js */ /* ** Extra JS added to the end of the file. */ static Blob blobOnLoad = BLOB_INITIALIZER; /* ** Generate and return a anchor tag like this: ** ** <a href="URL"> ** or <a id="ID"> ** ** The form of the anchor tag is determined by the g.javascriptHyperlink ** variable. The href="URL" form is used if g.javascriptHyperlink is false. ** If g.javascriptHyperlink is true then the ** id="ID" form is used and javascript is generated in the footer to cause ** href values to be inserted after the page has loaded. If ** g.perm.History is false, then the <a id="ID"> form is still ** generated but the javascript is not generated so the links never ** activate. ** ** If the user lacks the Hyperlink (h) property and the "auto-hyperlink" ** setting is true, then g.perm.Hyperlink is changed from 0 to 1 and ** g.javascriptHyperlink is set to 1. The g.javascriptHyperlink defaults ** to 0 and only changes to one if the user lacks the Hyperlink (h) property ** and the "auto-hyperlink" setting is enabled. ** ** Filling in the href="URL" using javascript is a defense against bots. ** ** The name of this routine is deliberately kept short so that can be ** easily used within @-lines. Example: ** ** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a> ** ** Note %z format. The string returned by this function is always ** obtained from fossil_malloc() so rendering it with %z will reclaim ** that memory space. |
︙ | ︙ | |||
167 168 169 170 171 172 173 | ** Most logged in users should have this property, since we can assume ** that a logged in user is not a bot. Only "nobody" lacks g.perm.Hyperlink, ** typically. */ char *xhref(const char *zExtra, const char *zFormat, ...){ char *zUrl; va_list ap; | < < < | | < < < < < < | | < < | | < | | | < < < < < < < < < < < < < < < < < | < | 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 | ** Most logged in users should have this property, since we can assume ** that a logged in user is not a bot. Only "nobody" lacks g.perm.Hyperlink, ** typically. */ char *xhref(const char *zExtra, const char *zFormat, ...){ char *zUrl; va_list ap; va_start(ap, zFormat); zUrl = vmprintf(zFormat, ap); va_end(ap); if( g.perm.Hyperlink && !g.javascriptHyperlink ){ char *zHUrl = mprintf("<a %s href=\"%h\">", zExtra, zUrl); fossil_free(zUrl); return zHUrl; } needHrefJs = 1; return mprintf("<a %s data-href='%z' href='%R/honeypot'>", zExtra, zUrl); } char *chref(const char *zExtra, const char *zFormat, ...){ char *zUrl; va_list ap; va_start(ap, zFormat); zUrl = vmprintf(zFormat, ap); va_end(ap); if( g.perm.Hyperlink && !g.javascriptHyperlink ){ char *zHUrl = mprintf("<a %s href=\"%h\">", zExtra, zUrl); fossil_free(zUrl); return zHUrl; } needHrefJs = 1; return mprintf("<a class='%s' data-href='%z' href='%R/honeypot'>", zExtra, zUrl); } char *href(const char *zFormat, ...){ char *zUrl; va_list ap; va_start(ap, zFormat); zUrl = vmprintf(zFormat, ap); va_end(ap); if( g.perm.Hyperlink && !g.javascriptHyperlink ){ char *zHUrl = mprintf("<a href=\"%h\">", zUrl); fossil_free(zUrl); return zHUrl; } needHrefJs = 1; return mprintf("<a data-href='%s' href='%R/honeypot'>", zUrl); } /* ** Generate <form method="post" action=ARG>. The ARG value is inserted ** by javascript. */ void form_begin(const char *zOtherArgs, const char *zAction, ...){ char *zLink; va_list ap; if( zOtherArgs==0 ) zOtherArgs = ""; va_start(ap, zAction); zLink = vmprintf(zAction, ap); va_end(ap); if( g.perm.Hyperlink && !g.javascriptHyperlink ){ @ <form method="POST" action="%z(zLink)" %s(zOtherArgs)> }else{ needHrefJs = 1; @ <form method="POST" data-action='%s(zLink)' action='%R/login' \ @ %s(zOtherArgs)> } } /* ** Add a new element to the submenu */ void style_submenu_element( const char *zLabel, |
︙ | ︙ | |||
367 368 369 370 371 372 373 | aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char *const *)az; aSubmenuCtrl[nSubmenuCtrl].eVisible = STYLE_NORMAL; aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI; nSubmenuCtrl++; } } | < < < < < < < | | | < | < < < < < | | < | < < < | < < < < < < < < < < < < < < > | < < < < | < < < < < < < | < | | > | < < < < < < | | < < | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | > > > | | > < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < | < < < < < < < < | | | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char *const *)az; aSubmenuCtrl[nSubmenuCtrl].eVisible = STYLE_NORMAL; aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI; nSubmenuCtrl++; } } /* ** Compare two submenu items for sorting purposes */ static int submenuCompare(const void *a, const void *b){ const struct Submenu *A = (const struct Submenu*)a; const struct Submenu *B = (const struct Submenu*)b; return fossil_strcmp(A->zLabel, B->zLabel); } /* Use this for the $current_page variable if it is not NULL. If it is ** NULL then use g.zPath. */ static char *local_zCurrentPage = 0; /* ** Set the desired $current_page to something other than g.zPath */ void style_set_current_page(const char *zFormat, ...){ fossil_free(local_zCurrentPage); if( zFormat==0 ){ local_zCurrentPage = 0; }else{ va_list ap; va_start(ap, zFormat); local_zCurrentPage = vmprintf(zFormat, ap); va_end(ap); } } /* ** Create a TH1 variable containing the URL for the specified config resource. ** The resulting variable name will be of the form $[zVarPrefix]_url. */ static void url_var( const char *zVarPrefix, const char *zConfigName, const char *zPageName ){ char *zVarName = mprintf("%s_url", zVarPrefix); char *zUrl = mprintf("%R/%s?id=%x", zPageName, skin_id(zConfigName)); Th_Store(zVarName, zUrl); free(zUrl); free(zVarName); } /* ** Create a TH1 variable containing the URL for the specified config image. ** The resulting variable name will be of the form $[zImageName]_image_url. */ static void image_url_var(const char *zImageName){ char *zVarPrefix = mprintf("%s_image", zImageName); char *zConfigName = mprintf("%s-image", zImageName); url_var(zVarPrefix, zConfigName, zImageName); free(zVarPrefix); free(zConfigName); } /* ** Return a random nonce that is stored in static space. For a particular ** run, the same nonce is always returned. */ char *style_nonce(void){ static char zNonce[52]; if( zNonce[0]==0 ){ unsigned char zSeed[24]; sqlite3_randomness(24, zSeed); encode16(zSeed,(unsigned char*)zNonce,24); } return zNonce; } /* ** Default HTML page header text through <body>. If the repository-specific ** header template lacks a <body> tag, then all of the following is ** prepended. */ static char zDfltHeader[] = @ <html> @ <head> @ <base href="$baseurl/$current_page" /> @ <meta http-equiv="Content-Security-Policy" \ @ content="default-src 'self' data: ; \ @ script-src 'self' 'nonce-$<nonce>' ;\ @ style-src 'self' 'unsafe-inline'" /> @ <meta name="viewport" content="width=device-width, initial-scale=1.0"> @ <title>$<project_name>: $<title></title> @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \ @ href="$home/timeline.rss" /> @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \ @ media="screen" /> @ </head> @ <body> ; /* ** Initialize all the default TH1 variables */ static void style_init_th1_vars(const char *zTitle){ Th_Store("nonce", style_nonce()); Th_Store("project_name", db_get("project-name","Unnamed Fossil Project")); Th_Store("project_description", db_get("project-description","")); if( zTitle ) Th_Store("title", zTitle); Th_Store("baseurl", g.zBaseURL); Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL); Th_Store("home", g.zTop); Th_Store("index_page", db_get("index-page","/home")); if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath); Th_Store("current_page", local_zCurrentPage); Th_Store("csrf_token", g.zCsrfToken); Th_Store("release_version", RELEASE_VERSION); Th_Store("manifest_version", MANIFEST_VERSION); Th_Store("manifest_date", MANIFEST_DATE); Th_Store("compiler_name", COMPILER_NAME); url_var("stylesheet", "css", "style.css"); image_url_var("logo"); image_url_var("background"); if( !login_is_nobody() ){ Th_Store("login", g.zLogin); } } /* ** Draw the header. */ void style_header(const char *zTitleFormat, ...){ va_list ap; char *zTitle; const char *zHeader = skin_get("header"); login_check_credentials(); va_start(ap, zTitleFormat); zTitle = vmprintf(zTitleFormat, ap); va_end(ap); cgi_destination(CGI_HEADER); @ <!DOCTYPE html> if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1); /* Generate the header up through the main menu */ style_init_th1_vars(zTitle); if( sqlite3_strlike("%<body%", zHeader, 0)!=0 ){ Th_Render(zDfltHeader); } if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1); Th_Render(zHeader); if( g.thTrace ) Th_Trace("END_HEADER<br />\n", -1); Th_Unstore("title"); /* Avoid collisions with ticket field names */ cgi_destination(CGI_BODY); g.cgiOutput = 1; headerHasBeenGenerated = 1; sideboxUsed = 0; if( g.perm.Debug && P("showqp") ){ @ <div class="debug"> cgi_print_all(0, 0); @ </div> } } #if INTERFACE /* Allowed parameters for style_adunit() */ #define ADUNIT_OFF 0x0001 /* Do not allow ads on this page */ |
︙ | ︙ | |||
889 890 891 892 893 894 895 | return 0; } /* ** Indicate that the table-sorting javascript is needed. */ void style_table_sorter(void){ | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | < | | < < < < | | > > | > > > > > > < < < < < < < > | | | < < < < < < < < < < < < < > | | < | < < < < < < < < < < < < < < | | | < < < < < < < < | | < < | | | | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | return 0; } /* ** Indicate that the table-sorting javascript is needed. */ void style_table_sorter(void){ needSortJs = 1; } /* ** Indicate that the table-sorting javascript is needed. */ void style_graph_generator(void){ needGraphJs = 1; } /* ** Generate code to load a single javascript file */ void style_load_one_js_file(const char *zFile){ @ <script src='%R/builtin/%s(zFile)?id=%S(MANIFEST_UUID)'></script> } /* ** All extra JS files to load. */ static const char *azJsToLoad[4]; static int nJsToLoad = 0; /* ** Register a new JS file to load at the end of the document. */ void style_load_js(const char *zName){ int i; for(i=0; i<nJsToLoad; i++){ if( fossil_strcmp(zName, azJsToLoad[i])==0 ) return; } if( nJsToLoad>=sizeof(azJsToLoad)/sizeof(azJsToLoad[0]) ){ fossil_panic("too many JS files"); } azJsToLoad[nJsToLoad++] = zName; } /* ** Generate code to load all required javascript files. */ static void style_load_all_js_files(void){ int i; if( needHrefJs ){ int nDelay = db_get_int("auto-hyperlink-delay",0); int bMouseover; /* Load up the page data */ bMouseover = (!g.isHuman || db_get_boolean("auto-hyperlink-ishuman",0)) && db_get_boolean("auto-hyperlink-mouseover",0); @ <script id='href-data' type='application/json'>\ @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script> } @ <script nonce="%h(style_nonce())"> if( needHrefJs ){ cgi_append_content(builtin_text("href.js"),-1); } if( needSortJs ){ cgi_append_content(builtin_text("sorttable.js"),-1); } if( needGraphJs ){ cgi_append_content(builtin_text("graph.js"),-1); } for(i=0; i<nJsToLoad; i++){ cgi_append_content(builtin_text(azJsToLoad[i]),-1); } if( blob_size(&blobOnLoad)>0 ){ @ window.onload = function(){ cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad)); cgi_append_content("\n}\n", -1); } @ </script> } /* ** Extra JS to run after all content is loaded. */ void style_js_onload(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); blob_vappendf(&blobOnLoad, zFormat, ap); va_end(ap); } /* ** Draw the footer at the bottom of the page. */ void style_footer(void){ const char *zFooter; const char *zAd = 0; unsigned int mAdFlags = 0; if( !headerHasBeenGenerated ) return; /* Go back and put the submenu at the top of the page. We delay the ** creation of the submenu until the end so that we can add elements ** to the submenu while generating page text. */ cgi_destination(CGI_HEADER); if( nSubmenu+nSubmenuCtrl>0 ){ int i; if( nSubmenuCtrl ){ @ <form id='f01' method='GET' action='%R/%s(g.zPath)'> @ <input type='hidden' name='udc' value='1'> } @ <div class="submenu"> if( nSubmenu>0 ){ qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare); for(i=0; i<nSubmenu; i++){ struct Submenu *p = &aSubmenu[i]; if( p->zLink==0 ){ @ <span class="label">%h(p->zLabel)</span> }else{ @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a> } } } for(i=0; i<nSubmenuCtrl; i++){ const char *zQPN = aSubmenuCtrl[i].zName; const char *zDisabled = ""; const char *zXtraClass = ""; if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){ zDisabled = " disabled"; }else if( zQPN ){ cgi_tag_query_parameter(zQPN); } switch( aSubmenuCtrl[i].eType ){ case FF_ENTRY: @ <span class='submenuctrl%s(zXtraClass)'>\ @ %h(aSubmenuCtrl[i].zLabel)\ @ <input type='text' name='%s(zQPN)' value='%h(PD(zQPN, ""))' \ if( aSubmenuCtrl[i].iSize<0 ){ @ size='%d(-aSubmenuCtrl[i].iSize)' \ }else if( aSubmenuCtrl[i].iSize>0 ){ @ size='%d(aSubmenuCtrl[i].iSize)' \ @ maxlength='%d(aSubmenuCtrl[i].iSize)' \ } @ id='submenuctrl-%d(i)'%s(zDisabled)></span> break; case FF_MULTI: { int j; const char *zVal = P(zQPN); if( zXtraClass[0] ){ @ <span class='%s(zXtraClass+1)'> } if( aSubmenuCtrl[i].zLabel ){ @ %h(aSubmenuCtrl[i].zLabel)\ } @ <select class='submenuctrl' size='1' name='%s(zQPN)' \ @ id='submenuctrl-%d(i)'%s(zDisabled)> for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){ const char *zQPV = aSubmenuCtrl[i].azChoice[j]; @ <option value='%h(zQPV)'\ if( fossil_strcmp(zVal, zQPV)==0 ){ @ selected\ } |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | @ selected\ } @ >%h(aSubmenuCtrl[i].zFalse)</option> @ </select> break; } case FF_CHECKBOX: { | | | > | | | | | > | < > > > > | > | | | < < > > > > > > > > > > > > > > > > > > > > > > > | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | @ selected\ } @ >%h(aSubmenuCtrl[i].zFalse)</option> @ </select> break; } case FF_CHECKBOX: { @ <label class='submenuctrl submenuckbox%s(zXtraClass)'>\ @ <input type='checkbox' name='%s(zQPN)' id='submenuctrl-%d(i)' \ if( PB(zQPN) ){ @ checked \ } if( aSubmenuCtrl[i].zJS ){ @ data-ctrl='%s(aSubmenuCtrl[i].zJS)'%s(zDisabled)>\ }else{ @ %s(zDisabled)>\ } @ %h(aSubmenuCtrl[i].zLabel)</label> break; } } } @ </div> if( nSubmenuCtrl ){ cgi_query_parameters_to_hidden(); cgi_tag_query_parameter(0); @ </form> style_load_one_js_file("menu.js"); } } zAd = style_adunit_text(&mAdFlags); if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){ @ <div class="content adunit_right_container"> @ <div class="adunit_right"> cgi_append_content(zAd, -1); @ </div> }else{ if( zAd ){ @ <div class="adunit_banner"> cgi_append_content(zAd, -1); @ </div> } @ <div class="content"> } cgi_destination(CGI_BODY); if( sideboxUsed ){ /* Put the footer at the bottom of the page. ** the additional clear/both is needed to extend the content ** part to the end of an optional sidebox. */ @ <div class="endContent"></div> } @ </div> zFooter = skin_get("footer"); if( sqlite3_strlike("%</body>%", zFooter, 0)==0 ){ style_load_all_js_files(); } if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1); Th_Render(zFooter); if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1); /* Render trace log if TH1 tracing is enabled. */ if( g.thTrace ){ cgi_append_content("<span class=\"thTrace\"><hr />\n", -1); cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog)); cgi_append_content("</span>\n", -1); } /* Add document end mark if it was not in the footer */ if( sqlite3_strlike("%</body>%", zFooter, 0)!=0 ){ style_load_all_js_files(); @ </body> @ </html> } } /* ** Begin a side-box on the right-hand side of a page. The title and ** the width of the box are given as arguments. The width is usually ** a percentage of total screen width. */ void style_sidebox_begin(const char *zTitle, const char *zWidth){ sideboxUsed = 1; @ <div class="sidebox" style="width:%s(zWidth)"> @ <div class="sideboxTitle">%h(zTitle)</div> } /* End the side-box */ void style_sidebox_end(void){ @ </div> } /* ** Insert the cssDefaultList[] table, generated from default_css.txt ** using the mkcss.c program. */ #include "default_css.h" /* ** Append all of the default CSS to the CGI output. */ void cgi_append_default_css(void) { int i; cgi_printf("%s", builtin_text("skins/default/css.txt")); for( i=0; cssDefaultList[i].elementClass; i++ ){ if( cssDefaultList[i].elementClass[0] ){ cgi_printf("%s {\n%s\n}\n\n", cssDefaultList[i].elementClass, cssDefaultList[i].value ); } } } /* ** Search string zCss for zSelector. ** ** Return true if found. Return false if not found */ static int containsSelector(const char *zCss, const char *zSelector){ |
︙ | ︙ | |||
1187 1188 1189 1190 1191 1192 1193 | /* ** COMMAND: test-contains-selector ** ** Usage: %fossil test-contains-selector FILENAME SELECTOR ** ** Determine if the CSS stylesheet FILENAME contains SELECTOR. | < < < < < | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | /* ** COMMAND: test-contains-selector ** ** Usage: %fossil test-contains-selector FILENAME SELECTOR ** ** Determine if the CSS stylesheet FILENAME contains SELECTOR. */ void contains_selector_cmd(void){ int found; char *zSelector; Blob css; if( g.argc!=4 ) usage("FILENAME SELECTOR"); blob_read_from_file(&css, g.argv[2], ExtFILE); |
︙ | ︙ | |||
1218 1219 1220 1221 1222 1223 1224 | const char *zScript = skin_get("js"); if( P("test") ){ /* Render the script as plain-text for testing purposes, if the "test" ** query parameter is present */ cgi_set_content_type("text/plain"); }else{ /* Default behavior is to return javascript */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < | < | | | | | < | > > | < | | > > > | | | > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | const char *zScript = skin_get("js"); if( P("test") ){ /* Render the script as plain-text for testing purposes, if the "test" ** query parameter is present */ cgi_set_content_type("text/plain"); }else{ /* Default behavior is to return javascript */ cgi_set_content_type("application/javascript"); } style_init_th1_vars(0); Th_Render(zScript?zScript:""); } /* ** WEBPAGE: style.css ** ** Return the style sheet. */ void page_style_css(void){ Blob css; int i; int isInit = 0; cgi_set_content_type("text/css"); blob_init(&css,skin_get("css"),-1); /* add special missing definitions */ for(i=1; cssDefaultList[i].elementClass; i++){ char *z = blob_str(&css); if( !containsSelector(z, cssDefaultList[i].elementClass) ){ if( !isInit ){ isInit = 1; blob_append(&css, "\n/***********************************************************\n" "** All CSS above is supplied by the repository \"skin\".\n" "** That which follows is generated automatically by Fossil\n" "** to fill in needed selectors that are missing from the\n" "** \"skin\" CSS.\n" "***********************************************************/\n", -1); } blob_appendf(&css, "%s {\n%s}\n", cssDefaultList[i].elementClass, cssDefaultList[i].value); } } /* Process through TH1 in order to give an opportunity to substitute ** variables such as $baseurl. */ Th_Store("baseurl", g.zBaseURL); Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL); Th_Store("home", g.zTop); image_url_var("logo"); image_url_var("background"); Th_Render(blob_str(&css)); /* Tell CGI that the content returned by this page is considered cacheable */ g.isConst = 1; } /* ** WEBPAGE: builtin ** URL: builtin/FILENAME ** ** Return the built-in text given by FILENAME. This is used internally ** by many Fossil web pages to load built-in javascript files. ** ** If the id= query parameter is present, then Fossil assumes that the ** result is immutable and sets a very large cache retention time (1 year). */ void page_builtin_text(void){ Blob out; const char *zName = P("name"); const char *zTxt = 0; const char *zId = P("id"); int nId; if( zName ) zTxt = builtin_text(zName); if( zTxt==0 ){ cgi_set_status(404, "Not Found"); @ File "%h(zName)" not found return; } if( sqlite3_strglob("*.js", zName)==0 ){ cgi_set_content_type("application/javascript"); }else{ cgi_set_content_type("text/plain"); } if( zId && (nId = (int)strlen(zId))>=8 && strncmp(zId,MANIFEST_UUID,nId)==0 ){ g.isConst = 1; }else{ etag_check(0,0); } blob_init(&out, zTxt, -1); cgi_set_content(&out); } /* ** All possible capabilities */ static const char allCap[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKL"; /* ** Compute the current login capabilities */ static char *find_capabilities(char *zCap){ int i, j; |
︙ | ︙ | |||
1369 1370 1371 1372 1373 1374 1375 | } /* ** WEBPAGE: honeypot ** This page is a honeypot for spiders and bots. */ void honeypot_page(void){ | | | < < < < < < < < < < < > | > > > > > > > > > > > > > > > > > | < | 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | } /* ** WEBPAGE: honeypot ** This page is a honeypot for spiders and bots. */ void honeypot_page(void){ cgi_set_status(403, "Forbidden"); @ <p>Please enable javascript or log in to see this content</p> } /* ** Webpages that encounter an error due to missing or incorrect ** query parameters can jump to this routine to render an error ** message screen. ** ** For administators, or if the test_env_enable setting is true, then ** details of the request environment are displayed. Otherwise, just ** the error message is shown. ** ** If zFormat is an empty string, then this is the /test_env page. */ void webpage_error(const char *zFormat, ...){ int i; int showAll; char *zErr = 0; int isAuth = 0; char zCap[100]; static const char *const azCgiVars[] = { "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE", "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER", "SQLITE_TMPDIR", "TMPDIR", "TEMP", "TMP", "FOSSIL_VFS", "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION", "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS", "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST" }; login_check_credentials(); if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){ isAuth = 1; } for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); if( zFormat[0] ){ va_list ap; va_start(ap, zFormat); zErr = vmprintf(zFormat, ap); va_end(ap); style_header("Bad Request"); @ <h1>/%h(g.zPath): %h(zErr)</h1> |
︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 | showAll = PB("showall"); style_submenu_checkbox("showall", "Cookies", 0, 0); style_submenu_element("Stats", "%R/stat"); } if( isAuth ){ #if !defined(_WIN32) | | | | | | | | | < < < < < < | | | | | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 | showAll = PB("showall"); style_submenu_checkbox("showall", "Cookies", 0, 0); style_submenu_element("Stats", "%R/stat"); } if( isAuth ){ #if !defined(_WIN32) @ uid=%d(getuid()), gid=%d(getgid())<br /> #endif @ g.zBaseURL = %h(g.zBaseURL)<br /> @ g.zHttpsURL = %h(g.zHttpsURL)<br /> @ g.zTop = %h(g.zTop)<br /> @ g.zPath = %h(g.zPath)<br /> @ g.userUid = %d(g.userUid)<br /> @ g.zLogin = %h(g.zLogin)<br /> @ g.isHuman = %d(g.isHuman)<br /> if( g.nRequest ){ @ g.nRequest = %d(g.nRequest)<br /> } if( g.nPendingRequest>1 ){ @ g.nPendingRequest = %d(g.nPendingRequest)<br /> } @ capabilities = %s(find_capabilities(zCap))<br /> if( zCap[0] ){ @ anonymous-adds = %s(find_anon_capabilities(zCap))<br /> } @ g.zRepositoryName = %h(g.zRepositoryName)<br /> @ load_average() = %f(load_average())<br /> @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br /> @ <hr /> P("HTTP_USER_AGENT"); cgi_print_all(showAll, 0); if( showAll && blob_size(&g.httpHeader)>0 ){ @ <hr /> @ <pre> @ %h(blob_str(&g.httpHeader)) @ </pre> } } style_footer(); if( zErr ){ cgi_reply(); fossil_exit(1); } } /* ** Generate a Not Yet Implemented error page. */ void webpage_not_yet_implemented(void){ webpage_error("Not yet implemented"); } /* ** Generate a webpage for a webpage_assert(). */ void webpage_assert_page(const char *zFile, int iLine, const char *zExpr){ fossil_warning("assertion fault at %s:%d - %s", zFile, iLine, zExpr); cgi_reset_content(); webpage_error("assertion fault at %s:%d - %s", zFile, iLine, zExpr); } #if INTERFACE # define webpage_assert(T) if(!(T)){webpage_assert_page(__FILE__,__LINE__,#T);} #endif |
Deleted src/style.chat.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/style.fileedit.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/style.pikchrshow.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/style.wikiedit.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/sync.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 | ******************************************************************************* ** ** This file contains code used to push, pull, and sync a repository */ #include "config.h" #include "sync.h" #include <assert.h> /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < | > > > | | > > > | < | < < > > | < | < < < | > > > > > > > | > > > > > > | | < | < | < < | | 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 | ******************************************************************************* ** ** This file contains code used to push, pull, and sync a repository */ #include "config.h" #include "sync.h" #include <assert.h> /* ** If the repository is configured for autosyncing, then do an ** autosync. This will be a pull if the argument is true or a push ** if the argument is false. ** ** Return the number of errors. */ int autosync(int flags){ const char *zAutosync; int rc; int configSync = 0; /* configuration changes transferred */ if( g.fNoSync ){ return 0; } if( flags==SYNC_PUSH && db_get_boolean("dont-push",0) ){ return 0; } zAutosync = db_get("autosync", 0); if( zAutosync ){ if( (flags & SYNC_PUSH)!=0 && fossil_strncmp(zAutosync,"pull",4)==0 ){ return 0; /* Do not auto-push when autosync=pullonly */ } if( is_false(zAutosync) ){ return 0; /* Autosync is completely off */ } }else{ /* Autosync defaults on. To make it default off, "return" here. */ } url_parse(0, URL_REMEMBER); if( g.url.protocol==0 ) return 0; if( g.url.user!=0 && g.url.passwd==0 ){ g.url.passwd = unobscure(db_get("last-sync-pw", 0)); g.url.flags |= URL_PROMPT_PW; url_prompt_for_password(); } g.zHttpAuth = get_httpauth(); url_remember(); #if 0 /* Disabled for now */ if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){ /* When doing an automatic pull, also automatically pull shuns from ** the server if pull_shuns is enabled. ** ** TODO: What happens if the shun list gets really big? ** Maybe the shunning list should only be pulled on every 10th ** autosync, or something? */ configSync = CONFIGSET_SHUN; } #endif if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE; fossil_print("Autosync: %s\n", g.url.canonical); url_enable_proxy("via proxy: "); rc = client_sync(flags, configSync, 0); return rc; } /* ** This routine will try a number of times to perform autosync with a ** 0.5 second sleep between attempts. ** ** Return zero on success and non-zero on a failure. If failure occurs ** and doPrompt flag is true, ask the user if they want to continue, and ** if they answer "yes" then return zero in spite of the failure. */ int autosync_loop(int flags, int nTries, int doPrompt){ int n = 0; int rc = 0; if( (flags & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) && db_get_boolean("uv-sync",0) ){ flags |= SYNC_UNVERSIONED; } while( (n==0 || n<nTries) && (rc=autosync(flags)) ){ if( rc ){ if( ++n<nTries ){ fossil_warning("Autosync failed, making another attempt."); sqlite3_sleep(500); }else{ fossil_warning("Autosync failed."); } |
︙ | ︙ | |||
243 244 245 246 247 248 249 | ** and sync. If a command-line argument is given, that is the URL ** of a server to sync against. If no argument is given, use the ** most recently synced URL. Remember the current URL for next time. */ static void process_sync_args( unsigned *pConfigFlags, /* Write configuration flags here */ unsigned *pSyncFlags, /* Write sync flags here */ | | < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < | > | | > | < | | > > > < | | < | | | < < < > < < | < | < < < | | | | < | | | | < < < | < | | | | | | < < < | < | | > < | | < | | < < < | | | < > | < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | < > | > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | ** and sync. If a command-line argument is given, that is the URL ** of a server to sync against. If no argument is given, use the ** most recently synced URL. Remember the current URL for next time. */ static void process_sync_args( unsigned *pConfigFlags, /* Write configuration flags here */ unsigned *pSyncFlags, /* Write sync flags here */ int uvOnly /* Special handling flags for UV sync */ ){ const char *zUrl = 0; const char *zHttpAuth = 0; unsigned configSync = 0; unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW; int urlOptional = 0; if( find_option("autourl",0,0)!=0 ){ urlOptional = 1; urlFlags = 0; } zHttpAuth = find_option("httpauth","B",1); if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER; if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags &= ~URL_REMEMBER; if( !uvOnly ){ if( find_option("private",0,0)!=0 ){ *pSyncFlags |= SYNC_PRIVATE; } /* The --verily option to sync, push, and pull forces extra igot cards ** to be exchanged. This can overcome malfunctions in the sync protocol. */ if( find_option("verily",0,0)!=0 ){ *pSyncFlags |= SYNC_RESYNC; } } if( find_option("private",0,0)!=0 ){ *pSyncFlags |= SYNC_PRIVATE; } if( find_option("verbose","v",0)!=0 ){ *pSyncFlags |= SYNC_VERBOSE; } url_proxy_options(); clone_ssh_find_options(); if( !uvOnly ) db_find_and_open_repository(0, 0); db_open_config(0, 0); if( g.argc==2 ){ if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN; }else if( g.argc==3 ){ zUrl = g.argv[2]; } if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) && db_get_boolean("uv-sync",0) ){ *pSyncFlags |= SYNC_UNVERSIONED; } if( urlFlags & URL_REMEMBER ){ clone_ssh_db_set_options(); } url_parse(zUrl, urlFlags); remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl); url_remember(); if( g.url.protocol==0 ){ if( urlOptional ) fossil_exit(0); usage("URL"); } user_select(); if( g.argc==2 ){ if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){ fossil_print("Sync with %s\n", g.url.canonical); }else if( (*pSyncFlags) & SYNC_PUSH ){ fossil_print("Push to %s\n", g.url.canonical); }else if( (*pSyncFlags) & SYNC_PULL ){ fossil_print("Pull from %s\n", g.url.canonical); } } url_enable_proxy("via proxy: "); *pConfigFlags |= configSync; } /* ** COMMAND: pull ** ** Usage: %fossil pull ?URL? ?options? ** ** Pull all sharable changes from a remote repository into the local repository. ** Sharable changes include public check-ins, and wiki, ticket, and tech-note ** edits. Add the --private option to pull private branches. Use the ** "configuration pull" command to pull website configuration details. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote-url, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** ** Options: ** ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol, ** if required by the remote website ** --from-parent-project Pull content from the parent project ** --ipv4 Use only IPv4, not IPv6 ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy ** --private Pull private branches too ** -R|--repository REPO Local repository to pull into ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** ** See also: clone, config pull, push, remote-url, sync */ void pull_cmd(void){ unsigned configFlags = 0; unsigned syncFlags = SYNC_PULL; if( find_option("from-parent-project",0,0)!=0 ){ syncFlags |= SYNC_FROMPARENT; } process_sync_args(&configFlags, &syncFlags, 0); /* We should be done with options.. */ verify_all_options(); client_sync(syncFlags, configFlags, 0); } /* ** COMMAND: push ** ** Usage: %fossil push ?URL? ?options? ** ** Push all sharable changes from the local repository to a remote repository. ** Sharable changes include public check-ins, and wiki, ticket, and tech-note ** edits. Use --private to also push private branches. Use the ** "configuration push" command to push website configuration details. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote-url, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** ** Options: ** ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol, ** if required by the remote website ** --ipv4 Use only IPv4, not IPv6 ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy ** --private Push private branches too ** -R|--repository REPO Local repository to push from ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** ** See also: clone, config push, pull, remote-url, sync */ void push_cmd(void){ unsigned configFlags = 0; unsigned syncFlags = SYNC_PUSH; process_sync_args(&configFlags, &syncFlags, 0); /* We should be done with options.. */ verify_all_options(); if( db_get_boolean("dont-push",0) ){ fossil_fatal("pushing is prohibited: the 'dont-push' option is set"); } client_sync(syncFlags, 0, 0); } /* ** COMMAND: sync ** ** Usage: %fossil sync ?URL? ?options? ** ** Synchronize all sharable changes between the local repository and a ** remote repository. Sharable changes include public check-ins and ** edits to wiki pages, tickets, and technical notes. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote-url, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** ** Options: ** ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol, ** if required by the remote website ** --ipv4 Use only IPv4, not IPv6 ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy ** --private Sync private branches too ** -R|--repository REPO Local repository to sync with ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -u|--unversioned Also sync unversioned content ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** ** See also: clone, pull, push, remote-url */ void sync_cmd(void){ unsigned configFlags = 0; unsigned syncFlags = SYNC_PUSH|SYNC_PULL; if( find_option("unversioned","u",0)!=0 ){ syncFlags |= SYNC_UNVERSIONED; } process_sync_args(&configFlags, &syncFlags, 0); /* We should be done with options.. */ verify_all_options(); if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH; client_sync(syncFlags, configFlags, 0); if( (syncFlags & SYNC_PUSH)==0 ){ fossil_warning("pull only: the 'dont-push' option is set"); } } /* ** Handle the "fossil unversioned sync" and "fossil unversioned revert" ** commands. */ void sync_unversioned(unsigned syncFlags){ unsigned configFlags = 0; (void)find_option("uv-noop",0,0); process_sync_args(&configFlags, &syncFlags, 1); verify_all_options(); client_sync(syncFlags, 0, 0); } /* ** COMMAND: remote-url ** ** Usage: %fossil remote-url ?URL|off? ** ** Query and/or change the default server URL used by the "pull", "push", ** and "sync" commands. ** ** The remote-url is set automatically by a "clone" command or by any ** "sync", "push", or "pull" command that specifies an explicit URL. ** The default remote-url is used by auto-syncing and by "sync", "push", ** "pull" that omit the server URL. ** ** See "fossil help clone" for further information about URL formats ** ** See also: clone, push, pull, sync */ void remote_url_cmd(void){ char *zUrl; db_find_and_open_repository(0, 0); /* We should be done with options.. */ verify_all_options(); if( g.argc!=2 && g.argc!=3 ){ usage("?URL|off?"); } if( g.argc==3 ){ db_unset("last-sync-url", 0); db_unset("last-sync-pw", 0); db_unset("http-auth", 0); if( is_false(g.argv[2]) ) return; url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW); } url_remember(); zUrl = db_get("last-sync-url", 0); if( zUrl==0 ){ fossil_print("off\n"); return; }else{ url_parse(zUrl, 0); fossil_print("%s\n", g.url.canonical); } } |
Changes to src/tag.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | PQueue queue; /* Queue of check-ins to be tagged */ Stmt s; /* Query the children of :pid to which to propagate */ Stmt ins; /* INSERT INTO tagxref */ Stmt eventupdate; /* UPDATE event */ assert( tagType==0 || tagType==2 ); pqueuex_init(&queue); | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | PQueue queue; /* Queue of check-ins to be tagged */ Stmt s; /* Query the children of :pid to which to propagate */ Stmt ins; /* INSERT INTO tagxref */ Stmt eventupdate; /* UPDATE event */ assert( tagType==0 || tagType==2 ); pqueuex_init(&queue); pqueuex_insert(&queue, pid, 0.0, 0); /* Query for children of :pid to which to propagate the tag. ** Three returns: (1) rid of the child. (2) timestamp of child. ** (3) True to propagate or false to block. */ db_prepare(&s, "SELECT cid, plink.mtime," |
︙ | ︙ | |||
77 78 79 80 81 82 83 | ); } if( tagid==TAG_BGCOLOR ){ db_prepare(&eventupdate, "UPDATE event SET bgcolor=%Q WHERE objid=:rid", zValue ); } | | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | ); } if( tagid==TAG_BGCOLOR ){ db_prepare(&eventupdate, "UPDATE event SET bgcolor=%Q WHERE objid=:rid", zValue ); } while( (pid = pqueuex_extract(&queue, 0))!=0 ){ db_bind_int(&s, ":pid", pid); while( db_step(&s)==SQLITE_ROW ){ int doit = db_column_int(&s, 2); if( doit ){ int cid = db_column_int(&s, 0); double mtime = db_column_double(&s, 1); pqueuex_insert(&queue, cid, mtime, 0); db_bind_int(&ins, ":rid", cid); db_step(&ins); db_reset(&ins); if( tagid==TAG_BGCOLOR ){ db_bind_int(&eventupdate, ":rid", cid); db_step(&eventupdate); db_reset(&eventupdate); |
︙ | ︙ | |||
218 219 220 221 222 223 224 | } } if( zCol ){ db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d", zCol, zValue, rid); if( tagid==TAG_COMMENT ){ char *zCopy = mprintf("%s", zValue); | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | } } if( zCol ){ db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d", zCol, zValue, rid); if( tagid==TAG_COMMENT ){ char *zCopy = mprintf("%s", zValue); wiki_extract_links(zCopy, rid, 0, mtime, 1, WIKI_INLINE); free(zCopy); } } if( tagid==TAG_DATE ){ db_multi_exec("UPDATE event " " SET mtime=julianday(%Q)," " omtime=coalesce(omtime,mtime)" |
︙ | ︙ | |||
280 281 282 283 284 285 286 | tag_insert(zTag, tagtype, zValue, -1, 0.0, rid); db_end_transaction(0); } /* ** OR this value into the tagtype argument to tag_add_artifact to ** cause the tag to be displayed on standard output rather than be | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | tag_insert(zTag, tagtype, zValue, -1, 0.0, rid); db_end_transaction(0); } /* ** OR this value into the tagtype argument to tag_add_artifact to ** cause the tag to be displayed on standard output rather than be ** inserted. Used for --dryrun options and debugging. */ #if INTERFACE #define TAG_ADD_DRYRUN 0x04 #endif /* ** Add a control record to the repository that either creates |
︙ | ︙ | |||
357 358 359 360 361 362 363 | fossil_print("%s", blob_str(&ctrl)); blob_reset(&ctrl); }else{ nrid = content_put(&ctrl); manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS); } assert( blob_is_reset(&ctrl) ); | < | < < < < < < < < < < < < < < < < < < < < < < | | < | | < | | < < | | < | > > < < < < | | | < | < < < < < < < < < | | > > < | < < < | < < | | | < < < < < < | < < < < < < < < < < < < < < < < | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | fossil_print("%s", blob_str(&ctrl)); blob_reset(&ctrl); }else{ nrid = content_put(&ctrl); manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS); } assert( blob_is_reset(&ctrl) ); manifest_to_disk(rid); } /* ** COMMAND: tag ** ** Usage: %fossil tag SUBCOMMAND ... ** ** Run various subcommands to control tags and properties. ** ** %fossil tag add ?OPTIONS? TAGNAME CHECK-IN ?VALUE? ** ** Add a new tag or property to CHECK-IN. The tag will ** be usable instead of a CHECK-IN in commands such as ** update and merge. If the --propagate flag is present, ** the tag value propagates to all descendants of CHECK-IN ** ** Options: ** --raw Raw tag name. ** --propagate Propagating tag. ** --date-override DATETIME Set date and time added. ** --user-override USER Name USER when adding the tag. ** --dryrun|-n Display the tag text, but do not ** actually insert it into the database. ** ** The --date-override and --user-override options support ** importing history from other SCM systems. DATETIME has ** the form 'YYYY-MMM-DD HH:MM:SS'. ** ** %fossil tag cancel ?--raw? TAGNAME CHECK-IN ** ** Remove the tag TAGNAME from CHECK-IN, and also remove ** the propagation of the tag to any descendants. Use the ** the --dryrun or -n options to see what would have happened. ** ** %fossil tag find ?OPTIONS? TAGNAME ** ** List all objects that use TAGNAME. TYPE can be "ci" for ** check-ins or "e" for events. The limit option limits the number ** of results to the given value. ** ** Options: ** --raw Raw tag name. ** -t|--type TYPE One of "ci", or "e". ** -n|--limit N Limit to N results. ** ** %fossil tag list|ls ?--raw? ?CHECK-IN? ** ** List all tags, or if CHECK-IN is supplied, list ** all tags and their values for CHECK-IN. ** ** The option --raw allows the manipulation of all types of tags ** used for various internal purposes in fossil. It also shows ** "cancel" tags for the "find" and "list" subcommands. You should ** not use this option to make changes unless you are sure what ** you are doing. ** |
︙ | ︙ | |||
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | ** fossil update tag:decaf ** ** will assume that "decaf" is a tag/branch name. ** */ void tag_cmd(void){ int n; db_find_and_open_repository(0, 0); if( g.argc<3 ){ goto tag_cmd_usage; } n = strlen(g.argv[2]); if( n==0 ){ goto tag_cmd_usage; } if( strncmp(g.argv[2],"add",n)==0 ){ char *zValue; int dryRun = 0; | > > > > > < < < < < < | | < < < < < < < < < < < < < | < < < < < < < | | < < < < < < < < < < < < < | < < < < | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | ** fossil update tag:decaf ** ** will assume that "decaf" is a tag/branch name. ** */ void tag_cmd(void){ int n; int fRaw = find_option("raw","",0)!=0; int fPropagate = find_option("propagate","",0)!=0; const char *zPrefix = fRaw ? "" : "sym-"; const char *zFindLimit = find_option("limit","n",1); const int nFindLimit = zFindLimit ? atoi(zFindLimit) : -2000; db_find_and_open_repository(0, 0); if( g.argc<3 ){ goto tag_cmd_usage; } n = strlen(g.argv[2]); if( n==0 ){ goto tag_cmd_usage; } if( strncmp(g.argv[2],"add",n)==0 ){ char *zValue; int dryRun = 0; const char *zDateOvrd = find_option("date-override",0,1); const char *zUserOvrd = find_option("user-override",0,1); if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN; if( g.argc!=5 && g.argc!=6 ){ usage("add ?options? TAGNAME CHECK-IN ?VALUE?"); } zValue = g.argc==6 ? g.argv[5] : 0; db_begin_transaction(); tag_add_artifact(zPrefix, g.argv[3], g.argv[4], zValue, 1+fPropagate+dryRun,zDateOvrd,zUserOvrd); db_end_transaction(0); }else if( strncmp(g.argv[2],"branch",n)==0 ){ fossil_fatal("the \"fossil tag branch\" command is discontinued\n" "Use the \"fossil branch new\" command instead."); }else if( strncmp(g.argv[2],"cancel",n)==0 ){ int dryRun = 0; if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN; if( g.argc!=5 ){ usage("cancel ?options? TAGNAME CHECK-IN"); } db_begin_transaction(); tag_add_artifact(zPrefix, g.argv[3], g.argv[4], 0, dryRun, 0, 0); db_end_transaction(0); }else if( strncmp(g.argv[2],"find",n)==0 ){ Stmt q; const char *zType = find_option("type","t",1); Blob sql = empty_blob; if( zType==0 || zType[0]==0 ) zType = "*"; if( g.argc!=4 ){ usage("find ?--raw? ?-t|--type TYPE? ?-n|--limit #? TAGNAME"); } if( fRaw ){ |
︙ | ︙ | |||
607 608 609 610 611 612 613 | db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%s\n", db_column_text(&q, 0)); } db_finalize(&q); }else{ | | < < < | < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < | < < < | < | < < < < < < < < < < < < < < < < < < < | | < | > | | | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%s\n", db_column_text(&q, 0)); } db_finalize(&q); }else{ int tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", g.argv[3]); if( tagid>0 ){ blob_append_sql(&sql, "%s" " AND event.type GLOB '%q'" " AND blob.rid IN (" " SELECT rid FROM tagxref" " WHERE tagtype>0 AND tagid=%d" ")" " ORDER BY event.mtime DESC /*sort*/", timeline_query_for_tty(), zType, tagid ); db_prepare(&q, "%s", blob_sql_text(&sql)); blob_reset(&sql); print_timeline(&q, nFindLimit, 79, 0); db_finalize(&q); } } }else if(( strncmp(g.argv[2],"list",n)==0 )||( strncmp(g.argv[2],"ls",n)==0 )){ Stmt q; if( g.argc==3 ){ db_prepare(&q, "SELECT tagname FROM tag" " WHERE EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=tag.tagid" " AND tagtype>0)" " ORDER BY tagname" ); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); if( fRaw ){ fossil_print("%s\n", zName); }else if( strncmp(zName, "sym-", 4)==0 ){ fossil_print("%s\n", &zName[4]); } } db_finalize(&q); }else if( g.argc==4 ){ int rid = name_to_rid(g.argv[3]); db_prepare(&q, "SELECT tagname, value FROM tagxref, tag" " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid" " AND tagtype>%d" " ORDER BY tagname", rid, fRaw ? -1 : 0 ); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zValue = db_column_text(&q, 1); if( fRaw==0 ){ if( strncmp(zName, "sym-", 4)!=0 ) continue; zName += 4; } if( zValue && zValue[0] ){ fossil_print("%s=%s\n", zName, zValue); }else{ fossil_print("%s\n", zName); } } db_finalize(&q); }else{ usage("list ?CHECK-IN?"); } }else { goto tag_cmd_usage; } /* Cleanup */ |
︙ | ︙ | |||
789 790 791 792 793 794 795 | ** ** Reparenting is accomplished by adding a parent tag. So to undo the ** reparenting operation, simply delete the tag. ** ** --test Make database entries but do not add the tag artifact. ** So the reparent operation will be undone by the next ** "fossil rebuild" command. | | < < < < | < < | < < | | | < < < < < < < < < < < < < < | | | | | < < < < < < < | > | < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | ** ** Reparenting is accomplished by adding a parent tag. So to undo the ** reparenting operation, simply delete the tag. ** ** --test Make database entries but do not add the tag artifact. ** So the reparent operation will be undone by the next ** "fossil rebuild" command. ** --dryrun | -n Print the tag that would have been created but do not ** actually change the database in any way. */ void reparent_cmd(void){ int bTest = find_option("test","",0)!=0; int rid; int i; Blob value; char *zUuid; int dryRun = 0; if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN; db_find_and_open_repository(0, 0); verify_all_options(); if( g.argc<4 ){ usage("[OPTIONS] CHECK-IN PARENT ..."); } rid = name_to_typed_rid(g.argv[2], "ci"); blob_init(&value, 0, 0); for(i=3; i<g.argc; i++){ int pid = name_to_typed_rid(g.argv[i], "ci"); if( i>3 ) blob_append(&value, " ", 1); zUuid = rid_to_uuid(pid); blob_append(&value, zUuid, strlen(zUuid)); fossil_free(zUuid); } if( bTest && !dryRun ){ tag_insert("parent", 1, blob_str(&value), -1, 0.0, rid); }else{ zUuid = rid_to_uuid(rid); tag_add_artifact("","parent",zUuid,blob_str(&value),1|dryRun,0,0); } } /* ** WEBPAGE: taglist ** ** List all non-propagating symbolic tags. */ void taglist_page(void){ Stmt q; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); } login_anonymous_available(); style_header("Tags"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Timeline", "tagtimeline"); @ <h2>Non-propagating tags:</h2> db_prepare(&q, "SELECT substr(tagname,5)" " FROM tag" " WHERE EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=tag.tagid" " AND tagtype=1)" " AND tagname GLOB 'sym-*'" " ORDER BY tagname" ); @ <ul> while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); if( g.perm.Hyperlink ){ @ <li>%z(chref("taglink","%R/timeline?t=%T&n=200",zName)) @ %h(zName)</a></li> }else{ @ <li><span class="tagDsp">%h(zName)</span></li> } } @ </ul> db_finalize(&q); style_footer(); } /* ** WEBPAGE: /tagtimeline ** ** Render a timeline with all check-ins that contain non-propagating ** symbolic tags. */ void tagtimeline_page(void){ Stmt q; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("Tagged Check-ins"); style_submenu_element("List", "taglist"); login_anonymous_available(); @ <h2>Check-ins with non-propagating tags:</h2> db_prepare(&q, "%s AND blob.rid IN (SELECT rid FROM tagxref" " WHERE tagtype=1 AND srcid>0" " AND tagid IN (SELECT tagid FROM tag " " WHERE tagname GLOB 'sym-*'))" " ORDER BY event.mtime DESC /*sort*/", timeline_query_for_www() ); www_print_timeline(&q, 0, 0, 0, 0, 0); db_finalize(&q); @ <br /> style_footer(); } |
Changes to src/tar.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** This file contains code used to generate tarballs. */ #include "config.h" #include <assert.h> | > > > > | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** ******************************************************************************* ** ** This file contains code used to generate tarballs. */ #include "config.h" #include <assert.h> #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #include "tar.h" /* ** State information for the tarball builder. */ static struct tarball_t { unsigned char *aHdr; /* Space for building headers */ |
︙ | ︙ | |||
242 243 244 245 246 247 248 | n /= 10; } /* adding the length extended the length field? */ if(blen > next10){ blen++; } /* build the string */ | | < | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | n /= 10; } /* adding the length extended the length field? */ if(blen > next10){ blen++; } /* build the string */ blob_appendf(&tball.pax, "%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue); /* this _must_ be right */ if(blob_size(&tball.pax) != blen){ fossil_panic("internal error: PAX tar header has bad length"); } } /* ** set the header type, calculate the checksum and output |
︙ | ︙ | |||
419 420 421 422 423 424 425 | /* ** COMMAND: test-tarball ** ** Generate a GZIP-compressed tarball in the file given by the first argument ** that contains files given in the second and subsequent arguments. ** | | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | /* ** COMMAND: test-tarball ** ** Generate a GZIP-compressed tarball in the file given by the first argument ** that contains files given in the second and subsequent arguments. ** ** -h, --dereference Follow symlinks; archive the files they point to. */ void test_tarball_cmd(void){ int i; Blob zip; int eFType = SymFILE; if( g.argc<3 ){ usage("ARCHIVE [options] FILE...."); } if( find_option("dereference","h",0) ){ eFType = ExtFILE; } sqlite3_open(":memory:", &g.db); tar_begin(-1); for(i=3; i<g.argc; i++){ Blob file; blob_zero(&file); blob_read_from_file(&file, g.argv[i], eFType); tar_add_file(g.argv[i], &file, file_perm(0,0), file_mtime(0,0)); blob_reset(&file); } tar_finish(&zip); blob_write_to_file(&zip, g.argv[2]); } /* |
︙ | ︙ | |||
460 461 462 463 464 465 466 | ** If the RID object does not exist in the repository, then ** pTar is zeroed. ** ** zDir is a "synthetic" subdirectory which all files get ** added to as part of the tarball. It may be 0 or an empty string, in ** which case it is ignored. The intention is to create a tarball which ** politely expands into a subdir instead of filling your current dir | | | | < | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | ** If the RID object does not exist in the repository, then ** pTar is zeroed. ** ** zDir is a "synthetic" subdirectory which all files get ** added to as part of the tarball. It may be 0 or an empty string, in ** which case it is ignored. The intention is to create a tarball which ** politely expands into a subdir instead of filling your current dir ** with source files. For example, pass a UUID or "ProjectName". ** */ void tarball_of_checkin( int rid, /* The RID of the checkin from which to form a tarball */ Blob *pTar, /* Write the tarball into this blob */ const char *zDir, /* Directory prefix for all file added to tarball */ Glob *pInclude, /* Only add files matching this pattern */ Glob *pExclude /* Exclude files matching this pattern */ ){ Blob mfile, hash, file; Manifest *pManifest; ManifestFile *pFile; Blob filename; int nPrefix; char *zName = 0; |
︙ | ︙ | |||
495 496 497 498 499 500 501 | blob_appendf(&filename, "%s/", zDir); } nPrefix = blob_size(&filename); pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0); if( pManifest ){ int flg, eflg = 0; | | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | blob_appendf(&filename, "%s/", zDir); } nPrefix = blob_size(&filename); pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0); if( pManifest ){ int flg, eflg = 0; mTime = (pManifest->rDate - 2440587.5)*86400.0; tar_begin(mTime); flg = db_get_manifest_setting(); if( flg ){ /* eflg is the effective flags, taking include/exclude into account */ if( (pInclude==0 || glob_match(pInclude, "manifest")) && !glob_match(pExclude, "manifest") && (flg & MFESTFLG_RAW) ){ eflg |= MFESTFLG_RAW; |
︙ | ︙ | |||
520 521 522 523 524 525 526 | eflg |= MFESTFLG_TAGS; } if( eflg & (MFESTFLG_RAW|MFESTFLG_UUID) ){ if( eflg & MFESTFLG_RAW ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); | > | | | < > < < < | | < > > > < < < < < | | < > < < < | | < < < | | | < | < < < < < < < < < < < < < < | < < < | | < | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | eflg |= MFESTFLG_TAGS; } if( eflg & (MFESTFLG_RAW|MFESTFLG_UUID) ){ if( eflg & MFESTFLG_RAW ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); } if( eflg & MFESTFLG_RAW ) { sterilize_manifest(&mfile); tar_add_file(zName, &mfile, 0, mTime); } } blob_reset(&mfile); if( eflg & MFESTFLG_UUID ){ blob_append(&hash, "\n", 1); blob_resize(&filename, nPrefix); blob_append(&filename, "manifest.uuid", -1); zName = blob_str(&filename); tar_add_file(zName, &hash, 0, mTime); } if( eflg & MFESTFLG_TAGS ){ Blob tagslist; blob_zero(&tagslist); get_checkin_taglist(rid, &tagslist); blob_resize(&filename, nPrefix); blob_append(&filename, "manifest.tags", -1); zName = blob_str(&filename); tar_add_file(zName, &tagslist, 0, mTime); blob_reset(&tagslist); } } manifest_file_rewind(pManifest); while( (pFile = manifest_file_next(pManifest,0))!=0 ){ int fid; if( pInclude!=0 && !glob_match(pInclude, pFile->zName) ) continue; if( glob_match(pExclude, pFile->zName) ) continue; fid = uuid_to_rid(pFile->zUuid, 0); if( fid ){ content_get(fid, &file); blob_resize(&filename, nPrefix); blob_append(&filename, pFile->zName, -1); zName = blob_str(&filename); tar_add_file(zName, &file, manifest_file_mperm(pFile), mTime); blob_reset(&file); } } }else{ blob_append(&filename, blob_str(&hash), 16); zName = blob_str(&filename); mTime = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0;"); tar_begin(mTime); tar_add_file(zName, &mfile, 0, mTime); } manifest_destroy(pManifest); blob_reset(&mfile); blob_reset(&hash); blob_reset(&filename); tar_finish(pTar); } /* ** COMMAND: tarball* ** ** Usage: %fossil tarball VERSION OUTPUTFILE [OPTIONS] ** ** Generate a compressed tarball for a specified version. If the --name ** option is used, its argument becomes the name of the top-level directory ** in the resulting tarball. If --name is omitted, the top-level directory ** name is derived from the project name, the check-in date and time, and ** the artifact ID of the check-in. ** ** The GLOBLIST argument to --exclude and --include can be a comma-separated ** list of glob patterns, where each glob pattern may optionally be enclosed ** in "..." or '...' so that it may contain commas. If a file matches both ** --include and --exclude then it is excluded. ** ** Options: ** -X|--exclude GLOBLIST Comma-separated list of GLOBs of files to exclude ** --include GLOBLIST Comma-separated list of GLOBs of files to include ** --name DIRECTORYNAME The name of the top-level directory in the archive ** -R REPOSITORY Specify a Fossil repository */ void tarball_cmd(void){ int rid; Blob tarball; const char *zName; Glob *pInclude = 0; Glob *pExclude = 0; const char *zInclude; const char *zExclude; zName = find_option("name", 0, 1); zExclude = find_option("exclude", "X", 1); if( zExclude ) pExclude = glob_create(zExclude); zInclude = find_option("include", 0, 1); if( zInclude ) pInclude = glob_create(zInclude); db_find_and_open_repository(0, 0); /* We should be done with options.. */ verify_all_options(); if( g.argc!=4 ){ usage("VERSION OUTPUTFILE"); } g.zOpenRevision = g.argv[2]; rid = name_to_typed_rid(g.argv[2], "ci"); if( rid==0 ){ fossil_fatal("Check-in not found: %s", g.argv[2]); return; } if( zName==0 ){ zName = db_text("default-name", "SELECT replace(%Q,' ','_') " " || strftime('_%%Y-%%m-%%d_%%H%%M%%S_', event.mtime) " " || substr(blob.uuid, 1, 10)" " FROM event, blob" " WHERE event.objid=%d" " AND blob.rid=%d", db_get("project-name", "unnamed"), rid, rid ); } tarball_of_checkin(rid, &tarball, zName, pInclude, pExclude); glob_free(pInclude); glob_free(pExclude); blob_write_to_file(&tarball, g.argv[3]); blob_reset(&tarball); } /* ** Check to see if the input string is of the form: ** ** checkin-name/filename.ext ** ** In other words, check to see if the input contains a single '/' ** character that separates a valid check-in name from a filename. ** ** If the condition is true, return the check-in name and set the ** input string to be the filename. ** |
︙ | ︙ | |||
703 704 705 706 707 708 709 | zName[n] = 0; *pzName = fossil_strdup(&zName[n+1]); return zName; } /* ** WEBPAGE: tarball | | | | | | | | | | < < < | | > | | | | < | | | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | zName[n] = 0; *pzName = fossil_strdup(&zName[n+1]); return zName; } /* ** WEBPAGE: tarball ** URL: /tarball ** ** Generate a compressed tarball for the check-in specified by the "r" ** query parameter. Return that compressed tarball as the HTTP reply ** content. ** ** The r= and name= query parameters can be specified as extensions to the ** URI. Example, the following URIs are all equivalent: ** ** /tarball/release/xyz.tar.gz ** /tarball?r=release&name=xyz.tar.gz ** /tarball/xyz.tar.gz?r=release ** /tarball?name=release/xyz.tar.gz ** ** Query parameters: ** ** name=NAME[.tar.gz] The base name of the output file. The default ** value is a configuration parameter in the project ** settings. A prefix of the name, omitting the ** extension, is used as the top-most directory name. ** ** r=TAG The check-in that is turned into a compressed tarball. ** Defaults to "trunk". This query parameter used to ** be called "uuid" and "uuid" is still accepted for ** backwards compatibility. If the name= query parameter ** contains one "/" character then the part before the / ** is the TAG and the part after the / is the true name. ** If no TAG is specified by any of the above means, then ** "trunk" is used as the default. ** ** in=PATTERN Only include files that match the comma-separate ** list of GLOB patterns in PATTERN, as with ex= ** ** ex=PATTERN Omit any file that match PATTERN. PATTERN is a ** comma-separated list of GLOB patterns, where each ** pattern can optionally be quoted using ".." or '..'. |
︙ | ︙ | |||
758 759 760 761 762 763 764 | Glob *pInclude = 0; /* The compiled in= glob pattern */ Glob *pExclude = 0; /* The compiled ex= glob pattern */ Blob tarball; /* Tarball accumulated here */ const char *z; login_check_credentials(); if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } | | < < < | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | Glob *pInclude = 0; /* The compiled in= glob pattern */ Glob *pExclude = 0; /* The compiled ex= glob pattern */ Blob tarball; /* Tarball accumulated here */ const char *z; login_check_credentials(); if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } load_control(); zName = fossil_strdup(PD("name","")); z = P("r"); if( z==0 ) z = P("uuid"); if( z==0 ) z = tar_uuid_from_name(&zName); if( z==0 ) z = "trunk"; g.zOpenRevision = zRid = fossil_strdup(z); nRid = strlen(zRid); zInclude = P("in"); if( zInclude ) pInclude = glob_create(zInclude); zExclude = P("ex"); if( zExclude ) pExclude = glob_create(zExclude); nName = strlen(zName); if( nName>7 && fossil_strcmp(&zName[nName-7], ".tar.gz")==0 ){ /* Special case: Remove the ".tar.gz" suffix. */ nName -= 7; zName[nName] = 0; }else{ /* If the file suffix is not ".tar.gz" then just remove the |
︙ | ︙ | |||
807 808 809 810 811 812 813 | if( zInclude ) blob_appendf(&cacheKey, ",in=%Q", zInclude); if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude); zKey = blob_str(&cacheKey); etag_check(ETAG_HASH, zKey); if( P("debug")!=0 ){ style_header("Tarball Generator Debug Screen"); | | | | | | | | < | < | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | if( zInclude ) blob_appendf(&cacheKey, ",in=%Q", zInclude); if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude); zKey = blob_str(&cacheKey); etag_check(ETAG_HASH, zKey); if( P("debug")!=0 ){ style_header("Tarball Generator Debug Screen"); @ zName = "%h(zName)"<br /> @ rid = %d(rid)<br /> if( zInclude ){ @ zInclude = "%h(zInclude)"<br /> } if( zExclude ){ @ zExclude = "%h(zExclude)"<br /> } @ zKey = "%h(zKey)" style_footer(); return; } if( referred_from_login() ){ style_header("Tarball Download"); @ <form action='%R/tarball/%h(zName).tar.gz'> cgi_query_parameters_to_hidden(); @ <p>Tarball named <b>%h(zName).tar.gz</b> holding the content @ of check-in <b>%h(zRid)</b>: @ <input type="submit" value="Download" /> @ </form> style_footer(); return; } blob_zero(&tarball); if( cache_read(&tarball, zKey)==0 ){ tarball_of_checkin(rid, &tarball, zName, pInclude, pExclude); cache_write(&tarball, zKey); } glob_free(pInclude); glob_free(pExclude); fossil_free(zName); fossil_free(zRid); blob_reset(&cacheKey); cgi_set_content(&tarball); cgi_set_content_type("application/x-compressed"); } |
Deleted src/terminal.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/th.c.
︙ | ︙ | |||
197 198 199 200 201 202 203 204 205 206 | */ struct Buffer { char *zBuf; int nBuf; int nBufAlloc; }; typedef struct Buffer Buffer; static void thBufferInit(Buffer *); static void thBufferFree(Th_Interp *interp, Buffer *); | > < < < < < < < < | < < < < < < < | | < | < < | | | | | | | | < > | < | | < | > | < | < < < < < < < < | < < | | > > | 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 | */ struct Buffer { char *zBuf; int nBuf; int nBufAlloc; }; typedef struct Buffer Buffer; static int thBufferWrite(Th_Interp *interp, Buffer *, const char *, int); static void thBufferInit(Buffer *); static void thBufferFree(Th_Interp *interp, Buffer *); /* ** Append nAdd bytes of content copied from zAdd to the end of buffer ** pBuffer. If there is not enough space currently allocated, resize ** the allocation to make space. */ static int thBufferWrite( Th_Interp *interp, Buffer *pBuffer, const char *zAdd, int nAdd ){ int nReq; if( nAdd<0 ){ nAdd = th_strlen(zAdd); } nReq = pBuffer->nBuf+nAdd+1; if( nReq>pBuffer->nBufAlloc ){ char *zNew; int nNew; nNew = nReq*2; zNew = (char *)Th_Malloc(interp, nNew); memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf); Th_Free(interp, pBuffer->zBuf); pBuffer->nBufAlloc = nNew; pBuffer->zBuf = zNew; } memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd); pBuffer->nBuf += nAdd; pBuffer->zBuf[pBuffer->nBuf] = '\0'; return TH_OK; } #define thBufferWrite(a,b,c,d) thBufferWrite(a,b,(const char *)c,d) /* ** Initialize the Buffer structure pointed to by pBuffer. */ static void thBufferInit(Buffer *pBuffer){ memset(pBuffer, 0, sizeof(Buffer)); } |
︙ | ︙ | |||
644 645 646 647 648 649 650 | int rc = thSubstWord(interp, &zWord[i+1], nWord-i-2); if( rc!=TH_OK ) return rc; zInner = Th_GetResult(interp, &nInner); thBufferInit(&varname); thBufferWrite(interp, &varname, &zWord[1], i); thBufferWrite(interp, &varname, zInner, nInner); | | | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | int rc = thSubstWord(interp, &zWord[i+1], nWord-i-2); if( rc!=TH_OK ) return rc; zInner = Th_GetResult(interp, &nInner); thBufferInit(&varname); thBufferWrite(interp, &varname, &zWord[1], i); thBufferWrite(interp, &varname, zInner, nInner); thBufferWrite(interp, &varname, ")", 1); rc = Th_GetVar(interp, varname.zBuf, varname.nBuf); thBufferFree(interp, &varname); return rc; } } return Th_GetVar(interp, &zWord[1], nWord-1); } |
︙ | ︙ | |||
706 707 708 709 710 711 712 | int rc = TH_OK; Buffer output; int i; thBufferInit(&output); if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){ | | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | int rc = TH_OK; Buffer output; int i; thBufferInit(&output); if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){ rc = thBufferWrite(interp, &output, &zWord[1], nWord-2); }else{ /* If the word is surrounded by double-quotes strip these away. */ if( nWord>1 && (zWord[0]=='"' && zWord[nWord-1]=='"') ){ zWord++; nWord -= 2; } |
︙ | ︙ | |||
736 737 738 739 740 741 742 | } case '$': if( !interp->isListMode ){ xGet = thNextVarname; xSubst = thSubstVarname; break; } default: { | | | | 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | } case '$': if( !interp->isListMode ){ xGet = thNextVarname; xSubst = thSubstVarname; break; } default: { thBufferWrite(interp, &output, &zWord[i], 1); continue; /* Go to the next iteration of the for(...) loop */ } } rc = xGet(interp, &zWord[i], nWord-i, &nGet); if( rc==TH_OK ){ rc = xSubst(interp, &zWord[i], nGet); } if( rc==TH_OK ){ const char *zRes; int nRes; zRes = Th_GetResult(interp, &nRes); rc = thBufferWrite(interp, &output, zRes, nRes); i += (nGet-1); } } } if( rc==TH_OK ){ Th_SetResult(interp, output.zBuf, output.nBuf); |
︙ | ︙ | |||
847 848 849 850 851 852 853 | goto finish; } zInput = &zInput[nWord]; nInput = nList-(zInput-zList); if( nWord>0 ){ zWord = Th_GetResult(interp, &nWord); thBufferWrite(interp, &strbuf, zWord, nWord); | | | | | | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | goto finish; } zInput = &zInput[nWord]; nInput = nList-(zInput-zList); if( nWord>0 ){ zWord = Th_GetResult(interp, &nWord); thBufferWrite(interp, &strbuf, zWord, nWord); thBufferWrite(interp, &strbuf, "\0", 1); thBufferWrite(interp, &lenbuf, &nWord, sizeof(int)); nCount++; } } assert((lenbuf.nBuf/sizeof(int))==nCount); assert((pazElem && panElem) || (!pazElem && !panElem)); if( pazElem && rc==TH_OK ){ int i; char *zElem; int *anElem; char **azElem = Th_Malloc(interp, sizeof(char*) * nCount + /* azElem */ sizeof(int) * nCount + /* anElem */ strbuf.nBuf /* space for list element strings */ ); anElem = (int *)&azElem[nCount]; zElem = (char *)&anElem[nCount]; memcpy(anElem, lenbuf.zBuf, lenbuf.nBuf); memcpy(zElem, strbuf.zBuf, strbuf.nBuf); for(i=0; i<nCount;i++){ azElem[i] = zElem; zElem += (anElem[i] + 1); } *pazElem = azElem; *panElem = anElem; } |
︙ | ︙ | |||
1151 1152 1153 1154 1155 1156 1157 | ** ** If the create argument is non-zero and the named variable does not exist ** it is created. Otherwise, an error is left in the interpreter result ** and NULL returned. ** ** If the arrayok argument is false and the named variable is an array, ** an error is left in the interpreter result and NULL returned. If | | | | 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | ** ** If the create argument is non-zero and the named variable does not exist ** it is created. Otherwise, an error is left in the interpreter result ** and NULL returned. ** ** If the arrayok argument is false and the named variable is an array, ** an error is left in the interpreter result and NULL returned. If ** arrayok is true an array name is Ok. */ static Th_Variable *thFindValue( Th_Interp *interp, const char *zVar, /* Pointer to variable name */ int nVar, /* Number of bytes at nVar */ int create, /* If true, create the variable if not found */ int arrayok, /* If true, an array is Ok. Otherwise array==error */ int noerror, /* If false, set interpreter result to error */ Find *pFind /* If non-zero, place output here */ ){ const char *zOuter; int nOuter; const char *zInner; int nInner; |
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); return TH_ERROR; } return Th_SetResult(interp, pValue->zData, pValue->nData); } | < < < < < < < < < < < < < < < < < < < < < | 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); return TH_ERROR; } return Th_SetResult(interp, pValue->zData, pValue->nData); } /* ** Return true if variable (zVar, nVar) exists. */ int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0); return pValue && (pValue->zData || pValue->pHash); } |
︙ | ︙ | |||
1339 1340 1341 1342 1343 1344 1345 | Th_Free(interp, pValue->zData); pValue->zData = 0; } assert(zValue || nValue==0); pValue->zData = Th_Malloc(interp, nValue+1); pValue->zData[nValue] = '\0'; | | | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | Th_Free(interp, pValue->zData); pValue->zData = 0; } assert(zValue || nValue==0); pValue->zData = Th_Malloc(interp, nValue+1); pValue->zData[nValue] = '\0'; memcpy(pValue->zData, zValue, nValue); pValue->nData = nValue; return TH_OK; } /* ** Create a variable link so that accessing variable (zLocal, nLocal) is |
︙ | ︙ | |||
1458 1459 1460 1461 1462 1463 1464 | */ char *th_strdup(Th_Interp *interp, const char *z, int n){ char *zRes; if( n<0 ){ n = th_strlen(z); } zRes = Th_Malloc(interp, n+1); | | | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | */ char *th_strdup(Th_Interp *interp, const char *z, int n){ char *zRes; if( n<0 ){ n = th_strlen(z); } zRes = Th_Malloc(interp, n+1); memcpy(zRes, z, n); zRes[n] = '\0'; return zRes; } /* ** Argument zPre must be a nul-terminated string. Set the interpreter ** result to a string containing the contents of zPre, followed by |
︙ | ︙ | |||
1518 1519 1520 1521 1522 1523 1524 | if( n<0 ){ n = th_strlen(z); } if( z && n>0 ){ char *zResult; zResult = Th_Malloc(pInterp, n+1); | | | 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 | if( n<0 ){ n = th_strlen(z); } if( z && n>0 ){ char *zResult; zResult = Th_Malloc(pInterp, n+1); memcpy(zResult, z, n); zResult[n] = '\0'; pInterp->zResult = zResult; pInterp->nResult = n; } return TH_OK; } |
︙ | ︙ | |||
1564 1565 1566 1567 1568 1569 1570 | pInterp->nResult = 0; return zResult; }else{ return (char *)Th_Malloc(pInterp, 1); } } | | | < | | < | < < | < < | < < | | < < | 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 | pInterp->nResult = 0; return zResult; }else{ return (char *)Th_Malloc(pInterp, 1); } } /* ** Wrappers around the supplied malloc() and free() */ void *Th_Malloc(Th_Interp *pInterp, int nByte){ void *p = pInterp->pVtab->xMalloc(nByte); if( p ){ memset(p, 0, nByte); } return p; } void Th_Free(Th_Interp *pInterp, void *z){ if( z ){ pInterp->pVtab->xFree(z); } } /* ** Install a new th1 command. ** ** If a command of the same name already exists, it is deleted automatically. */ int Th_CreateCommand( |
︙ | ︙ | |||
1770 1771 1772 1773 1774 1775 1776 | int *pnList, /* IN/OUT: Current length of *pzList */ const char *zElem, /* Data to append */ int nElem /* Length of nElem */ ){ Buffer output; int i; | | | | | | < < < < < < < < < | | | | | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 | int *pnList, /* IN/OUT: Current length of *pzList */ const char *zElem, /* Data to append */ int nElem /* Length of nElem */ ){ Buffer output; int i; int hasSpecialChar = 0; int hasEscapeChar = 0; int nBrace = 0; output.zBuf = *pzList; output.nBuf = *pnList; output.nBufAlloc = output.nBuf; if( nElem<0 ){ nElem = th_strlen(zElem); } if( output.nBuf>0 ){ thBufferWrite(interp, &output, " ", 1); } for(i=0; i<nElem; i++){ char c = zElem[i]; if( th_isspecial(c) ) hasSpecialChar = 1; if( c=='\\' ) hasEscapeChar = 1; if( c=='{' ) nBrace++; if( c=='}' ) nBrace--; } if( nElem==0 || (!hasEscapeChar && hasSpecialChar && nBrace==0) ){ thBufferWrite(interp, &output, "{", 1); thBufferWrite(interp, &output, zElem, nElem); thBufferWrite(interp, &output, "}", 1); }else{ for(i=0; i<nElem; i++){ char c = zElem[i]; if( th_isspecial(c) ) thBufferWrite(interp, &output, "\\", 1); thBufferWrite(interp, &output, &c, 1); } } *pzList = output.zBuf; *pnList = output.nBuf; return TH_OK; |
︙ | ︙ | |||
1840 1841 1842 1843 1844 1845 1846 | if( nElem<0 ){ nElem = th_strlen(zElem); } nNew = *pnStr + nElem; zNew = Th_Malloc(interp, nNew); | | | | 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 | if( nElem<0 ){ nElem = th_strlen(zElem); } nNew = *pnStr + nElem; zNew = Th_Malloc(interp, nNew); memcpy(zNew, *pzStr, *pnStr); memcpy(&zNew[*pnStr], zElem, nElem); Th_Free(interp, *pzStr); *pzStr = zNew; *pnStr = nNew; return TH_OK; } |
︙ | ︙ | |||
1887 1888 1889 1890 1891 1892 1893 | Th_Free(interp, (void *)interp); } /* ** Create a new interpreter. */ Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){ | < < < | | | < < < < | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 | Th_Free(interp, (void *)interp); } /* ** Create a new interpreter. */ Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){ Th_Interp *p; /* Allocate and initialise the interpreter and the global frame */ p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame)); memset(p, 0, sizeof(Th_Interp)); p->pVtab = pVtab; p->paCmd = Th_HashNew(p); thPushFrame(p, (Th_Frame *)&p[1]); thInitialize(p); return p; } |
︙ | ︙ | |||
2407 2408 2409 2410 2411 2412 2413 | } if( pNew->pOp || pNew->nValue ){ if( pNew->nValue ){ /* A terminal. Copy the string value. */ assert( !pNew->pOp ); pNew->zValue = Th_Malloc(interp, pNew->nValue); | | | | 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 | } if( pNew->pOp || pNew->nValue ){ if( pNew->nValue ){ /* A terminal. Copy the string value. */ assert( !pNew->pOp ); pNew->zValue = Th_Malloc(interp, pNew->nValue); memcpy(pNew->zValue, z, pNew->nValue); i += pNew->nValue; } if( (nToken%16)==0 ){ /* Grow the apToken array. */ Expr **apTokenOld = apToken; apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16)); memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken); } /* Put the new token at the end of the apToken array */ apToken[nToken] = pNew; nToken++; }else{ Th_Free(interp, pNew); |
︙ | ︙ | |||
2585 2586 2587 2588 2589 2590 2591 | pRet = 0; } if( op>0 && !pRet ){ pRet = (Th_HashEntry *)Th_Malloc(interp, sizeof(Th_HashEntry) + nKey); pRet->zKey = (char *)&pRet[1]; pRet->nKey = nKey; | | | 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 | pRet = 0; } if( op>0 && !pRet ){ pRet = (Th_HashEntry *)Th_Malloc(interp, sizeof(Th_HashEntry) + nKey); pRet->zKey = (char *)&pRet[1]; pRet->nKey = nKey; memcpy(pRet->zKey, zKey, nKey); pRet->pNext = pHash->a[iKey]; pHash->a[iKey] = pRet; } return pRet; } |
︙ | ︙ | |||
2868 2869 2870 2871 2872 2873 2874 | /* ** Set the result of the interpreter to the th1 representation of ** the integer iVal and return TH_OK. */ int Th_SetResultInt(Th_Interp *interp, int iVal){ int isNegative = 0; | < | | | | | 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 | /* ** Set the result of the interpreter to the th1 representation of ** the integer iVal and return TH_OK. */ int Th_SetResultInt(Th_Interp *interp, int iVal){ int isNegative = 0; char zBuf[32]; char *z = &zBuf[32]; if( iVal<0 ){ isNegative = 1; iVal = iVal * -1; } *(--z) = '\0'; *(--z) = (char)(48+((unsigned)iVal%10)); while( (iVal = ((unsigned)iVal/10))>0 ){ *(--z) = (char)(48+((unsigned)iVal%10)); assert(z>zBuf); } if( isNegative ){ *(--z) = '-'; } return Th_SetResult(interp, z, -1); |
︙ | ︙ |
Changes to src/th.h.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** Opaque handle for interpeter. */ typedef struct Th_Interp Th_Interp; /* ** Create and delete interpreters. */ | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** Opaque handle for interpeter. */ typedef struct Th_Interp Th_Interp; /* ** Create and delete interpreters. */ Th_Interp * Th_CreateInterp(Th_Vtab *pVtab); void Th_DeleteInterp(Th_Interp *); /* ** Evaluate an TH program in the stack frame identified by parameter ** iFrame, according to the following rules: ** ** * If iFrame is 0, this means the current frame. |
︙ | ︙ | |||
54 55 56 57 58 59 60 | int Th_ExistsVar(Th_Interp *, const char *, int); int Th_ExistsArrayVar(Th_Interp *, const char *, int); int Th_GetVar(Th_Interp *, const char *, int); int Th_SetVar(Th_Interp *, const char *, int, const char *, int); int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); int Th_UnsetVar(Th_Interp *, const char *, int); | < < < < < < < < < < < < < | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | int Th_ExistsVar(Th_Interp *, const char *, int); int Th_ExistsArrayVar(Th_Interp *, const char *, int); int Th_GetVar(Th_Interp *, const char *, int); int Th_SetVar(Th_Interp *, const char *, int, const char *, int); int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); int Th_UnsetVar(Th_Interp *, const char *, int); typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); /* ** Register new commands. */ int Th_CreateCommand( Th_Interp *interp, |
︙ | ︙ | |||
132 133 134 135 136 137 138 | */ int Th_ErrorMessage(Th_Interp *, const char *, const char *, int); /* ** Access the memory management functions associated with the specified ** interpreter. */ | < | | < < < < < < < < < < < < < < < < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | */ int Th_ErrorMessage(Th_Interp *, const char *, const char *, int); /* ** Access the memory management functions associated with the specified ** interpreter. */ void *Th_Malloc(Th_Interp *, int); void Th_Free(Th_Interp *, void *); /* ** Functions for handling TH lists. */ int Th_ListAppend(Th_Interp *, char **, int *, const char *, int); int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *); |
︙ | ︙ |
Changes to src/th_lang.c.
︙ | ︙ | |||
161 162 163 164 165 166 167 | if( rc==TH_BREAK ) rc = TH_OK; return rc; } /* ** TH Syntax: ** | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | if( rc==TH_BREAK ) rc = TH_OK; return rc; } /* ** TH Syntax: ** ** list ?arg1 ?arg2? ...? */ static int list_command( Th_Interp *interp, void *ctx, int argc, const char **argv, |
︙ | ︙ | |||
223 224 225 226 227 228 229 | } Th_SetResult(interp, zList, nList); Th_Free(interp, zList); return TH_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | } Th_SetResult(interp, zList, nList); Th_Free(interp, zList); return TH_OK; } /* ** TH Syntax: ** ** lindex list index */ static int lindex_command( |
︙ | ︙ | |||
923 924 925 926 927 928 929 | } return Th_SetResultInt(interp, argl[2]); } /* ** TH Syntax: ** | < < < < < < < < < < < < < < < < < < < < < < < < | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | } return Th_SetResultInt(interp, argl[2]); } /* ** TH Syntax: ** ** string range STRING FIRST LAST */ static int string_range_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ int iStart; int iEnd; |
︙ | ︙ | |||
1216 1217 1218 1219 1220 1221 1222 | static const Th_SubCommand aSub[] = { { "compare", string_compare_command }, { "first", string_first_command }, { "index", string_index_command }, { "is", string_is_command }, { "last", string_last_command }, { "length", string_length_command }, | < | 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 | static const Th_SubCommand aSub[] = { { "compare", string_compare_command }, { "first", string_first_command }, { "index", string_index_command }, { "is", string_is_command }, { "last", string_last_command }, { "length", string_length_command }, { "range", string_range_command }, { "repeat", string_repeat_command }, { "trim", string_trim_command }, { "trimleft", string_trim_command }, { "trimright", string_trim_command }, { 0, 0 } }; |
︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 | static int breakpoint_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ | | | < < | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | static int breakpoint_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ int cnt = 0; cnt++; return TH_OK; } /* ** Register the built-in th1 language commands with interpreter interp. ** Usually this is called soon after interpreter creation. */ int th_register_language(Th_Interp *interp){ /* Array of built-in commands. */ struct _Command { const char *zName; Th_CommandProc xProc; void *pContext; } aCommand[] = { {"array", array_command, 0}, {"catch", catch_command, 0}, {"expr", expr_command, 0}, {"for", for_command, 0}, {"if", if_command, 0}, {"info", info_command, 0}, {"lindex", lindex_command, 0}, {"list", list_command, 0}, {"llength", llength_command, 0}, {"lsearch", lsearch_command, 0}, {"proc", proc_command, 0}, {"rename", rename_command, 0}, {"set", set_command, 0}, |
︙ | ︙ |
Changes to src/th_main.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ** interpreter creation and initialization process. */ #define TH_INIT_NONE ((u32)0x00000000) /* No flags. */ #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ | < < < | | | | < < < < | 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 | ** interpreter creation and initialization process. */ #define TH_INIT_NONE ((u32)0x00000000) /* No flags. */ #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ #define TH_INIT_MASK ((u32)0x0000000F) /* All possible init flags. */ /* ** Useful and/or "well-known" combinations of flag values. */ #define TH_INIT_DEFAULT (TH_INIT_NONE) /* Default flags. */ #define TH_INIT_HOOK (TH_INIT_NEED_CONFIG | TH_INIT_FORCE_SETUP) #define TH_INIT_FORBID_MASK (TH_INIT_FORCE_TCL) /* Illegal from a script. */ #endif /* ** Flags set by functions in this file to keep track of integration state ** information. These flags should not be used outside of this file. */ #define TH_STATE_CONFIG ((u32)0x00000010) /* We opened the config. */ #define TH_STATE_REPOSITORY ((u32)0x00000020) /* We opened the repository. */ #define TH_STATE_MASK ((u32)0x00000030) /* All possible state flags. */ #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** These are the "well-known" TH1 error messages that occur when no hook is ** registered to be called prior to executing a command or processing a web ** page, respectively. If one of these errors is seen, it will not be sent ** or displayed to the remote user or local interactive user, respectively. */ #define NO_COMMAND_HOOK_ERROR "no such command: command_hook" #define NO_WEBPAGE_HOOK_ERROR "no such command: webpage_hook" #endif /* ** These macros are used within this file to detect if the repository and ** configuration ("user") database are currently open. */ #define Th_IsRepositoryOpen() (g.repositoryOpen) #define Th_IsConfigOpen() (g.zConfigDbName!=0) /* ** Global variable counting the number of outstanding calls to malloc() ** made by the th1 implementation. This is used to catch memory leaks ** in the interpreter. Obviously, it also means th1 is not threadsafe. */ static int nOutstandingMalloc = 0; /* |
︙ | ︙ | |||
102 103 104 105 106 107 108 | /* ** Returns the number of outstanding TH1 memory allocations. */ int Th_GetOutstandingMalloc(){ return nOutstandingMalloc; } | < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | /* ** Returns the number of outstanding TH1 memory allocations. */ int Th_GetOutstandingMalloc(){ return nOutstandingMalloc; } /* ** Generate a TH1 trace message if debugging is enabled. */ void Th_Trace(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); |
︙ | ︙ | |||
133 134 135 136 137 138 139 | /* ** Checks if the TH1 trace log needs to be enabled. If so, prepares ** it for use. */ void Th_InitTraceLog(){ g.thTrace = find_option("th-trace", 0, 0)!=0; if( g.thTrace ){ | < | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /* ** Checks if the TH1 trace log needs to be enabled. If so, prepares ** it for use. */ void Th_InitTraceLog(){ g.thTrace = find_option("th-trace", 0, 0)!=0; if( g.thTrace ){ blob_zero(&g.thLog); } } /* ** Prints the entire contents of the TH1 trace log to the standard ** output channel. |
︙ | ︙ | |||
155 156 157 158 159 160 161 | } /* ** - adopted from ls_cmd_rev in checkin.c ** - adopted commands/error handling for usage within th1 ** - interface adopted to allow result creation as TH1 List ** | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | } /* ** - adopted from ls_cmd_rev in checkin.c ** - adopted commands/error handling for usage within th1 ** - interface adopted to allow result creation as TH1 List ** ** Takes a checkin identifier in zRev and an optiona glob pattern in zGLOB ** as parameter returns a TH list in pzList,pnList with filenames matching ** glob pattern with the checking */ static void dir_cmd_rev( Th_Interp *interp, char **pzList, int *pnList, |
︙ | ︙ | |||
274 275 276 277 278 279 280 | ** True if output is enabled. False if disabled. */ static int enableOutput = 1; /* ** TH1 command: enable_output BOOLEAN ** | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | ** True if output is enabled. False if disabled. */ static int enableOutput = 1; /* ** TH1 command: enable_output BOOLEAN ** ** Enable or disable the puts and wiki commands. */ static int enableOutputCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ int rc; if( argc<2 || argc>3 ){ return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN"); } rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput); if( g.thTrace ){ Th_Trace("enable_output {%.*s} -> %d<br />\n", argl[1],argv[1],enableOutput); } return rc; } /* ** Returns a name for a TH1 return code. */ |
︙ | ︙ | |||
354 355 356 357 358 359 360 | default: { sqlite3_snprintf(sizeof(zRc), zRc, "TH1 return code %d", rc); } } return zRc; } | < < < < < < < < < < < < < < < | | | < < < < < | < < < < < < < < | < < < | | | | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | default: { sqlite3_snprintf(sizeof(zRc), zRc, "TH1 return code %d", rc); } } return zRc; } /* ** Send text to the appropriate output: Either to the console ** or to the CGI reply buffer. Escape all characters with special ** meaning to HTML if the encode parameter is true. */ static void sendText(const char *z, int n, int encode){ if( enableOutput && n ){ if( n<0 ) n = strlen(z); if( encode ){ z = htmlize(z, n); n = strlen(z); } if( g.cgiOutput ){ cgi_append_content(z, n); }else{ fwrite(z, 1, n, stdout); fflush(stdout); } if( encode ) free((char*)z); } } static void sendError(const char *z, int n, int forceCgi){ int savedEnable = enableOutput; enableOutput = 1; if( forceCgi || g.cgiOutput ){ sendText("<hr /><p class=\"thmainError\">", -1, 0); } sendText("ERROR: ", -1, 0); sendText((char*)z, n, 1); sendText(forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0); enableOutput = savedEnable; } /* ** Convert name to an rid. This function was copied from name_to_typed_rid() ** in name.c; however, it has been modified to report TH1 script errors instead ** of "fatal errors". |
︙ | ︙ | |||
490 491 492 493 494 495 496 | return rid; } } Th_SetResult(interp, "file name not found in manifest", -1); return 0; } | < < < < < < < < < < < < < < < < < < < < | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | return rid; } } Th_SetResult(interp, "file name not found in manifest", -1); return 0; } /* ** TH1 command: puts STRING ** TH1 command: html STRING ** ** Output STRING escaped for HTML (html) or unchanged (puts). */ static int putsCmd( Th_Interp *interp, void *pConvert, int argc, const char **argv, int *argl ){ if( argc!=2 ){ return Th_WrongNumArgs(interp, "puts STRING"); } sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert); return TH_OK; } /* ** TH1 command: redirect URL ?withMethod? ** ** Issues an HTTP redirect to the specified URL and then exits the process. |
︙ | ︙ | |||
604 605 606 607 608 609 610 | int argc, const char **argv, int *argl ){ if( argc!=1 ){ return Th_WrongNumArgs(interp, "verifyCsrf"); } | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | int argc, const char **argv, int *argl ){ if( argc!=1 ){ return Th_WrongNumArgs(interp, "verifyCsrf"); } login_verify_csrf_secret(); return TH_OK; } /* ** TH1 command: markdown STRING ** ** Renders the input string as markdown. The result is a two-element list. |
︙ | ︙ | |||
664 665 666 667 668 669 670 | blob_zero(&src); blob_init(&src, (char*)argv[1], argl[1]); blob_zero(&title); blob_zero(&body); markdown_to_html(&src, &title, &body); Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title)); Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body)); Th_SetResult(interp, zValue, nValue); | < | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | blob_zero(&src); blob_init(&src, (char*)argv[1], argl[1]); blob_zero(&title); blob_zero(&body); markdown_to_html(&src, &title, &body); Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title)); Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body)); Th_SetResult(interp, zValue, nValue); return TH_OK; } /* ** TH1 command: decorate STRING ** TH1 command: wiki STRING ** |
︙ | ︙ | |||
792 793 794 795 796 797 798 | for(i=1; rc==1 && i<argc; i++){ if( g.thTrace ){ Th_ListAppend(interp, &zCapList, &nCapList, argv[i], argl[i]); } rc = login_has_capability((char*)argv[i],argl[i],*(int*)p); } if( g.thTrace ){ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | for(i=1; rc==1 && i<argc; i++){ if( g.thTrace ){ Th_ListAppend(interp, &zCapList, &nCapList, argv[i], argl[i]); } rc = login_has_capability((char*)argv[i],argl[i],*(int*)p); } if( g.thTrace ){ Th_Trace("[%s %#h] => %d<br />\n", argv[0], nCapList, zCapList, rc); Th_Free(interp, zCapList); } Th_SetResultInt(interp, rc); return TH_OK; } /* ** TH1 command: searchable STRING... ** ** Return true if searching in any of the document classes identified ** by STRING is enabled for the repository and user has the necessary ** capabilities to perform the search. |
︙ | ︙ | |||
909 910 911 912 913 914 915 | case 't': match |= searchCap & SRCH_TKT; break; case 'w': match |= searchCap & SRCH_WIKI; break; } } if( !match ) rc = 0; } if( g.thTrace ){ | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | case 't': match |= searchCap & SRCH_TKT; break; case 'w': match |= searchCap & SRCH_WIKI; break; } } if( !match ) rc = 0; } if( g.thTrace ){ Th_Trace("[searchable %#h] => %d<br />\n", argl[1], argv[1], rc); } Th_SetResultInt(interp, rc); return TH_OK; } /* ** TH1 command: hasfeature STRING |
︙ | ︙ | |||
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 | /* placeholder for following ifdefs... */ } #if defined(FOSSIL_ENABLE_SSL) else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){ rc = 1; } #endif else if( 0 == fossil_strnicmp( zArg, "legacyMvRm\0", 11 ) ){ rc = 1; } #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) else if( 0 == fossil_strnicmp( zArg, "execRelPaths\0", 13 ) ){ rc = 1; } #endif #if defined(FOSSIL_ENABLE_TH1_DOCS) else if( 0 == fossil_strnicmp( zArg, "th1Docs\0", 8 ) ){ | > > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | /* placeholder for following ifdefs... */ } #if defined(FOSSIL_ENABLE_SSL) else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){ rc = 1; } #endif #if defined(FOSSIL_ENABLE_LEGACY_MV_RM) else if( 0 == fossil_strnicmp( zArg, "legacyMvRm\0", 11 ) ){ rc = 1; } #endif #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) else if( 0 == fossil_strnicmp( zArg, "execRelPaths\0", 13 ) ){ rc = 1; } #endif #if defined(FOSSIL_ENABLE_TH1_DOCS) else if( 0 == fossil_strnicmp( zArg, "th1Docs\0", 8 ) ){ |
︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 | rc = 1; } #endif else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){ rc = 1; } if( g.thTrace ){ | | | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | rc = 1; } #endif else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){ rc = 1; } if( g.thTrace ){ Th_Trace("[hasfeature %#h] => %d<br />\n", argl[1], zArg, rc); } Th_SetResultInt(interp, rc); return TH_OK; } /* |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | } #if defined(FOSSIL_ENABLE_TCL) if( g.tcl.interp ){ rc = 1; } #endif if( g.thTrace ){ | | | 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | } #if defined(FOSSIL_ENABLE_TCL) if( g.tcl.interp ){ rc = 1; } #endif if( g.thTrace ){ Th_Trace("[tclReady] => %d<br />\n", rc); } Th_SetResultInt(interp, rc); return TH_OK; } /* |
︙ | ︙ | |||
1088 1089 1090 1091 1092 1093 1094 | if( argc!=2 ){ return Th_WrongNumArgs(interp, "anycap STRING"); } for(i=0; rc==0 && i<argl[1]; i++){ rc = login_has_capability((char*)&argv[1][i],1,0); } if( g.thTrace ){ | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | if( argc!=2 ){ return Th_WrongNumArgs(interp, "anycap STRING"); } for(i=0; rc==0 && i<argl[1]; i++){ rc = login_has_capability((char*)&argv[1][i],1,0); } if( g.thTrace ){ Th_Trace("[anycap %#h] => %d<br />\n", argl[1], argv[1], rc); } Th_SetResultInt(interp, rc); return TH_OK; } /* ** TH1 command: combobox NAME TEXT-LIST NUMLINES |
︙ | ︙ | |||
1132 1133 1134 1135 1136 1137 1138 | if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR; Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem); blob_init(&name, (char*)argv[1], argl[1]); zValue = Th_Fetch(blob_str(&name), &nValue); zH = htmlize(blob_buffer(&name), blob_size(&name)); z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height); free(zH); | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR; Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem); blob_init(&name, (char*)argv[1], argl[1]); zValue = Th_Fetch(blob_str(&name), &nValue); zH = htmlize(blob_buffer(&name), blob_size(&name)); z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height); free(zH); sendText(z, -1, 0); free(z); blob_reset(&name); for(i=0; i<nElem; i++){ zH = htmlize((char*)azElem[i], aszElem[i]); if( zValue && aszElem[i]==nValue && memcmp(zValue, azElem[i], nValue)==0 ){ z = mprintf("<option value=\"%s\" selected=\"selected\">%s</option>", zH, zH); }else{ z = mprintf("<option value=\"%s\">%s</option>", zH, zH); } free(zH); sendText(z, -1, 0); free(z); } sendText("</select>", -1, 0); Th_Free(interp, azElem); } return TH_OK; } /* ** TH1 command: linecount STRING MAX MIN ** ** Return one more than the number of \n characters in STRING. But |
︙ | ︙ | |||
1268 1269 1270 1271 1272 1273 1274 | Th_SetResult(interp, g.zRepositoryName, -1); return TH_OK; } /* ** TH1 command: checkout ?BOOLEAN? ** | | | | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 | Th_SetResult(interp, g.zRepositoryName, -1); return TH_OK; } /* ** TH1 command: checkout ?BOOLEAN? ** ** Return the fully qualified directory name of the current checkout or an ** empty string if it is not available. Optionally, it will attempt to find ** the current checkout, opening the configuration ("user") database and the ** repository as necessary, if the boolean argument is non-zero. */ static int checkoutCmd( Th_Interp *interp, void *p, int argc, const char **argv, |
︙ | ︙ | |||
1323 1324 1325 1326 1327 1328 1329 | /* ** TH1 command: globalState NAME ?DEFAULT? ** ** Returns a string containing the value of the specified global state ** variable -OR- the specified default value. Currently, the supported ** items are: ** | | | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 | /* ** TH1 command: globalState NAME ?DEFAULT? ** ** Returns a string containing the value of the specified global state ** variable -OR- the specified default value. Currently, the supported ** items are: ** ** "checkout" = The active local checkout directory, if any. ** "configuration" = The active configuration database file name, ** if any. ** "executable" = The fully qualified executable file name. ** "flags" = The TH1 initialization flags. ** "log" = The error log file name, if any. ** "repository" = The active local repository file name, if ** any. |
︙ | ︙ | |||
1482 1483 1484 1485 1486 1487 1488 | return Th_WrongNumArgs(interp, "render STRING"); } rc = Th_Render(argv[1]); Th_SetResult(interp, 0, 0); return rc; } | < < < < < < < < < < < < < < < < < < < | 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | return Th_WrongNumArgs(interp, "render STRING"); } rc = Th_Render(argv[1]); Th_SetResult(interp, 0, 0); return rc; } /* ** TH1 command: styleHeader TITLE ** ** Render the configured style header for the selected skin. */ static int styleHeaderCmd( Th_Interp *interp, |
︙ | ︙ | |||
1542 1543 1544 1545 1546 1547 1548 | const char **argv, int *argl ){ if( argc!=1 ){ return Th_WrongNumArgs(interp, "styleFooter"); } if( Th_IsRepositoryOpen() ){ | | | | < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 | const char **argv, int *argl ){ if( argc!=1 ){ return Th_WrongNumArgs(interp, "styleFooter"); } if( Th_IsRepositoryOpen() ){ style_footer(); Th_SetResult(interp, 0, 0); return TH_OK; }else{ Th_SetResult(interp, "repository unavailable", -1); return TH_ERROR; } } /* ** TH1 command: styleScript ** ** Render the configured JavaScript for the selected skin. */ static int styleScriptCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ if( argc!=1 ){ return Th_WrongNumArgs(interp, "styleScript"); } if( Th_IsRepositoryOpen() ){ const char *zScript = skin_get("js"); if( zScript==0 ) zScript = ""; Th_Render(zScript); Th_SetResult(interp, 0, 0); return TH_OK; }else{ Th_SetResult(interp, "repository unavailable", -1); return TH_ERROR; } } /* ** TH1 command: artifact ID ?FILENAME? ** ** Attempts to locate the specified artifact and return its contents. An ** error is generated if the repository is not open or the artifact cannot ** be found. |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 | } }else{ Th_SetResult(interp, "repository unavailable", -1); return TH_ERROR; } } | < < < < < < < < < < < < < < < < < < < | | 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 | } }else{ Th_SetResult(interp, "repository unavailable", -1); return TH_ERROR; } } /* ** TH1 command: unversioned content FILENAME ** ** Attempts to locate the specified unversioned file and return its contents. ** An error is generated if the repository is not open or the unversioned file ** cannot be found. */ static int unversionedContentCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ if( argc!=3 ){ return Th_WrongNumArgs(interp, "unversioned content FILENAME"); } if( Th_IsRepositoryOpen() ){ Blob content; if( unversioned_content(argv[2], &content)==0 ){ Th_SetResult(interp, blob_str(&content), blob_size(&content)); blob_reset(&content); return TH_OK; }else{ return TH_ERROR; } }else{ |
︙ | ︙ | |||
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 | { "content", unversionedContentCmd }, { "list", unversionedListCmd }, { 0, 0 } }; return Th_CallSubCommand(interp, p, argc, argv, argl, aSub); } /* ** TH1 command: utime ** ** Return the number of microseconds of CPU time consumed by the current ** process in user space. */ static int utimeCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ sqlite3_uint64 x; char zUTime[50]; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 | { "content", unversionedContentCmd }, { "list", unversionedListCmd }, { 0, 0 } }; return Th_CallSubCommand(interp, p, argc, argv, argl, aSub); } #ifdef _WIN32 # include <windows.h> #else # include <sys/time.h> # include <sys/resource.h> #endif /* ** Get user and kernel times in microseconds. */ static void getCpuTimes(sqlite3_uint64 *piUser, sqlite3_uint64 *piKernel){ #ifdef _WIN32 FILETIME not_used; FILETIME kernel_time; FILETIME user_time; GetProcessTimes(GetCurrentProcess(), ¬_used, ¬_used, &kernel_time, &user_time); if( piUser ){ *piUser = ((((sqlite3_uint64)user_time.dwHighDateTime)<<32) + (sqlite3_uint64)user_time.dwLowDateTime + 5)/10; } if( piKernel ){ *piKernel = ((((sqlite3_uint64)kernel_time.dwHighDateTime)<<32) + (sqlite3_uint64)kernel_time.dwLowDateTime + 5)/10; } #else struct rusage s; getrusage(RUSAGE_SELF, &s); if( piUser ){ *piUser = ((sqlite3_uint64)s.ru_utime.tv_sec)*1000000 + s.ru_utime.tv_usec; } if( piKernel ){ *piKernel = ((sqlite3_uint64)s.ru_stime.tv_sec)*1000000 + s.ru_stime.tv_usec; } #endif } /* ** TH1 command: utime ** ** Return the number of microseconds of CPU time consumed by the current ** process in user space. */ static int utimeCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ sqlite3_uint64 x; char zUTime[50]; getCpuTimes(&x, 0); sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x); Th_SetResult(interp, zUTime, -1); return TH_OK; } /* ** TH1 command: stime ** ** Return the number of microseconds of CPU time consumed by the current ** process in system space. */ static int stimeCmd( Th_Interp *interp, void *p, int argc, const char **argv, int *argl ){ sqlite3_uint64 x; char zUTime[50]; getCpuTimes(0, &x); sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x); Th_SetResult(interp, zUTime, -1); return TH_OK; } /* |
︙ | ︙ | |||
1850 1851 1852 1853 1854 1855 1856 | return Th_WrongNumArgs(interp, "repository ?BOOLEAN?"); } if( argc==2 ){ if( Th_ToInt(interp, argv[1], argl[1], &n) ){ return TH_ERROR; } if( n<1 ) n = 1; | | | 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 | return Th_WrongNumArgs(interp, "repository ?BOOLEAN?"); } if( argc==2 ){ if( Th_ToInt(interp, argv[1], argl[1], &n) ){ return TH_ERROR; } if( n<1 ) n = 1; if( n>sizeof(aRand) ) n = sizeof(aRand); }else{ n = 10; } sqlite3_randomness(n, aRand); encode16(aRand, zOut, n); Th_SetResult(interp, (const char *)zOut, -1); return TH_OK; |
︙ | ︙ | |||
1953 1954 1955 1956 1957 1958 1959 | for(i=0; i<nCol; i++){ const char *zCol = sqlite3_column_name(pStmt, i); int szCol = th_strlen(zCol); const char *zVal = (const char*)sqlite3_column_text(pStmt, i); int szVal = sqlite3_column_bytes(pStmt, i); Th_SetVar(interp, zCol, szCol, zVal, szVal); } | < < < < < < < < < | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 | for(i=0; i<nCol; i++){ const char *zCol = sqlite3_column_name(pStmt, i); int szCol = th_strlen(zCol); const char *zVal = (const char*)sqlite3_column_text(pStmt, i); int szVal = sqlite3_column_bytes(pStmt, i); Th_SetVar(interp, zCol, szCol, zVal, szVal); } res = Th_Eval(interp, 0, argv[2], argl[2]); if( res==TH_BREAK || res==TH_CONTINUE ) res = TH_OK; } rc = sqlite3_finalize(pStmt); if( rc!=SQLITE_OK ){ if( noComplain ) return TH_OK; Th_ErrorMessage(interp, "SQL error: ", sqlite3_errmsg(g.db), -1); return TH_ERROR; |
︙ | ︙ | |||
2014 2015 2016 2017 2018 2019 2020 | Th_ErrorMessage(interp, "no value for setting \"", argv[nArg], -1); rc = TH_ERROR; }else{ Th_SetResult(interp, 0, 0); rc = TH_OK; } if( g.thTrace ){ | | | 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 | Th_ErrorMessage(interp, "no value for setting \"", argv[nArg], -1); rc = TH_ERROR; }else{ Th_SetResult(interp, 0, 0); rc = TH_OK; } if( g.thTrace ){ Th_Trace("[setting %s%#h] => %d<br />\n", strict ? "strict " : "", argl[nArg], argv[nArg], rc); } return rc; } /* ** TH1 command: glob_match ?-one? ?--? patternList string |
︙ | ︙ | |||
2221 2222 2223 2224 2225 2226 2227 | }else{ Th_ErrorMessage(interp, "synchronous requests are not yet implemented", 0, 0); blob_reset(&payload); return TH_ERROR; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | }else{ Th_ErrorMessage(interp, "synchronous requests are not yet implemented", 0, 0); blob_reset(&payload); return TH_ERROR; } } /* ** Attempts to open the configuration ("user") database. Optionally, also ** attempts to try to find the repository and open it. */ void Th_OpenConfig( int openRepository |
︙ | ︙ | |||
2310 2311 2312 2313 2314 2315 2316 | */ void Th_FossilInit(u32 flags){ int wasInit = 0; int needConfig = flags & TH_INIT_NEED_CONFIG; int forceReset = flags & TH_INIT_FORCE_RESET; int forceTcl = flags & TH_INIT_FORCE_TCL; int forceSetup = flags & TH_INIT_FORCE_SETUP; | < | < < < < < < < < < < | | < < < < < < < < < | | 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 | */ void Th_FossilInit(u32 flags){ int wasInit = 0; int needConfig = flags & TH_INIT_NEED_CONFIG; int forceReset = flags & TH_INIT_FORCE_RESET; int forceTcl = flags & TH_INIT_FORCE_TCL; int forceSetup = flags & TH_INIT_FORCE_SETUP; static unsigned int aFlags[] = { 0, 1, WIKI_LINKSONLY }; static int anonFlag = LOGIN_ANON; static int zeroInt = 0; static struct _Command { const char *zName; Th_CommandProc xProc; void *pContext; } aCommand[] = { {"anoncap", hascapCmd, (void*)&anonFlag}, {"anycap", anycapCmd, 0}, {"artifact", artifactCmd, 0}, {"checkout", checkoutCmd, 0}, {"combobox", comboboxCmd, 0}, {"date", dateCmd, 0}, {"decorate", wikiCmd, (void*)&aFlags[2]}, {"dir", dirCmd, 0}, {"enable_output", enableOutputCmd, 0}, {"encode64", encode64Cmd, 0}, {"getParameter", getParameterCmd, 0}, {"glob_match", globMatchCmd, 0}, {"globalState", globalStateCmd, 0}, {"httpize", httpizeCmd, 0}, {"hascap", hascapCmd, (void*)&zeroInt}, {"hasfeature", hasfeatureCmd, 0}, {"html", putsCmd, (void*)&aFlags[0]}, {"htmlize", htmlizeCmd, 0}, {"http", httpCmd, 0}, {"insertCsrf", insertCsrfCmd, 0}, {"linecount", linecntCmd, 0}, {"markdown", markdownCmd, 0}, {"puts", putsCmd, (void*)&aFlags[1]}, {"query", queryCmd, 0}, {"randhex", randhexCmd, 0}, {"redirect", redirectCmd, 0}, {"regexp", regexpCmd, 0}, {"reinitialize", reinitializeCmd, 0}, {"render", renderCmd, 0}, {"repository", repositoryCmd, 0}, {"searchable", searchableCmd, 0}, {"setParameter", setParameterCmd, 0}, {"setting", settingCmd, 0}, {"styleFooter", styleFooterCmd, 0}, {"styleHeader", styleHeaderCmd, 0}, {"styleScript", styleScriptCmd, 0}, {"tclReady", tclReadyCmd, 0}, {"trace", traceCmd, 0}, {"stime", stimeCmd, 0}, {"unversioned", unversionedCmd, 0}, {"utime", utimeCmd, 0}, {"verifyCsrf", verifyCsrfCmd, 0}, {"wiki", wikiCmd, (void*)&aFlags[0]}, {0, 0, 0} }; if( g.thTrace ){ Th_Trace("th1-init 0x%x => 0x%x<br />\n", g.th1Flags, flags); } if( needConfig ){ /* ** This function uses several settings which may be defined in the ** repository and/or the global configuration. Since the caller ** passed a non-zero value for the needConfig parameter, make sure ** the necessary database connections are open prior to continuing. */ Th_OpenConfig(1); } if( forceReset || forceTcl || g.interp==0 ){ int created = 0; int i; if( g.interp==0 ){ g.interp = Th_CreateInterp(&vtab); created = 1; } if( forceReset || created ){ th_register_language(g.interp); /* Basic scripting commands. */ } #ifdef FOSSIL_ENABLE_TCL if( forceTcl || fossil_getenv("TH1_ENABLE_TCL")!=0 || |
︙ | ︙ | |||
2432 2433 2434 2435 2436 2437 2438 | g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */ } if( g.th1Setup ){ rc = Th_Eval(g.interp, 0, g.th1Setup, -1); if( rc==TH_ERROR ){ int nResult = 0; char *zResult = (char*)Th_GetResult(g.interp, &nResult); | | | < < < < < < < < < < < < < < | | 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 | g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */ } if( g.th1Setup ){ rc = Th_Eval(g.interp, 0, g.th1Setup, -1); if( rc==TH_ERROR ){ int nResult = 0; char *zResult = (char*)Th_GetResult(g.interp, &nResult); sendError(zResult, nResult, 0); } } if( g.thTrace ){ Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup, Th_ReturnCodeName(rc, 0)); } } g.th1Flags &= ~TH_INIT_MASK; g.th1Flags |= (flags & TH_INIT_MASK); } /* ** Store a string value in a variable in the interpreter. */ void Th_Store(const char *zName, const char *zValue){ Th_FossilInit(TH_INIT_DEFAULT); if( zValue ){ if( g.thTrace ){ Th_Trace("set %h {%h}<br />\n", zName, zValue); } Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue)); } } /* ** Appends an element to a TH1 list value. This function is called by the |
︙ | ︙ | |||
2508 2509 2510 2511 2512 2513 2514 | char *zValue = 0; int nValue = 0; int i; for(i=0; i<nList; i++){ Th_ListAppend(g.interp, &zValue, &nValue, pzList[i], -1); } if( g.thTrace ){ | | | | 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 | char *zValue = 0; int nValue = 0; int i; for(i=0; i<nList; i++){ Th_ListAppend(g.interp, &zValue, &nValue, pzList[i], -1); } if( g.thTrace ){ Th_Trace("set %h {%h}<br />\n", zName, zValue); } Th_SetVar(g.interp, zName, -1, zValue, nValue); Th_Free(g.interp, zValue); } } /* ** Store an integer value in a variable in the interpreter. */ void Th_StoreInt(const char *zName, int iValue){ Blob value; char *zValue; Th_FossilInit(TH_INIT_DEFAULT); blob_zero(&value); blob_appendf(&value, "%d", iValue); zValue = blob_str(&value); if( g.thTrace ){ Th_Trace("set %h {%h}<br />\n", zName, zValue); } Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue)); blob_reset(&value); } /* ** Unset a variable. |
︙ | ︙ | |||
2657 2658 2659 2660 2661 2662 2663 | int nResult = 0; char *zResult = (char*)Th_GetResult(g.interp, &nResult); /* ** Make sure that the TH1 script error was not caused by a "missing" ** command hook handler as that is not actually an error condition. */ if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ | | | | 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 | int nResult = 0; char *zResult = (char*)Th_GetResult(g.interp, &nResult); /* ** Make sure that the TH1 script error was not caused by a "missing" ** command hook handler as that is not actually an error condition. */ if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ sendError(zResult, nResult, 0); }else{ /* ** There is no command hook handler "installed". This situation ** is NOT actually an error. */ rc = TH_OK; } } /* ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does ** not exist because commands are not being hooked), return TH_OK because we ** do not want to skip executing essential commands unless the called command ** (i.e. "command_hook") explicitly forbids this by successfully returning ** TH_BREAK or TH_CONTINUE. */ if( g.thTrace ){ Th_Trace("[command_hook {%h}] => %h<br />\n", zName, Th_ReturnCodeName(rc, 0)); } /* ** Does our call to Th_FossilInit() result in opening a database? If so, ** clean it up now. This is very important because some commands do not ** expect the repository and/or the configuration ("user") database to be ** open prior to their own code doing so. |
︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 | if( !Th_AreHooksEnabled() ) return rc; Th_FossilInit(TH_INIT_HOOK); Th_Store("cmd_name", zName); Th_StoreList("cmd_args", g.argv, g.argc); Th_StoreInt("cmd_flags", cmdFlags); rc = Th_Eval(g.interp, 0, "command_notify", -1); if( g.thTrace ){ | | | 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 | if( !Th_AreHooksEnabled() ) return rc; Th_FossilInit(TH_INIT_HOOK); Th_Store("cmd_name", zName); Th_StoreList("cmd_args", g.argv, g.argc); Th_StoreInt("cmd_flags", cmdFlags); rc = Th_Eval(g.interp, 0, "command_notify", -1); if( g.thTrace ){ Th_Trace("[command_notify {%h}] => %h<br />\n", zName, Th_ReturnCodeName(rc, 0)); } /* ** Does our call to Th_FossilInit() result in opening a database? If so, ** clean it up now. This is very important because some commands do not ** expect the repository and/or the configuration ("user") database to be ** open prior to their own code doing so. |
︙ | ︙ | |||
2744 2745 2746 2747 2748 2749 2750 | int nResult = 0; char *zResult = (char*)Th_GetResult(g.interp, &nResult); /* ** Make sure that the TH1 script error was not caused by a "missing" ** webpage hook handler as that is not actually an error condition. */ if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ | | | | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 | int nResult = 0; char *zResult = (char*)Th_GetResult(g.interp, &nResult); /* ** Make sure that the TH1 script error was not caused by a "missing" ** webpage hook handler as that is not actually an error condition. */ if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ sendError(zResult, nResult, 1); }else{ /* ** There is no webpage hook handler "installed". This situation ** is NOT actually an error. */ rc = TH_OK; } } /* ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does ** not exist because commands are not being hooked), return TH_OK because we ** do not want to skip processing essential web pages unless the called ** command (i.e. "webpage_hook") explicitly forbids this by successfully ** returning TH_BREAK or TH_CONTINUE. */ if( g.thTrace ){ Th_Trace("[webpage_hook {%h}] => %h<br />\n", zName, Th_ReturnCodeName(rc, 0)); } /* ** Does our call to Th_FossilInit() result in opening a database? If so, ** clean it up now. This is very important because some commands do not ** expect the repository and/or the configuration ("user") database to be ** open prior to their own code doing so. |
︙ | ︙ | |||
2793 2794 2795 2796 2797 2798 2799 | if( !Th_AreHooksEnabled() ) return rc; Th_FossilInit(TH_INIT_HOOK); Th_Store("web_name", zName); Th_StoreList("web_args", g.argv, g.argc); Th_StoreInt("web_flags", cmdFlags); rc = Th_Eval(g.interp, 0, "webpage_notify", -1); if( g.thTrace ){ | | | 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 | if( !Th_AreHooksEnabled() ) return rc; Th_FossilInit(TH_INIT_HOOK); Th_Store("web_name", zName); Th_StoreList("web_args", g.argv, g.argc); Th_StoreInt("web_flags", cmdFlags); rc = Th_Eval(g.interp, 0, "webpage_notify", -1); if( g.thTrace ){ Th_Trace("[webpage_notify {%h}] => %h<br />\n", zName, Th_ReturnCodeName(rc, 0)); } /* ** Does our call to Th_FossilInit() result in opening a database? If so, ** clean it up now. This is very important because some commands do not ** expect the repository and/or the configuration ("user") database to be ** open prior to their own code doing so. |
︙ | ︙ | |||
2821 2822 2823 2824 2825 2826 2827 | return 1; } return db_get_boolean("th1-docs", 0); } #endif | < | > > > | | < < | | < < < < < < < < < | < < < | < | | | | | < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 | return 1; } return db_get_boolean("th1-docs", 0); } #endif /* ** The z[] input contains text mixed with TH1 scripts. ** The TH1 scripts are contained within <th1>...</th1>. ** TH1 variables are $aaa or $<aaa>. The first form of ** variable is literal. The second is run through htmlize ** before being inserted. ** ** This routine processes the template and writes the results ** on either stdout or into CGI. */ int Th_Render(const char *z){ int i = 0; int n; int rc = TH_OK; char *zResult; Th_FossilInit(TH_INIT_DEFAULT); while( z[i] ){ if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){ const char *zVar; int nVar; int encode = 1; sendText(z, i, 0); if( z[i+1]=='<' ){ /* Variables of the form $<aaa> are html escaped */ zVar = &z[i+2]; nVar = n-2; }else{ /* Variables of the form $aaa are output raw */ zVar = &z[i+1]; nVar = n; encode = 0; } rc = Th_GetVar(g.interp, (char*)zVar, nVar); z += i+1+n; i = 0; zResult = (char*)Th_GetResult(g.interp, &n); sendText((char*)zResult, n, encode); }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){ sendText(z, i, 0); z += i+5; for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){} if( g.thTrace ){ Th_Trace("eval {<pre>%#h</pre>}<br />", i, z); } rc = Th_Eval(g.interp, 0, (const char*)z, i); if( rc!=TH_OK ) break; z += i; if( z[0] ){ z += 6; } i = 0; }else{ i++; } } if( rc==TH_ERROR ){ zResult = (char*)Th_GetResult(g.interp, &n); sendError(zResult, n, 1); }else{ sendText(z, i, 0); } return rc; } /* ** COMMAND: test-th-render ** ** Usage: %fossil test-th-render FILE ** ** Read the content of the file named "FILE" as if it were a header or ** footer or ticket rendering script, evaluate it, and show the results ** on standard output. ** ** Options: ** ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --open-config Open the configuration database ** --set-anon-caps Set anonymous login capabilities ** --set-user-caps Set user login capabilities ** --th-trace Trace TH1 execution (for debugging purposes) */ |
︙ | ︙ | |||
2985 2986 2987 2988 2989 2990 2991 | /* ** COMMAND: test-th-eval ** ** Usage: %fossil test-th-eval SCRIPT ** ** Evaluate SCRIPT as if it were a header or footer or ticket rendering | | < > < < | 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 | /* ** COMMAND: test-th-eval ** ** Usage: %fossil test-th-eval SCRIPT ** ** Evaluate SCRIPT as if it were a header or footer or ticket rendering ** script and show the results on standard output. ** ** Options: ** ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --open-config Open the configuration database ** --set-anon-caps Set anonymous login capabilities ** --set-user-caps Set user login capabilities ** --th-trace Trace TH1 execution (for debugging purposes) */ void test_th_eval(void){ int rc; const char *zRc; int forceCgi, fullHttpReply; Th_InitTraceLog(); forceCgi = find_option("cgi", 0, 0)!=0; fullHttpReply = find_option("http", 0, 0)!=0; if( fullHttpReply ) forceCgi = 1; if( forceCgi ) Th_ForceCgi(fullHttpReply); if( find_option("open-config", 0, 0)!=0 ){ Th_OpenConfig(1); |
︙ | ︙ | |||
3024 3025 3026 3027 3028 3029 3030 | login_set_capabilities(zCap ? zCap : "sx", 0); g.useLocalauth = 1; } verify_all_options(); if( g.argc!=3 ){ usage("script"); } | < < < < < < | < > < < | < | 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 | login_set_capabilities(zCap ? zCap : "sx", 0); g.useLocalauth = 1; } verify_all_options(); if( g.argc!=3 ){ usage("script"); } Th_FossilInit(TH_INIT_DEFAULT); rc = Th_Eval(g.interp, 0, g.argv[2], -1); zRc = Th_ReturnCodeName(rc, 1); fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0)); Th_PrintTraceLog(); if( forceCgi ) cgi_reply(); } /* ** COMMAND: test-th-source ** ** Usage: %fossil test-th-source FILE ** ** Evaluate the contents of the file named "FILE" as if it were a header ** or footer or ticket rendering script and show the results on standard ** output. ** ** Options: ** ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --open-config Open the configuration database ** --set-anon-caps Set anonymous login capabilities ** --set-user-caps Set user login capabilities ** --th-trace Trace TH1 execution (for debugging purposes) */ void test_th_source(void){ int rc; const char *zRc; int forceCgi, fullHttpReply; Blob in; Th_InitTraceLog(); forceCgi = find_option("cgi", 0, 0)!=0; fullHttpReply = find_option("http", 0, 0)!=0; if( fullHttpReply ) forceCgi = 1; if( forceCgi ) Th_ForceCgi(fullHttpReply); if( find_option("open-config", 0, 0)!=0 ){ Th_OpenConfig(1); } if( find_option("set-anon-caps", 0, 0)!=0 ){ const char *zCap = fossil_getenv("TH1_TEST_ANON_CAPS"); |
︙ | ︙ | |||
3091 3092 3093 3094 3095 3096 3097 | usage("file"); } blob_zero(&in); blob_read_from_file(&in, g.argv[2], ExtFILE); Th_FossilInit(TH_INIT_DEFAULT); rc = Th_Eval(g.interp, 0, blob_str(&in), -1); zRc = Th_ReturnCodeName(rc, 1); | < | < < | 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 | usage("file"); } blob_zero(&in); blob_read_from_file(&in, g.argv[2], ExtFILE); Th_FossilInit(TH_INIT_DEFAULT); rc = Th_Eval(g.interp, 0, blob_str(&in), -1); zRc = Th_ReturnCodeName(rc, 1); fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0)); Th_PrintTraceLog(); if( forceCgi ) cgi_reply(); } #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** COMMAND: test-th-hook |
︙ | ︙ | |||
3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 | ** and "web_flags" to appropriate values. ** ** webnotify Executes the TH1 procedure [webpage_notify], after ** setting the TH1 variables "web_name", "web_args", ** and "web_flags" to appropriate values. ** ** Options: ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --th-trace Trace TH1 execution (for debugging purposes) */ void test_th_hook(void){ int rc = TH_OK; int nResult = 0; | > | 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 | ** and "web_flags" to appropriate values. ** ** webnotify Executes the TH1 procedure [webpage_notify], after ** setting the TH1 variables "web_name", "web_args", ** and "web_flags" to appropriate values. ** ** Options: ** ** --cgi Include a CGI response header in the output ** --http Include an HTTP response header in the output ** --th-trace Trace TH1 execution (for debugging purposes) */ void test_th_hook(void){ int rc = TH_OK; int nResult = 0; |
︙ | ︙ | |||
3163 3164 3165 3166 3167 3168 3169 | rc = Th_WebpageNotify(g.argv[3], (unsigned int)atoi(g.argv[4])); }else{ fossil_fatal("Unknown TH1 hook %s", g.argv[2]); } if( g.interp ){ zResult = (char*)Th_GetResult(g.interp, &nResult); } | | | | | | | | 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 | rc = Th_WebpageNotify(g.argv[3], (unsigned int)atoi(g.argv[4])); }else{ fossil_fatal("Unknown TH1 hook %s", g.argv[2]); } if( g.interp ){ zResult = (char*)Th_GetResult(g.interp, &nResult); } sendText("RESULT (", -1, 0); sendText(Th_ReturnCodeName(rc, 0), -1, 0); sendText(")", -1, 0); if( zResult && nResult>0 ){ sendText(": ", -1, 0); sendText(zResult, nResult, 0); } sendText("\n", -1, 0); Th_PrintTraceLog(); if( forceCgi ) cgi_reply(); } #endif |
Changes to src/th_tcl.c.
︙ | ︙ | |||
96 97 98 99 100 101 102 | # define _WIN32_WINNT 0x0502 /* SetDllDirectory, Windows XP SP2 */ # endif # include <windows.h> # ifndef TCL_DIRECTORY_SEP # define TCL_DIRECTORY_SEP '\\' # endif # ifndef TCL_LIBRARY_NAME | | | | | | | 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 | # define _WIN32_WINNT 0x0502 /* SetDllDirectory, Windows XP SP2 */ # endif # include <windows.h> # ifndef TCL_DIRECTORY_SEP # define TCL_DIRECTORY_SEP '\\' # endif # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "tcl86.dll\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (4) # endif # ifndef dlopen # define dlopen(a,b) (void *)LoadLibrary((a)) # endif # ifndef dlsym # define dlsym(a,b) GetProcAddress((HANDLE)(a),(b)) # endif # ifndef dlclose # define dlclose(a) FreeLibrary((HANDLE)(a)) # endif # else # include <dlfcn.h> # ifndef TCL_DIRECTORY_SEP # define TCL_DIRECTORY_SEP '/' # endif # if defined(__CYGWIN__) # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "libtcl8.6.dll\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (8) # endif # elif defined(__APPLE__) # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "libtcl8.6.dylib\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (8) # endif # elif defined(__FreeBSD__) # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "libtcl86.so\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (7) # endif # else # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "libtcl8.6.so\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (8) # endif # endif /* defined(__CYGWIN__) */ # endif /* defined(_WIN32) */ # ifndef TCL_FINDEXECUTABLE_NAME |
︙ | ︙ | |||
970 971 972 973 974 975 976 | *pxDeleteInterp = xDeleteInterp; *pxFinalize = xFinalize; return TH_OK; } } while( --aFileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */ aFileName[TCL_MINOR_OFFSET] = 'x'; Th_ErrorMessage(interp, | | | 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 | *pxDeleteInterp = xDeleteInterp; *pxFinalize = xFinalize; return TH_OK; } } while( --aFileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */ aFileName[TCL_MINOR_OFFSET] = 'x'; Th_ErrorMessage(interp, "could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"", aFileName, -1); return TH_ERROR; #else *phLibrary = 0; *pxFindExecutable = Tcl_FindExecutable; *pxCreateInterp = Tcl_CreateInterp; *pxDeleteInterp = Tcl_DeleteInterp; |
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 | Tcl_IncrRefCount(objPtr); resultObjPtr = Tcl_SetVar2Ex(pInterp, "argv0", NULL, objPtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(objPtr); objPtr = 0; if( !resultObjPtr ){ return TCL_ERROR; } | | | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 | Tcl_IncrRefCount(objPtr); resultObjPtr = Tcl_SetVar2Ex(pInterp, "argv0", NULL, objPtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(objPtr); objPtr = 0; if( !resultObjPtr ){ return TCL_ERROR; } objPtr = Tcl_NewIntObj(argc - 1); Tcl_IncrRefCount(objPtr); resultObjPtr = Tcl_SetVar2Ex(pInterp, "argc", NULL, objPtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(objPtr); objPtr = 0; if( !resultObjPtr ){ return TCL_ERROR; } |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 | Tcl_DeleteInterp(tclInterp); /* TODO: Redundant? */ tclInterp = 0; return TH_ERROR; } tclContext->interp = tclInterp; if( Tcl_Init(tclInterp)!=TCL_OK ){ Th_ErrorMessage(interp, | | < | < | | < | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 | Tcl_DeleteInterp(tclInterp); /* TODO: Redundant? */ tclInterp = 0; return TH_ERROR; } tclContext->interp = tclInterp; if( Tcl_Init(tclInterp)!=TCL_OK ){ Th_ErrorMessage(interp, "Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1); Tcl_DeleteInterp(tclInterp); tclContext->interp = tclInterp = 0; return TH_ERROR; } if( setTclArguments(tclInterp, argc, argv)!=TCL_OK ){ Th_ErrorMessage(interp, "Tcl error setting arguments:", Tcl_GetStringResult(tclInterp), -1); Tcl_DeleteInterp(tclInterp); tclContext->interp = tclInterp = 0; return TH_ERROR; } /* ** Determine (and cache) if an objProc can be called directly for a Tcl ** command invoked via the tclInvoke TH1 command. */ tclContext->useObjProc = canUseObjProc(); /* ** Determine (and cache) whether or not we can use TIP #285 (asynchronous ** script cancellation). */ tclContext->useTip285 = canUseTip285(); /* Add the TH1 integration commands to Tcl. */ Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp); Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL); Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL); /* If necessary, evaluate the custom Tcl setup script. */ setup = tclContext->setup; if( setup && Tcl_Eval(tclInterp, setup)!=TCL_OK ){ Th_ErrorMessage(interp, "Tcl setup script error:", Tcl_GetStringResult(tclInterp), -1); Tcl_DeleteInterp(tclInterp); tclContext->interp = tclInterp = 0; return TH_ERROR; } return TH_OK; } |
︙ | ︙ |
Changes to src/timeline.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 | */ #define TIMELINE_MODE_NONE 0 #define TIMELINE_MODE_BEFORE 1 #define TIMELINE_MODE_AFTER 2 #define TIMELINE_MODE_CHILDREN 3 #define TIMELINE_MODE_PARENTS 4 | < < < < < < < | | | | | 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 | */ #define TIMELINE_MODE_NONE 0 #define TIMELINE_MODE_BEFORE 1 #define TIMELINE_MODE_AFTER 2 #define TIMELINE_MODE_CHILDREN 3 #define TIMELINE_MODE_PARENTS 4 /* ** Add an appropriate tag to the output if "rid" is unpublished (private) */ #define UNPUB_TAG "<em>(unpublished)</em>" void tag_private_status(int rid){ if( content_is_private(rid) ){ cgi_printf("%s", UNPUB_TAG); } } /* ** Generate a hyperlink to a version. */ void hyperlink_to_uuid(const char *zUuid){ if( g.perm.Hyperlink ){ @ %z(chref("timelineHistLink","%R/info/%!S",zUuid))[%S(zUuid)]</a> }else{ @ <span class="timelineHistDsp">[%S(zUuid)]</span> } } /* ** Generate a hyperlink to a date & time. */ void hyperlink_to_date(const char *zDate, const char *zSuffix){ |
︙ | ︙ | |||
96 97 98 99 100 101 102 | } } /* ** Allowed flags for the tmFlags argument to www_print_timeline */ #if INTERFACE | | | | | | | | | | | | | | | | | | | | | < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < | < | | < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | } } /* ** Allowed flags for the tmFlags argument to www_print_timeline */ #if INTERFACE #define TIMELINE_ARTID 0x000001 /* Show artifact IDs on non-check-in lines */ #define TIMELINE_LEAFONLY 0x000002 /* Show "Leaf" but not "Merge", "Fork" etc */ #define TIMELINE_BRIEF 0x000004 /* Combine adjacent elements of same obj */ #define TIMELINE_GRAPH 0x000008 /* Compute a graph */ #define TIMELINE_DISJOINT 0x000010 /* Elements are not contiguous */ #define TIMELINE_FCHANGES 0x000020 /* Detail file changes */ #define TIMELINE_BRCOLOR 0x000040 /* Background color by branch name */ #define TIMELINE_UCOLOR 0x000080 /* Background color by user */ #define TIMELINE_FRENAMES 0x000100 /* Detail only file name changes */ #define TIMELINE_UNHIDE 0x000200 /* Unhide check-ins with "hidden" tag */ #define TIMELINE_SHOWRID 0x000400 /* Show RID values in addition to UUIDs */ #define TIMELINE_BISECT 0x000800 /* Show supplimental bisect information */ #define TIMELINE_COMPACT 0x001000 /* Use the "compact" view style */ #define TIMELINE_VERBOSE 0x002000 /* Use the "detailed" view style */ #define TIMELINE_MODERN 0x004000 /* Use the "modern" view style */ #define TIMELINE_COLUMNAR 0x008000 /* Use the "columns" view style */ #define TIMELINE_CLASSIC 0x010000 /* Use the "classic" view style */ #define TIMELINE_VIEWS 0x01f000 /* Mask for all of the view styles */ #define TIMELINE_NOSCROLL 0x100000 /* Don't scroll to the selection */ #define TIMELINE_FILEDIFF 0x200000 /* Show File differences, not ckin diffs */ #endif /* ** Hash a string and use the hash to determine a background color. */ char *hash_color(const char *z){ int i; /* Loop counter */ unsigned int h = 0; /* Hash on the branch name */ int r, g, b; /* Values for red, green, and blue */ int h1, h2, h3, h4; /* Elements of the hash value */ int mx, mn; /* Components of HSV */ static char zColor[10]; /* The resulting color */ static int ix[2] = {0,0}; /* Color chooser parameters */ if( ix[0]==0 ){ if( skin_detail_boolean("white-foreground") ){ ix[0] = 140; ix[1] = 40; }else{ ix[0] = 216; ix[1] = 16; } } for(i=0; z[i]; i++ ){ h = (h<<11) ^ (h<<1) ^ (h>>3) ^ z[i]; } h1 = h % 6; h /= 6; h3 = h % 30; h /= 30; h4 = h % 40; h /= 40; mx = ix[0] - h3; mn = mx - h4 - ix[1]; h2 = (h%(mx - mn)) + mn; switch( h1 ){ case 0: r = mx; g = h2, b = mn; break; case 1: r = h2; g = mx, b = mn; break; case 2: r = mn; g = mx, b = h2; break; case 3: r = mn; g = h2, b = mx; break; case 4: r = h2; g = mn, b = mx; break; default: r = mx; g = mn, b = h2; break; } sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b); return zColor; } /* ** COMMAND: test-hash-color ** ** Usage: %fossil test-hash-color TAG ... ** ** Print out the color names associated with each tag. Used for ** testing the hash_color() function. */ void test_hash_color(void){ int i; for(i=2; i<g.argc; i++){ fossil_print("%20s: %s\n", g.argv[i], hash_color(g.argv[i])); } } /* ** WEBPAGE: hash-color-test ** ** Print out the color names associated with each tag. Used for ** testing the hash_color() function. */ void test_hash_color_page(void){ const char *zBr; char zNm[10]; int i, cnt; login_check_credentials(); style_header("Hash Color Test"); for(i=cnt=0; i<10; i++){ sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i); zBr = P(zNm); if( zBr && zBr[0] ){ @ <p style='border:1px solid;background-color:%s(hash_color(zBr));'> @ %h(zBr) - %s(hash_color(zBr)) - @ Omnes nos quasi oves erravimus unusquisque in viam @ suam declinavit.</p> cnt++; } } if( cnt ){ @ <hr /> } @ <form method="post" action="%s(g.zTop)/hash-color-test"> @ <p>Enter candidate branch names below and see them displayed in their @ default background colors above.</p> for(i=0; i<10; i++){ sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i); zBr = P(zNm); @ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br /> } @ <input type="submit"> @ </form> style_footer(); } /* ** Return a new timelineTable id. */ int timeline_tableid(void){ static int id = 0; return id++; } /* ** Output a timeline in the web format given a query. The query ** should return these columns: ** ** 0. rid ** 1. UUID ** 2. Date/Time ** 3. Comment string ** 4. User ** 5. True if is a leaf ** 6. background color ** 7. type ("ci", "w", "t", "e", "g", "div") ** 8. list of symbolic tags. ** 9. tagid for ticket or wiki or event ** 10. Short comment to user for repeated tickets and wiki */ void www_print_timeline( Stmt *pQuery, /* Query to implement the timeline */ int tmFlags, /* Flags controlling display behavior */ const char *zThisUser, /* Suppress links to this user */ const char *zThisTag, /* Suppress links to this tag */ int selectedRid, /* Highlight the line with this RID value */ void (*xExtra)(int) /* Routine to call on each line of display */ ){ int mxWikiLen; Blob comment; int prevTagid = 0; int suppressCnt = 0; char zPrevDate[20]; GraphContext *pGraph = 0; int prevWasDivider = 0; /* True if previous output row was <hr> */ int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ static Stmt qbranch; int pendingEndTr = 0; /* True if a </td></tr> is needed */ int vid = 0; /* Current checkout version */ int dateFormat = 0; /* 0: HH:MM (default) */ int bCommentGitStyle = 0; /* Only show comments through first blank line */ const char *zStyle; /* Sub-name for classes for the style */ const char *zDateFmt; int iTableId = timeline_tableid(); if( cgi_is_loopback(g.zIpAddr) && db_open_local(0) ){ vid = db_lget_int("checkout", 0); } zPrevDate[0] = 0; mxWikiLen = db_get_int("timeline-max-comment", 0); dateFormat = db_get_int("timeline-date-format", 0); bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0); if( (tmFlags & TIMELINE_VIEWS)==0 ){ tmFlags |= timeline_ss_cookie(); } if( tmFlags & TIMELINE_COLUMNAR ){ zStyle = "Columnar"; }else if( tmFlags & TIMELINE_COMPACT ){ zStyle = "Compact"; |
︙ | ︙ | |||
245 246 247 248 249 250 251 | if( tmFlags & TIMELINE_GRAPH ){ pGraph = graph_init(); } db_static_prepare(&qbranch, "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid", TAG_BRANCH ); | < < < < | | < < | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | if( tmFlags & TIMELINE_GRAPH ){ pGraph = graph_init(); } db_static_prepare(&qbranch, "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid", TAG_BRANCH ); @ <table id="timelineTable%d(iTableId)" class="timelineTable"> blob_zero(&comment); while( db_step(pQuery)==SQLITE_ROW ){ int rid = db_column_int(pQuery, 0); const char *zUuid = db_column_text(pQuery, 1); int isLeaf = db_column_int(pQuery, 5); const char *zBgClr = db_column_text(pQuery, 6); const char *zDate = db_column_text(pQuery, 2); const char *zType = db_column_text(pQuery, 7); const char *zUser = db_column_text(pQuery, 4); const char *zTagList = db_column_text(pQuery, 8); int tagid = db_column_int(pQuery, 9); const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; const char *zBr = 0; /* Branch */ int commentColumn = 3; /* Column containing comment text */ int modPending; /* Pending moderation */ char *zDateLink; /* URL for the link on the timestamp */ int drawDetailEllipsis; /* True to show ellipsis in place of detail */ int gidx = 0; /* Graph row identifier */ int isSelectedOrCurrent = 0; /* True if current row is selected */ char zTime[20]; if( zDate==0 ){ zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */ } modPending = moderation_pending(rid); if( tagid ){ |
︙ | ︙ | |||
301 302 303 304 305 306 307 | } if( pendingEndTr ){ @ </td></tr> pendingEndTr = 0; } if( fossil_strcmp(zType,"div")==0 ){ if( !prevWasDivider ){ | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | } if( pendingEndTr ){ @ </td></tr> pendingEndTr = 0; } if( fossil_strcmp(zType,"div")==0 ){ if( !prevWasDivider ){ @ <tr><td colspan="3"><hr class="timelineMarker" /></td></tr> } prevWasDivider = 1; continue; } prevWasDivider = 0; /* Date format codes: ** (0) HH:MM |
︙ | ︙ | |||
344 345 346 347 348 349 350 | }else{ zTime[0] = 0; } pendingEndTr = 1; if( rid==selectedRid ){ @ <tr class="timelineSelected"> isSelectedOrCurrent = 1; | < < < < < < < < < < < < < < < < < | | | | | < < < < | < < < < | < < < < < < < < < < < < < < < < < < | < | < | < < < < < < < < < < < < < | | < | | | | < < < | < | | | > > | | | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | }else{ zTime[0] = 0; } pendingEndTr = 1; if( rid==selectedRid ){ @ <tr class="timelineSelected"> isSelectedOrCurrent = 1; }else if( rid==vid ){ @ <tr class="timelineCurrent"> isSelectedOrCurrent = 1; }else { @ <tr> } if( zType[0]=='e' && tagid ){ char *zId; zId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d", tagid); zDateLink = href("%R/technote/%s",zId); free(zId); }else if( zUuid ){ zDateLink = chref("timelineHistLink", "%R/info/%!S", zUuid); }else{ zDateLink = mprintf("<a>"); } @ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td> @ <td class="timelineGraph"> if( tmFlags & TIMELINE_UCOLOR ) zBgClr = zUser ? hash_color(zUser) : 0; if( zType[0]=='c' && (pGraph || zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0) ){ db_reset(&qbranch); db_bind_int(&qbranch, ":rid", rid); if( db_step(&qbranch)==SQLITE_ROW ){ zBr = db_column_text(&qbranch, 0); }else{ zBr = "trunk"; } if( zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0 ){ if( zBr==0 || strcmp(zBr,"trunk")==0 ){ zBgClr = 0; }else{ zBgClr = hash_color(zBr); } } } if( zType[0]=='c' && pGraph ){ int nParent = 0; int aParent[GR_MAX_RAIL]; static Stmt qparent; db_static_prepare(&qparent, "SELECT pid FROM plink" " WHERE cid=:rid AND pid NOT IN phantom" " ORDER BY isprim DESC /*sort*/" ); db_bind_int(&qparent, ":rid", rid); while( db_step(&qparent)==SQLITE_ROW && nParent<count(aParent) ){ aParent[nParent++] = db_column_int(&qparent, 0); } db_reset(&qparent); gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr, zUuid, isLeaf); db_reset(&qbranch); @ <div id="m%d(gidx)" class="tl-nodemark"></div> }else if( zType[0]=='e' && pGraph && zBgClr && zBgClr[0] ){ /* For technotes, make a graph node with nParent==(-1). This will ** not actually draw anything on the graph, but it will set the ** background color of the timeline entry */ gidx = graph_add_row(pGraph, rid, -1, 0, zBr, zBgClr, zUuid, 0); @ <div id="m%d(gidx)" class="tl-nodemark"></div> } @</td> if( !isSelectedOrCurrent ){ @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'> }else{ @ <td class="timeline%s(zStyle)Cell"> } if( pGraph && zType[0]!='c' ){ @ • } if( modPending ){ @ <span class="modpending">(Awaiting Moderator Approval)</span> } if( (tmFlags & TIMELINE_BISECT)!=0 && zType[0]=='c' ){ static Stmt bisectQuery; db_static_prepare(&bisectQuery, "SELECT seq, stat FROM bilog WHERE rid=:rid"); db_bind_int(&bisectQuery, ":rid", rid); if( db_step(&bisectQuery)==SQLITE_ROW ){ @ <b>%s(db_column_text(&bisectQuery,1))</b> @ (%d(db_column_int(&bisectQuery,0))) } db_reset(&bisectQuery); } drawDetailEllipsis = (tmFlags & (TIMELINE_COMPACT))!=0; db_column_blob(pQuery, commentColumn, &comment); if( tmFlags & TIMELINE_COMPACT ){ @ <span class='timelineCompactComment' data-id='%d(rid)'> }else{ @ <span class='timeline%s(zStyle)Comment'> } if( (tmFlags & TIMELINE_CLASSIC)!=0 ){ if( zType[0]=='c' ){ hyperlink_to_uuid(zUuid); if( isLeaf ){ if( db_exists("SELECT 1 FROM tagxref" " WHERE rid=%d AND tagid=%d AND tagtype>0", rid, TAG_CLOSED) ){ @ <span class="timelineLeaf">Closed-Leaf:</span> }else{ @ <span class="timelineLeaf">Leaf:</span> } } }else if( zType[0]=='e' && tagid ){ hyperlink_to_event_tagid(tagid<0?-tagid:tagid); }else if( (tmFlags & TIMELINE_ARTID)!=0 ){ hyperlink_to_uuid(zUuid); } if( tmFlags & TIMELINE_SHOWRID ){ int srcId = delta_source_rid(rid); if( srcId ){ @ (%d(rid)←%d(srcId)) }else{ @ (%d(rid)) } } } if( zType[0]!='c' ){ /* Comments for anything other than a check-in are generated by ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */ wiki_convert(&comment, 0, WIKI_INLINE); }else{ if( bCommentGitStyle ){ /* Truncate comment at first blank line */ int ii, jj; int n = blob_size(&comment); char *z = blob_str(&comment); for(ii=0; ii<n; ii++){ if( z[ii]=='\n' ){ for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){} if( z[jj]=='\n' ) break; } } z[ii] = 0; cgi_printf("%W",z); }else if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){ Blob truncated; blob_zero(&truncated); blob_append(&truncated, blob_buffer(&comment), mxWikiLen); blob_append(&truncated, "...", 3); @ %W(blob_str(&truncated)) blob_reset(&truncated); drawDetailEllipsis = 0; |
︙ | ︙ | |||
595 596 597 598 599 600 601 | */ if( drawDetailEllipsis ){ @ <span class='timelineEllipsis' id='ellipsis-%d(rid)' \ @ data-id='%d(rid)'>...</span> } if( tmFlags & TIMELINE_COLUMNAR ){ if( !isSelectedOrCurrent ){ | | | | > > | < < < | < < < | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | */ if( drawDetailEllipsis ){ @ <span class='timelineEllipsis' id='ellipsis-%d(rid)' \ @ data-id='%d(rid)'>...</span> } if( tmFlags & TIMELINE_COLUMNAR ){ if( !isSelectedOrCurrent ){ @ <td class="timelineDetailCell" id='md%d(gidx)'> }else{ @ <td class="timelineDetailCell"> } } if( tmFlags & TIMELINE_COMPACT ){ cgi_printf("<span class='clutter' id='detail-%d'>",rid); } cgi_printf("<span class='timeline%sDetail'>", zStyle); if( (tmFlags & (TIMELINE_CLASSIC|TIMELINE_VERBOSE|TIMELINE_COMPACT))!=0 ){ cgi_printf("("); } if( (tmFlags & TIMELINE_CLASSIC)==0 ){ if( zType[0]=='c' ){ if( isLeaf ){ if( db_exists("SELECT 1 FROM tagxref" " WHERE rid=%d AND tagid=%d AND tagtype>0", rid, TAG_CLOSED) ){ @ <span class='timelineLeaf'>Closed-Leaf</span> }else{ @ <span class='timelineLeaf'>Leaf</span> } } cgi_printf("check-in: %z%S</a> ",href("%R/info/%!S",zUuid),zUuid); }else if( zType[0]=='e' && tagid ){ cgi_printf("technote: "); hyperlink_to_event_tagid(tagid<0?-tagid:tagid); }else{ cgi_printf("artifact: %z%S</a> ",href("%R/info/%!S",zUuid),zUuid); } }else if( zType[0]=='g' || zType[0]=='w' || zType[0]=='t' || zType[0]=='f'){ cgi_printf("artifact: %z%S</a> ",href("%R/info/%!S",zUuid),zUuid); } if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){ char *zLink = mprintf("%R/timeline?u=%h&c=%t&y=a", zDispUser, zDate); cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser); }else{ cgi_printf("user: %h", zDispUser); } /* Generate the "tags: TAGLIST" at the end of the comment, together ** with hyperlinks to the tag list. |
︙ | ︙ | |||
674 675 676 677 678 679 680 | cgi_printf(" tags: %h", zTagList); } } if( tmFlags & TIMELINE_SHOWRID ){ int srcId = delta_source_rid(rid); if( srcId ){ | | < | < | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | cgi_printf(" tags: %h", zTagList); } } if( tmFlags & TIMELINE_SHOWRID ){ int srcId = delta_source_rid(rid); if( srcId ){ cgi_printf(" id: %d←%d", rid, srcId); }else{ cgi_printf(" id: %d", rid); } } tag_private_status(rid); if( xExtra ){ xExtra(rid); } /* End timelineDetail */ |
︙ | ︙ | |||
729 730 731 732 733 734 735 | int fid = db_column_int(&fchngQuery, 1); int isDel = fid==0; const char *zOldName = db_column_text(&fchngQuery, 5); const char *zOld = db_column_text(&fchngQuery, 4); const char *zNew = db_column_text(&fchngQuery, 3); const char *zUnpub = ""; char *zA; | | | < | < | | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | int fid = db_column_int(&fchngQuery, 1); int isDel = fid==0; const char *zOldName = db_column_text(&fchngQuery, 5); const char *zOld = db_column_text(&fchngQuery, 4); const char *zNew = db_column_text(&fchngQuery, 3); const char *zUnpub = ""; char *zA; char zId[40]; if( !inUl ){ @ <ul class="filelist"> inUl = 1; } if( tmFlags & TIMELINE_SHOWRID ){ int srcId = delta_source_rid(fid); if( srcId ){ sqlite3_snprintf(sizeof(zId), zId, " (%d←%d) ", fid, srcId); }else{ sqlite3_snprintf(sizeof(zId), zId, " (%d) ", fid); } }else{ zId[0] = 0; } if( (tmFlags & TIMELINE_FRENAMES)!=0 ){ if( !isNew && !isDel && zOldName!=0 ){ @ <li> %h(zOldName) → %h(zFilename)%s(zId) } continue; } |
︙ | ︙ | |||
778 779 780 781 782 783 784 | @ <li>%h(zOldName) → %s(zA)%h(zFilename)%s(zId)</a> %s(zUnpub) }else{ @ <li>%s(zA)%h(zFilename)</a>%s(zId) %s(zUnpub) } @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a></li> } fossil_free(zA); | < < < < < < < < < < < < < < < < < | | < | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | @ <li>%h(zOldName) → %s(zA)%h(zFilename)%s(zId)</a> %s(zUnpub) }else{ @ <li>%s(zA)%h(zFilename)</a>%s(zId) %s(zUnpub) } @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a></li> } fossil_free(zA); } db_reset(&fchngQuery); if( inUl ){ @ </ul> } } } if( suppressCnt ){ @ <span class="timelineDisabled">... %d(suppressCnt) similar @ event%s(suppressCnt>1?"s":"") omitted.</span> suppressCnt = 0; } if( pendingEndTr ){ @ </td></tr> } if( pGraph ){ graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0); if( pGraph->nErr ){ graph_free(pGraph); pGraph = 0; }else{ @ <tr class="timelineBottom"><td></td><td></td><td></td></tr> } } @ </table> if( fchngQueryInit ) db_finalize(&fchngQuery); timeline_output_graph_javascript(pGraph, tmFlags, iTableId); } |
︙ | ︙ | |||
881 882 883 884 885 886 887 | int showArrowheads; /* True to draw arrowheads. False to omit. */ int circleNodes; /* True for circle nodes. False for square nodes */ int colorGraph; /* Use colors for graph lines */ int iTopRow; /* Index of the top row of the graph */ int fileDiff; /* True for file diff. False for check-in diff */ int omitDescenders; /* True to omit descenders */ int scrollToSelect; /* True to scroll to the selection */ | < < < < < < < < < | < | | | | < | < < < | < < < < < | | < | | | < < < < < | < | < < | < | < < < < < < < | < < | < | > | < < < < < | | | < < < < < < | | < < < < < < < < | | | | < < < < < | < | | < | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 | int showArrowheads; /* True to draw arrowheads. False to omit. */ int circleNodes; /* True for circle nodes. False for square nodes */ int colorGraph; /* Use colors for graph lines */ int iTopRow; /* Index of the top row of the graph */ int fileDiff; /* True for file diff. False for check-in diff */ int omitDescenders; /* True to omit descenders */ int scrollToSelect; /* True to scroll to the selection */ iRailPitch = atoi(PD("railpitch","0")); showArrowheads = skin_detail_boolean("timeline-arrowheads"); circleNodes = skin_detail_boolean("timeline-circle-nodes"); colorGraph = skin_detail_boolean("timeline-color-graph-lines"); iTopRow = pGraph->pFirst ? pGraph->pFirst->idx : 0; omitDescenders = (tmFlags & TIMELINE_DISJOINT)!=0; fileDiff = (tmFlags & TIMELINE_FILEDIFF)!=0; scrollToSelect = (tmFlags & TIMELINE_NOSCROLL)==0; @ <script id='timeline-data-%d(iTableId)' type='application/json'>{ @ "iTableId": %d(iTableId), @ "circleNodes": %d(circleNodes), @ "showArrowheads": %d(showArrowheads), @ "iRailPitch": %d(iRailPitch), @ "colorGraph": %d(colorGraph), @ "nomo": %d(PB("nomo")), @ "iTopRow": %d(iTopRow), @ "omitDescenders": %d(omitDescenders), @ "fileDiff": %d(fileDiff), @ "scrollToSelect": %d(scrollToSelect), @ "nrail": %d(pGraph->mxRail+1), @ "baseUrl": "%R", if( pGraph->nRow==0 ){ @ "rowinfo": null }else{ @ "rowinfo": [ } /* the rowinfo[] array contains all the information needed to generate ** the graph. Each entry contains information for a single row: ** ** id: The id of the <div> element for the row. This is an integer. ** to get an actual id, prepend "m" to the integer. The top node ** is iTopRow and numbers increase moving down the timeline. ** bg: The background color for this row ** r: The "rail" that the node for this row sits on. The left-most ** rail is 0 and the number increases to the right. ** d: True if there is a "descender" - an arrow coming from the bottom ** of the page straight up to this node. ** mo: "merge-out". If non-negative, this is the rail position ** for the upward portion of a merge arrow. The merge arrow goes up ** to the row identified by mu:. If this value is negative then ** node has no merge children and no merge-out line is drawn. ** mu: The id of the row which is the top of the merge-out arrow. ** u: Draw a thick child-line out of the top of this node and up to ** the node with an id equal to this value. 0 if it is straight to ** the top of the page, -1 if there is no thick-line riser. ** f: 0x01: a leaf node. ** au: An array of integers that define thick-line risers for branches. ** The integers are in pairs. For each pair, the first integer is ** is the rail on which the riser should run and the second integer ** is the id of the node upto which the riser should run. ** mi: "merge-in". An array of integer rail positions from which ** merge arrows should be drawn into this node. If the value is ** negative, then the rail position is the absolute value of mi[] ** and a thin merge-arrow descender is drawn to the bottom of ** the screen. ** h: The artifact hash of the object being graphed */ for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){ cgi_printf("{\"id\":%d,", pRow->idx); cgi_printf("\"bg\":\"%s\",", pRow->zBgClr); cgi_printf("\"r\":%d,", pRow->iRail); cgi_printf("\"d\":%d,", pRow->bDescender); cgi_printf("\"mo\":%d,", pRow->mergeOut); cgi_printf("\"mu\":%d,", pRow->mergeUpto); cgi_printf("\"u\":%d,", pRow->aiRiser[pRow->iRail]); cgi_printf("\"f\":%d,", pRow->isLeaf ? 1 : 0); cgi_printf("\"au\":"); cSep = '['; for(i=0; i<GR_MAX_RAIL; i++){ if( i==pRow->iRail ) continue; if( pRow->aiRiser[i]>0 ){ cgi_printf("%c%d,%d", cSep, i, pRow->aiRiser[i]); cSep = ','; } } if( cSep=='[' ) cgi_printf("["); cgi_printf("],"); if( colorGraph && pRow->zBgClr[0]=='#' ){ cgi_printf("\"fg\":\"%s\",", bg_to_fg(pRow->zBgClr)); } /* mi */ cgi_printf("\"mi\":"); cSep = '['; for(i=0; i<GR_MAX_RAIL; i++){ if( pRow->mergeIn[i] ){ int mi = i; if( (pRow->mergeDown >> i) & 1 ) mi = -mi; cgi_printf("%c%d", cSep, mi); cSep = ','; } } if( cSep=='[' ) cgi_printf("["); cgi_printf("],\"h\":\"%!S\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "]\n"); } @ }</script> style_graph_generator(); graph_free(pGraph); } } /* ** Create a temporary table suitable for storing timeline data. */ |
︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 | return zBase; } /* ** Convert a symbolic name used as an argument to the a=, b=, or c= ** query parameters of timeline into a julianday mtime value. */ | | < < < < < < < < < < | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | return zBase; } /* ** Convert a symbolic name used as an argument to the a=, b=, or c= ** query parameters of timeline into a julianday mtime value. */ double symbolic_name_to_mtime(const char *z){ double mtime; int rid; if( z==0 ) return -1.0; if( fossil_isdate(z) ){ mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z); if( mtime>0.0 ) return mtime; } rid = symbolic_name_to_rid(z, "*"); if( rid ){ mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); }else{ mtime = db_double(-1.0, "SELECT max(event.mtime) FROM event, tag, tagxref" " WHERE tag.tagname GLOB 'event-%q*'" |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 | /* ** Add the select/option box to the timeline submenu that is used to ** set the y= parameter that determines which elements to display ** on the timeline. */ static void timeline_y_submenu(int isDisabled){ static int i = 0; | | < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < > > > > > > > | | < | | | < < | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | /* ** Add the select/option box to the timeline submenu that is used to ** set the y= parameter that determines which elements to display ** on the timeline. */ static void timeline_y_submenu(int isDisabled){ static int i = 0; static const char *az[14]; if( i==0 ){ az[0] = "all"; az[1] = "Any Type"; i = 2; if( g.perm.Read ){ az[i++] = "ci"; az[i++] = "Check-ins"; az[i++] = "g"; az[i++] = "Tags"; } if( g.perm.RdWiki ){ az[i++] = "e"; az[i++] = "Tech Notes"; } if( g.perm.RdTkt ){ az[i++] = "t"; az[i++] = "Tickets"; } if( g.perm.RdWiki ){ az[i++] = "w"; az[i++] = "Wiki"; } if( g.perm.RdForum ){ az[i++] = "f"; az[i++] = "Forum"; } assert( i<=count(az) ); } if( i>2 ){ style_submenu_multichoice("y", i/2, az, isDisabled); } } /* ** Convert the current "ss" display preferences cookie into an ** appropriate TIMELINE_* flag */ int timeline_ss_cookie(void){ int tmFlags; switch( cookie_value("ss","m")[0] ){ case 'c': tmFlags = TIMELINE_COMPACT; break; case 'v': tmFlags = TIMELINE_VERBOSE; break; case 'j': tmFlags = TIMELINE_COLUMNAR; break; case 'x': tmFlags = TIMELINE_CLASSIC; break; default: tmFlags = TIMELINE_MODERN; break; } return tmFlags; } /* ** Add the select/option box to the timeline submenu that is used to ** set the ss= parameter that determines the viewing mode. ** ** Return the TIMELINE_* value appropriate for the view-style. */ int timeline_ss_submenu(void){ static const char *azViewStyles[] = { "m", "Modern View", "j", "Columnar View", "c", "Compact View", "v", "Verbose View", "x", "Classic View", }; cookie_link_parameter("ss","ss","m"); style_submenu_multichoice("ss", sizeof(azViewStyles)/(2*sizeof(azViewStyles[0])), azViewStyles, 0); return timeline_ss_cookie(); } /* ** If the zChng string is not NULL, then it should be a comma-separated ** list of glob patterns for filenames. Add an term to the WHERE clause ** for the SQL statement under construction that excludes any check-in that ** does not modify one or more files matching the globs. */ static void addFileGlobExclusion( const char *zChng, /* The filename GLOB list */ Blob *pSql /* The SELECT statement under construction */ ){ if( zChng==0 || zChng[0]==0 ) return; blob_append_sql(pSql," AND event.objid IN (" "SELECT mlink.mid FROM mlink, filename" " WHERE mlink.fnid=filename.fnid AND %s)", glob_expr("filename.name", zChng)); } static void addFileGlobDescription( const char *zChng, /* The filename GLOB list */ Blob *pDescription /* Result description */ ){ if( zChng==0 || zChng[0]==0 ) return; blob_appendf(pDescription, " that include changes to files matching '%h'", zChng); } /* ** Tag match expression type code. */ typedef enum { MS_EXACT, /* Matches a single tag by exact string comparison. */ MS_GLOB, /* Matches tags against a list of GLOB patterns. */ MS_LIKE, /* Matches tags against a list of LIKE patterns. */ MS_REGEXP /* Matches tags against a list of regular expressions. */ } MatchStyle; /* ** Quote a tag string by surrounding it with double quotes and preceding ** internal double quotes and backslashes with backslashes. */ static const char *tagQuote( |
︙ | ︙ | |||
1345 1346 1347 1348 1349 1350 1351 | return blob_str(&blob); } /* ** Construct the tag match SQL expression. ** ** This function is adapted from glob_expr() to support the MS_EXACT, MS_GLOB, | < < | | 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | return blob_str(&blob); } /* ** Construct the tag match SQL expression. ** ** This function is adapted from glob_expr() to support the MS_EXACT, MS_GLOB, ** MS_LIKE, and MS_REGEXP match styles. For MS_EXACT, the returned expression ** checks for integer match against the tag ID which is looked up directly by ** this function. For the other modes, the returned SQL expression performs ** string comparisons against the tag names, so it is necessary to join against ** the tag table to access the "tagname" column. ** ** Each pattern is adjusted to to start with "sym-" and be anchored at end. ** |
︙ | ︙ | |||
1409 1410 1411 1412 1413 1414 1415 | }else if( matchStyle==MS_LIKE ){ zStart = "("; zDelimiter = " OR "; zEnd = ")"; zPrefix = "tagname LIKE 'sym-"; zSuffix = "'"; zIntro = "SQL LIKE pattern "; | | < < < < < < < | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | }else if( matchStyle==MS_LIKE ){ zStart = "("; zDelimiter = " OR "; zEnd = ")"; zPrefix = "tagname LIKE 'sym-"; zSuffix = "'"; zIntro = "SQL LIKE pattern "; }else/* if( matchStyle==MS_REGEXP )*/{ zStart = "(tagname REGEXP '^sym-("; zDelimiter = "|"; zEnd = ")$')"; zPrefix = ""; zSuffix = ""; zIntro = "regular expression "; } /* Convert the list of matches into an SQL expression and text description. */ blob_zero(&expr); blob_zero(&desc); blob_zero(&err); while( 1 ){ |
︙ | ︙ | |||
1527 1528 1529 1530 1531 1532 1533 | blob_append(&expr, zEnd, -1); return blob_str(&expr); } /* If execution reaches this point, the pattern was empty. Return NULL. */ return 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < | < < < < < < < < < | < < < < < < | < < < < < < < < < < < | | < < < < < | < | < < < < < | | | < < < | < < < | < < < < < < | | | < | < < < | < < < | < < < < < < < < < < < < < < < < < < | | < | < < < < < < < < < | | > < < < < < < < < < < | < < | < < < < < < < < < | < < < < < < | | < < < | < < < < < | < < < < < < < < < < < | < < < < < | < | < < < < < < | | < < < < < | 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 | blob_append(&expr, zEnd, -1); return blob_str(&expr); } /* If execution reaches this point, the pattern was empty. Return NULL. */ return 0; } /* ** WEBPAGE: timeline ** ** Query parameters: ** ** a=TIMEORTAG After this event ** b=TIMEORTAG Before this event ** c=TIMEORTAG "Circa" this event ** m=TIMEORTAG Mark this event ** n=COUNT Maximum number of events. "all" for no limit ** p=CHECKIN Parents and ancestors of CHECKIN ** d=CHECKIN Children and descendants of CHECKIN ** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN ** t=TAG Show only check-ins with the given TAG ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel ** rel Show related check-ins as well as those matching t=TAG ** mionly Limit rel to show ancestors but not descendants ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP ** u=USER Only show items associated with USER ** y=TYPE 'ci', 'w', 't', 'e', 'f', or 'all'. ** ss=VIEWSTYLE c: "Compact" v: "Verbose" m: "Modern" j: "Columnar" ** advm Use the "Advanced" or "Busy" menu design. ** ng No Graph. ** nd Do not highlight the focus check-in ** v Show details of files changed ** f=CHECKIN Show family (immediate parents and children) of CHECKIN ** from=CHECKIN Path from... ** to=CHECKIN ... to this ** shortest ... show only the shortest path ** uf=FILE_HASH Show only check-ins that contain the given file version ** chng=GLOBLIST Show only check-ins that involve changes to a file whose ** name matches one of the comma-separate GLOBLIST ** brbg Background color from branch name ** ubg Background color from user ** namechng Show only check-ins that have filename changes ** forks Show only forks and their children ** ym=YYYY-MM Show only events for the given year/month ** yw=YYYY-WW Show only events for the given week of the given year ** yw=YYYY-MM-DD Show events for the week that includes the given day ** ymd=YYYY-MM-DD Show only events on the given day ** days=N Show events over the previous N days ** datefmt=N Override the date format ** bisect Show the check-ins that are in the current bisect ** showid Show RIDs ** showsql Show the SQL text ** ** p= and d= can appear individually or together. If either p= or d= ** appear, then u=, y=, a=, and b= are ignored. ** ** If both a= and b= appear then both upper and lower bounds are honored. ** ** CHECKIN or TIMEORTAG can be a check-in hash prefix, or a tag, or the ** name of a branch. */ void page_timeline(void){ Stmt q; /* Query used to generate the timeline */ Blob sql; /* text of SQL used to generate timeline */ Blob desc; /* Description of the timeline */ int nEntry; /* Max number of entries on timeline */ int p_rid = name_to_typed_rid(P("p"),"ci"); /* artifact p and its parents */ int d_rid = name_to_typed_rid(P("d"),"ci"); /* artifact d and descendants */ int f_rid = name_to_typed_rid(P("f"),"ci"); /* artifact f and close family */ const char *zUser = P("u"); /* All entries by this user if not NULL */ const char *zType; /* Type of events to display */ const char *zAfter = P("a"); /* Events after this time */ const char *zBefore = P("b"); /* Events before this time */ const char *zCirca = P("c"); /* Events near this time */ const char *zMark = P("m"); /* Mark this event or an event this time */ const char *zTagName = P("t"); /* Show events with this tag */ const char *zBrName = P("r"); /* Equivalent to t=TAG&rel */ int related = PB("rel"); /* Show events related to zTagName */ const char *zMatchStyle = P("ms"); /* Tag/branch match style string */ MatchStyle matchStyle = MS_EXACT; /* Match style code */ const char *zMatchDesc = 0; /* Tag match expression description text */ const char *zError = 0; /* Tag match error string */ const char *zTagSql = 0; /* Tag/branch match SQL expression */ const char *zSearch = P("s"); /* Search string */ const char *zUses = P("uf"); /* Only show check-ins hold this file */ const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */ const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */ char *zYearWeekStart = 0; /* YYYY-MM-DD for start of YYYY-WW */ const char *zDay = P("ymd"); /* Check-ins for the day YYYY-MM-DD */ const char *zNDays = P("days"); /* Show events over the previous N days */ int nDays = 0; /* Numeric value for zNDays */ const char *zChng = P("chng"); /* List of GLOBs for files that changed */ int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */ int forkOnly = PB("forks"); /* Show only forks and their children */ int bisectOnly = PB("bisect"); /* Show the check-ins of the bisect */ int tmFlags = 0; /* Timeline flags */ const char *zThisTag = 0; /* Suppress links to this tag */ const char *zThisUser = 0; /* Suppress links to this user */ HQuery url; /* URL for various branch links */ int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */ int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ int noMerge = P("shortest")==0; /* Follow merge links if shorter */ int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ int pd_rid; double rBefore, rAfter, rCirca; /* Boundary times */ const char *z; char *zOlderButton = 0; /* URL for Older button at the bottom */ char *zNewerButton = 0; /* URL for Newer button at the top */ int selectedRid = -9999999; /* Show a highlight on this RID */ int disableY = 0; /* Disable type selector on submenu */ int advancedMenu = 0; /* Use the advanced menu design */ char *zPlural; /* Ending for plural forms */ /* Set number of rows to display */ cookie_read_parameter("n","n"); z = P("n"); if( z==0 ) z = db_get("timeline-default-length",0); if( z ){ if( fossil_strcmp(z,"all")==0 ){ nEntry = 0; }else{ nEntry = atoi(z); if( nEntry<=0 ){ z = "10"; nEntry = 10; } } }else{ z = "50"; nEntry = 50; } cgi_replace_query_parameter("n",z); cookie_write_parameter("n","n",0); tmFlags |= timeline_ss_submenu(); cookie_link_parameter("advm","advm","0"); advancedMenu = atoi(PD("advm","0")); /* To view the timeline, must have permission to read project data. */ pd_rid = name_to_typed_rid(P("dp"),"ci"); if( pd_rid ){ p_rid = d_rid = pd_rid; } login_check_credentials(); if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum) || (bisectOnly && !g.perm.Setup) ){ login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); return; } cookie_read_parameter("y","y"); zType = P("y"); if( zType==0 ){ zType = g.perm.Read ? "ci" : "all"; cgi_set_parameter("y", zType); } if( zType[0]=='a' || zType[0]=='c' ){ cookie_write_parameter("y","y",zType); } cookie_render(); url_initialize(&url, "timeline"); cgi_query_parameters_to_url(&url); /* Convert r=TAG to t=TAG&rel. */ if( zBrName && !related ){ cgi_delete_query_parameter("r"); cgi_set_query_parameter("t", zBrName); cgi_set_query_parameter("rel", "1"); zTagName = zBrName; related = 1; } /* Ignore empty tag query strings. */ if( zTagName && !*zTagName ){ zTagName = 0; } /* Finish preliminary processing of tag match queries. */ if( zTagName ){ /* Interpet the tag style string. */ if( fossil_stricmp(zMatchStyle, "glob")==0 ){ matchStyle = MS_GLOB; }else if( fossil_stricmp(zMatchStyle, "like")==0 ){ matchStyle = MS_LIKE; }else if( fossil_stricmp(zMatchStyle, "regexp")==0 ){ matchStyle = MS_REGEXP; }else{ /* For exact maching, inhibit links to the selected tag. */ zThisTag = zTagName; } /* Display a checkbox to enable/disable display of related check-ins. */ if( advancedMenu ){ style_submenu_checkbox("rel", "Related", 0, 0); } |
︙ | ︙ | |||
2046 2047 2048 2049 2050 2051 2052 | if( (zTagSql && db_int(0,"SELECT count(*) " "FROM tagxref NATURAL JOIN tag WHERE %s",zTagSql/*safe-for-%s*/)<=nEntry) ){ nEntry = -1; zCirca = 0; } if( zType[0]=='a' ){ | | | < < < < | | < < < < < < < < < < < < < < | 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 | if( (zTagSql && db_int(0,"SELECT count(*) " "FROM tagxref NATURAL JOIN tag WHERE %s",zTagSql/*safe-for-%s*/)<=nEntry) ){ nEntry = -1; zCirca = 0; } if( zType[0]=='a' ){ tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; }else{ tmFlags |= TIMELINE_GRAPH; } if( PB("ng") || zSearch!=0 ){ tmFlags &= ~TIMELINE_GRAPH; } if( PB("brbg") ){ tmFlags |= TIMELINE_BRCOLOR; } if( PB("unhide") ){ tmFlags |= TIMELINE_UNHIDE; } if( PB("ubg") ){ tmFlags |= TIMELINE_UCOLOR; } if( zUses!=0 ){ int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses); if( ufid ){ zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid); db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)"); compute_uses_file("usesfile", ufid, 0); zType = "ci"; disableY = 1; }else{ zUses = 0; } } if( renameOnly ){ db_multi_exec( "CREATE TEMP TABLE rnfile(rid INTEGER PRIMARY KEY);" |
︙ | ︙ | |||
2113 2114 2115 2116 2117 2118 2119 | " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n" " GROUP BY pid" " HAVING count(*)>1;\n" "INSERT OR IGNORE INTO rnfork(rid)" " SELECT cid FROM plink\n" " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=cid)==" " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n" | < < < < < < < | < < < < < < < > > | > < | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < < < < | < | | | | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < | < < | < < < < | < | < < < | < < < < < < < < < < | < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < < < < < < < < < < | | | | < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < | 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 | " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n" " GROUP BY pid" " HAVING count(*)>1;\n" "INSERT OR IGNORE INTO rnfork(rid)" " SELECT cid FROM plink\n" " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=cid)==" " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n" " AND pid IN rnfork;", TAG_BRANCH, TAG_BRANCH, TAG_BRANCH, TAG_BRANCH ); tmFlags |= TIMELINE_UNHIDE; zType = "ci"; disableY = 1; } if( bisectOnly && fossil_strcmp(g.zIpAddr,"127.0.0.1")==0 && db_open_local(0) ){ int iCurrent = db_lget_int("checkout",0); bisect_create_bilog_table(iCurrent); tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT; zType = "ci"; disableY = 1; }else{ bisectOnly = 0; } style_header("Timeline"); if( advancedMenu ){ style_submenu_element("Help", "%R/help?cmd=/timeline"); } login_anonymous_available(); timeline_temp_table(); blob_zero(&sql); blob_zero(&desc); blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1); blob_append(&sql, timeline_query_for_www(), -1); if( PB("fc") || PB("v") || PB("detail") ){ tmFlags |= TIMELINE_FCHANGES; } if( (tmFlags & TIMELINE_UNHIDE)==0 ){ blob_append_sql(&sql, " AND NOT EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n", TAG_HIDDEN ); } if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){ /* If from= and to= are present, display all nodes on a path connecting ** the two */ PathNode *p = 0; const char *zFrom = 0; const char *zTo = 0; if( from_rid && to_rid ){ p = path_shortest(from_rid, to_rid, noMerge, 0); zFrom = P("from"); zTo = P("to"); }else{ if( path_common_ancestor(me_rid, you_rid) ){ p = path_first(); } zFrom = P("me"); zTo = P("you"); } blob_append(&sql, " AND event.objid IN (0", -1); while( p ){ blob_append_sql(&sql, ",%d", p->rid); p = p->u.pTo; } blob_append(&sql, ")", -1); path_reset(); addFileGlobExclusion(zChng, &sql); tmFlags |= TIMELINE_DISJOINT; db_multi_exec("%s", blob_sql_text(&sql)); if( advancedMenu ){ style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); } blob_appendf(&desc, "%d check-ins going from ", db_int(0, "SELECT count(*) FROM timeline")); blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom); blob_append(&desc, " to ", -1); blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo); addFileGlobDescription(zChng, &desc); }else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){ /* If p= or d= is present, ignore all other parameters other than n= */ char *zUuid; int np, nd; tmFlags |= TIMELINE_DISJOINT; if( p_rid && d_rid ){ if( p_rid!=d_rid ) p_rid = d_rid; if( P("n")==0 ) nEntry = 10; } db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" ); zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", p_rid ? p_rid : d_rid); blob_append_sql(&sql, " AND event.objid IN ok"); nd = 0; if( d_rid ){ compute_descendants(d_rid, nEntry+1); nd = db_int(0, "SELECT count(*)-1 FROM ok"); if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); if( useDividers ) selectedRid = d_rid; db_multi_exec("DELETE FROM ok"); } if( p_rid ){ compute_ancestors(p_rid, nEntry+1, 0); np = db_int(0, "SELECT count(*)-1 FROM ok"); if( np>0 ){ if( nd>0 ) blob_appendf(&desc, " and "); blob_appendf(&desc, "%d ancestors", np); db_multi_exec("%s", blob_sql_text(&sql)); } if( useDividers ) selectedRid = p_rid; } blob_appendf(&desc, " of %z[%S]</a>", href("%R/info/%!S", zUuid), zUuid); if( d_rid ){ if( p_rid ){ /* If both p= and d= are set, we don't have the uuid of d yet. */ zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid); } } if( advancedMenu ){ |
︙ | ︙ | |||
2447 2448 2449 2450 2451 2452 2453 | db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "INSERT INTO ok VALUES(%d);" "INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;" "INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;", f_rid, f_rid, f_rid ); | < < < < < < < < < | | < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | < < < < < < < | < < < < < < < < < < < < < < < < < | < < < < < < < | | | | | | | < < | < < < < < | > | | < | | < < > | > < | | < | | | | | | | > > < | 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 | db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" "INSERT INTO ok VALUES(%d);" "INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;" "INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;", f_rid, f_rid, f_rid ); blob_append_sql(&sql, " AND event.objid IN ok"); db_multi_exec("%s", blob_sql_text(&sql)); if( useDividers ) selectedRid = f_rid; blob_appendf(&desc, "Parents and children of check-in "); zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); blob_appendf(&desc, "%z[%S]</a>", href("%R/info/%!S", zUuid), zUuid); tmFlags |= TIMELINE_DISJOINT; if( advancedMenu ){ style_submenu_checkbox("unhide", "Unhide", 0, 0); style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); } }else{ /* Otherwise, a timeline based on a span of time */ int n; const char *zEType = "event"; char *zDate; Blob cond; blob_zero(&cond); if( zChng && *zChng ){ addFileGlobExclusion(zChng, &cond); tmFlags |= TIMELINE_DISJOINT; } if( zUses ){ blob_append_sql(&cond, " AND event.objid IN usesfile "); } if( renameOnly ){ blob_append_sql(&cond, " AND event.objid IN rnfile "); } if( forkOnly ){ blob_append_sql(&cond, " AND event.objid IN rnfork "); } if( bisectOnly ){ blob_append_sql(&cond, " AND event.objid IN (SELECT rid FROM bilog) "); } if( zYearMonth ){ blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%m',event.mtime) ", zYearMonth); } else if( zYearWeek ){ char *z = db_text(0, "SELECT strftime('%%Y-%%W',%Q)", zYearWeek); if( z && z[0] ){ zYearWeekStart = db_text(0, "SELECT date(%Q,'-6 days','weekday 1')", zYearWeek); zYearWeek = z; }else{ if( strlen(zYearWeek)==7 ){ zYearWeekStart = db_text(0, "SELECT date('%.4q-01-01','+%d days','weekday 1')", zYearWeek, atoi(zYearWeek+5)*7); }else{ zYearWeekStart = 0; } if( zYearWeekStart==0 || zYearWeekStart[0]==0 ){ zYearWeekStart = db_text(0, "SELECT date('now','-6 days','weekday 1');"); zYearWeek = db_text(0, "SELECT strftime('%%Y-%%W','now','-6 days','weekday 1')"); } } blob_append_sql(&cond, " AND %Q=strftime('%%Y-%%W',event.mtime) ", zYearWeek); nEntry = -1; } else if( zDay ){ zDay = db_text(0, "SELECT date(%Q)", zDay); if( zDay==0 || zDay[0]==0 ){ zDay = db_text(0, "SELECT date('now')"); } blob_append_sql(&cond, " AND %Q=date(event.mtime) ", zDay); nEntry = -1; } else if( zNDays ){ nDays = atoi(zNDays); if( nDays<1 ) nDays = 1; blob_append_sql(&cond, " AND event.mtime>=julianday('now','-%d days') ", nDays); nEntry = -1; } if( zTagSql ){ blob_append_sql(&cond, " AND (EXISTS(SELECT 1 FROM tagxref NATURAL JOIN tag" " WHERE %s AND tagtype>0 AND rid=blob.rid)\n", zTagSql/*safe-for-%s*/); if( related ){ /* The next two blob_appendf() calls add SQL that causes check-ins that ** are not part of the branch which are parents or children of the ** branch to be included in the report. This related check-ins are ** useful in helping to visualize what has happened on a quiescent ** branch that is infrequently merged with a much more activate branch. */ blob_append_sql(&cond, " OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=cid" " NATURAL JOIN tag WHERE %s AND tagtype>0 AND pid=blob.rid)\n", zTagSql/*safe-for-%s*/ ); if( (tmFlags & TIMELINE_UNHIDE)==0 ){ blob_append_sql(&cond, " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid" " WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)\n", TAG_HIDDEN ); } if( P("mionly")==0 ){ blob_append_sql(&cond, " OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid" " NATURAL JOIN tag WHERE %s AND tagtype>0 AND cid=blob.rid)\n", zTagSql/*safe-for-%s*/ ); if( (tmFlags & TIMELINE_UNHIDE)==0 ){ blob_append_sql(&cond, " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid" " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)\n", TAG_HIDDEN ); } } } blob_append_sql(&cond, ")"); } if( (zType[0]=='w' && !g.perm.RdWiki) || (zType[0]=='t' && !g.perm.RdTkt) || (zType[0]=='e' && !g.perm.RdWiki) || (zType[0]=='c' && !g.perm.Read) || (zType[0]=='g' && !g.perm.Read) || (zType[0]=='f' && !g.perm.RdForum) ){ zType = "all"; } |
︙ | ︙ | |||
2771 2772 2773 2774 2775 2776 2777 | if( g.perm.RdForum ){ blob_append_sql(&cond, "%c'f'", cSep); cSep = ','; } blob_append_sql(&cond, ")"); } }else{ /* zType!="all" */ | < < < < | < < < > < < < | < < < < < < < | | | < | | | | 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 | if( g.perm.RdForum ){ blob_append_sql(&cond, "%c'f'", cSep); cSep = ','; } blob_append_sql(&cond, ")"); } }else{ /* zType!="all" */ blob_append_sql(&cond, " AND event.type=%Q", zType); if( zType[0]=='c' ){ zEType = "check-in"; }else if( zType[0]=='w' ){ zEType = "wiki"; }else if( zType[0]=='t' ){ zEType = "ticket change"; }else if( zType[0]=='e' ){ zEType = "technical note"; }else if( zType[0]=='g' ){ zEType = "tag"; }else if( zType[0]=='f' ){ zEType = "forum post"; } } if( zUser ){ int n = db_int(0,"SELECT count(*) FROM event" " WHERE user=%Q OR euser=%Q", zUser, zUser); if( n<=nEntry ){ zCirca = zBefore = zAfter = 0; nEntry = -1; } blob_append_sql(&cond, " AND (event.user=%Q OR event.euser=%Q)", zUser, zUser); zThisUser = zUser; } if( zSearch ){ blob_append_sql(&cond, " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", zSearch, zSearch); } rBefore = symbolic_name_to_mtime(zBefore); rAfter = symbolic_name_to_mtime(zAfter); rCirca = symbolic_name_to_mtime(zCirca); blob_append_sql(&sql, "%s", blob_sql_text(&cond)); if( rAfter>0.0 ){ if( rBefore>0.0 ){ blob_append_sql(&sql, " AND event.mtime>=%.17g AND event.mtime<=%.17g" " ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND); nEntry = -1; |
︙ | ︙ | |||
2846 2847 2848 2849 2850 2851 2852 | rBefore+ONE_SECOND); zCirca = 0; url_add_parameter(&url, "c", 0); }else if( rCirca>0.0 ){ Blob sql2; blob_init(&sql2, blob_sql_text(&sql), -1); blob_append_sql(&sql2, | | > < < < < | | < | | | | | < < < < | | < < < | | | | | | < | < | < | 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 | rBefore+ONE_SECOND); zCirca = 0; url_add_parameter(&url, "c", 0); }else if( rCirca>0.0 ){ Blob sql2; blob_init(&sql2, blob_sql_text(&sql), -1); blob_append_sql(&sql2, " AND event.mtime<=%f ORDER BY event.mtime DESC", rCirca); if( nEntry>0 ){ blob_append_sql(&sql2," LIMIT %d", (nEntry+1)/2); nEntry -= (nEntry+1)/2; } if( PB("showsql") ){ @ <pre>%h(blob_sql_text(&sql2))</pre> } db_multi_exec("%s", blob_sql_text(&sql2)); blob_reset(&sql2); blob_append_sql(&sql, " AND event.mtime>=%f ORDER BY event.mtime ASC", rCirca ); if( zMark==0 ) zMark = zCirca; }else{ blob_append_sql(&sql, " ORDER BY event.mtime DESC"); } if( nEntry>0 ) blob_append_sql(&sql, " LIMIT %d", nEntry); db_multi_exec("%s", blob_sql_text(&sql)); n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/"); zPlural = n==1 ? "" : "s"; if( zYearMonth ){ blob_appendf(&desc, "%d %s%s for %h", n, zEType, zPlural, zYearMonth); }else if( zYearWeek ){ blob_appendf(&desc, "%d %s%s for week %h beginning on %h", n, zEType, zPlural, zYearWeek, zYearWeekStart); }else if( zDay ){ blob_appendf(&desc, "%d %s%s occurring on %h", n, zEType, zPlural, zDay); }else if( zNDays ){ blob_appendf(&desc, "%d %s%s within the past %d day%s", n, zEType, zPlural, nDays, nDays>1 ? "s" : ""); }else if( zBefore==0 && zCirca==0 && n>=nEntry && nEntry>0 ){ blob_appendf(&desc, "%d most recent %s%s", n, zEType, zPlural); }else{ blob_appendf(&desc, "%d %s%s", n, zEType, zPlural); } if( zUses ){ char *zFilenames = names_of_file(zUses); blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames, href("%R/artifact/%!S",zUses), zUses); tmFlags |= TIMELINE_DISJOINT; } if( renameOnly ){ blob_appendf(&desc, " that contain filename changes"); tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES; } if( forkOnly ){ blob_appendf(&desc, " associated with forks"); tmFlags |= TIMELINE_DISJOINT; } if( bisectOnly ){ blob_appendf(&desc, " in the most recent bisect"); tmFlags |= TIMELINE_DISJOINT; } if( zUser ){ blob_appendf(&desc, " by user %h", zUser); tmFlags |= TIMELINE_DISJOINT; } if( zTagSql ){ if( matchStyle==MS_EXACT ){ if( related ){ blob_appendf(&desc, " related to %h", zMatchDesc); }else{ blob_appendf(&desc, " tagged with %h", zMatchDesc); } }else{ if( related ){ blob_appendf(&desc, " related to tags matching %h", zMatchDesc); }else{ blob_appendf(&desc, " with tags matching %h", zMatchDesc); } } tmFlags |= TIMELINE_DISJOINT; } addFileGlobDescription(zChng, &desc); if( rAfter>0.0 ){ if( rBefore>0.0 ){ blob_appendf(&desc, " occurring between %h and %h.<br />", zAfter, zBefore); }else{ blob_appendf(&desc, " occurring on or after %h.<br />", zAfter); } }else if( rBefore>0.0 ){ blob_appendf(&desc, " occurring on or before %h.<br />", zBefore); }else if( rCirca>0.0 ){ blob_appendf(&desc, " occurring around %h.<br />", zCirca); } if( zSearch ){ blob_appendf(&desc, " matching \"%h\"", zSearch); } if( g.perm.Hyperlink ){ static const char *const azMatchStyles[] = { "exact", "Exact", "glob", "Glob", "like", "Like", "regexp", "Regexp" }; double rDate; zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){ zDate = mprintf("%s", (zAfter ? zAfter : zBefore)); } if( zDate ){ rDate = symbolic_name_to_mtime(zDate); if( db_int(0, "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" " WHERE blob.rid=event.objid AND mtime<=%.17g%s)", rDate-ONE_SECOND, blob_sql_text(&cond)) ){ zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); } free(zDate); } zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){ zDate = mprintf("%s", (zBefore ? zBefore : zAfter)); } if( zDate ){ rDate = symbolic_name_to_mtime(zDate); if( db_int(0, "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob" " WHERE blob.rid=event.objid AND mtime>=%.17g%s)", rDate+ONE_SECOND, blob_sql_text(&cond)) ){ zNewerButton = fossil_strdup(url_render(&url, "a", zDate, "b", 0)); } free(zDate); } if( advancedMenu ){ if( zType[0]=='a' || zType[0]=='c' ){ style_submenu_checkbox("unhide", "Unhide", 0, 0); } |
︙ | ︙ | |||
3009 3010 3011 3012 3013 3014 3015 | if( PB("showsql") ){ @ <pre>%h(blob_sql_text(&sql))</pre> } if( search_restrict(SRCH_CKIN)!=0 ){ style_submenu_element("Search", "%R/search?y=c"); } if( advancedMenu ){ | | < | < | | < < < | < < < < < < < | < < < < < < < < < < < < < < | < | < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < | < | | 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 | if( PB("showsql") ){ @ <pre>%h(blob_sql_text(&sql))</pre> } if( search_restrict(SRCH_CKIN)!=0 ){ style_submenu_element("Search", "%R/search?y=c"); } if( advancedMenu ){ style_submenu_element("Basic", "%s", url_render(&url, "advm", "0", 0, 0)); }else{ style_submenu_element("Advanced", "%s", url_render(&url, "advm", "1", 0, 0)); } if( PB("showid") ) tmFlags |= TIMELINE_SHOWRID; if( useDividers && zMark && zMark[0] ){ double r = symbolic_name_to_mtime(zMark); if( r>0.0 ) selectedRid = timeline_add_divider(r); } blob_zero(&sql); db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/"); if( fossil_islower(desc.aData[0]) ){ desc.aData[0] = fossil_toupper(desc.aData[0]); } @ <h2>%b(&desc)</h2> blob_reset(&desc); /* Report any errors. */ if( zError ){ @ <p class="generalError">%h(zError)</p> } if( zNewerButton ){ @ %z(chref("button","%z",zNewerButton))More ↑</a> } www_print_timeline(&q, tmFlags, zThisUser, zThisTag, selectedRid, 0); db_finalize(&q); if( zOlderButton ){ @ %z(chref("button","%z",zOlderButton))More ↓</a> } style_footer(); } /* ** The input query q selects various records. Print a human-readable ** summary of those records. ** ** Limit number of lines or entries printed to nLimit. If nLimit is zero ** there is no limit. If nLimit is greater than zero, limit the number of ** complete entries printed. If nLimit is less than zero, attempt to limit ** the number of lines printed (this is basically the legacy behavior). ** The line limit, if used, is approximate because it is only checked on a ** per-entry basis. If verbose mode, the file name details are considered ** to be part of the entry. ** ** The query should return these columns: ** ** 0. rid ** 1. uuid ** 2. Date/Time ** 3. Comment string and user ** 4. Number of non-merge children ** 5. Number of parents ** 6. mtime ** 7. branch */ void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){ int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit; int nLine = 0; int nEntry = 0; char zPrevDate[20]; const char *zCurrentUuid = 0; int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ int rc; zPrevDate[0] = 0; if( g.localOpen ){ int rid = db_lget_int("checkout", 0); zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); } while( (rc=db_step(q))==SQLITE_ROW ){ int rid = db_column_int(q, 0); const char *zId = db_column_text(q, 1); const char *zDate = db_column_text(q, 2); const char *zCom = db_column_text(q, 3); int nChild = db_column_int(q, 4); int nParent = db_column_int(q, 5); char *zFree = 0; int n = 0; char zPrefix[80]; if( nAbsLimit!=0 ){ if( nLimit<0 && nLine>=nAbsLimit ){ fossil_print("--- line limit (%d) reached ---\n", nAbsLimit); break; /* line count limit hit, stop. */ }else if( nEntry>=nAbsLimit ){ fossil_print("--- entry limit (%d) reached ---\n", nAbsLimit); break; /* entry count limit hit, stop. */ } } if( fossil_strnicmp(zDate, zPrevDate, 10) ){ fossil_print("=== %.10s ===\n", zDate); memcpy(zPrevDate, zDate, 10); nLine++; /* record another line */ } if( zCom==0 ) zCom = ""; fossil_print("%.8s ", &zDate[11]); zPrefix[0] = 0; if( nParent>1 ){ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* "); n = strlen(zPrefix); } if( nChild>1 ){ const char *zBrType; |
︙ | ︙ | |||
3278 3279 3280 3281 3282 3283 3284 | sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*CURRENT* "); n += strlen(zPrefix+n); } if( content_is_private(rid) ){ sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*UNPUBLISHED* "); n += strlen(zPrefix+n); } | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | | < | 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 | sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*CURRENT* "); n += strlen(zPrefix+n); } if( content_is_private(rid) ){ sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*UNPUBLISHED* "); n += strlen(zPrefix+n); } zFree = mprintf("[%S] %s%s", zId, zPrefix, zCom); /* record another X lines */ nLine += comment_print(zFree, zCom, 9, width, g.comFmtFlags); fossil_free(zFree); if(verboseFlag){ if( !fchngQueryInit ){ db_prepare(&fchngQuery, "SELECT (pid<=0) AS isnew," " (fid==0) AS isdel," |
︙ | ︙ | |||
3348 3349 3350 3351 3352 3353 3354 | fossil_print(" DELETED %s\n",zFilename); }else{ fossil_print(" EDITED %s\n", zFilename); } nLine++; /* record another line */ } db_reset(&fchngQuery); | < < < < | 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 | fossil_print(" DELETED %s\n",zFilename); }else{ fossil_print(" EDITED %s\n", zFilename); } nLine++; /* record another line */ } db_reset(&fchngQuery); } nEntry++; /* record another complete entry */ } if( rc==SQLITE_DONE ){ /* Did the underlying query actually have all entries? */ if( nAbsLimit==0 ){ fossil_print("+++ end of timeline (%d) +++\n", nEntry); }else{ |
︙ | ︙ | |||
3388 3389 3390 3391 3392 3393 3394 | @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) @ || ')' as comment, @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) @ AS primPlinkCount, @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, @ event.mtime AS mtime, | | < < < < < < < < | 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 | @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) @ || ')' as comment, @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) @ AS primPlinkCount, @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, @ event.mtime AS mtime, @ tagxref.value AS branch @ FROM tag CROSS JOIN event CROSS JOIN blob @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid @ AND tagxref.tagtype>0 @ AND tagxref.rid=blob.rid @ WHERE blob.rid=event.objid @ AND tag.tagname='branch' ; |
︙ | ︙ | |||
3427 3428 3429 3430 3431 3432 3433 | ** Return true if the input string can be converted to a julianday. */ static int fossil_is_julianday(const char *zDate){ return db_int(0, "SELECT EXISTS (SELECT julianday(%Q) AS jd" " WHERE jd IS NOT NULL)", zDate); } | < | 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 | ** Return true if the input string can be converted to a julianday. */ static int fossil_is_julianday(const char *zDate){ return db_int(0, "SELECT EXISTS (SELECT julianday(%Q) AS jd" " WHERE jd IS NOT NULL)", zDate); } /* ** COMMAND: timeline ** ** Usage: %fossil timeline ?WHEN? ?CHECKIN|DATETIME? ?OPTIONS? ** ** Print a summary of activity going backwards in date and time ** specified or from the current date and time if no arguments |
︙ | ︙ | |||
3454 3455 3456 3457 3458 3459 3460 | ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. ** ** ** Options: | < < < < < < < < < < < < < < < < < < < < | < < | | | > | < < < < < < < < < < < < < < < < < < < < < < | 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 | ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. ** ** ** Options: ** -n|--limit N If N is positive, output the first N entries. If ** N is negative, output the first -N lines. If N is ** zero, no limit. Default is -20 meaning 20 lines. ** -p|--path PATH Output items affecting PATH only. ** PATH can be a file or a sub directory. ** --offset P skip P changes ** --sql Show the SQL used to generate the timeline ** -t|--type TYPE Output items from the given types only, such as: ** ci = file commits only ** e = technical notes only ** t = tickets only ** w = wiki commits only ** -v|--verbose Output the list of files changed by each commit ** and the type of each change (edited, deleted, ** etc.) after the check-in comment. ** -W|--width <num> Width of lines (default is to auto-detect). Must be ** >20 or 0 (= no limit, resulting in a single line per ** entry). ** -R REPO_FILE Specifies the repository db to use. Default is ** the current checkout's repository. */ void timeline_cmd(void){ Stmt q; int n, k, width; const char *zLimit; const char *zWidth; const char *zOffset; const char *zType; char *zOrigin; char *zDate; Blob sql; int objid = 0; Blob uuid; int mode = TIMELINE_MODE_NONE; int verboseFlag = 0 ; int iOffset; const char *zFilePattern = 0; Blob treeName; int showSql = 0; verboseFlag = find_option("verbose","v", 0)!=0; if( !verboseFlag){ verboseFlag = find_option("showfiles","f", 0)!=0; /* deprecated */ } db_find_and_open_repository(0, 0); zLimit = find_option("limit","n",1); zWidth = find_option("width","W",1); zType = find_option("type","t",1); zFilePattern = find_option("path","p",1); showSql = find_option("sql",0,0)!=0; if( !zLimit ){ zLimit = find_option("count",0,1); } if( zLimit ){ n = atoi(zLimit); |
︙ | ︙ | |||
3586 3587 3588 3589 3590 3591 3592 | mode = TIMELINE_MODE_CHILDREN; }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){ mode = TIMELINE_MODE_PARENTS; }else if( strncmp(g.argv[2],"parents",k)==0 ){ mode = TIMELINE_MODE_PARENTS; }else if(!zType && !zLimit){ usage("?WHEN? ?CHECKIN|DATETIME? ?-n|--limit #? ?-t|--type TYPE? " | | | 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 | mode = TIMELINE_MODE_CHILDREN; }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){ mode = TIMELINE_MODE_PARENTS; }else if( strncmp(g.argv[2],"parents",k)==0 ){ mode = TIMELINE_MODE_PARENTS; }else if(!zType && !zLimit){ usage("?WHEN? ?CHECKIN|DATETIME? ?-n|--limit #? ?-t|--type TYPE? " "?-W|--width WIDTH? ?-p|--path PATH"); } if( '-' != *g.argv[3] ){ zOrigin = g.argv[3]; }else{ zOrigin = "now"; } }else if( g.argc==3 ){ |
︙ | ︙ | |||
3608 3609 3610 3611 3612 3613 3614 | if( fossil_strcmp(zOrigin, "now")==0 ){ if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){ fossil_fatal("cannot compute descendants or ancestors of a date"); } zDate = mprintf("(SELECT datetime('now'))"); }else if( strncmp(zOrigin, "current", k)==0 ){ if( !g.localOpen ){ | | | 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 | if( fossil_strcmp(zOrigin, "now")==0 ){ if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){ fossil_fatal("cannot compute descendants or ancestors of a date"); } zDate = mprintf("(SELECT datetime('now'))"); }else if( strncmp(zOrigin, "current", k)==0 ){ if( !g.localOpen ){ fossil_fatal("must be within a local checkout to use 'current'"); } objid = db_lget_int("checkout",0); zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid); }else if( fossil_is_julianday(zOrigin) ){ const char *zShift = ""; if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){ fossil_fatal("cannot compute descendants or ancestors of a date"); |
︙ | ︙ | |||
3657 3658 3659 3660 3661 3662 3663 | /* When zFilePattern is specified, compute complete ancestry; * limit later at print_timeline() */ if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){ db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); if( mode==TIMELINE_MODE_CHILDREN ){ compute_descendants(objid, (zFilePattern ? 0 : n)); }else{ | | | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 | /* When zFilePattern is specified, compute complete ancestry; * limit later at print_timeline() */ if( mode==TIMELINE_MODE_CHILDREN || mode==TIMELINE_MODE_PARENTS ){ db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); if( mode==TIMELINE_MODE_CHILDREN ){ compute_descendants(objid, (zFilePattern ? 0 : n)); }else{ compute_ancestors(objid, (zFilePattern ? 0 : n), 0); } blob_append_sql(&sql, "\n AND blob.rid IN ok"); } if( zType && (zType[0]!='a') ){ blob_append_sql(&sql, "\n AND event.type=%Q ", zType); } if( zFilePattern ){ |
︙ | ︙ | |||
3684 3685 3686 3687 3688 3689 3690 | "(SELECT fnid FROM filename" " WHERE name=%Q COLLATE nocase" " OR lower(name) GLOB lower('%q/*'))", blob_str(&treeName), blob_str(&treeName)); } blob_append(&sql, ")", -1); } | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 | "(SELECT fnid FROM filename" " WHERE name=%Q COLLATE nocase" " OR lower(name) GLOB lower('%q/*'))", blob_str(&treeName), blob_str(&treeName)); } blob_append(&sql, ")", -1); } blob_append_sql(&sql, "\nORDER BY event.mtime DESC"); if( iOffset>0 ){ /* Don't handle LIMIT here, otherwise print_timeline() * will not determine the end-marker correctly! */ blob_append_sql(&sql, "\n LIMIT -1 OFFSET %d", iOffset); } if( showSql ){ fossil_print("%s\n", blob_str(&sql)); } db_prepare_blob(&q, &sql); blob_reset(&sql); print_timeline(&q, n, width, verboseFlag); db_finalize(&q); } /* ** COMMAND: test-timewarp-list ** ** Usage: %fossil test-timewarp-list ?-v|---verbose? |
︙ | ︙ | |||
3897 3898 3899 3900 3901 3902 3903 | } db_finalize(&q); if( cnt==0 ){ @ <p>No timewarps in this repository</p> }else{ @ </tbody></table></div> } | | | 2645 2646 2647 2648 2649 2650 2651 2652 2653 | } db_finalize(&q); if( cnt==0 ){ @ <p>No timewarps in this repository</p> }else{ @ </tbody></table></div> } style_footer(); } |
Changes to src/tkt.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | #include "config.h" #include "tkt.h" #include <assert.h> /* ** The list of database user-defined fields in the TICKET table. ** The real table also contains some addition fields for internal | | < < < < < < < < < | 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 | #include "config.h" #include "tkt.h" #include <assert.h> /* ** The list of database user-defined fields in the TICKET table. ** The real table also contains some addition fields for internal ** used. The internal-use fields begin with "tkt_". */ static int nField = 0; static struct tktFieldInfo { char *zName; /* Name of the database field */ char *zValue; /* Value to store */ char *zAppend; /* Value to append */ unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */ } *aField; #define USEDBY_TICKET 01 #define USEDBY_TICKETCHNG 02 #define USEDBY_BOTH 03 static u8 haveTicket = 0; /* True if the TICKET table exists */ static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */ static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */ static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */ /* ** Compare two entries in aField[] for sorting purposes */ static int nameCmpr(const void *a, const void *b){ return fossil_strcmp(((const struct tktFieldInfo*)a)->zName, ((const struct tktFieldInfo*)b)->zName); |
︙ | ︙ | |||
76 77 78 79 80 81 82 | ** in sorted order in aField[]. ** ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and ** TICKETCHANGE tables exist, respectively. */ static void getAllTicketFields(void){ Stmt q; | | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | 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 | ** in sorted order in aField[]. ** ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and ** TICKETCHANGE tables exist, respectively. */ static void getAllTicketFields(void){ Stmt q; int i; static int once = 0; if( once ) return; once = 1; db_prepare(&q, "PRAGMA table_info(ticket)"); while( db_step(&q)==SQLITE_ROW ){ const char *zFieldName = db_column_text(&q, 1); haveTicket = 1; if( memcmp(zFieldName,"tkt_",4)==0 ){ if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1; continue; } if( nField%10==0 ){ aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) ); } aField[nField].zName = mprintf("%s", zFieldName); aField[nField].mUsed = USEDBY_TICKET; nField++; } db_finalize(&q); db_prepare(&q, "PRAGMA table_info(ticketchng)"); while( db_step(&q)==SQLITE_ROW ){ const char *zFieldName = db_column_text(&q, 1); haveTicketChng = 1; if( memcmp(zFieldName,"tkt_",4)==0 ){ if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1; continue; } if( (i = fieldId(zFieldName))>=0 ){ aField[i].mUsed |= USEDBY_TICKETCHNG; continue; } if( nField%10==0 ){ aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) ); } aField[nField].zName = mprintf("%s", zFieldName); aField[nField].mUsed = USEDBY_TICKETCHNG; nField++; } db_finalize(&q); qsort(aField, nField, sizeof(aField[0]), nameCmpr); for(i=0; i<nField; i++){ aField[i].zValue = ""; aField[i].zAppend = 0; } } /* ** Query the database for all TICKET fields for the specific ** ticket whose name is given by the "name" CGI parameter. ** Load the values for all fields into the interpreter. |
︙ | ︙ | |||
230 231 232 233 234 235 236 | const char *z; for(i=0; (z = cgi_parameter_name(i))!=0; i++){ Th_Store(z, P(z)); } } | < < < < < < < < < < < < < < < < < | | < < < < | > | | > | > | < | < < < > > > > | | | < < < < < < < < < < < < < | | < < < < | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | const char *z; for(i=0; (z = cgi_parameter_name(i))!=0; i++){ Th_Store(z, P(z)); } } /* ** Update an entry of the TICKET and TICKETCHNG tables according to the ** information in the ticket artifact given in p. Attempt to create ** the appropriate TICKET table entry if tktid is zero. If tktid is nonzero ** then it will be the ROWID of an existing TICKET entry. ** ** Parameter rid is the recordID for the ticket artifact in the BLOB table. ** ** Return the new rowid of the TICKET table entry. */ static int ticket_insert(const Manifest *p, int rid, int tktid){ Blob sql1, sql2, sql3; Stmt q; int i, j; char *aUsed; if( tktid==0 ){ db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) " "VALUES(%Q, 0)", p->zTicketUuid); tktid = db_last_insert_rowid(); } blob_zero(&sql1); blob_zero(&sql2); blob_zero(&sql3); blob_append_sql(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); if( haveTicketCTime ){ blob_append_sql(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)"); } aUsed = fossil_malloc( nField ); memset(aUsed, 0, nField); for(i=0; i<p->nField; i++){ const char *zName = p->aField[i].zName; const char *zBaseName = zName[0]=='+' ? zName+1 : zName; j = fieldId(zBaseName); if( j<0 ) continue; aUsed[j] = 1; if( aField[j].mUsed & USEDBY_TICKET ){ const char *zUsedByName = zName; if( zUsedByName[0]=='+' ){ zUsedByName++; blob_append_sql(&sql1,", \"%w\"=coalesce(\"%w\",'') || %Q", zUsedByName, zUsedByName, p->aField[i].zValue); }else{ blob_append_sql(&sql1,", \"%w\"=%Q", zUsedByName, p->aField[i].zValue); } } if( aField[j].mUsed & USEDBY_TICKETCHNG ){ const char *zUsedByName = zName; if( zUsedByName[0]=='+' ){ zUsedByName++; } blob_append_sql(&sql2, ",\"%w\"", zUsedByName); blob_append_sql(&sql3, ",%Q", p->aField[i].zValue); } if( rid>0 ){ wiki_extract_links(p->aField[i].zValue, rid, 1, p->rDate, i==0, 0); } } blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid); db_prepare(&q, "%s", blob_sql_text(&sql1)); db_bind_double(&q, ":mtime", p->rDate); db_step(&q); db_finalize(&q); blob_reset(&sql1); if( blob_size(&sql2)>0 || haveTicketChngRid ){ int fromTkt = 0; if( haveTicketChngRid ){ blob_append(&sql2, ",tkt_rid", -1); blob_append_sql(&sql3, ",%d", rid); } for(i=0; i<nField; i++){ if( aUsed[i]==0 && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH ){ const char *z = aField[i].zName; if( z[0]=='+' ) z++; fromTkt = 1; blob_append_sql(&sql2, ",\"%w\"", z); blob_append_sql(&sql3, ",\"%w\"", z); } } if( fromTkt ){ db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d", blob_sql_text(&sql2), tktid, blob_sql_text(&sql3), tktid); }else{ db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" "VALUES(%d,:mtime%s)", blob_sql_text(&sql2), tktid, blob_sql_text(&sql3)); } db_bind_double(&q, ":mtime", p->rDate); db_step(&q); db_finalize(&q); } blob_reset(&sql2); blob_reset(&sql3); fossil_free(aUsed); return tktid; } /* ** Returns non-zero if moderation is required for ticket changes and ticket ** attachments. */ |
︙ | ︙ | |||
440 441 442 443 444 445 446 | ** Rebuild an entire entry in the TICKET table */ void ticket_rebuild_entry(const char *zTktUuid){ char *zTag = mprintf("tkt-%s", zTktUuid); int tagid = tag_findid(zTag, 1); Stmt q; Manifest *pTicket; | | < | < < < | < < < < < < < < < < < < < < < < < | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | ** Rebuild an entire entry in the TICKET table */ void ticket_rebuild_entry(const char *zTktUuid){ char *zTag = mprintf("tkt-%s", zTktUuid); int tagid = tag_findid(zTag, 1); Stmt q; Manifest *pTicket; int tktid; int createFlag = 1; fossil_free(zTag); getAllTicketFields(); if( haveTicket==0 ) return; tktid = db_int(0, "SELECT tkt_id FROM ticket WHERE tkt_uuid=%Q", zTktUuid); search_doc_touch('t', tktid, 0); if( haveTicketChng ){ db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid); } db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid); tktid = 0; db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); pTicket = manifest_get(rid, CFTYPE_TICKET, 0); if( pTicket ){ tktid = ticket_insert(pTicket, rid, tktid); manifest_ticket_event(rid, pTicket, createFlag, tagid); manifest_destroy(pTicket); } createFlag = 0; } db_finalize(&q); } /* ** Create the TH1 interpreter and load the "common" code. */ void ticket_init(void){ |
︙ | ︙ | |||
509 510 511 512 513 514 515 516 517 | int ticket_change(const char *zUuid){ const char *zConfig; Th_FossilInit(TH_INIT_DEFAULT); Th_Store("uuid", zUuid); zConfig = ticket_change_code(); return Th_Eval(g.interp, 0, zConfig, -1); } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | int ticket_change(const char *zUuid){ const char *zConfig; Th_FossilInit(TH_INIT_DEFAULT); Th_Store("uuid", zUuid); zConfig = ticket_change_code(); return Th_Eval(g.interp, 0, zConfig, -1); } /* ** Recreate the TICKET and TICKETCHNG tables. */ void ticket_create_table(int separateConnection){ const char *zSql; db_multi_exec( "DROP TABLE IF EXISTS ticket;" "DROP TABLE IF EXISTS ticketchng;" ); zSql = ticket_table_schema(); if( separateConnection ){ if( db_transaction_nesting_depth() ) db_end_transaction(0); db_init_database(g.zRepositoryName, zSql, 0); }else{ db_multi_exec("%s", zSql/*safe-for-%s*/); } } /* ** Repopulate the TICKET and TICKETCHNG tables from scratch using all ** available ticket artifacts. */ void ticket_rebuild(void){ |
︙ | ︙ | |||
712 713 714 715 716 717 718 | @ mUsed = %d(aField[i].mUsed); } @ </ul></div> } /* ** WEBPAGE: tktview | | < < < < | | | | | < | | | < < < < < < < < < < < < < < | | < | | | | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | @ mUsed = %d(aField[i].mUsed); } @ </ul></div> } /* ** WEBPAGE: tktview ** URL: tktview?name=UUID ** ** View a ticket identified by the name= query parameter. */ void tktview_page(void){ const char *zScript; char *zFullName; const char *zUuid = PD("name",""); login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; } if( g.anon.WrTkt || g.anon.ApndTkt ){ style_submenu_element("Edit", "%s/tktedit?name=%T", g.zTop, PD("name","")); } if( g.perm.Hyperlink ){ style_submenu_element("History", "%s/tkthistory/%T", g.zTop, zUuid); style_submenu_element("Timeline", "%s/tkttimeline/%T", g.zTop, zUuid); style_submenu_element("Check-ins", "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); } if( g.anon.NewTkt ){ style_submenu_element("New Ticket", "%s/tktnew", g.zTop); } if( g.anon.ApndTkt && g.anon.Attach ){ style_submenu_element("Attach", "%s/attachadd?tkt=%T&from=%s/tktview/%t", g.zTop, zUuid, g.zTop, zUuid); } if( P("plaintext") ){ style_submenu_element("Formatted", "%R/tktview/%s", zUuid); }else{ style_submenu_element("Plaintext", "%R/tktview/%s?plaintext", zUuid); } style_header("View Ticket"); if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); ticket_init(); initializeVariablesFromCGI(); getAllTicketFields(); initializeVariablesFromDb(); zScript = ticket_viewpage_code(); if( P("showfields")!=0 ) showAllFields(); if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); Th_Render(zScript); if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); zFullName = db_text(0, "SELECT tkt_uuid FROM ticket" " WHERE tkt_uuid GLOB '%q*'", zUuid); if( zFullName ){ attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>"); } style_footer(); } /* ** TH1 command: append_field FIELD STRING ** ** FIELD is the name of a database column to which we might want ** to append text. STRING is the text to be appended to that |
︙ | ︙ | |||
806 807 808 809 810 811 812 | ){ int idx; if( argc!=3 ){ return Th_WrongNumArgs(interp, "append_field FIELD STRING"); } if( g.thTrace ){ | | < < < < < < < < < < < < < < < < < < | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | ){ int idx; if( argc!=3 ){ return Th_WrongNumArgs(interp, "append_field FIELD STRING"); } if( g.thTrace ){ Th_Trace("append_field %#h {%#h}<br />\n", argl[1], argv[1], argl[2], argv[2]); } for(idx=0; idx<nField; idx++){ if( memcmp(aField[idx].zName, argv[1], argl[1])==0 && aField[idx].zName[argl[1]]==0 ){ break; } } if( idx>=nField ){ Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]); return TH_ERROR; } aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]); return TH_OK; } /* ** Write a ticket into the repository. */ static int ticket_put( Blob *pTicket, /* The text of the ticket change record */ const char *zTktId, /* The ticket to which this change is applied */ int needMod /* True if moderation is needed */ ){ int result; int rid; manifest_crosslink_begin(); rid = content_put_ex(pTicket, 0, 0, 0, needMod); if( rid==0 ){ fossil_fatal("trouble committing ticket: %s", g.zErrMsg); } if( needMod ){ moderation_table_create(); db_multi_exec( "INSERT INTO modreq(objid, tktid) VALUES(%d,%Q)", rid, zTktId ); }else{ db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid); db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid); } result = (manifest_crosslink(rid, pTicket, MC_NONE)==0); assert( blob_is_reset(pTicket) ); if( !result ){ result = manifest_crosslink_end(MC_PERMIT_HOOKS); }else{ |
︙ | ︙ | |||
892 893 894 895 896 897 898 | static int submitTicketCmd( Th_Interp *interp, void *pUuid, int argc, const char **argv, int *argl ){ | | | | < < < < < | < < | | > | | < < < | < < | > < < < < < < < < < < < < < < < | | | | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | static int submitTicketCmd( Th_Interp *interp, void *pUuid, int argc, const char **argv, int *argl ){ char *zDate; const char *zUuid; int i; int nJ = 0; Blob tktchng, cksum; int needMod; login_verify_csrf_secret(); if( !captcha_is_correct(0) ){ @ <p class="generalError">Error: Incorrect security code.</p> return TH_OK; } zUuid = (const char *)pUuid; blob_zero(&tktchng); zDate = date_in_standard_format("now"); blob_appendf(&tktchng, "D %s\n", zDate); free(zDate); for(i=0; i<nField; i++){ if( aField[i].zAppend ){ blob_appendf(&tktchng, "J +%s %z\n", aField[i].zName, fossilize(aField[i].zAppend, -1)); ++nJ; } } for(i=0; i<nField; i++){ const char *zValue; int nValue; if( aField[i].zAppend ) continue; zValue = Th_Fetch(aField[i].zName, &nValue); if( zValue ){ while( nValue>0 && fossil_isspace(zValue[nValue-1]) ){ nValue--; } if( ((aField[i].mUsed & USEDBY_TICKETCHNG)!=0 && nValue>0) || memcmp(zValue, aField[i].zValue, nValue)!=0 || strlen(aField[i].zValue)!=nValue ){ if( memcmp(aField[i].zName, "private_", 8)==0 ){ zValue = db_conceal(zValue, nValue); blob_appendf(&tktchng, "J %s %s\n", aField[i].zName, zValue); }else{ blob_appendf(&tktchng, "J %s %#F\n", aField[i].zName, nValue, zValue); } nJ++; } } } if( *(char**)pUuid ){ zUuid = db_text(0, "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%q*'", P("name") ); }else{ zUuid = db_text(0, "SELECT lower(hex(randomblob(20)))"); } *(const char**)pUuid = zUuid; blob_appendf(&tktchng, "K %s\n", zUuid); blob_appendf(&tktchng, "U %F\n", login_name()); md5sum_blob(&tktchng, &cksum); blob_appendf(&tktchng, "Z %b\n", &cksum); if( nJ==0 ){ blob_reset(&tktchng); return TH_OK; } needMod = ticket_need_moderation(0); if( g.zPath[0]=='d' ){ const char *zNeedMod = needMod ? "required" : "skipped"; /* If called from /debug_tktnew or /debug_tktedit... */ @ <div style="color:blue"> @ <p>Ticket artifact that would have been submitted:</p> @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote> @ <blockquote><pre>Moderation would be %h(zNeedMod).</pre></blockquote> @ </div> @ <hr /> return TH_OK; }else{ if( g.thTrace ){ Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n" "}<br />\n", blob_str(&tktchng)); } ticket_put(&tktchng, zUuid, needMod); } return ticket_change(zUuid); } /* ** WEBPAGE: tktnew ** WEBPAGE: debug_tktnew ** ** Enter a new ticket. The tktnew_template script in the ticket ** configuration is used. The /tktnew page is the official ticket ** entry page. The /debug_tktnew page is used for debugging the ** tktnew_template in the ticket configuration. /debug_tktnew works ** just like /tktnew except that it does not really save the new ticket ** when you press submit - it just prints the ticket artifact at the ** top of the screen. */ void tktnew_page(void){ const char *zScript; char *zNewUuid = 0; login_check_credentials(); if( !g.perm.NewTkt ){ login_needed(g.anon.NewTkt); return; } if( P("cancel") ){ cgi_redirect("home"); } style_header("New Ticket"); ticket_standard_submenu(T_ALL_BUT(T_NEW)); if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br />\n", -1); ticket_init(); initializeVariablesFromCGI(); getAllTicketFields(); initializeVariablesFromDb(); if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); login_insert_csrf_secret(); if( P("date_override") && g.perm.Setup ){ @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> } zScript = ticket_newpage_code(); Th_Store("login", login_name()); Th_Store("date", db_text(0, "SELECT datetime('now')")); Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zNewUuid, 0); if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1); if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){ cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid)); return; } captcha_generate(0); @ </form> if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); style_footer(); } /* ** WEBPAGE: tktedit ** WEBPAGE: debug_tktedit ** ** Edit a ticket. The ticket is identified by the name CGI parameter. |
︙ | ︙ | |||
1075 1076 1077 1078 1079 1080 1081 | login_check_credentials(); if( !g.perm.ApndTkt && !g.perm.WrTkt ){ login_needed(g.anon.ApndTkt || g.anon.WrTkt); return; } zName = P("name"); if( P("cancel") ){ | | < | | | | | > | | | | | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 | login_check_credentials(); if( !g.perm.ApndTkt && !g.perm.WrTkt ){ login_needed(g.anon.ApndTkt || g.anon.WrTkt); return; } zName = P("name"); if( P("cancel") ){ cgi_redirectf("tktview?name=%T", zName); } style_header("Edit Ticket"); if( zName==0 || (nName = strlen(zName))<4 || nName>HNAME_LEN_SHA1 || !validate16(zName,nName) ){ @ <span class="tktError">Not a valid ticket id: "%h(zName)"</span> style_footer(); return; } nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'", zName); if( nRec==0 ){ @ <span class="tktError">No such ticket: "%h(zName)"</span> style_footer(); return; } if( nRec>1 ){ @ <span class="tktError">%d(nRec) tickets begin with: @ "%h(zName)"</span> style_footer(); return; } if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1); ticket_init(); getAllTicketFields(); initializeVariablesFromCGI(); initializeVariablesFromDb(); if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); @ <input type="hidden" name="name" value="%s(zName)" /> login_insert_csrf_secret(); zScript = ticket_editpage_code(); Th_Store("login", login_name()); Th_Store("date", db_text(0, "SELECT datetime('now')")); Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1); if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){ cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName)); return; } captcha_generate(0); @ </form> if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1); style_footer(); } /* ** Check the ticket table schema in zSchema to see if it appears to ** be well-formed. If everything is OK, return NULL. If something is ** amiss, then return a pointer to a string (obtained from malloc) that ** describes the problem. |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 1163 | } } sqlite3_close(db); } return zErr; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < > > > < | < > | | | < | > | > > > > > > > > > > > > > > > > > > > > > > > > > | | | < < < < < < < < < < < | < | < > | | | | | < | < < < < < < < < < | | > < < > | > | | | | < < < < < < < < | < < | < < < < | < < < < < > > > > > > > > < | | < | | < < < < < < < < < < < < < | | < < < < < < < < < < < | < < < < < < < < < < | < | < | < < < < > | | < < < < | | < | < < < < < < < < < | | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 | } } sqlite3_close(db); } return zErr; } /* ** WEBPAGE: tkttimeline ** URL: /tkttimeline?name=TICKETUUID&y=TYPE ** ** Show the change history for a single ticket in timeline format. */ void tkttimeline_page(void){ Stmt q; char *zTitle; char *zSQL; const char *zUuid; char *zFullUuid; int tagid; char zGlobPattern[50]; const char *zType; login_check_credentials(); if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(g.anon.Hyperlink && g.anon.RdTkt); return; } zUuid = PD("name",""); zType = PD("y","a"); if( zType[0]!='c' ){ style_submenu_element("Check-ins", "%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid); }else{ style_submenu_element("Timeline", "%s/tkttimeline?name=%T", g.zTop, zUuid); } style_submenu_element("History", "%s/tkthistory/%s", g.zTop, zUuid); style_submenu_element("Status", "%s/info/%s", g.zTop, zUuid); if( zType[0]=='c' ){ zTitle = mprintf("Check-ins Associated With Ticket %h", zUuid); }else{ zTitle = mprintf("Timeline Of Ticket %h", zUuid); } style_header("%z", zTitle); sqlite3_snprintf(6, zGlobPattern, "%s", zUuid); canonical16(zGlobPattern, strlen(zGlobPattern)); tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); if( tagid==0 ){ @ No such ticket: %h(zUuid) style_footer(); return; } zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d", tagid); if( zType[0]=='c' ){ zSQL = mprintf( "%s AND event.objid IN " " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' " "AND '%s' GLOB (target||'*')) " "ORDER BY mtime DESC", timeline_query_for_www(), zFullUuid, zFullUuid ); }else{ zSQL = mprintf( "%s AND event.objid IN " " (SELECT rid FROM tagxref WHERE tagid=%d" " UNION SELECT srcid FROM backlink" " WHERE target GLOB '%.4s*'" " AND '%s' GLOB (target||'*')" " UNION SELECT attachid FROM attachment" " WHERE target=%Q) " "ORDER BY mtime DESC", timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid ); } db_prepare(&q, "%z", zSQL/*safe-for-%s*/); www_print_timeline(&q, TIMELINE_ARTID|TIMELINE_DISJOINT|TIMELINE_GRAPH, 0, 0, 0, 0); db_finalize(&q); style_footer(); } /* ** WEBPAGE: tkthistory ** URL: /tkthistory?name=TICKETUUID ** ** Show the complete change history for a single ticket */ void tkthistory_page(void){ Stmt q; char *zTitle; const char *zUuid; int tagid; int nChng = 0; login_check_credentials(); if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(g.anon.Hyperlink && g.anon.RdTkt); return; } zUuid = PD("name",""); zTitle = mprintf("History Of Ticket %h", zUuid); style_submenu_element("Status", "%s/info/%s", g.zTop, zUuid); style_submenu_element("Check-ins", "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid); style_submenu_element("Timeline", "%s/tkttimeline?name=%s", g.zTop, zUuid); if( P("plaintext")!=0 ){ style_submenu_element("Formatted", "%R/tkthistory/%s", zUuid); }else{ style_submenu_element("Plaintext", "%R/tkthistory/%s?plaintext", zUuid); } style_header("%z", zTitle); tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); if( tagid==0 ){ @ No such ticket: %h(zUuid) style_footer(); return; } db_prepare(&q, "SELECT datetime(mtime,toLocal()), objid, uuid, NULL, NULL, NULL" " FROM event, blob" " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" " AND blob.rid=event.objid" " UNION " "SELECT datetime(mtime,toLocal()), attachid, uuid, src, filename, user" " FROM attachment, blob" " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" " AND blob.rid=attachid" " ORDER BY 1", tagid, tagid ); while( db_step(&q)==SQLITE_ROW ){ Manifest *pTicket; const char *zDate = db_column_text(&q, 0); int rid = db_column_int(&q, 1); const char *zChngUuid = db_column_text(&q, 2); const char *zFile = db_column_text(&q, 4); if( nChng==0 ){ @ <ol> } nChng++; if( zFile!=0 ){ const char *zSrc = db_column_text(&q, 3); const char *zUser = db_column_text(&q, 5); if( zSrc==0 || zSrc[0]==0 ){ @ @ <li><p>Delete attachment "%h(zFile)" }else{ @ @ <li><p>Add attachment @ "%z(href("%R/artifact/%!S",zSrc))%s(zFile)</a>" } @ [%z(href("%R/artifact/%!S",zChngUuid))%S(zChngUuid)</a>] @ (rid %d(rid)) by hyperlink_to_user(zUser,zDate," on"); hyperlink_to_date(zDate, ".</p>"); }else{ pTicket = manifest_get(rid, CFTYPE_TICKET, 0); if( pTicket ){ @ @ <li><p>Ticket change @ [%z(href("%R/artifact/%!S",zChngUuid))%S(zChngUuid)</a>] @ (rid %d(rid)) by hyperlink_to_user(pTicket->zUser,zDate," on"); hyperlink_to_date(zDate, ":"); @ </p> ticket_output_change_artifact(pTicket, "a"); } manifest_destroy(pTicket); } } db_finalize(&q); if( nChng ){ @ </ol> } style_footer(); } /* ** Return TRUE if the given BLOB contains a newline character. */ static int contains_newline(Blob *p){ const char *z = blob_str(p); while( *z ){ if( *z=='\n' ) return 1; z++; } return 0; } /* ** The pTkt object is a ticket change artifact. Output a detailed ** description of this object. */ void ticket_output_change_artifact(Manifest *pTkt, const char *zListType){ int i; int wikiFlags = WIKI_NOBADLINKS; const char *zBlock = "<blockquote>"; const char *zEnd = "</blockquote>"; if( P("plaintext")!=0 ){ wikiFlags |= WIKI_LINKSONLY; zBlock = "<blockquote><pre class='verbatim'>"; zEnd = "</pre></blockquote>"; } if( zListType==0 ) zListType = "1"; @ <ol type="%s(zListType)"> for(i=0; i<pTkt->nField; i++){ Blob val; const char *z; z = pTkt->aField[i].zName; blob_set(&val, pTkt->aField[i].zValue); if( z[0]=='+' ){ @ <li>Appended to %h(&z[1]):%s(zBlock) wiki_convert(&val, 0, wikiFlags); @ %s(zEnd)</li> }else if( blob_size(&val)>50 || contains_newline(&val) ){ @ <li>Change %h(z) to:%s(zBlock) wiki_convert(&val, 0, wikiFlags); @ %s(zEnd)</li> }else{ @ <li>Change %h(z) to "%h(blob_str(&val))"</li> } blob_reset(&val); } @ </ol> } /* ** COMMAND: ticket* ** ** Usage: %fossil ticket SUBCOMMAND ... ** ** Run various subcommands to control tickets ** ** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?OPTIONS? ** ** Options: ** -l|--limit LIMITCHAR ** -q|--quote ** -R|--repository FILE ** ** Run the ticket report, identified by the report format title ** used in the GUI. The data is written as flat file on stdout, ** using TAB as separator. The separator can be changed using ** the -l or --limit option. ** ** If TICKETFILTER is given on the commandline, the query is |
︙ | ︙ | |||
1528 1529 1530 1531 1532 1533 1534 | ** Otherwise, the simplified encoding as on the show report raw page ** in the GUI is used. This has no effect in JSON mode. ** ** Instead of the report title it's possible to use the report ** number; the special report number 0 lists all columns defined in ** the ticket table. ** | | | | | | | | | | | 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 | ** Otherwise, the simplified encoding as on the show report raw page ** in the GUI is used. This has no effect in JSON mode. ** ** Instead of the report title it's possible to use the report ** number; the special report number 0 lists all columns defined in ** the ticket table. ** ** %fossil ticket list fields ** %fossil ticket ls fields ** ** List all fields defined for ticket in the fossil repository. ** ** %fossil ticket list reports ** %fossil ticket ls reports ** ** List all ticket reports defined in the fossil repository. ** ** %fossil ticket set TICKETUUID (FIELD VALUE)+ ?-q|--quote? ** %fossil ticket change TICKETUUID (FIELD VALUE)+ ?-q|--quote? ** ** Change ticket identified by TICKETUUID to set the values of ** each field FIELD to VALUE. ** ** Field names as defined in the TICKET table. By default, these ** names include: type, status, subsystem, priority, severity, foundin, ** resolution, title, and comment, but other field names can be added ** or substituted in customized installations. ** ** If you use +FIELD, the VALUE is appended to the field FIELD. You ** can use more than one field/value pair on the commandline. Using ** --quote enables the special character decoding as in "ticket ** show", which allows setting multiline text or text with special ** characters. ** ** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? ** ** Like set, but create a new ticket with the given values. ** ** %fossil ticket history TICKETUUID ** ** Show the complete change history for the ticket ** ** Note that the values in set|add are not validated against the ** definitions given in "Ticket Common Script". */ void ticket_cmd(void){ int n; const char *zUser; const char *zDate; const char *zTktUuid; /* do some ints, we want to be inside a checkout */ db_find_and_open_repository(0, 0); user_select(); zUser = find_option("user-override",0,1); if( zUser==0 ) zUser = login_name(); zDate = find_option("date-override",0,1); if( zDate==0 ) zDate = "now"; |
︙ | ︙ | |||
1649 1650 1651 1652 1653 1654 1655 | rptshow( zRep, zSep, zFilterUuid, tktEncoding ); } }else{ /* add a new ticket or update an existing ticket */ enum { set,add,history,err } eCmd = err; int i = 0; Blob tktchng, cksum; | < | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | rptshow( zRep, zSep, zFilterUuid, tktEncoding ); } }else{ /* add a new ticket or update an existing ticket */ enum { set,add,history,err } eCmd = err; int i = 0; Blob tktchng, cksum; /* get command type (set/add) and get uuid, if needed for set */ if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 || strncmp(g.argv[2],"history",n)==0 ){ if( strncmp(g.argv[2],"history",n)==0 ){ eCmd = history; }else{ |
︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | z++; }else{ fossil_print(" Change "); } fossil_print("%h: ",z); if( blob_size(&val)>50 || contains_newline(&val)) { fossil_print("\n "); | | | | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 | z++; }else{ fossil_print(" Change "); } fossil_print("%h: ",z); if( blob_size(&val)>50 || contains_newline(&val)) { fossil_print("\n "); comment_print(blob_str(&val),0,4,-1,g.comFmtFlags); }else{ fossil_print("%s\n",blob_str(&val)); } blob_reset(&val); } } manifest_destroy(pTicket); } } db_finalize(&q); return; } /* read all given ticket field/value pairs from command line */ if( i==g.argc ){ fossil_fatal("empty %s command aborted!",g.argv[2]); } getAllTicketFields(); /* read commandline and assign fields in the aField[].zValue array */ while( i<g.argc ){ char *zFName; char *zFValue; int j; int append = 0; zFName = g.argv[i++]; |
︙ | ︙ | |||
1792 1793 1794 1795 1796 1797 1798 | if( append ){ aField[j].zAppend = zFValue; }else{ aField[j].zValue = zFValue; } } } | < < < < | < < | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 | if( append ){ aField[j].zAppend = zFValue; }else{ aField[j].zValue = zFValue; } } } /* now add the needed artifacts to the repository */ blob_zero(&tktchng); /* add the time to the ticket manifest */ blob_appendf(&tktchng, "D %s\n", zDate); /* append defined elements */ for(i=0; i<nField; i++){ char *zValue = 0; char *zPfx; if( aField[i].zAppend && aField[i].zAppend[0] ){ zPfx = " +"; zValue = aField[i].zAppend; }else if( aField[i].zValue && aField[i].zValue[0] ){ zPfx = " "; zValue = aField[i].zValue; }else{ continue; } if( memcmp(aField[i].zName, "private_", 8)==0 ){ zValue = db_conceal(zValue, strlen(zValue)); blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue); }else{ blob_appendf(&tktchng, "J%s%s %#F\n", zPfx, aField[i].zName, strlen(zValue), zValue); } } blob_appendf(&tktchng, "K %s\n", zTktUuid); blob_appendf(&tktchng, "U %F\n", zUser); md5sum_blob(&tktchng, &cksum); blob_appendf(&tktchng, "Z %b\n", &cksum); if( ticket_put(&tktchng, zTktUuid, ticket_need_moderation(1))==0 ){ fossil_fatal("%s", g.zErrMsg); }else{ fossil_print("ticket %s succeeded for %s\n", (eCmd==set?"set":"add"),zTktUuid); } } } } #if INTERFACE /* Standard submenu items for wiki pages */ |
︙ | ︙ | |||
1887 1888 1889 1890 1891 1892 1893 | /* ** WEBPAGE: tktsrch ** Usage: /tktsrch?s=PATTERN ** ** Full-text search of all current tickets */ void tkt_srchpage(void){ | < < | < < < < < | | 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | /* ** WEBPAGE: tktsrch ** Usage: /tktsrch?s=PATTERN ** ** Full-text search of all current tickets */ void tkt_srchpage(void){ login_check_credentials(); style_header("Ticket Search"); ticket_standard_submenu(T_ALL_BUT(T_SRCH)); search_screen(SRCH_TKT, 0); style_footer(); } |
Changes to src/tktsetup.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 | setup_menu_entry("Report List Page", "tktsetup_reportlist", "HTML with embedded TH1 code for the \"report list\" webpage."); setup_menu_entry("Report Template", "tktsetup_rpttplt", "The default ticket report format."); setup_menu_entry("Key Template", "tktsetup_keytplt", "The default color key for reports."); @ </table> | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | setup_menu_entry("Report List Page", "tktsetup_reportlist", "HTML with embedded TH1 code for the \"report list\" webpage."); setup_menu_entry("Report Template", "tktsetup_rpttplt", "The default ticket report format."); setup_menu_entry("Key Template", "tktsetup_keytplt", "The default color key for reports."); @ </table> style_footer(); } /* ** NOTE: When changing the table definition below, also change the ** equivalent definition found in schema.c. */ /* @-comment: ** */ |
︙ | ︙ | |||
84 85 86 87 88 89 90 | @ comment TEXT @ ); @ CREATE TABLE ticketchng( @ -- Do not change any column that begins with tkt_ @ tkt_id INTEGER REFERENCES ticket, @ tkt_rid INTEGER REFERENCES blob, @ tkt_mtime DATE, | < | < | | 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 | @ comment TEXT @ ); @ CREATE TABLE ticketchng( @ -- Do not change any column that begins with tkt_ @ tkt_id INTEGER REFERENCES ticket, @ tkt_rid INTEGER REFERENCES blob, @ tkt_mtime DATE, @ -- Add as many fields as required below this line @ login TEXT, @ username TEXT, @ mimetype TEXT, @ icomment TEXT @ ); @ CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime); ; /* ** Return the ticket table definition */ const char *ticket_table_schema(void){ return db_get("ticket-table", zDefaultTicketTable); } /* ** Common implementation for the ticket setup editor pages. */ static void tktsetup_generic( |
︙ | ︙ | |||
122 123 124 125 126 127 128 | int isSubmit; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } | < < | > | | > | | | | | | | | 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 | int isSubmit; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } if( PB("setup") ){ cgi_redirect("tktsetup"); } isSubmit = P("submit")!=0; z = P("x"); if( z==0 ){ z = db_get(zDbField, zDfltValue); } style_header("Edit %s", zTitle); if( P("clear")!=0 ){ login_verify_csrf_secret(); db_unset(zDbField, 0); if( xRebuild ) xRebuild(); cgi_redirect("tktsetup"); }else if( isSubmit ){ char *zErr = 0; login_verify_csrf_secret(); if( xText && (zErr = xText(z))!=0 ){ @ <p class="tktsetupError">ERROR: %h(zErr)</p> }else{ db_set(zDbField, z, 0); if( xRebuild ) xRebuild(); cgi_redirect("tktsetup"); } } @ <form action="%s(g.zTop)/%s(g.zPath)" method="post"><div> login_insert_csrf_secret(); @ <p>%s(zDesc)</p> @ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea> @ <blockquote><p> @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="clear" value="Revert To Default" /> @ <input type="submit" name="setup" value="Cancel" /> @ </p></blockquote> @ </div></form> @ <hr /> @ <h2>Default %s(zTitle)</h2> @ <blockquote><pre> @ %h(zDfltValue) @ </pre></blockquote> style_footer(); } /* ** WEBPAGE: tktsetup_tab ** Administrative page for defining the "ticket" table used ** to hold ticket information. */ |
︙ | ︙ | |||
298 299 300 301 302 303 304 | 0, 30 ); } static const char zDefaultNew[] = @ <th1> | | < < | | | | > | | | | < < | | | | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | 0, 30 ); } static const char zDefaultNew[] = @ <th1> @ if {![info exists mutype]} {set mutype {[links only]}} @ if {[info exists submit]} { @ set status Open @ if {$mutype eq "HTML"} { @ set mimetype "text/html" @ } elseif {$mutype eq "Wiki"} { @ set mimetype "text/x-fossil-wiki" @ } elseif {$mutype eq {[links only]}} { @ set mimetype "text/x-fossil-plain" @ } else { @ set mimetype "text/plain" @ } @ submit_ticket @ set preview 1 @ } @ </th1> @ <h1 style="text-align: center;">Enter A New Ticket</h1> @ <table cellpadding="5"> @ <tr> @ <td colspan="3"> @ Enter a one-line summary of the ticket:<br /> @ <input type="text" name="title" size="60" value="$<title>" /> @ </td> @ </tr> @ @ <tr> @ <td align="right">Type:</td> @ <td align="left"><th1>combobox type $type_choices 1</th1></td> @ <td align="left">What type of ticket is this?</td> @ </tr> @ @ <tr> @ <td align="right">Version:</td> @ <td align="left"> @ <input type="text" name="foundin" size="20" value="$<foundin>" /> @ </td> @ <td align="left">In what version or build number do you observe @ the problem?</td> @ </tr> @ @ <tr> @ <td align="right">Severity:</td> @ <td align="left"><th1>combobox severity $severity_choices 1</th1></td> @ <td align="left">How debilitating is the problem? How badly does the problem @ affect the operation of the product?</td> @ </tr> @ @ <tr> @ <td align="right">EMail:</td> @ <td align="left"> @ <input type="text" name="private_contact" value="$<private_contact>" @ size="30" /> @ </td> @ <td align="left"><u>Not publicly visible</u> @ Used by developers to contact you with questions.</td> @ </tr> @ @ <tr> @ <td colspan="3"> @ Enter a detailed description of the problem. @ For code defects, be sure to provide details on exactly how @ the problem can be reproduced. Provide as much detail as @ possible. Format: @ <th1>combobox mutype {Wiki HTML {Plain Text} {[links only]}} 1</th1> @ <br /> @ <th1>set nline [linecount $comment 50 10]</th1> @ <textarea name="icomment" cols="80" rows="$nline" @ wrap="virtual" class="wikiedit">$<icomment></textarea><br /> @ </tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr><td colspan="3"> @ Description Preview:<br /><hr /> @ <th1> @ if {$mutype eq "Wiki"} { @ wiki $icomment @ } elseif {$mutype eq "Plain Text"} { @ set r [randhex] @ wiki "<verbatim-$r>[string trimright $icomment]\n</verbatim-$r>" @ } elseif {$mutype eq {[links only]}} { @ set r [randhex] @ wiki "<verbatim-$r links>[string trimright $icomment]\n</verbatim-$r>" @ } else { @ wiki "<nowiki>$icomment\n</nowiki>" @ } @ </th1> @ <hr /></td></tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td><td align="left"> @ <input type="submit" name="preview" value="Preview" /> @ </td> @ <td align="left">See how the description will appear after formatting.</td> @ </tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr> @ <td><td align="left"> @ <input type="submit" name="submit" value="Submit" /> @ </td> @ <td align="left">After filling in the information above, press this @ button to create the new ticket</td> @ </tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td><td align="left"> @ <input type="submit" name="cancel" value="Cancel" /> @ </td> @ <td>Abandon and forget this ticket</td> @ </tr> @ </table> ; /* |
︙ | ︙ | |||
446 447 448 449 450 451 452 | 0, 40 ); } static const char zDefaultView[] = @ <table cellpadding="5"> | | < < > | > > < | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | 0, 40 ); } static const char zDefaultView[] = @ <table cellpadding="5"> @ <tr><td class="tktDspLabel">Ticket UUID:</td> @ <th1> @ if {[info exists tkt_uuid]} { @ if {[hascap s]} { @ html "<td class='tktDspValue' colspan='3'>$tkt_uuid " @ html "($tkt_id)</td></tr>\n" @ } else { @ html "<td class='tktDspValue' colspan='3'>$tkt_uuid</td></tr>\n" @ } @ } else { @ if {[hascap s]} { @ html "<td class='tktDspValue' colspan='3'>Deleted " @ html "(0)</td></tr>\n" @ } else { @ html "<td class='tktDspValue' colspan='3'>Deleted</td></tr>\n" @ } |
︙ | ︙ | |||
527 528 529 530 531 532 533 | @ set alwaysPlaintext [info exists plaintext] @ query {SELECT datetime(tkt_mtime) AS xdate, login AS xlogin, @ mimetype as xmimetype, icomment AS xcomment, @ username AS xusername @ FROM ticketchng @ WHERE tkt_id=$tkt_id AND length(icomment)>0} { @ if {$seenRow} { | | < | < < < | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | @ set alwaysPlaintext [info exists plaintext] @ query {SELECT datetime(tkt_mtime) AS xdate, login AS xlogin, @ mimetype as xmimetype, icomment AS xcomment, @ username AS xusername @ FROM ticketchng @ WHERE tkt_id=$tkt_id AND length(icomment)>0} { @ if {$seenRow} { @ html "<hr />\n" @ } else { @ html "<tr><td class='tktDspLabel'>User Comments:</td></tr>\n" @ html "<tr><td colspan='5' class='tktDspValue'>\n" @ set seenRow 1 @ } @ html "[htmlize $xlogin]" @ if {$xlogin ne $xusername && [string length $xusername]>0} { @ html " (claiming to be [htmlize $xusername])" @ } @ html " added on $xdate:\n" @ if {$alwaysPlaintext || $xmimetype eq "text/plain"} { @ set r [randhex] @ if {$xmimetype ne "text/plain"} {html "([htmlize $xmimetype])\n"} @ wiki "<verbatim-$r>[string trimright $xcomment]</verbatim-$r>\n" @ } elseif {$xmimetype eq "text/x-fossil-wiki"} { @ wiki "<p>\n[string trimright $xcomment]\n</p>\n" @ } elseif {$xmimetype eq "text/html"} { @ wiki "<p><nowiki>\n[string trimright $xcomment]\n</nowiki>\n" @ } else { @ set r [randhex] @ wiki "<verbatim-$r links>[string trimright $xcomment]</verbatim-$r>\n" @ } @ } |
︙ | ︙ | |||
590 591 592 593 594 595 596 | 0, 40 ); } static const char zDefaultEdit[] = @ <th1> | | < < | | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | 0, 40 ); } static const char zDefaultEdit[] = @ <th1> @ if {![info exists mutype]} {set mutype {[links only]}} @ if {![info exists icomment]} {set icomment {}} @ if {![info exists username]} {set username $login} @ if {[info exists submit]} { @ if {$mutype eq "Wiki"} { @ set mimetype text/x-fossil-wiki @ } elseif {$mutype eq "HTML"} { @ set mimetype text/html @ } elseif {$mutype eq {[links only]}} { @ set mimetype text/x-fossil-plain @ } else { @ set mimetype text/plain @ } @ submit_ticket @ set preview 1 @ } @ </th1> @ <table cellpadding="5"> @ <tr><td class="tktDspLabel">Title:</td><td> @ <input type="text" name="title" value="$<title>" size="60" /> @ </td></tr> @ @ <tr><td class="tktDspLabel">Status:</td><td> @ <th1>combobox status $status_choices 1</th1> @ </td></tr> @ @ <tr><td class="tktDspLabel">Type:</td><td> |
︙ | ︙ | |||
641 642 643 644 645 646 647 | @ <tr><td class="tktDspLabel">Subsystem:</td><td> @ <th1>combobox subsystem $subsystem_choices 1</th1> @ </td></tr> @ @ <th1>enable_output [hascap e]</th1> @ <tr><td class="tktDspLabel">Contact:</td><td> @ <input type="text" name="private_contact" size="40" | | | | | | < < | | | | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | @ <tr><td class="tktDspLabel">Subsystem:</td><td> @ <th1>combobox subsystem $subsystem_choices 1</th1> @ </td></tr> @ @ <th1>enable_output [hascap e]</th1> @ <tr><td class="tktDspLabel">Contact:</td><td> @ <input type="text" name="private_contact" size="40" @ value="$<private_contact>" /> @ </td></tr> @ <th1>enable_output 1</th1> @ @ <tr><td class="tktDspLabel">Version Found In:</td><td> @ <input type="text" name="foundin" size="50" value="$<foundin>" /> @ </td></tr> @ @ <tr><td colspan="2"> @ Append Remark with format @ <th1>combobox mutype {Wiki HTML {Plain Text} {[links only]}} 1</th1> @ from @ <input type="text" name="username" value="$<username>" size="30" />:<br /> @ <textarea name="icomment" cols="80" rows="15" @ wrap="virtual" class="wikiedit">$<icomment></textarea> @ </td></tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr><td colspan="2"> @ Description Preview:<br /><hr /> @ <th1> @ if {$mutype eq "Wiki"} { @ wiki $icomment @ } elseif {$mutype eq "Plain Text"} { @ set r [randhex] @ wiki "<verbatim-$r>\n[string trimright $icomment]\n</verbatim-$r>" @ } elseif {$mutype eq {[links only]}} { @ set r [randhex] @ wiki "<verbatim-$r links>\n[string trimright $icomment]</verbatim-$r>" @ } else { @ wiki "<nowiki>\n[string trimright $icomment]\n</nowiki>" @ } @ </th1> @ <hr /> @ </td></tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td align="right"> @ <input type="submit" name="preview" value="Preview" /> @ </td> @ <td align="left">See how the description will appear after formatting.</td> @ </tr> @ @ <th1>enable_output [info exists preview]</th1> @ <tr> @ <td align="right"> @ <input type="submit" name="submit" value="Submit" /> @ </td> @ <td align="left">Apply the changes shown above</td> @ </tr> @ <th1>enable_output 1</th1> @ @ <tr> @ <td align="right"> @ <input type="submit" name="cancel" value="Cancel" /> @ </td> @ <td>Abandon this edit</td> @ </tr> @ @ </table> ; |
︙ | ︙ | |||
901 902 903 904 905 906 907 | login_needed(0); return; } if( P("setup") ){ cgi_redirect("tktsetup"); } | < | | | < | | < | | < | | | | | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 | login_needed(0); return; } if( P("setup") ){ cgi_redirect("tktsetup"); } style_header("Ticket Display On Timelines"); db_begin_transaction(); @ <form action="%s(g.zTop)/tktsetup_timeline" method="post"><div> login_insert_csrf_secret(); @ <hr /> entry_attribute("Ticket Title", 40, "ticket-title-expr", "t", "title", 0); @ <p>An SQL expression in a query against the TICKET table that will @ return the title of the ticket for display purposes.</p> @ <hr /> entry_attribute("Ticket Status", 40, "ticket-status-column", "s", "status", 0); @ <p>The name of the column in the TICKET table that contains the ticket @ status in human-readable form. Case sensitive.</p> @ <hr /> entry_attribute("Ticket Closed", 40, "ticket-closed-expr", "c", "status='Closed'", 0); @ <p>An SQL expression that evaluates to true in a TICKET table query if @ the ticket is closed.</p> @ <hr /> @ <p> @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="setup" value="Cancel" /> @ </p> @ </div></form> db_end_transaction(0); style_footer(); } |
Added src/translate.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Copyright (c) 2002 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** SYNOPSIS: ** ** Input lines that begin with the "@" character are translated into ** either cgi_printf() statements or string literals and the ** translated code is written on standard output. ** ** The problem this program is attempt to solve is as follows: When ** writing CGI programs in C, we typically want to output a lot of HTML ** text to standard output. In pure C code, this involves doing a ** printf() with a big string containing all that text. But we have ** to insert special codes (ex: \n and \") for many common characters, ** which interferes with the readability of the HTML. ** ** This tool allows us to put raw HTML, without the special codes, in ** the middle of a C program. This program then translates the text ** into standard C by inserting all necessary backslashes and other ** punctuation. ** ** Enhancement #1: ** ** If the last non-whitespace character prior to the first "@" of a ** @-block is "=" or "," then the @-block is a string literal initializer ** rather than text that is to be output via cgi_printf(). Render it ** as such. ** ** Enhancement #2: ** ** Comments of the form: "|* @-comment: CC" (where "|" is really "/") ** cause CC to become a comment character for the @-substitution. ** Typical values for CC are "--" (for SQL text) or "#" (for Tcl script) ** or "//" (for C++ code). Lines of subsequent @-blocks that begin with ** CC are omitted from the output. ** ** Enhancement #3: ** ** If a non-enhancement #1 line ends in backslash, the backslash and the ** newline (\n) are not included in the argument to cgi_printf(). This ** is used to split one long output line across multiple source lines. */ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> /* ** Space to hold arguments at the end of the cgi_printf() */ #define MX_ARG_SP 10000 static char zArg[MX_ARG_SP]; static int nArg = 0; /* ** True if we are currently in a cgi_printf() */ static int inPrint = 0; /* ** True if we are currently doing a free string */ static int inStr = 0; /* ** Name of files being processed */ static const char *zInFile = "(stdin)"; /* ** Terminate an active cgi_printf() or free string */ static void end_block(FILE *out){ if( inPrint ){ zArg[nArg] = 0; fprintf(out, "%s);\n", zArg); nArg = 0; inPrint = 0; } } /* ** Translate the input stream into the output stream */ static void trans(FILE *in, FILE *out){ int i, j, k; /* Loop counters */ char c1, c2; /* Characters used to start a comment */ int lastWasEq = 0; /* True if last non-whitespace character was "=" */ int lastWasComma = 0; /* True if last non-whitespace character was "," */ int lineNo = 0; /* Line number */ char zLine[2000]; /* A single line of input */ char zOut[4000]; /* The input line translated into appropriate output */ c1 = c2 = '-'; while( fgets(zLine, sizeof(zLine), in) ){ lineNo++; for(i=0; zLine[i] && isspace(zLine[i]); i++){} if( zLine[i]!='@' ){ if( inPrint || inStr ) end_block(out); fprintf(out,"%s",zLine); /* 0123456789 12345 */ if( strncmp(zLine, "/* @-comment: ", 14)==0 ){ c1 = zLine[14]; c2 = zLine[15]; } i += strlen(&zLine[i]); while( i>0 && isspace(zLine[i-1]) ){ i--; } lastWasEq = i>0 && zLine[i-1]=='='; lastWasComma = i>0 && zLine[i-1]==','; }else if( lastWasEq || lastWasComma){ /* If the last non-whitespace character before the first @ was ** an "="(var init/set) or a ","(const definition in list) then ** generate a string literal. But skip comments ** consisting of all text between c1 and c2 (default "--") ** and end of line. */ int indent, omitline; char *zNewline = "\\n"; i++; if( isspace(zLine[i]) ){ i++; } indent = i - 2; if( indent<0 ) indent = 0; omitline = 0; for(j=0; zLine[i] && zLine[i]!='\r' && zLine[i]!='\n'; i++){ if( zLine[i]==c1 && (c2==' ' || zLine[i+1]==c2) ){ omitline = 1; break; } if( zLine[i]=='\\' && (zLine[i+1]==0 || zLine[i+1]=='\r' || zLine[i+1]=='\n') ){ zLine[i] = 0; zNewline = ""; /* fprintf(stderr, "%s:%d: omit newline\n", zInFile, lineNo); */ break; } if( zLine[i]=='\\' || zLine[i]=='"' ){ zOut[j++] = '\\'; } zOut[j++] = zLine[i]; } if( zNewline[0] ) while( j>0 && isspace(zOut[j-1]) ){ j--; } zOut[j] = 0; if( j<=0 && omitline ){ fprintf(out,"\n"); }else{ fprintf(out,"%*s\"%s%s\"\n",indent, "", zOut, zNewline); } }else{ /* Otherwise (if the last non-whitespace was not '=') then generate ** a cgi_printf() statement whose format is the text following the '@'. ** Substrings of the form "%C(...)" (where C is any sequence of ** characters other than \000 and '(') will put "%C" in the ** format and add the "(...)" as an argument to the cgi_printf call. */ const char *zNewline = "\\n"; int indent; int nC; char c; i++; if( isspace(zLine[i]) ){ i++; } indent = i; for(j=0; zLine[i] && zLine[i]!='\r' && zLine[i]!='\n'; i++){ if( zLine[i]=='\\' && (!zLine[i+1] || zLine[i+1]=='\r' || zLine[i+1]=='\n') ){ zNewline = ""; break; } if( zLine[i]=='"' || zLine[i]=='\\' ){ zOut[j++] = '\\'; } zOut[j++] = zLine[i]; if( zLine[i]!='%' || zLine[i+1]=='%' || zLine[i+1]==0 ) continue; for(nC=1; zLine[i+nC] && zLine[i+nC]!='('; nC++){} if( zLine[i+nC]!='(' || !isalpha(zLine[i+nC-1]) ) continue; while( --nC ) zOut[j++] = zLine[++i]; zArg[nArg++] = ','; k = 0; i++; while( (c = zLine[i])!=0 ){ zArg[nArg++] = c; if( c==')' ){ k--; if( k==0 ) break; }else if( c=='(' ){ k++; } i++; } } zOut[j] = 0; if( !inPrint ){ fprintf(out,"%*scgi_printf(\"%s%s\"",indent-2,"", zOut, zNewline); inPrint = 1; }else{ fprintf(out,"\n%*s\"%s%s\"",indent+5, "", zOut, zNewline); } } } } static void print_source_ref(const char *zSrcFile, FILE *out){ /* Set source line reference to the original source file. * This makes compiler show the original file name in the compile error * messages, instead of referring to the translated file. * NOTE: This somewhat complicates stepping in debugger, as the resuling * code would not match the referenced sources. */ #ifndef FOSSIL_DEBUG const char *arg; if( !*zSrcFile ){ return; } fprintf(out,"#line 1 \""); for(arg=zSrcFile; *arg; arg++){ if( *arg!='\\' ){ fprintf(out,"%c", *arg); }else{ fprintf(out,"\\\\"); } } fprintf(out,"\"\n"); #endif } int main(int argc, char **argv){ if( argc==2 ){ FILE *in = fopen(argv[1], "r"); if( in==0 ){ fprintf(stderr,"can not open %s\n", argv[1]); exit(1); } zInFile = argv[1]; print_source_ref(zInFile, stdout); trans(in, stdout); fclose(in); }else{ trans(stdin, stdout); } return 0; } |
Changes to src/undo.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | int new_exists; int old_exe; int new_exe; int new_link; int old_link; Blob current; Blob new; | | < < | | 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 | int new_exists; int old_exe; int new_exe; int new_link; int old_link; Blob current; Blob new; zFullname = mprintf("%s/%s", g.zLocalRoot, zPathname); old_link = db_column_int(&q, 3); new_exists = file_size(zFullname, RepoFILE)>=0; new_link = file_islink(0); if( new_exists ){ blob_read_from_file(¤t, zFullname, RepoFILE); new_exe = file_isexe(0,0); }else{ blob_zero(¤t); new_exe = 0; } blob_zero(&new); old_exists = db_column_int(&q, 1); old_exe = db_column_int(&q, 2); if( old_exists ){ db_ephemeral_blob(&q, 0, &new); } if( old_exists ){ if( new_exists ){ fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname); }else{ fossil_print("NEW %s\n", zPathname); } if( new_exists && (new_link || old_link) ){ file_delete(zFullname); |
︙ | ︙ | |||
164 165 166 167 168 169 170 | "INSERT OR IGNORE INTO stashfile SELECT * FROM undo_stashfile;" ); } } ncid = db_lget_int("undo_checkout", 0); ucid = db_lget_int("checkout", 0); db_lset_int("undo_checkout", ucid); | | | | 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 | "INSERT OR IGNORE INTO stashfile SELECT * FROM undo_stashfile;" ); } } ncid = db_lget_int("undo_checkout", 0); ucid = db_lget_int("checkout", 0); db_lset_int("undo_checkout", ucid); db_lset_int("checkout", ncid); } /* ** Reset the undo memory. */ void undo_reset(void){ static const char zSql[] = @ DROP TABLE IF EXISTS undo; @ DROP TABLE IF EXISTS undo_vfile; @ DROP TABLE IF EXISTS undo_vmerge; @ DROP TABLE IF EXISTS undo_stash; @ DROP TABLE IF EXISTS undo_stashfile; ; db_multi_exec(zSql /*works-like:""*/); db_lset_int("undo_available", 0); db_lset_int("undo_checkout", 0); } /* ** The following variable stores the original command-line of the ** command that is a candidate to be undone. |
︙ | ︙ | |||
235 236 237 238 239 240 241 | @ content BLOB -- Saved content @ ); @ CREATE TABLE localdb.undo_vfile AS SELECT * FROM vfile; @ CREATE TABLE localdb.undo_vmerge AS SELECT * FROM vmerge; ; if( undoDisable ) return; undo_reset(); | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | @ content BLOB -- Saved content @ ); @ CREATE TABLE localdb.undo_vfile AS SELECT * FROM vfile; @ CREATE TABLE localdb.undo_vmerge AS SELECT * FROM vmerge; ; if( undoDisable ) return; undo_reset(); db_multi_exec(zSql/*works-like:""*/); cid = db_lget_int("checkout", 0); db_lset_int("undo_checkout", cid); db_lset_int("undo_available", 1); db_lset("undo_cmdline", undoCmd); undoActive = 1; } |
︙ | ︙ | |||
267 268 269 270 271 272 273 | ** Save the current content of the file zPathname so that it ** will be undoable. The name is relative to the root of the ** tree. */ void undo_save(const char *zPathname){ if( undoDisable ) return; if( undo_maybe_save(zPathname, -1)!=UNDO_SAVED_OK ){ | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | ** Save the current content of the file zPathname so that it ** will be undoable. The name is relative to the root of the ** tree. */ void undo_save(const char *zPathname){ if( undoDisable ) return; if( undo_maybe_save(zPathname, -1)!=UNDO_SAVED_OK ){ fossil_panic("failed to save undo information for path: %s", zPathname); } } /* ** Possibly save the current content of the file zPathname so ** that it will be undoable. The name is relative to the root |
︙ | ︙ | |||
423 424 425 426 427 428 429 | /* ** COMMAND: undo ** COMMAND: redo* ** ** Usage: %fossil undo ?OPTIONS? ?FILENAME...? ** or: %fossil redo ?OPTIONS? ?FILENAME...? ** | | | | < < < | | | | | | < < < < < < < | < < < < | | | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | /* ** COMMAND: undo ** COMMAND: redo* ** ** Usage: %fossil undo ?OPTIONS? ?FILENAME...? ** or: %fossil redo ?OPTIONS? ?FILENAME...? ** ** Undo the changes to the working checkout caused by the most recent ** of the following operations: ** ** (1) fossil update (5) fossil stash apply ** (2) fossil merge (6) fossil stash drop ** (3) fossil revert (7) fossil stash goto ** (4) fossil stash pop ** ** The "fossil clean" operation can also be undone; however, this is ** currently limited to files that are less than 10MiB in size. ** ** If FILENAME is specified then restore the content of the named ** file(s) but otherwise leave the update or merge or revert in effect. ** The redo command undoes the effect of the most recent undo. ** ** If the -n|--dry-run option is present, no changes are made and instead ** the undo or redo command explains what actions the undo or redo would ** have done had the -n|--dry-run been omitted. ** ** A single level of undo/redo is supported. The undo/redo stack ** is cleared by the commit and checkout commands. ** ** Options: ** -n|--dry-run do not make changes but show what would be done ** ** See also: commit, status */ void undo_cmd(void){ int isRedo = g.argv[1][0]=='r'; int undo_available; int dryRunFlag = find_option("dry-run", "n", 0)!=0; const char *zCmd = isRedo ? "redo" : "undo"; |
︙ | ︙ |
Changes to src/unicode.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | 0x00217801, 0x00234C31, 0x0024E803, 0x0024F812, 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, 0x0027C802, 0x0027E802, 0x0027F402, 0x00280403, 0x0028F001, 0x0028F805, 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D402, 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, 0x002B8802, 0x002BC002, 0x002BE806, 0x002C0403, 0x002CF001, | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | | | | | | < | | | | | < | | | | | | | < | | 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 | 0x00217801, 0x00234C31, 0x0024E803, 0x0024F812, 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, 0x0027C802, 0x0027E802, 0x0027F402, 0x00280403, 0x0028F001, 0x0028F805, 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D402, 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, 0x002B8802, 0x002BC002, 0x002BE806, 0x002C0403, 0x002CF001, 0x002CF807, 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, 0x002FCC08, 0x00300005, 0x0030F807, 0x00311803, 0x00312804, 0x00315402, 0x00318802, 0x0031FC01, 0x00320404, 0x0032F001, 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, 0x00340004, 0x0034EC02, 0x0034F807, 0x00351803, 0x00352804, 0x00353C01, 0x00355C01, 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, 0x00621402, 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, 0x00677822, 0x00685C05, 0x00687802, 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, 0x006AC00F, 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x0073DC03, 0x0077003A, 0x0077EC05, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, 0x007FB403, 0x007FF402, 0x00800065, 0x0081980A, 0x0081E805, 0x00822805, 0x00828020, 0x00834021, 0x00840002, 0x00840C04, 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, 0x00852804, 0x00853C01, 0x00862802, 0x00864297, 0x0091000B, 0x0092704E, 0x00940276, 0x009E53E0, 0x00ADD820, 0x00AE6031, 0x00AF2835, 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, 0x00B5FC01, 0x00B7804F, 0x00B8C01F, 0x00BA001A, 0x00BA6C59, 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, 0x029A7802, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, 0x02A1D004, 0x02A20002, 0x02A2D012, 0x02A33802, 0x02A38012, 0x02A3E003, 0x02A3F001, 0x02A3FC01, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, 0x02A6CC1B, 0x02A77802, 0x02A79401, 0x02A8A40E, 0x02A90C01, 0x02A93002, 0x02A97004, 0x02A9DC03, 0x02A9EC03, 0x02AAC001, 0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, 0x02ABD402, 0x02AD6C01, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, 0x03F7F002, 0x03F8001A, 0x03F88033, 0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, 0x0404DC09, 0x0405E411, 0x04063003, 0x0406400C, 0x04068001, 0x0407402E, 0x040B8001, 0x040DD805, 0x040E7C01, 0x040F4001, 0x0415BC01, 0x04215C01, 0x0421DC02, 0x04247C01, 0x0424FC01, 0x04280403, 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, 0x0429FC01, 0x042B2001, 0x042B9402, 0x042BC007, 0x042CE407, 0x042E6404, 0x04349004, 0x043D180B, 0x043D5405, 0x04400003, 0x0440E016, 0x0441FC04, 0x0442C012, 0x04433401, 0x04440003, 0x04449C0E, 0x04450004, 0x04451402, 0x0445CC03, 0x04460003, 0x0446CC0E, 0x04471409, 0x04476C01, 0x04477403, 0x0448B013, 0x044AA401, 0x044B7C0C, 0x044C0004, 0x044CEC02, 0x044CF807, 0x044D1C02, 0x044D2C03, 0x044D5C01, 0x044D8802, 0x044D9807, 0x044DC005, 0x0450D412, 0x04512C05, 0x04516C01, 0x04517402, 0x0452C014, 0x04531801, 0x0456BC07, 0x0456E020, 0x04577002, 0x0458C014, 0x0459800D, 0x045AAC0D, 0x045C740F, 0x045CF004, 0x0460B010, 0x0468040A, 0x0468CC07, 0x0468EC0D, 0x0469440B, 0x046A2813, 0x046A7805, 0x0470BC08, 0x0470E008, 0x04710405, 0x0471C002, 0x04724816, 0x0472A40E, 0x0474C406, 0x0474E801, 0x0474F002, 0x0474FC07, 0x04751C01, 0x04762805, 0x04764002, 0x04764C05, 0x047BCC06, 0x0491C005, 0x05A9B802, 0x05ABC006, 0x05ACC010, 0x05AD1002, 0x05BA5C04, 0x05BD442E, 0x05BE3C04, 0x06F27008, 0x074000F6, 0x07440027, 0x0744A4C0, 0x07480046, 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, 0x075F0C01, 0x0760028C, 0x076A6C05, 0x076A840F, 0x07800007, 0x07802011, 0x07806C07, 0x07808C02, 0x07809805, 0x07A34007, 0x07A51007, 0x07A57802, 0x07B2B001, 0x07B2C001, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, 0x07C2C40F, 0x07C3040F, 0x07C34425, 0x07C4405C, 0x07C5C03D, 0x07C7981D, 0x07C8402C, 0x07C90009, 0x07C94002, 0x07C98006, 0x07CC03D5, 0x07DB800D, 0x07DBC00A, 0x07DC0074, 0x07DE0059, 0x07E0000C, 0x07E04038, 0x07E1400A, 0x07E18028, 0x07E2401E, 0x07E4000C, 0x07E4402F, 0x07E50031, 0x07E5CC04, 0x07E5E801, 0x07E5F027, 0x07E6C00A, 0x07E70003, 0x07E74030, 0x07E9800E, 0x38000401, 0x38008060, 0x380400F0, }; static const unsigned int aAscii[4] = { 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, }; if( (unsigned int)c<128 ){ return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 ); |
︙ | ︙ | |||
179 180 181 182 183 184 185 | ** If the argument is a codepoint corresponding to a lowercase letter ** in the ASCII range with a diacritic added, return the codepoint ** of the ASCII letter only. For example, if passed 235 - "LATIN ** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER ** E"). The resuls of passing a codepoint that corresponds to an ** uppercase letter are undefined. */ | | | | | < | | | < | | | < < | | < | < | < < | < < > | < < | < < < < < > | < < | < | | | | 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 256 257 | ** If the argument is a codepoint corresponding to a lowercase letter ** in the ASCII range with a diacritic added, return the codepoint ** of the ASCII letter only. For example, if passed 235 - "LATIN ** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER ** E"). The resuls of passing a codepoint that corresponds to an ** uppercase letter are undefined. */ static int unicode_remove_diacritic(int c){ static const unsigned short aDia[] = { 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62924, 63050, 63082, 63274, 63390, }; static const char aChar[] = { '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', 'e', 'i', 'o', 'u', 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; int iRes = 0; int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; int iLo = 0; while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; if( key >= aDia[iTest] ){ iRes = iTest; iLo = iTest+1; }else{ iHi = iTest-1; } } assert( key>=aDia[iRes] ); return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); } /* ** Return true if the argument interpreted as a unicode codepoint ** is a diacritical modifier character. */ int unicode_is_diacritic(int c){ unsigned int mask0 = 0x08029FDF; unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? (mask0 & (1 << (c-768))) : (mask1 & (1 << (c-768-32))); } /* ** Interpret the argument as a unicode codepoint. If the codepoint ** is an upper case character that has a lower case equivalent, ** return the codepoint corresponding to the lower case version. ** Otherwise, return a copy of the argument. ** ** The results are undefined if the value passed to this function ** is less than zero. */ int unicode_fold(int c, int bRemoveDiacritic){ /* Each entry in the following array defines a rule for folding a range ** of codepoints to lower case. The rule applies to a range of nRange ** codepoints starting at codepoint iCode. ** ** If the least significant bit in flags is clear, then the rule applies ** to all nRange codepoints (i.e. all nRange codepoints are upper case and ** need to be folded). Or, if it is set, then the rule only applies to |
︙ | ︙ | |||
291 292 293 294 295 296 297 | static const struct TableEntry { unsigned short iCode; unsigned char flags; unsigned char nRange; } aEntry[] = { {65, 14, 26}, {181, 66, 1}, {192, 14, 23}, {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | | | | | | | | < | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | static const struct TableEntry { unsigned short iCode; unsigned char flags; unsigned char nRange; } aEntry[] = { {65, 14, 26}, {181, 66, 1}, {192, 14, 23}, {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, {313, 1, 16}, {330, 1, 46}, {376, 152, 1}, {377, 1, 6}, {383, 140, 1}, {385, 52, 1}, {386, 1, 4}, {390, 46, 1}, {391, 0, 1}, {393, 44, 2}, {395, 0, 1}, {398, 34, 1}, {399, 40, 1}, {400, 42, 1}, {401, 0, 1}, {403, 44, 1}, {404, 48, 1}, {406, 54, 1}, {407, 50, 1}, {408, 0, 1}, {412, 54, 1}, {413, 56, 1}, {415, 58, 1}, {416, 1, 6}, {422, 62, 1}, {423, 0, 1}, {425, 62, 1}, {428, 0, 1}, {430, 62, 1}, {431, 0, 1}, {433, 60, 2}, {435, 1, 4}, {439, 64, 1}, {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, {497, 2, 1}, {498, 1, 4}, {502, 158, 1}, {503, 170, 1}, {504, 1, 40}, {544, 146, 1}, {546, 1, 18}, {570, 74, 1}, {571, 0, 1}, {573, 144, 1}, {574, 72, 1}, {577, 0, 1}, {579, 142, 1}, {580, 30, 1}, {581, 32, 1}, {582, 1, 10}, {837, 38, 1}, {880, 1, 4}, {886, 0, 1}, {895, 38, 1}, {902, 20, 1}, {904, 18, 3}, {908, 28, 1}, {910, 26, 2}, {913, 14, 17}, {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, {976, 176, 1}, {977, 178, 1}, {981, 182, 1}, {982, 180, 1}, {984, 1, 24}, {1008, 172, 1}, {1009, 174, 1}, {1012, 166, 1}, {1013, 164, 1}, {1015, 0, 1}, {1017, 188, 1}, {1018, 0, 1}, {1021, 146, 3}, {1024, 36, 16}, {1040, 14, 32}, {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, {1217, 1, 14}, {1232, 1, 96}, {1329, 24, 38}, {4256, 70, 38}, {4295, 70, 1}, {4301, 70, 1}, {5112, 186, 6}, {7296, 122, 1}, {7297, 124, 1}, {7298, 126, 1}, {7299, 130, 2}, {7301, 128, 1}, {7302, 132, 1}, {7303, 134, 1}, {7304, 96, 1}, {7312, 138, 43}, {7357, 138, 3}, {7680, 1, 150}, {7835, 168, 1}, {7838, 116, 1}, {7840, 1, 96}, {7944, 186, 8}, {7960, 186, 6}, {7976, 186, 8}, {7992, 186, 8}, {8008, 186, 6}, {8025, 187, 8}, {8040, 186, 8}, {8072, 186, 8}, {8088, 186, 8}, {8104, 186, 8}, {8120, 186, 2}, {8122, 162, 2}, {8124, 184, 1}, {8126, 120, 1}, {8136, 160, 4}, {8140, 184, 1}, {8152, 186, 2}, {8154, 156, 2}, {8168, 186, 2}, {8170, 154, 2}, {8172, 188, 1}, {8184, 148, 2}, {8186, 150, 2}, {8188, 184, 1}, {8486, 118, 1}, {8490, 112, 1}, {8491, 114, 1}, {8498, 12, 1}, {8544, 8, 16}, {8579, 0, 1}, {9398, 10, 26}, {11264, 24, 47}, {11360, 0, 1}, {11362, 108, 1}, {11363, 136, 1}, {11364, 110, 1}, {11367, 1, 6}, {11373, 104, 1}, {11374, 106, 1}, {11375, 100, 1}, {11376, 102, 1}, {11378, 0, 1}, {11381, 0, 1}, {11390, 98, 2}, {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, {42560, 1, 46}, {42624, 1, 28}, {42786, 1, 14}, {42802, 1, 62}, {42873, 1, 4}, {42877, 94, 1}, {42878, 1, 10}, {42891, 0, 1}, {42893, 86, 1}, {42896, 1, 4}, {42902, 1, 20}, {42922, 80, 1}, {42923, 76, 1}, {42924, 78, 1}, {42925, 82, 1}, {42926, 80, 1}, {42928, 90, 1}, {42929, 84, 1}, {42930, 88, 1}, {42931, 68, 1}, {42932, 1, 6}, {43888, 92, 80}, {65313, 14, 26}, }; static const unsigned short aiOff[] = { 1, 2, 8, 15, 16, 26, 28, 32, 34, 37, 38, 40, 48, 63, 64, 69, 71, 79, 80, 116, 202, 203, 205, 206, 207, 209, 210, 211, 213, 214, 217, 218, 219, 775, 928, 7264, 10792, 10795, 23217, 23221, 23228, 23231, 23254, 23256, 23275, 23278, 26672, 30204, 35267, 54721, 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, 57921, 58019, 58363, 59314, 59315, 59324, 59325, 59326, 59332, 59356, 61722, 62528, 65268, 65341, 65373, 65406, 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, 65514, 65521, 65527, 65528, 65529, }; int ret = c; assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); if( c<128 ){ |
︙ | ︙ | |||
401 402 403 404 405 406 407 | assert( iRes>=0 && c>=aEntry[iRes].iCode ); p = &aEntry[iRes]; if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; assert( ret>0 ); } | < | < | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | assert( iRes>=0 && c>=aEntry[iRes].iCode ); p = &aEntry[iRes]; if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; assert( ret>0 ); } if( bRemoveDiacritic ) ret = unicode_remove_diacritic(ret); } else if( c>=66560 && c<66600 ){ ret = c + 40; } else if( c>=66736 && c<66772 ){ ret = c + 40; |
︙ | ︙ |
Changes to src/unversioned.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** This file contains code used to implement unversioned file interfaces. */ #include "config.h" #include <assert.h> | > > > > | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** ******************************************************************************* ** ** This file contains code used to implement unversioned file interfaces. */ #include "config.h" #include <assert.h> #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #include "unversioned.h" #include <time.h> /* ** SQL code to implement the tables needed by the unversioned. */ static const char zUnversionedInit[] = |
︙ | ︙ | |||
55 56 57 58 59 60 61 | ** in exactly the same way. ** ** If debugFlag is set, force the value to be recomputed and write ** the text of the hashed string to stdout. */ const char *unversioned_content_hash(int debugFlag){ const char *zHash = debugFlag ? 0 : db_get("uv-hash", 0); | | < < < | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | ** in exactly the same way. ** ** If debugFlag is set, force the value to be recomputed and write ** the text of the hashed string to stdout. */ const char *unversioned_content_hash(int debugFlag){ const char *zHash = debugFlag ? 0 : db_get("uv-hash", 0); if( zHash==0 ){ Stmt q; db_prepare(&q, "SELECT printf('%%s %%s %%s\n',name,datetime(mtime,'unixepoch'),hash)" " FROM unversioned" " WHERE hash IS NOT NULL" " ORDER BY name" ); |
︙ | ︙ | |||
81 82 83 84 85 86 87 | } return zHash; } /* ** Initialize pContent to be the content of an unversioned file zName. ** | | < < | | < | < < < < < < < < < < < < | | 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 | } return zHash; } /* ** Initialize pContent to be the content of an unversioned file zName. ** ** Return 0 on success. Return 1 if zName is not found. */ int unversioned_content(const char *zName, Blob *pContent){ Stmt q; int rc = 1; blob_init(pContent, 0, 0); db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE name=%Q", zName); if( db_step(&q)==SQLITE_ROW ){ db_column_blob(&q, 1, pContent); if( db_column_int(&q, 0)==1 ){ blob_uncompress(pContent, pContent); } rc = 0; } db_finalize(&q); return rc; } /* ** Write unversioned content into the database. */ static void unversioned_write( const char *zUVFile, /* Name of the unversioned file */ Blob *pContent, /* File content */ sqlite3_int64 mtime /* Modification time */ ){ Stmt ins; Blob compressed; Blob hash; db_prepare(&ins, "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)" " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)" ); sha1sum_blob(pContent, &hash); blob_compress(pContent, &compressed); db_bind_text(&ins, ":name", zUVFile); db_bind_int(&ins, ":rcvid", g.rcvid); db_bind_int64(&ins, ":mtime", mtime); db_bind_text(&ins, ":hash", blob_str(&hash)); db_bind_int(&ins, ":sz", blob_size(pContent)); if( blob_size(&compressed) <= 0.8*blob_size(pContent) ){ |
︙ | ︙ | |||
154 155 156 157 158 159 160 | db_finalize(&ins); db_unset("uv-hash", 0); } /* ** Check the status of unversioned file zName. "mtime" and "zHash" are the | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | db_finalize(&ins); db_unset("uv-hash", 0); } /* ** Check the status of unversioned file zName. "mtime" and "zHash" are the ** time of last change and SHA1 hash of a copy of this file on a remote ** server. Return an integer status code as follows: ** ** 0: zName does not exist in the unversioned table. ** 1: zName exists and should be replaced by the mtime/zHash remote. ** 2: zName exists and is the same as zHash but has a older mtime ** 3: zName exists and is identical to mtime/zHash in all respects. ** 4: zName exists and is the same as zHash but has a newer mtime. ** 5: zName exists and should override the mtime/zHash remote. */ int unversioned_status( const char *zName, sqlite3_int64 mtime, |
︙ | ︙ | |||
198 199 200 201 202 203 204 | /* ** Extract command-line options for the "revert" and "sync" subcommands */ static int unversioned_sync_flags(unsigned syncFlags){ if( find_option("verbose","v",0)!=0 ){ syncFlags |= SYNC_UV_TRACE | SYNC_VERBOSE; } | | | | 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 | /* ** Extract command-line options for the "revert" and "sync" subcommands */ static int unversioned_sync_flags(unsigned syncFlags){ if( find_option("verbose","v",0)!=0 ){ syncFlags |= SYNC_UV_TRACE | SYNC_VERBOSE; } if( find_option("dryrun","n",0)!=0 ){ syncFlags |= SYNC_UV_DRYRUN | SYNC_UV_TRACE | SYNC_VERBOSE; } return syncFlags; } /* ** Return true if the zName contains any whitespace */ static int contains_whitespace(const char *zName){ while( zName[0] ){ if( fossil_isspace(zName[0]) ) return 1; zName++; } return 0; } /* ** COMMAND: uv* ** COMMAND: unversioned ** ** Usage: %fossil unversioned SUBCOMMAND ARGS... ** or: %fossil uv SUBCOMMAND ARGS.. ** ** Unversioned files (UV-files) are artifacts that are synced and are available ** for download but which do not preserve history. Only the most recent version |
︙ | ︙ | |||
250 251 252 253 254 255 256 | ** edit FILE Bring up FILE in a text editor for modification. ** ** export FILE OUTPUT Write the content of FILE into OUTPUT on disk ** ** list | ls Show all unversioned files held in the local ** repository. ** | < < < < < < < | < < < < < | > < | < > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | ** edit FILE Bring up FILE in a text editor for modification. ** ** export FILE OUTPUT Write the content of FILE into OUTPUT on disk ** ** list | ls Show all unversioned files held in the local ** repository. ** ** revert ?URL? Restore the state of all unversioned files in the ** local repository to match the remote repository ** URL. ** ** Options: ** -v|--verbose Extra diagnostic output ** -n|--dryrun Show what would have happened ** ** remove|rm|delete FILE ... ** Remove unversioned files from the local repository. ** Changes are not pushed to other repositories until ** the next sync. ** ** sync ?URL? Synchronize the state of all unversioned files with ** the remote repository URL. The most recent version ** of each file is propagated to all repositories and ** all prior versions are permanently forgotten. ** ** Options: ** -v|--verbose Extra diagnostic output ** -n|--dryrun Show what would have happened ** ** touch FILE ... Update the TIMESTAMP on all of the listed files ** ** Options: ** ** --mtime TIMESTAMP Use TIMESTAMP instead of "now" for the "add", ** "edit", "remove", and "touch" subcommands. */ void unversioned_cmd(void){ const char *zCmd; int nCmd; const char *zMtime = find_option("mtime", 0, 1); sqlite3_int64 mtime; db_find_and_open_repository(0, 0); unversioned_schema(); zCmd = g.argc>=3 ? g.argv[2] : "x"; nCmd = (int)strlen(zCmd); if( zMtime==0 ){ mtime = time(0); }else{ mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime); if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime); } if( memcmp(zCmd, "add", nCmd)==0 ){ const char *zError = 0; const char *zIn; const char *zAs; Blob file; int i; zAs = find_option("as",0,1); if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE"); verify_all_options(); db_begin_transaction(); content_rcvid_init("#!fossil unversioned add"); for(i=3; i<g.argc; i++){ zIn = zAs ? zAs : g.argv[i]; if( zIn[0]==0 ){ zError = "be empty string"; }else if( zIn[0]=='/' ){ |
︙ | ︙ | |||
338 339 340 341 342 343 344 | } blob_init(&file,0,0); blob_read_from_file(&file, g.argv[i], ExtFILE); unversioned_write(zIn, &file, mtime); blob_reset(&file); } db_end_transaction(0); | | | | < | < | | | | | | < < < < < < < < < < < < | < | < | | | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | } blob_init(&file,0,0); blob_read_from_file(&file, g.argv[i], ExtFILE); unversioned_write(zIn, &file, mtime); blob_reset(&file); } db_end_transaction(0); }else if( memcmp(zCmd, "cat", nCmd)==0 ){ int i; verify_all_options(); db_begin_transaction(); for(i=3; i<g.argc; i++){ Blob content; if( unversioned_content(g.argv[i], &content)==0 ){ blob_write_to_file(&content, "-"); } blob_reset(&content); } db_end_transaction(0); }else if( memcmp(zCmd, "edit", nCmd)==0 ){ const char *zEditor; /* Name of the text-editor command */ const char *zTFile; /* Temporary file */ const char *zUVFile; /* Name of the unversioned file */ char *zCmd; /* Command to run the text editor */ Blob content; /* Content of the unversioned file */ verify_all_options(); if( g.argc!=4) usage("edit UVFILE"); zUVFile = g.argv[3]; zEditor = fossil_text_editor(); if( zEditor==0 ) fossil_fatal("no text editor - set the VISUAL env variable"); zTFile = fossil_temp_filename(); if( zTFile==0 ) fossil_fatal("cannot find a temporary filename"); db_begin_transaction(); content_rcvid_init("#!fossil unversioned edit"); if( unversioned_content(zUVFile, &content) ){ fossil_fatal("no such uv-file: %Q", zUVFile); } if( looks_like_binary(&content) ){ fossil_fatal("cannot edit binary content"); } #if defined(_WIN32) || defined(__CYGWIN__) blob_add_cr(&content); #endif blob_write_to_file(&content, zTFile); zCmd = mprintf("%s \"%s\"", zEditor, zTFile); if( fossil_system(zCmd) ){ fossil_fatal("editor aborted: %Q", zCmd); } fossil_free(zCmd); blob_reset(&content); blob_read_from_file(&content, zTFile, ExtFILE); #if defined(_WIN32) || defined(__CYGWIN__) blob_to_lf_only(&content); #endif file_delete(zTFile); if( zMtime==0 ) mtime = time(0); unversioned_write(zUVFile, &content, mtime); db_end_transaction(0); blob_reset(&content); }else if( memcmp(zCmd, "export", nCmd)==0 ){ Blob content; verify_all_options(); if( g.argc!=5 ) usage("export UVFILE OUTPUT"); if( unversioned_content(g.argv[3], &content) ){ fossil_fatal("no such uv-file: %Q", g.argv[3]); } blob_write_to_file(&content, g.argv[4]); blob_reset(&content); }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ /* Show the hash value used during uv sync */ int debugFlag = find_option("debug",0,0)!=0; fossil_print("%s\n", unversioned_content_hash(debugFlag)); }else if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){ Stmt q; int allFlag = find_option("all","a",0)!=0; int longFlag = find_option("l",0,0)!=0 || (nCmd>1 && zCmd[1]=='i'); verify_all_options(); if( !longFlag ){ if( allFlag ){ db_prepare(&q, "SELECT name FROM unversioned ORDER BY name"); }else{ db_prepare(&q, "SELECT name FROM unversioned WHERE hash IS NOT NULL" " ORDER BY name"); } while( db_step(&q)==SQLITE_ROW ){ fossil_print("%s\n", db_column_text(&q,0)); } }else{ db_prepare(&q, "SELECT hash, datetime(mtime,'unixepoch'), sz, length(content), name" " FROM unversioned" " ORDER BY name;" ); while( db_step(&q)==SQLITE_ROW ){ const char *zHash = db_column_text(&q, 0); const char *zNoContent = ""; if( zHash==0 ){ if( !allFlag ) continue; zHash = "(deleted)"; |
︙ | ︙ | |||
461 462 463 464 465 466 467 | db_column_int(&q,3), db_column_text(&q,4), zNoContent ); } } db_finalize(&q); | < | < | | | | < < < < < < < < < < < < < < < | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | db_column_int(&q,3), db_column_text(&q,4), zNoContent ); } } db_finalize(&q); }else if( memcmp(zCmd, "revert", nCmd)==0 ){ unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED|SYNC_UV_REVERT); g.argv[1] = "sync"; g.argv[2] = "--uv-noop"; sync_unversioned(syncFlags); }else if( memcmp(zCmd, "remove", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 || memcmp(zCmd, "delete", nCmd)==0 ){ int i; verify_all_options(); db_begin_transaction(); for(i=3; i<g.argc; i++){ db_multi_exec( "UPDATE unversioned" " SET hash=NULL, content=NULL, mtime=%lld, sz=0 WHERE name=%Q", mtime, g.argv[i] ); } db_unset("uv-hash", 0); db_end_transaction(0); }else if( memcmp(zCmd,"sync",nCmd)==0 ){ unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED); g.argv[1] = "sync"; g.argv[2] = "--uv-noop"; sync_unversioned(syncFlags); }else if( memcmp(zCmd, "touch", nCmd)==0 ){ int i; verify_all_options(); db_begin_transaction(); for(i=3; i<g.argc; i++){ db_multi_exec( "UPDATE unversioned SET mtime=%lld WHERE name=%Q", mtime, g.argv[i] |
︙ | ︙ | |||
540 541 542 543 544 545 546 | int n = 0; const char *zOrderBy = "name"; int showDel = 0; char zSzName[100]; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } | < < | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | int n = 0; const char *zOrderBy = "name"; int showDel = 0; char zSzName[100]; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_header("Unversioned Files"); if( !db_table_exists("repository","unversioned") ){ @ No unversioned files on this server style_footer(); return; } if( PB("byage") ) zOrderBy = "mtime DESC"; if( PB("showdel") ) showDel = 1; db_prepare(&q, "SELECT" " name," |
︙ | ︙ | |||
569 570 571 572 573 574 575 | ); iNow = db_int64(0, "SELECT strftime('%%s','now');"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); sqlite3_int64 mtime = db_column_int(&q, 1); const char *zHash = db_column_text(&q, 2); int isDeleted = zHash==0; | < < < | < | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | ); iNow = db_int64(0, "SELECT strftime('%%s','now');"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); sqlite3_int64 mtime = db_column_int(&q, 1); const char *zHash = db_column_text(&q, 2); int isDeleted = zHash==0; int fullSize = db_column_int(&q, 3); char *zAge = human_readable_age((iNow - mtime)/86400.0); const char *zLogin = db_column_text(&q, 4); int rcvid = db_column_int(&q,5); if( zLogin==0 ) zLogin = ""; if( (n++)==0 ){ style_table_sorter(); @ <div class="uvlist"> @ <table cellpadding="2" cellspacing="0" border="1" class='sortable' \ @ data-column-types='tkKttn' data-init-sort='1'> @ <thead><tr> @ <th> Name @ <th> Age @ <th> Size @ <th> User @ <th> SHA1 if( g.perm.Admin ){ @ <th> rcvid } @ </tr></thead> @ <tbody> } @ <tr> |
︙ | ︙ | |||
610 611 612 613 614 615 616 | iTotalSz += fullSize; cnt++; @ <td> <a href='%R/uv/%T(zName)'>%h(zName)</a> </td> } @ <td data-sortkey='%016llx(-mtime)'> %s(zAge) </td> @ <td data-sortkey='%08x(fullSize)'> %s(zSzName) </td> @ <td> %h(zLogin) </td> | | < | < | | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | iTotalSz += fullSize; cnt++; @ <td> <a href='%R/uv/%T(zName)'>%h(zName)</a> </td> } @ <td data-sortkey='%016llx(-mtime)'> %s(zAge) </td> @ <td data-sortkey='%08x(fullSize)'> %s(zSzName) </td> @ <td> %h(zLogin) </td> @ <td> %h(zHash) </td> if( g.perm.Admin ){ if( rcvid ){ @ <td> <a href="%R/rcvfrom?rcvid=%d(rcvid)">%d(rcvid)</a> }else{ @ <td> } } @ </tr> fossil_free(zAge); } db_finalize(&q); if( n ){ approxSizeName(sizeof(zSzName), zSzName, iTotalSz); @ </tbody> @ <tfoot><tr><td><b>Total over %d(cnt) files</b><td><td>%s(zSzName) @ <td><td> if( g.perm.Admin ){ @ <td> } @ </tfoot> @ </table></div> }else{ @ No unversioned files on this server. } style_footer(); } /* ** WEBPAGE: juvlist ** ** Return a complete list of unversioned files as JSON. The JSON ** looks like this: |
︙ | ︙ | |||
659 660 661 662 663 664 665 | void uvlist_json_page(void){ Stmt q; char *zSep = "["; Blob json; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } | < | < | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | void uvlist_json_page(void){ Stmt q; char *zSep = "["; Blob json; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } cgi_set_content_type("text/json"); if( !db_table_exists("repository","unversioned") ){ blob_init(&json, "[]", -1); cgi_set_content(&json); return; } blob_init(&json, 0, 0); db_prepare(&q, |
︙ | ︙ | |||
685 686 687 688 689 690 691 | while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); sqlite3_int64 mtime = db_column_int(&q, 1); const char *zHash = db_column_text(&q, 2); int fullSize = db_column_int(&q, 3); const char *zLogin = db_column_text(&q, 4); if( zLogin==0 ) zLogin = ""; | | | | > | > | | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); sqlite3_int64 mtime = db_column_int(&q, 1); const char *zHash = db_column_text(&q, 2); int fullSize = db_column_int(&q, 3); const char *zLogin = db_column_text(&q, 4); if( zLogin==0 ) zLogin = ""; blob_appendf(&json, "%s{\"name\":\"", zSep); zSep = ",\n "; blob_append_json_string(&json, zName); blob_appendf(&json, "\",\n \"mtime\":%lld,\n \"hash\":\"", mtime); blob_append_json_string(&json, zHash); blob_appendf(&json, "\",\n \"size\":%d,\n \"user\":\"", fullSize); blob_append_json_string(&json, zLogin); blob_appendf(&json, "\"}"); } db_finalize(&q); blob_appendf(&json,"]\n"); cgi_set_content(&json); } |
Changes to src/update.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to merge the changes in the current | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to merge the changes in the current ** checkout into a different version and switch to that version. */ #include "config.h" #include "update.h" #include <assert.h> /* ** Return true if artifact rid is a version |
︙ | ︙ | |||
60 61 62 63 64 65 66 | } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** | | | | | | | | | | | < < | < < < < < < | | < | | < < | 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 | } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** ** Change the version of the current checkout to VERSION. Any ** uncommitted changes are retained and applied to the new checkout. ** ** The VERSION argument can be a specific version or tag or branch ** name. If the VERSION argument is omitted, then the leaf of the ** subtree that begins at the current version is used, if there is ** only a single leaf. VERSION can also be "current" to select the ** leaf of the current version or "latest" to select the most recent ** check-in. ** ** If one or more FILES are listed after the VERSION then only the ** named files are candidates to be updated, and any updates to them ** will be treated as edits to the current version. Using a directory ** name for one of the FILES arguments is the same as using every ** subdirectory and file beneath that directory. ** ** If FILES is omitted, all files in the current checkout are subject ** to being updated and the version of the current checkout is changed ** to VERSION. Any uncommitted changes are retained and applied to the ** new checkout. ** ** The -n or --dry-run option causes this command to do a "dry run". ** It prints out what would have happened but does not actually make ** any changes to the current checkout or the repository. ** ** The -v or --verbose option prints status information about ** unchanged files in addition to those file that actually do change. ** ** Options: ** --case-sensitive <BOOL> override case-sensitive setting ** --debug print debug information on stdout ** --latest acceptable in place of VERSION, update to latest version ** --force-missing force update if missing content after sync ** -n|--dry-run If given, display instead of run actions ** -v|--verbose print status information about all files ** -W|--width <num> Width of lines (default is to auto-detect). Must be >20 ** or 0 (= no limit, resulting in a single line per entry). ** ** See also: revert */ void update_cmd(void){ int vid; /* Current version */ int tid=0; /* Target version - version we are changing to */ Stmt q; int latestFlag; /* --latest. Pick the latest version if true */ int dryRunFlag; /* -n or --dry-run. Do a dry run */ int verboseFlag; /* -v or --verbose. Output extra information */ int forceMissingFlag; /* --force-missing. Continue if missing content */ int debugFlag; /* --debug option */ int setmtimeFlag; /* --setmtime. Set mtimes on files */ int nChng; /* Number of file renames */ int *aChng; /* Array of file renames */ int i; /* Loop counter */ int nConflict = 0; /* Number of merge conflicts */ int nOverwrite = 0; /* Number of unmanaged files overwritten */ int nUpdate = 0; /* Number of changes of any kind */ int width; /* Width of printed comment lines */ Stmt mtimeXfer; /* Statement to transfer mtimes */ const char *zWidth; /* Width option string value */ if( !internalUpdate ){ undo_capture_command_line(); url_proxy_options(); |
︙ | ︙ | |||
153 154 155 156 157 158 159 | if( !dryRunFlag ){ dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */ } verboseFlag = find_option("verbose","v",0)!=0; forceMissingFlag = find_option("force-missing",0,0)!=0; debugFlag = find_option("debug",0,0)!=0; setmtimeFlag = find_option("setmtime",0,0)!=0; | < < | | > | | 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 | if( !dryRunFlag ){ dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */ } verboseFlag = find_option("verbose","v",0)!=0; forceMissingFlag = find_option("force-missing",0,0)!=0; debugFlag = find_option("debug",0,0)!=0; setmtimeFlag = find_option("setmtime",0,0)!=0; /* We should be done with options.. */ verify_all_options(); db_must_be_within_tree(); vid = db_lget_int("checkout", 0); user_select(); if( !dryRunFlag && !internalUpdate ){ if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, db_get_int("autosync-tries", 1), 1) ){ fossil_fatal("update abandoned due to sync failure"); } } /* Create any empty directories now, as well as after the update, ** so changes in settings are reflected now */ if( !dryRunFlag ) ensure_empty_dirs_created(); if( internalUpdate ){ tid = internalUpdate; }else if( g.argc>=3 ){ if( fossil_strcmp(g.argv[2], "current")==0 ){ /* If VERSION is "current", then use the same algorithm to find the ** target as if VERSION were omitted. */ |
︙ | ︙ | |||
221 222 223 224 225 226 227 | compute_leaves(vid, closeCode); db_prepare(&q, "%s " " AND event.objid IN leaves" " ORDER BY event.mtime DESC", timeline_query_for_tty() ); | | < < < < | | 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 | compute_leaves(vid, closeCode); db_prepare(&q, "%s " " AND event.objid IN leaves" " ORDER BY event.mtime DESC", timeline_query_for_tty() ); print_timeline(&q, -100, width, 0); db_finalize(&q); fossil_fatal("Multiple descendants"); } } tid = db_int(0, "SELECT rid FROM leaves, event" " WHERE event.objid=leaves.rid" " ORDER BY event.mtime DESC"); if( tid==0 ) tid = vid; } if( tid==0 ){ return; } db_begin_transaction(); vfile_check_signature(vid, CKSIG_ENOTFILE); if( !dryRunFlag && !internalUpdate ) undo_begin(); if( load_vfile_from_rid(tid) && !forceMissingFlag ){ fossil_fatal("missing content, unable to update"); }; /* ** The record.fn field is used to match files against each other. The ** FV table contains one row for each each unique filename in ** in the current checkout, the pivot, and the version being merged. */ db_multi_exec( "DROP TABLE IF EXISTS fv;" "CREATE TEMP TABLE fv(" " fn TEXT %s PRIMARY KEY," /* The filename relative to root */ " idv INTEGER," /* VFILE entry for current version */ " idt INTEGER," /* VFILE entry for target version */ |
︙ | ︙ | |||
387 388 389 390 391 392 393 | blob_reset(&treename); } db_multi_exec("%s", blob_sql_text(&sql)); blob_reset(&sql); } /* | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | blob_reset(&treename); } db_multi_exec("%s", blob_sql_text(&sql)); blob_reset(&sql); } /* ** Alter the content of the checkout so that it conforms with the ** target */ db_prepare(&q, "SELECT fn, idv, ridv, idt, ridt, chnged, fnt," " isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1" ); db_prepare(&mtimeXfer, |
︙ | ︙ | |||
425 426 427 428 429 430 431 | zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); nameChng = fossil_strcmp(zName, zNewName); nUpdate++; if( deleted ){ db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt); } if( idv>0 && ridv==0 && idt>0 && ridt>0 ){ | | | < < < < < | < < | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); nameChng = fossil_strcmp(zName, zNewName); nUpdate++; if( deleted ){ db_multi_exec("UPDATE vfile SET deleted=1 WHERE id=%d", idt); } if( idv>0 && ridv==0 && idt>0 && ridt>0 ){ /* Conflict. This file has been added to the current checkout ** but also exists in the target checkout. Use the current version. */ fossil_print("CONFLICT %s\n", zName); nConflict++; }else if( idt>0 && idv==0 ){ /* File added in the target. */ if( file_isfile_or_link(zFullPath) ){ fossil_print("ADD %s - overwrites an unmanaged file\n", zName); nOverwrite++; }else{ fossil_print("ADD %s\n", zName); } if( !dryRunFlag && !internalUpdate ) undo_save(zName); if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0); }else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){ |
︙ | ︙ | |||
464 465 466 467 468 469 470 | /* The file missing from the local check-out. Restore it to the ** version that appears in the target. */ fossil_print("UPDATE %s\n", zName); if( !dryRunFlag && !internalUpdate ) undo_save(zName); if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0); }else if( idt==0 && idv>0 ){ if( ridv==0 ){ | | | < < < < < < < < < < < < < < < < < < < < < | < < < < | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | /* The file missing from the local check-out. Restore it to the ** version that appears in the target. */ fossil_print("UPDATE %s\n", zName); if( !dryRunFlag && !internalUpdate ) undo_save(zName); if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0); }else if( idt==0 && idv>0 ){ if( ridv==0 ){ /* Added in current checkout. Continue to hold the file as ** as an addition */ db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv); }else if( chnged ){ /* Edited locally but deleted from the target. Do not track the ** file but keep the edited version around. */ fossil_print("CONFLICT %s - edited locally but deleted by update\n", zName); nConflict++; }else{ fossil_print("REMOVE %s\n", zName); if( !dryRunFlag && !internalUpdate ) undo_save(zName); if( !dryRunFlag ) file_delete(zFullPath); } }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){ /* Merge the changes in the current tree into the target version */ Blob r, t, v; int rc; if( nameChng ){ fossil_print("MERGE %s -> %s\n", zName, zNewName); }else{ fossil_print("MERGE %s\n", zName); } if( islinkv || islinkt ){ fossil_print("***** Cannot merge symlink %s\n", zNewName); nConflict++; }else{ unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0; if( !dryRunFlag && !internalUpdate ) undo_save(zName); content_get(ridt, &t); content_get(ridv, &v); rc = merge_3way(&v, zFullPath, &t, &r, mergeFlags); if( rc>=0 ){ if( !dryRunFlag ){ blob_write_to_file(&r, zFullNewPath); file_setexe(zFullNewPath, isexe); } if( rc>0 ){ fossil_print("***** %d merge conflicts in %s\n", rc, zNewName); nConflict++; } }else{ if( !dryRunFlag ){ blob_write_to_file(&t, zFullNewPath); file_setexe(zFullNewPath, isexe); } fossil_print("***** Cannot merge binary file %s\n", zNewName); nConflict++; } } if( nameChng && !dryRunFlag ) file_delete(zFullPath); blob_reset(&v); blob_reset(&t); blob_reset(&r); |
︙ | ︙ | |||
565 566 567 568 569 570 571 | db_finalize(&q); db_finalize(&mtimeXfer); fossil_print("%.79c\n",'-'); if( nUpdate==0 ){ show_common_info(tid, "checkout:", 1, 0); fossil_print("%-13s None. Already up-to-date\n", "changes:"); }else{ | < < < > | | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | db_finalize(&q); db_finalize(&mtimeXfer); fossil_print("%.79c\n",'-'); if( nUpdate==0 ){ show_common_info(tid, "checkout:", 1, 0); fossil_print("%-13s None. Already up-to-date\n", "changes:"); }else{ show_common_info(tid, "updated-to:", 1, 0); fossil_print("%-13s %d file%s modified.\n", "changes:", nUpdate, nUpdate>1 ? "s" : ""); } /* Report on conflicts */ if( !dryRunFlag ){ Stmt q; int nMerge = 0; db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid" " WHERE id<=0"); while( db_step(&q)==SQLITE_ROW ){ const char *zLabel = "merge"; switch( db_column_int(&q, 1) ){ case -1: zLabel = "cherrypick merge"; break; case -2: zLabel = "backout merge"; break; } fossil_warning("uncommitted %s against %S.", |
︙ | ︙ | |||
615 616 617 618 619 620 621 | /* ** Clean up the mid and pid VFILE entries. Then commit the changes. */ if( dryRunFlag ){ db_end_transaction(1); /* With --dry-run, rollback changes */ }else{ | < | < < < < < < < < < | | | | | > > | > > > > | | < < < < < > > | | | < | | | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 | /* ** Clean up the mid and pid VFILE entries. Then commit the changes. */ if( dryRunFlag ){ db_end_transaction(1); /* With --dry-run, rollback changes */ }else{ ensure_empty_dirs_created(); if( g.argc<=3 ){ /* All files updated. Shift the current checkout to the target. */ db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid); checkout_set_all_exe(tid); manifest_to_disk(tid); db_lset_int("checkout", tid); }else{ /* A subset of files have been checked out. Keep the current ** checkout unchanged. */ db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); } if( !internalUpdate ) undo_finish(); if( setmtimeFlag ) vfile_check_signature(tid, CKSIG_SETMTIME); db_end_transaction(0); } } /* ** Create empty directories specified by the empty-dirs setting. */ void ensure_empty_dirs_created(void){ char *zEmptyDirs = db_get("empty-dirs", 0); if( zEmptyDirs!=0 ){ int i; Blob dirName; Blob dirsList; zEmptyDirs = fossil_strdup(zEmptyDirs); for(i=0; zEmptyDirs[i]; i++){ if( zEmptyDirs[i]==',' ) zEmptyDirs[i] = ' '; } blob_init(&dirsList, zEmptyDirs, -1); while( blob_token(&dirsList, &dirName) ){ char *zDir = blob_str(&dirName); char *zPath = mprintf("%s/%s", g.zLocalRoot, zDir); switch( file_isdir(zPath, RepoFILE) ){ case 0: { /* doesn't exist */ fossil_free(zPath); zPath = mprintf("%s/%s/x", g.zLocalRoot, zDir); if( file_mkfolder(zPath, RepoFILE, 0, 1)!=0 ) { fossil_warning("couldn't create directory %s as " "required by empty-dirs setting", zDir); } break; } case 1: { /* exists, and is a directory */ /* do nothing - required directory exists already */ break; } case 2: { /* exists, but isn't a directory */ fossil_warning("file %s found, but a directory is required " "by empty-dirs setting", zDir); } } fossil_free(zPath); blob_reset(&dirName); } blob_reset(&dirsList); fossil_free(zEmptyDirs); } } /* ** Get the manifest record for a given revision, or the current checkout if ** zRevision is NULL. */ Manifest *historical_manifest( const char *zRevision /* The check-in to query, or NULL for current */ ){ int vid; Manifest *pManifest; /* Determine the check-in manifest artifact ID. Panic on failure. */ if( zRevision ){ vid = name_to_typed_rid(zRevision, "ci"); }else if( !g.localOpen ){ vid = name_to_typed_rid(db_get("main-branch", "trunk"), "ci"); }else{ vid = db_lget_int("checkout", 0); if( !is_a_version(vid) ){ zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); if( zRevision ){ fossil_fatal("checkout artifact is not a check-in: %s", zRevision); }else{ fossil_fatal("invalid checkout artifact ID: %d", vid); } } } /* Parse the manifest, given its artifact ID. Panic on failure. */ if( !(pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0)) ){ if( zRevision ){ fossil_fatal("could not parse manifest for check-in: %s", zRevision); }else{ fossil_fatal("could not parse manifest for current checkout"); } } /* Return the manifest pointer. The caller must use manifest_destroy() to * clean up when finished using the manifest. */ return pManifest; } /* ** Get the contents of a file within the check-in "zRevision". If ** zRevision==NULL then get the file content for the current checkout. */ int historical_blob( const char *zRevision, /* The check-in containing the file */ const char *zFile, /* Full treename of the file */ Blob *pBlob, /* Put the content here */ int fatal /* If nonzero, panic if file/artifact not found */ ){ |
︙ | ︙ | |||
780 781 782 783 784 785 786 | /* Return 1 on success and (assuming fatal is not set) 0 if not found. */ return result; } /* ** COMMAND: revert ** | | | > < < < | < | | | | < < | < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | | | | | | | < < < < < < < < < < < | < < | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | /* Return 1 on success and (assuming fatal is not set) 0 if not found. */ return result; } /* ** COMMAND: revert ** ** Usage: %fossil revert ?-r REVISION? ?FILE ...? ** ** Revert to the current repository version of FILE, or to ** the version associated with baseline REVISION if the -r flag ** appears. ** ** If FILE was part of a rename operation, both the original file ** and the renamed file are reverted. ** ** Revert all files if no file name is provided. ** ** If a file is reverted accidentally, it can be restored using ** the "fossil undo" command. ** ** Options: ** -r REVISION revert given FILE(s) back to given REVISION ** ** See also: redo, undo, update */ void revert_cmd(void){ Manifest *pCoManifest; /* Manifest of current checkout */ Manifest *pRvManifest; /* Manifest of selected revert version */ ManifestFile *pCoFile; /* File within current checkout manifest */ ManifestFile *pRvFile; /* File within revert version manifest */ const char *zFile; /* Filename relative to checkout root */ const char *zRevision; /* Selected revert version, NULL if current */ Blob record = BLOB_INITIALIZER; /* Contents of each reverted file */ int i; Stmt q; undo_capture_command_line(); zRevision = find_option("revision", "r", 1); verify_all_options(); if( g.argc<2 ){ usage("?OPTIONS? [FILE] ..."); } if( zRevision && g.argc<3 ){ fossil_fatal("the --revision option does not work for the entire tree"); } db_must_be_within_tree(); /* Get manifests of revert version and (if different) current checkout. */ pRvManifest = historical_manifest(zRevision); pCoManifest = zRevision ? historical_manifest(0) : 0; db_begin_transaction(); undo_begin(); db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);"); if( g.argc>2 ){ for(i=2; i<g.argc; i++){ Blob fname; zFile = mprintf("%/", g.argv[i]); blob_zero(&fname); file_tree_name(zFile, &fname, 0, 1); db_multi_exec( "REPLACE INTO torevert VALUES(%B);" "INSERT OR IGNORE INTO torevert" " SELECT pathname" " FROM vfile" " WHERE origname=%B;", &fname, &fname ); blob_reset(&fname); } }else{ int vid; vid = db_lget_int("checkout", 0); vfile_check_signature(vid, 0); db_multi_exec( "DELETE FROM vmerge;" "INSERT OR IGNORE INTO torevert " " SELECT pathname" " FROM vfile " " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;" ); } db_multi_exec( "INSERT OR IGNORE INTO torevert" " SELECT origname" " FROM vfile" " WHERE origname!=pathname AND pathname IN (SELECT name FROM torevert);" ); blob_zero(&record); db_prepare(&q, "SELECT name FROM torevert"); if( zRevision==0 ){ int vid = db_lget_int("checkout", 0); zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); } while( db_step(&q)==SQLITE_ROW ){ char *zFull; zFile = db_column_text(&q, 0); zFull = mprintf("%/%/", g.zLocalRoot, zFile); pRvFile = manifest_file_find(pRvManifest, zFile); if( !pRvFile ){ if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q", zFile, zFile)==0 ){ fossil_print("UNMANAGE %s\n", zFile); }else{ undo_save(zFile); file_delete(zFull); fossil_print("DELETE %s\n", zFile); } db_multi_exec( "UPDATE OR REPLACE vfile" " SET pathname=origname, origname=NULL" " WHERE pathname=%Q AND origname!=pathname;" "DELETE FROM vfile WHERE pathname=%Q", zFile, zFile ); }else{ sqlite3_int64 mtime; int rvChnged = 0; int rvPerm = manifest_file_mperm(pRvFile); /* Determine if reverted-to file is different than checked out file. */ if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){ rvChnged = manifest_file_mperm(pRvFile)!=rvPerm || fossil_strcmp(pRvFile->zUuid, pCoFile->zUuid)!=0; } /* Get contents of reverted-to file. */ content_get(fast_uuid_to_rid(pRvFile->zUuid), &record); |
︙ | ︙ | |||
973 974 975 976 977 978 979 | blob_write_to_file(&record, zFull); } file_setexe(zFull, rvPerm==PERM_EXE); fossil_print("REVERT %s\n", zFile); mtime = file_mtime(zFull, RepoFILE); db_multi_exec( "UPDATE vfile" | | < | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 | blob_write_to_file(&record, zFull); } file_setexe(zFull, rvPerm==PERM_EXE); fossil_print("REVERT %s\n", zFile); mtime = file_mtime(zFull, RepoFILE); db_multi_exec( "UPDATE vfile" " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,mrid=rid" " WHERE pathname=%Q OR origname=%Q", mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile ); } blob_reset(&record); free(zFull); } |
︙ | ︙ |
Changes to src/url.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 | #endif #endif #if INTERFACE /* ** Flags for url_parse() */ | | | | | | | < < < < < | | | < | | | | | | | | | | | < | | < | < > > > > > > > > > | > > | | < < < < < < < < < < < < < < < < < < < | < < < < < | < | | | < | < < < < < < < < < < < < < < < < < < < > > | | 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 | #endif #endif #if INTERFACE /* ** Flags for url_parse() */ #define URL_PROMPT_PW 0x001 /* Prompt for password if needed */ #define URL_REMEMBER 0x002 /* Remember the url for later reuse */ #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */ #define URL_REMEMBER_PW 0x008 /* Should remember pw */ #define URL_PROMPTED 0x010 /* Prompted for PW already */ #define URL_OMIT_USER 0x020 /* Omit the user name from URL */ /* ** The URL related data used with this subsystem. */ struct UrlData { int isFile; /* True if a "file:" url */ int isHttps; /* True if a "https:" url */ int isSsh; /* True if an "ssh:" url */ char *name; /* Hostname for http: or filename for file: */ char *hostname; /* The HOST: parameter on http headers */ char *protocol; /* "http" or "https" */ int port; /* TCP port number for http: or https: */ int dfltPort; /* The default port for the given protocol */ char *path; /* Pathname for http: */ char *user; /* User id for http: */ char *passwd; /* Password for http: */ char *canonical; /* Canonical representation of the URL */ char *proxyAuth; /* Proxy-Authorizer: string */ char *fossil; /* The fossil query parameter on ssh: */ unsigned flags; /* Boolean flags controlling URL processing */ int useProxy; /* Used to remember that a proxy is in use */ char *proxyUrlPath; int proxyOrigPort; /* Tunneled port number for https through proxy */ }; #endif /* INTERFACE */ /* ** Convert a string to lower-case. */ static void url_tolower(char *z){ while( *z ){ *z = fossil_tolower(*z); z++; } } /* ** Parse the given URL. Populate members of the provided UrlData structure ** as follows: ** ** isFile True if FILE: ** isHttps True if HTTPS: ** isSsh True if SSH: ** protocol "http" or "https" or "file" ** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** port TCP port number for HTTP or HTTPS. ** dfltPort Default TCP port number (80 or 443). ** path Path name for HTTP or HTTPS. ** user Userid. ** passwd Password. ** hostname HOST:PORT or just HOST if port is the default. ** canonical The URL in canonical form, omitting the password ** */ void url_parse_local( const char *zUrl, unsigned int urlFlags, UrlData *pUrlData ){ int i, j, c; char *zFile = 0; if( zUrl==0 ){ zUrl = db_get("last-sync-url", 0); if( zUrl==0 ) return; if( pUrlData->passwd==0 ){ pUrlData->passwd = unobscure(db_get("last-sync-pw", 0)); } } if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 || strncmp(zUrl, "ssh://", 6)==0 ){ int iStart; char *zLogin; char *zExe; char cQuerySep = '?'; pUrlData->isFile = 0; pUrlData->useProxy = 0; if( zUrl[4]=='s' ){ pUrlData->isHttps = 1; pUrlData->protocol = "https"; pUrlData->dfltPort = 443; iStart = 8; }else if( zUrl[0]=='s' ){ pUrlData->isSsh = 1; pUrlData->protocol = "ssh"; pUrlData->dfltPort = 22; pUrlData->fossil = "fossil"; iStart = 6; }else{ pUrlData->isHttps = 0; pUrlData->protocol = "http"; pUrlData->dfltPort = 80; iStart = 7; } |
︙ | ︙ | |||
216 217 218 219 220 221 222 | n = strlen(pUrlData->name); if( pUrlData->name[0]=='[' && n>2 && pUrlData->name[n-1]==']' ){ pUrlData->name++; pUrlData->name[n-2] = 0; } zLogin = mprintf(""); } | | < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | n = strlen(pUrlData->name); if( pUrlData->name[0]=='[' && n>2 && pUrlData->name[n-1]==']' ){ pUrlData->name++; pUrlData->name[n-2] = 0; } zLogin = mprintf(""); } url_tolower(pUrlData->name); if( c==':' ){ pUrlData->port = 0; i++; while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){ pUrlData->port = pUrlData->port*10 + c - '0'; i++; } pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port); }else{ pUrlData->port = pUrlData->dfltPort; pUrlData->hostname = pUrlData->name; } dehttpize(pUrlData->name); pUrlData->path = mprintf("%s", &zUrl[i]); |
︙ | ︙ | |||
254 255 256 257 258 259 260 | while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; } } if( pUrlData->path[i] ){ pUrlData->path[i] = 0; i++; } if( fossil_strcmp(zName,"fossil")==0 ){ | < | < < | | | < < < < | 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 | while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; } } if( pUrlData->path[i] ){ pUrlData->path[i] = 0; i++; } if( fossil_strcmp(zName,"fossil")==0 ){ pUrlData->fossil = zValue; dehttpize(pUrlData->fossil); zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil); cQuerySep = '&'; } } dehttpize(pUrlData->path); if( pUrlData->dfltPort==pUrlData->port ){ pUrlData->canonical = mprintf( "%s://%s%T%T%s", pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe ); }else{ pUrlData->canonical = mprintf( "%s://%s%T:%d%T%s", pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port, pUrlData->path, zExe ); } if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++; free(zLogin); }else if( strncmp(zUrl, "file:", 5)==0 ){ pUrlData->isFile = 1; if( zUrl[5]=='/' && zUrl[6]=='/' ){ i = 7; }else{ i = 5; |
︙ | ︙ | |||
314 315 316 317 318 319 320 | if( pUrlData->isFile ){ Blob cfile; dehttpize(zFile); file_canonical_name(zFile, &cfile, 0); free(zFile); zFile = 0; pUrlData->protocol = "file"; | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | > > > | < < < < | > > > > > > > > > > > > > < < | < < | | < < < < < < < < < < < | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | if( pUrlData->isFile ){ Blob cfile; dehttpize(zFile); file_canonical_name(zFile, &cfile, 0); free(zFile); zFile = 0; pUrlData->protocol = "file"; pUrlData->path = ""; pUrlData->name = mprintf("%b", &cfile); pUrlData->canonical = mprintf("file://%T", pUrlData->name); blob_reset(&cfile); }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){ url_prompt_for_password_local(pUrlData); }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){ if( isatty(fileno(stdin)) ){ if( save_password_prompt(pUrlData->passwd) ){ pUrlData->flags = urlFlags |= URL_REMEMBER_PW; }else{ pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW; } } } } /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g" structure as follows: ** ** g.url.isFile True if FILE: ** g.url.isHttps True if HTTPS: ** g.url.isSsh True if SSH: ** g.url.protocol "http" or "https" or "file" ** g.url.name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** g.url.port TCP port number for HTTP or HTTPS. ** g.url.dfltPort Default TCP port number (80 or 443). ** g.url.path Path name for HTTP or HTTPS. ** g.url.user Userid. ** g.url.passwd Password. ** g.url.hostname HOST:PORT or just HOST if port is the default. ** g.url.canonical The URL in canonical form, omitting the password ** ** HTTP url format as follows (HTTPS is the same with a different scheme): ** ** http://userid:password@host:port/path ** ** SSH url format is: ** ** ssh://userid@host:port/path?fossil=path/to/fossil.exe ** */ void url_parse(const char *zUrl, unsigned int urlFlags){ url_parse_local(zUrl, urlFlags, &g.url); } /* ** COMMAND: test-urlparser ** ** Usage: %fossil test-urlparser URL ?options? ** ** --remember Store results in last-sync-url ** --prompt-pw Prompt for password if missing */ void cmd_test_urlparser(void){ int i; unsigned fg = 0; url_proxy_options(); if( find_option("remember",0,0) ){ db_must_be_within_tree(); fg |= URL_REMEMBER; } if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW; if( g.argc!=3 && g.argc!=4 ){ usage("URL"); } url_parse(g.argv[2], fg); for(i=0; i<2; i++){ fossil_print("g.url.isFile = %d\n", g.url.isFile); fossil_print("g.url.isHttps = %d\n", g.url.isHttps); fossil_print("g.url.isSsh = %d\n", g.url.isSsh); fossil_print("g.url.protocol = %s\n", g.url.protocol); fossil_print("g.url.name = %s\n", g.url.name); fossil_print("g.url.port = %d\n", g.url.port); fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort); fossil_print("g.url.hostname = %s\n", g.url.hostname); fossil_print("g.url.path = %s\n", g.url.path); fossil_print("g.url.user = %s\n", g.url.user); fossil_print("g.url.passwd = %s\n", g.url.passwd); fossil_print("g.url.canonical = %s\n", g.url.canonical); fossil_print("g.url.fossil = %s\n", g.url.fossil); fossil_print("g.url.flags = 0x%02x\n", g.url.flags); if( g.url.isFile || g.url.isSsh ) break; if( i==0 ){ fossil_print("********\n"); url_enable_proxy("Using proxy: "); } } } /* ** Proxy specified on the command-line using the --proxy option. ** If there is no --proxy option on the command-line then this ** variable holds a NULL pointer. */ static const char *zProxyOpt = 0; /* ** Extract any proxy options from the command-line. ** ** --proxy URL|off ** ** This also happens to be a convenient function to use to look for ** the --nosync option that will temporarily disable the "autosync" ** feature. */ void url_proxy_options(void){ zProxyOpt = find_option("proxy", 0, 1); if( find_option("nosync",0,0) ) g.fNoSync = 1; if( find_option("ipv4",0,0) ) g.fIPv4 = 1; } /* ** If the "proxy" setting is defined, then change the URL settings ** (initialized by a prior call to url_parse()) so that the HTTP ** header will be appropriate for the proxy and so that the TCP/IP ** connection will be opened to the proxy rather than to the server. ** ** If zMsg is not NULL and a proxy is used, then print zMsg followed ** by the canonical name of the proxy (with userid and password suppressed). */ void url_enable_proxy(const char *zMsg){ const char *zProxy; zProxy = zProxyOpt; if( zProxy==0 ){ zProxy = db_get("proxy", 0); if( zProxy==0 || zProxy[0]==0 || is_false(zProxy) ){ zProxy = fossil_getenv("http_proxy"); } } if( zProxy && zProxy[0] && !is_false(zProxy) && !g.url.isSsh && !g.url.isFile ){ char *zOriginalUrl = g.url.canonical; char *zOriginalHost = g.url.hostname; |
︙ | ︙ | |||
608 609 610 611 612 613 614 | g.url.proxyAuth = mprintf("Basic %z", zCredentials2); free(zCredentials1); } g.url.user = zOriginalUser; g.url.passwd = zOriginalPasswd; g.url.isHttps = fOriginalIsHttps; g.url.useProxy = 1; | < | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | g.url.proxyAuth = mprintf("Basic %z", zCredentials2); free(zCredentials1); } g.url.user = zOriginalUser; g.url.passwd = zOriginalPasswd; g.url.isHttps = fOriginalIsHttps; g.url.useProxy = 1; g.url.proxyUrlPath = zOriginalUrlPath; g.url.proxyOrigPort = iOriginalPort; g.url.flags = uOriginalFlags; } } #if INTERFACE |
︙ | ︙ | |||
697 698 699 700 701 702 703 | const char *zName2, /* Second override */ const char *zValue2 /* Second override value */ ){ const char *zSep = "?"; int i; blob_reset(&p->url); | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | const char *zName2, /* Second override */ const char *zValue2 /* Second override value */ ){ const char *zSep = "?"; int i; blob_reset(&p->url); blob_appendf(&p->url, "%s/%s", g.zTop, p->zBase); for(i=0; i<p->nParam; i++){ const char *z = p->azValue[i]; if( zName1 && fossil_strcmp(zName1,p->azName[i])==0 ){ zName1 = 0; z = zValue1; if( z==0 ) continue; } |
︙ | ︙ | |||
738 739 740 741 742 743 744 | void url_prompt_for_password_local(UrlData *pUrlData){ if( pUrlData->isSsh || pUrlData->isFile ) return; if( isatty(fileno(stdin)) && (pUrlData->flags & URL_PROMPT_PW)!=0 && (pUrlData->flags & URL_PROMPTED)==0 ){ pUrlData->flags |= URL_PROMPTED; | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | void url_prompt_for_password_local(UrlData *pUrlData){ if( pUrlData->isSsh || pUrlData->isFile ) return; if( isatty(fileno(stdin)) && (pUrlData->flags & URL_PROMPT_PW)!=0 && (pUrlData->flags & URL_PROMPTED)==0 ){ pUrlData->flags |= URL_PROMPTED; pUrlData->passwd = prompt_for_user_password(pUrlData->user); if( pUrlData->passwd[0] && (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0 ){ if( save_password_prompt(pUrlData->passwd) ){ pUrlData->flags |= URL_REMEMBER_PW; }else{ pUrlData->flags &= ~URL_REMEMBER_PW; |
︙ | ︙ | |||
767 768 769 770 771 772 773 | } /* ** Remember the URL and password if requested. */ void url_remember(void){ if( g.url.flags & URL_REMEMBER ){ | < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | } /* ** Remember the URL and password if requested. */ void url_remember(void){ if( g.url.flags & URL_REMEMBER ){ db_set("last-sync-url", g.url.canonical, 0); if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){ db_set("last-sync-pw", obscure(g.url.passwd), 0); } } } /* Preemptively prompt for a password if a username is given in the ** URL but no password. */ void url_get_password_if_needed(void){ if( (g.url.user && g.url.user[0]) && (g.url.passwd==0 || g.url.passwd[0]==0) && isatty(fileno(stdin)) ){ url_prompt_for_password(); } } |
Changes to src/user.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | break; } if( z[i]>0 && z[i]<' ' ) z[i] = ' '; } blob_append(pBlob, z, -1); } | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | break; } if( z[i]>0 && z[i]<' ' ) z[i] = ' '; } blob_append(pBlob, z, -1); } #if defined(_WIN32) || defined(__BIONIC__) #ifdef _WIN32 #include <conio.h> #endif /* ** getpass() for Windows and Android. */ |
︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 119 120 121 122 123 | void freepass(){ if( !zPwdBuffer ) return; assert( nPwdBuffer>0 ); fossil_secure_free_page(zPwdBuffer, nPwdBuffer); } #endif /* ** Scramble substitution matrix: */ static char aSubst[256]; /* ** Descramble the password | > > > > > > > > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | void freepass(){ if( !zPwdBuffer ) return; assert( nPwdBuffer>0 ); fossil_secure_free_page(zPwdBuffer, nPwdBuffer); } #endif #if defined(_WIN32) || defined(WIN32) # include <io.h> # include <fcntl.h> # undef popen # define popen _popen # undef pclose # define pclose _pclose #endif /* ** Scramble substitution matrix: */ static char aSubst[256]; /* ** Descramble the password |
︙ | ︙ | |||
155 156 157 158 159 160 161 | unsigned char zB[30]; int nA = 25; int nB = 0; int i; memcpy(zOrig, "abcdefghijklmnopqrstuvwyz", nA+1); memcpy(zA, zOrig, nA+1); assert( nA==(int)strlen((char*)zA) ); | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | unsigned char zB[30]; int nA = 25; int nB = 0; int i; memcpy(zOrig, "abcdefghijklmnopqrstuvwyz", nA+1); memcpy(zA, zOrig, nA+1); assert( nA==(int)strlen((char*)zA) ); for(i=0; i<sizeof(aSubst); i++) aSubst[i] = i; printFive(zA); while( nA>0 ){ int x = randint(nA); zB[nB++] = zA[x]; zA[x] = zA[--nA]; } assert( nB==25 ); |
︙ | ︙ | |||
268 269 270 271 272 273 274 275 276 277 278 279 280 281 | /* ** Prompt to save Fossil user password */ int save_password_prompt(const char *passwd){ Blob x; char c; if( fossil_security_level()>=1 ) return 0; prompt_user("remember password (Y/n)? ", &x); c = blob_str(&x)[0]; blob_reset(&x); return ( c!='n' && c!='N' ); } | > > > > | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | /* ** Prompt to save Fossil user password */ int save_password_prompt(const char *passwd){ Blob x; char c; const char *old = db_get("last-sync-pw", 0); if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){ return 0; } if( fossil_security_level()>=1 ) return 0; prompt_user("remember password (Y/n)? ", &x); c = blob_str(&x)[0]; blob_reset(&x); return ( c!='n' && c!='N' ); } |
︙ | ︙ | |||
311 312 313 314 315 316 317 | strip_string(pIn, z); } } /* ** COMMAND: user* ** | | | < < < < | | | | | | | < < | < | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | strip_string(pIn, z); } } /* ** COMMAND: user* ** ** Usage: %fossil user SUBCOMMAND ... ?-R|--repository FILE? ** ** Run various subcommands on users of the open repository or of ** the repository identified by the -R or --repository option. ** ** %fossil user capabilities USERNAME ?STRING? ** ** Query or set the capabilities for user USERNAME ** ** %fossil user default ?USERNAME? ** ** Query or set the default user. The default user is the ** user for command-line interaction. ** ** %fossil user list ** %fossil user ls ** ** List all users known to the repository ** ** %fossil user new ?USERNAME? ?CONTACT-INFO? ?PASSWORD? ** ** Create a new user in the repository. Users can never be ** deleted. They can be denied all access but they must continue ** to exist in the database. ** ** %fossil user password USERNAME ?PASSWORD? ** ** Change the web access password for a user. */ void user_cmd(void){ int n; db_find_and_open_repository(0, 0); if( g.argc<3 ){ usage("capabilities|default|list|new|password ..."); } n = strlen(g.argv[2]); if( n>=2 && strncmp(g.argv[2],"new",n)==0 ){ Blob passwd, login, caps, contact; char *zPw; blob_init(&caps, db_get("default-perms", "u"), -1); if( g.argc>=4 ){ blob_init(&login, g.argv[3], -1); }else{ prompt_user("login: ", &login); } if( db_exists("SELECT 1 FROM user WHERE login=%B", &login) ){ fossil_fatal("user %b already exists", &login); } if( g.argc>=5 ){ blob_init(&contact, g.argv[4], -1); }else{ prompt_user("contact-info: ", &contact); } if( g.argc>=6 ){ blob_init(&passwd, g.argv[5], -1); }else{ prompt_for_password("password: ", &passwd, 1); } zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login), 0); db_multi_exec( "INSERT INTO user(login,pw,cap,info,mtime)" "VALUES(%B,%Q,%B,%B,now())", &login, zPw, &caps, &contact ); free(zPw); }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){ if( g.argc==3 ){ user_select(); fossil_print("%s\n", g.zLogin); }else{ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.argv[3]) ){ fossil_fatal("no such user: %s", g.argv[3]); } if( g.localOpen ){ db_lset("default-user", g.argv[3]); }else{ db_set("default-user", g.argv[3], 0); } } }else if(( n>=2 && strncmp(g.argv[2],"list",n)==0 ) || ( n>=2 && strncmp(g.argv[2],"ls",n)==0 )){ Stmt q; db_prepare(&q, "SELECT login, info FROM user ORDER BY login"); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1)); } db_finalize(&q); }else if( n>=2 && strncmp(g.argv[2],"password",2)==0 ){ |
︙ | ︙ | |||
424 425 426 427 428 429 430 | zPrompt = mprintf("New password for %s: ", g.argv[3]); prompt_for_password(zPrompt, &pw, 1); } if( blob_size(&pw)==0 ){ fossil_print("password unchanged\n"); }else{ char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); | < < < < < < < < < < < < < < < < < < < < < < | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | zPrompt = mprintf("New password for %s: ", g.argv[3]); prompt_for_password(zPrompt, &pw, 1); } if( blob_size(&pw)==0 ){ fossil_print("password unchanged\n"); }else{ char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d", zSecret, uid); free(zSecret); } }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){ int uid; if( g.argc!=4 && g.argc!=5 ){ usage("capabilities USERNAME ?PERMISSIONS?"); } uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]); if( uid==0 ){ fossil_fatal("no such user: %s", g.argv[3]); } if( g.argc==5 ){ db_multi_exec( "UPDATE user SET cap=%Q, mtime=now() WHERE uid=%d", g.argv[4], uid ); } fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); }else{ fossil_fatal("user subcommand should be one of: " "capabilities default list new password"); } } /* ** Attempt to set the user to zLogin */ static int attempt_user(const char *zLogin){ |
︙ | ︙ | |||
512 513 514 515 516 517 518 | ** (7) Try the USERNAME environment variable. ** ** (8) Check if the user can be extracted from the remote URL. ** ** The user name is stored in g.zLogin. The uid is in g.userUid. */ void user_select(void){ | < | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | ** (7) Try the USERNAME environment variable. ** ** (8) Check if the user can be extracted from the remote URL. ** ** The user name is stored in g.zLogin. The uid is in g.userUid. */ void user_select(void){ if( g.userUid ) return; if( g.zLogin ){ if( attempt_user(g.zLogin)==0 ){ fossil_fatal("no such user: %s", g.zLogin); }else{ return; } |
︙ | ︙ | |||
534 535 536 537 538 539 540 | if( attempt_user(fossil_getenv("USER")) ) return; if( attempt_user(fossil_getenv("LOGNAME")) ) return; if( attempt_user(fossil_getenv("USERNAME")) ) return; | < | | | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | if( attempt_user(fossil_getenv("USER")) ) return; if( attempt_user(fossil_getenv("LOGNAME")) ) return; if( attempt_user(fossil_getenv("USERNAME")) ) return; url_parse(0, 0); if( g.url.user && attempt_user(g.url.user) ) return; fossil_print( "Cannot figure out who you are! Consider using the --user\n" "command line option, setting your USER environment variable,\n" "or setting a default user with \"fossil user default USER\".\n" ); fossil_fatal("cannot determine user"); |
︙ | ︙ | |||
558 559 560 561 562 563 564 | ** Print details about sources of fossil usernames. */ void test_usernames_cmd(void){ db_find_and_open_repository(0, 0); fossil_print("Initial g.zLogin: %s\n", g.zLogin); fossil_print("Initial g.userUid: %d\n", g.userUid); | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | ** Print details about sources of fossil usernames. */ void test_usernames_cmd(void){ db_find_and_open_repository(0, 0); fossil_print("Initial g.zLogin: %s\n", g.zLogin); fossil_print("Initial g.userUid: %d\n", g.userUid); fossil_print("checkout default-user: %s\n", g.localOpen ? db_lget("default-user","") : "<<no open checkout>>"); fossil_print("default-user: %s\n", db_get("default-user","")); fossil_print("FOSSIL_USER: %s\n", fossil_getenv("FOSSIL_USER")); fossil_print("USER: %s\n", fossil_getenv("USER")); fossil_print("LOGNAME: %s\n", fossil_getenv("LOGNAME")); fossil_print("USERNAME: %s\n", fossil_getenv("USERNAME")); url_parse(0, 0); fossil_print("URL user: %s\n", g.url.user); user_select(); fossil_print("Final g.zLogin: %s\n", g.zLogin); fossil_print("Final g.userUid: %d\n", g.userUid); } /* ** COMMAND: test-hash-passwords ** ** Usage: %fossil test-hash-passwords REPOSITORY ** ** Convert all local password storage to use a SHA1 hash of the password ** rather than cleartext. Passwords that are already stored as the SHA1 ** has are unchanged. */ void user_hash_passwords_cmd(void){ if( g.argc!=3 ) usage("REPOSITORY"); db_open_repository(g.argv[2]); sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0, sha1_shared_secret_sql_function, 0, 0); db_multi_exec( "UPDATE user SET pw=shared_secret(pw,login), mtime=now()" " WHERE length(pw)>0 AND length(pw)!=40" ); } /* ** COMMAND: test-prompt-user ** ** Usage: %fossil test-prompt-user PROMPT ** ** Prompts the user for input and then prints it verbatim (i.e. without ** a trailing line terminator). |
︙ | ︙ | |||
665 666 667 668 669 670 671 | iVerify = atoi(g.argv[3]); prompt_for_password(g.argv[2], &answer, iVerify); fossil_print("[%s]\n", blob_str(&answer)); } /* ** WEBPAGE: access_log | < | | | | | | < < | | | | | | | | | | | | | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | iVerify = atoi(g.argv[3]); prompt_for_password(g.argv[2], &answer, iVerify); fossil_print("[%s]\n", blob_str(&answer)); } /* ** WEBPAGE: access_log ** ** Show login attempts, including timestamp and IP address. ** Requires Admin privileges. ** ** Query parameters: ** ** y=N 1: success only. 2: failure only. 3: both (default: 3) ** n=N Number of entries to show (default: 200) ** o=N Skip this many entries (default: 0) */ void access_log_page(void){ int y = atoi(PD("y","3")); int n = atoi(PD("n","200")); int skip = atoi(PD("o","0")); const char *zUser = P("u"); Blob sql; Stmt q; int cnt = 0; int rc; int fLogEnabled; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } create_accesslog_table(); if( P("delall") && P("delallbtn") ){ db_multi_exec("DELETE FROM accesslog"); cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip); return; } if( P("delanon") && P("delanonbtn") ){ db_multi_exec("DELETE FROM accesslog WHERE uname='anonymous'"); cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip); return; } if( P("delfail") && P("delfailbtn") ){ db_multi_exec("DELETE FROM accesslog WHERE NOT success"); cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip); return; } if( P("delold") && P("deloldbtn") ){ db_multi_exec("DELETE FROM accesslog WHERE rowid in" "(SELECT rowid FROM accesslog ORDER BY rowid DESC" " LIMIT -1 OFFSET 200)"); cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n); return; } style_header("Access Log"); blob_zero(&sql); blob_append_sql(&sql, "SELECT uname, ipaddr, datetime(mtime,toLocal()), success" " FROM accesslog" ); if( zUser ){ blob_append_sql(&sql, " WHERE uname=%Q", zUser); n = 1000000000; skip = 0; }else if( y==1 ){ blob_append(&sql, " WHERE success", -1); }else if( y==2 ){ blob_append(&sql, " WHERE NOT success", -1); } blob_append_sql(&sql," ORDER BY rowid DESC LIMIT %d OFFSET %d", n+1, skip); if( skip ){ style_submenu_element("Newer", "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0, n, y); } rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql)); fLogEnabled = db_get_boolean("access-log", 0); @ <div align="center">Access logging is %s(fLogEnabled?"on":"off"). @ (Change this on the <a href="setup_settings">settings</a> page.)</div> @ <table border="1" cellpadding="5" class="sortable" align="center" \ @ data-column-types='Ttt' data-init-sort='1'> @ <thead><tr><th width="33%%">Date</th><th width="34%%">User</th> @ <th width="33%%">IP Address</th></tr></thead><tbody> while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zIP = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); int bSuccess = db_column_int(&q, 3); cnt++; if( cnt>n ){ style_submenu_element("Older", "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip+n, n, y); break; } if( bSuccess ){ @ <tr> }else{ @ <tr bgcolor="#ffacc0"> } @ <td>%s(zDate)</td><td>%h(zName)</td><td>%h(zIP)</td></tr> } if( skip>0 || cnt>n ){ style_submenu_element("All", "%s/access_log?n=10000000", g.zTop); } @ </tbody></table> db_finalize(&q); @ <hr /> @ <form method="post" action="%s(g.zTop)/access_log"> @ <label><input type="checkbox" name="delold"> @ Delete all but the most recent 200 entries</input></label> @ <input type="submit" name="deloldbtn" value="Delete"></input> @ </form> @ <form method="post" action="%s(g.zTop)/access_log"> @ <label><input type="checkbox" name="delanon"> @ Delete all entries for user "anonymous"</input></label> @ <input type="submit" name="delanonbtn" value="Delete"></input> @ </form> @ <form method="post" action="%s(g.zTop)/access_log"> @ <label><input type="checkbox" name="delfail"> @ Delete all failed login attempts</input></label> @ <input type="submit" name="delfailbtn" value="Delete"></input> @ </form> @ <form method="post" action="%s(g.zTop)/access_log"> @ <label><input type="checkbox" name="delall"> @ Delete all entries</input></label> @ <input type="submit" name="delallbtn" value="Delete"></input> @ </form> style_table_sorter(); style_footer(); } |
Changes to src/utf8.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | assert( 0 ); /* Never used in unix */ return fossil_strdup(zUtf8); /* TODO: implement for unix */ #endif } /* ** Deallocate any memory that was previously allocated by | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | assert( 0 ); /* Never used in unix */ return fossil_strdup(zUtf8); /* TODO: implement for unix */ #endif } /* ** Deallocate any memory that was previously allocated by ** fossil_unicode_to_utf8(). */ void fossil_unicode_free(void *pOld){ fossil_free(pOld); } #if defined(__APPLE__) && !defined(WITHOUT_ICONV) # include <iconv.h> |
︙ | ︙ | |||
297 298 299 300 301 302 303 | #elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__) fossil_free(pOld); #else /* No-op on all other unix */ #endif } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | #elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__) fossil_free(pOld); #else /* No-op on all other unix */ #endif } /* ** Display UTF-8 on the console. Return the number of ** Characters written. If stdout or stderr is redirected ** to a file, -1 is returned and nothing is written ** to the console. */ #ifdef _WIN32 |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | */ #include "config.h" #include "util.h" #if defined(USE_MMAN_H) # include <sys/mman.h> # include <unistd.h> #endif | < < < > | < < < < < < | | 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 | */ #include "config.h" #include "util.h" #if defined(USE_MMAN_H) # include <sys/mman.h> # include <unistd.h> #endif /* ** For the fossil_timer_xxx() family of functions... */ #ifdef _WIN32 # include <windows.h> #else # include <sys/time.h> # include <sys/resource.h> # include <unistd.h> # include <fcntl.h> # include <errno.h> #endif /* ** Exit. Take care to close the database first. */ NORETURN void fossil_exit(int rc){ db_close(1); #ifndef _WIN32 if( g.fAnyTrace ){ fprintf(stderr, "/***** Subprocess %d exit(%d) *****/\n", getpid(), rc); fflush(stderr); } #endif exit(rc); } /* ** Malloc and free routines that cannot fail */ void *fossil_malloc(size_t n){ void *p = malloc(n==0 ? 1 : n); if( p==0 ) fossil_panic("out of memory"); return p; } void fossil_free(void *p){ free(p); } void *fossil_realloc(void *p, size_t n){ p = realloc(p, n); if( p==0 ) fossil_panic("out of memory"); return p; } void fossil_secure_zero(void *p, size_t n){ volatile unsigned char *vp = (volatile unsigned char *)p; size_t i; if( p==0 ) return; |
︙ | ︙ | |||
104 105 106 107 108 109 110 | fossil_get_page_size(&pageSize); assert( pageSize>0 ); assert( pageSize%2==0 ); #if defined(_WIN32) p = VirtualAlloc(NULL, pageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); if( p==NULL ){ | | | | | | 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 | fossil_get_page_size(&pageSize); assert( pageSize>0 ); assert( pageSize%2==0 ); #if defined(_WIN32) p = VirtualAlloc(NULL, pageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); if( p==NULL ){ fossil_panic("VirtualAlloc failed: %lu\n", GetLastError()); } if( !VirtualLock(p, pageSize) ){ fossil_panic("VirtualLock failed: %lu\n", GetLastError()); } #elif defined(USE_MMAN_H) p = mmap(0, pageSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if( p==MAP_FAILED ){ fossil_panic("mmap failed: %d\n", errno); } if( mlock(p, pageSize) ){ fossil_panic("mlock failed: %d\n", errno); } #else p = fossil_malloc(pageSize); #endif fossil_secure_zero(p, pageSize); if( pN ) *pN = pageSize; return p; |
︙ | ︙ | |||
147 148 149 150 151 152 153 | fossil_panic("munmap failed: %d\n", errno); } #else fossil_free(p); #endif } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > | | 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 | fossil_panic("munmap failed: %d\n", errno); } #else fossil_free(p); #endif } /* ** This function implements a cross-platform "system()" interface. */ int fossil_system(const char *zOrigCmd){ int rc; #if defined(_WIN32) /* On windows, we have to put double-quotes around the entire command. ** Who knows why - this is just the way windows works. */ char *zNewCmd = mprintf("\"%s\"", zOrigCmd); wchar_t *zUnicode = fossil_utf8_to_unicode(zNewCmd); if( g.fSystemTrace ) { fossil_trace("SYSTEM: %s\n", zNewCmd); } rc = _wsystem(zUnicode); fossil_unicode_free(zUnicode); free(zNewCmd); #else /* On unix, evaluate the command directly. */ if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd); /* Unix systems should never shell-out while processing an HTTP request, ** either via CGI, SCGI, or direct HTTP. The following assert verifies ** this. And the following assert proves that Fossil is not vulnerable ** to the ShellShock or BashDoor bug. */ assert( g.cgiOutput==0 ); /* The regular system() call works to get a shell on unix */ fossil_limit_memory(0); rc = system(zOrigCmd); fossil_limit_memory(1); #endif return rc; } /* ** Like strcmp() except that it accepts NULL pointers. NULL sorts before ** all non-NULL string pointers. Also, this strcmp() is a binary comparison ** that does not consider locale. */ int fossil_strcmp(const char *zA, const char *zB){ if( zA==0 ){ if( zB==0 ) return 0; return -1; }else if( zB==0 ){ return +1; }else{ int a, b; do{ a = *zA++; b = *zB++; }while( a==b && a!=0 ); return ((unsigned char)a) - (unsigned char)b; } } int fossil_strncmp(const char *zA, const char *zB, int nByte){ if( zA==0 ){ if( zB==0 ) return 0; return -1; }else if( zB==0 ){ |
︙ | ︙ | |||
447 448 449 450 451 452 453 | } if( piKernel ){ *piKernel = ((sqlite3_uint64)s.ru_stime.tv_sec)*1000000 + s.ru_stime.tv_usec; } #endif } | < < < < < < < < < < < < < < | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | } if( piKernel ){ *piKernel = ((sqlite3_uint64)s.ru_stime.tv_sec)*1000000 + s.ru_stime.tv_usec; } #endif } /* ** Internal helper type for fossil_timer_xxx(). */ enum FossilTimerEnum { FOSSIL_TIMER_COUNT = 10 /* Number of timers we can track. */ }; |
︙ | ︙ | |||
593 594 595 596 597 598 599 | #endif } /* ** Returns TRUE if zSym is exactly HNAME_LEN_SHA1 or HNAME_LEN_K256 ** bytes long and contains only lower-case ASCII hexadecimal values. */ | | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | #endif } /* ** Returns TRUE if zSym is exactly HNAME_LEN_SHA1 or HNAME_LEN_K256 ** bytes long and contains only lower-case ASCII hexadecimal values. */ int fossil_is_uuid(const char *zSym){ int sz = zSym ? (int)strlen(zSym) : 0; return (HNAME_LEN_SHA1==sz || HNAME_LEN_K256==sz) && validate16(zSym, sz); } /* ** Return true if the input string is NULL or all whitespace. ** Return false if the input string contains text. |
︙ | ︙ | |||
643 644 645 646 647 648 649 | } /* ** Construct a temporary filename. ** ** The returned string is obtained from sqlite3_malloc() and must be ** freed by the caller. | < < | < < < < < < < < < < < < < < < < < < | < < < < < < > < < < < < < < < < < < < < < | < | < | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | } /* ** Construct a temporary filename. ** ** The returned string is obtained from sqlite3_malloc() and must be ** freed by the caller. */ char *fossil_temp_filename(void){ char *zTFile = 0; sqlite3 *db; if( g.db ){ db = g.db; }else{ sqlite3_open("",&db); } sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTFile); if( g.db==0 ) sqlite3_close(db); return zTFile; } /* ** Turn memory limits for stack and heap on and off. The argument ** is true to turn memory limits on and false to turn them off. ** |
︙ | ︙ | |||
753 754 755 756 757 758 759 | void fossil_pledge(const char *promises){ if( pledge(promises, 0) ){ fossil_panic("pledge(\"%s\",NULL) fails with errno=%d", promises, (int)errno); } } #endif /* defined(HAVE_PLEDGE) */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 523 524 525 526 527 528 529 | void fossil_pledge(const char *promises){ if( pledge(promises, 0) ){ fossil_panic("pledge(\"%s\",NULL) fails with errno=%d", promises, (int)errno); } } #endif /* defined(HAVE_PLEDGE) */ |
Changes to src/verify.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | ** This routine is called just prior to each commit operation. ** ** Invoke verify_rid() on every record that has been added or modified ** in the repository, in order to make sure that the repository is sane. */ static int verify_at_commit(void){ int rid; | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ** This routine is called just prior to each commit operation. ** ** Invoke verify_rid() on every record that has been added or modified ** in the repository, in order to make sure that the repository is sane. */ static int verify_at_commit(void){ int rid; content_clear_cache(); inFinalVerify = 1; rid = bag_first(&toVerify); while( rid>0 ){ verify_rid(rid); rid = bag_next(&toVerify, rid); } bag_clear(&toVerify); |
︙ | ︙ |
Changes to src/vfile.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | db_begin_transaction(); p = manifest_get(vid, CFTYPE_MANIFEST, 0); if( p==0 ) { db_end_transaction(1); return 0; } db_prepare(&ins, | | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | db_begin_transaction(); p = manifest_get(vid, CFTYPE_MANIFEST, 0); if( p==0 ) { db_end_transaction(1); return 0; } db_prepare(&ins, "INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname) " " VALUES(:vid,:isexe,:islink,:id,:id,:name)"); db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid"); db_bind_int(&ins, ":vid", vid); manifest_file_rewind(p); nMissing = 0; while( (pFile = manifest_file_next(p,0))!=0 ){ if( pFile->zUuid==0 || uuid_is_shunned(pFile->zUuid) ) continue; db_bind_text(&ridq, ":uuid", pFile->zUuid); |
︙ | ︙ | |||
157 158 159 160 161 162 163 | ** the file has changed without having the check the size, mtime, ** or on-disk content. ** ** If the size of the file has changed, then we always know that the file ** changed without having to look at the mtime or on-disk content. ** ** The mtime of the file is only a factor if the mtime-changes setting | > | < | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | ** the file has changed without having the check the size, mtime, ** or on-disk content. ** ** If the size of the file has changed, then we always know that the file ** changed without having to look at the mtime or on-disk content. ** ** The mtime of the file is only a factor if the mtime-changes setting ** is false and the CKSIG_HASH flag is false. If the mtime-changes ** setting is true (or undefined - it defaults to true) or if CKSIG_HASH ** is true, then we do not trust the mtime and will examine the on-disk ** content to determine if a file really is the same. ** ** If the mtime is used, it is used only to determine if files are the same. ** If the mtime of a file has changed, we still examine the on-disk content ** to see whether or not the edit was a null-edit. */ void vfile_check_signature(int vid, unsigned int cksigFlags){ int nErr = 0; |
︙ | ︙ | |||
240 241 242 243 244 245 246 | ** if --hash is used, check to see if they have been edited by ** looking at their artifact hashes */ const char *zUuid = db_column_text(&q, 5); int nUuid = db_column_bytes(&q, 5); assert( origSize==currentSize ); if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1; } | | < < < | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | ** if --hash is used, check to see if they have been edited by ** looking at their artifact hashes */ const char *zUuid = db_column_text(&q, 5); int nUuid = db_column_bytes(&q, 5); assert( origSize==currentSize ); if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1; } if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){ i64 desiredMtime; if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){ if( currentMtime!=desiredMtime ){ file_set_mtime(zName, desiredMtime); currentMtime = file_mtime(zName, RepoFILE); } } } #ifndef _WIN32 if( origPerm!=PERM_LNK && currentPerm==PERM_LNK ){ /* Changing to a symlink takes priority over all other change types. */ chnged = 7; }else if( chnged==0 || chnged==6 || chnged==7 || chnged==8 || chnged==9 ){ /* Confirm metadata change types. */ if( origPerm==currentPerm ){ chnged = 0; }else if( currentPerm==PERM_EXE ){ chnged = 6; }else if( origPerm==PERM_EXE ){ |
︙ | ︙ | |||
314 315 316 317 318 319 320 | const char *zName; id = db_column_int(&q, 0); zName = db_column_text(&q, 1); rid = db_column_int(&q, 2); isExe = db_column_int(&q, 3); isLink = db_column_int(&q, 4); | < < < | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | const char *zName; id = db_column_int(&q, 0); zName = db_column_text(&q, 1); rid = db_column_int(&q, 2); isExe = db_column_int(&q, 3); isLink = db_column_int(&q, 4); content_get(rid, &content); if( file_is_the_same(&content, zName) ){ blob_reset(&content); if( file_setexe(zName, isExe) ){ db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName, RepoFILE), id); } |
︙ | ︙ | |||
363 364 365 366 367 368 369 370 | blob_reset(&content); db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName, RepoFILE), id); } db_finalize(&q); } /* | > > > > > > > > > > > > > > > > > > | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 | blob_reset(&content); db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName, RepoFILE), id); } db_finalize(&q); } /* ** Delete from the disk every file in VFILE vid. */ void vfile_unlink(int vid){ Stmt q; db_prepare(&q, "SELECT %Q || pathname FROM vfile" " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid); while( db_step(&q)==SQLITE_ROW ){ const char *zName; zName = db_column_text(&q, 0); file_delete(zName); } db_finalize(&q); db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid); } /* ** Check to see if the directory named in zPath is the top of a checkout. ** In other words, check to see if directory pPath contains a file named ** "_FOSSIL_" or ".fslckout". Return true or false. */ int vfile_top_of_checkout(const char *zPath){ char *zFile; int fileFound = 0; zFile = mprintf("%s/_FOSSIL_", zPath); fileFound = file_size(zFile, ExtFILE)>=1024; fossil_free(zFile); if( !fileFound ){ zFile = mprintf("%s/.fslckout", zPath); fileFound = file_size(zFile, ExtFILE)>=1024; fossil_free(zFile); } /* Check for ".fos" for legacy support. But the use of ".fos" as the ** per-checkout database name is deprecated. At some point, all support ** for ".fos" will end and this code should be removed. This comment ** added on 2012-02-04. */ if( !fileFound ){ zFile = mprintf("%s/.fos", zPath); fileFound = file_size(zFile, ExtFILE)>=1024; fossil_free(zFile); |
︙ | ︙ | |||
408 409 410 411 412 413 414 | "original", "output", }; int i, j, n; if( sqlite3_strglob("ci-comment-????????????.txt", zName)==0 ) return 1; for(; zName[0]!=0; zName++){ | < | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | "original", "output", }; int i, j, n; if( sqlite3_strglob("ci-comment-????????????.txt", zName)==0 ) return 1; for(; zName[0]!=0; zName++){ if( zName[0]=='/' && sqlite3_strglob("/ci-comment-????????????.txt", zName)==0 ){ return 1; } if( zName[0]!='-' ) continue; for(i=0; i<count(azTemp); i++){ n = (int)strlen(azTemp[i]); if( memcmp(azTemp[i], zName+1, n) ) continue; if( zName[n+1]==0 ) return 1; |
︙ | ︙ | |||
435 436 437 438 439 440 441 | ** Values for the scanFlags parameter to vfile_scan(). */ #define SCAN_ALL 0x001 /* Includes files that begin with "." */ #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */ #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */ #define SCAN_MTIME 0x008 /* Populate mtime column */ #define SCAN_SIZE 0x010 /* Populate size column */ | < < > | < | < < | | < < < < < < < < < < | | | | < | | < | | < | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | ** Values for the scanFlags parameter to vfile_scan(). */ #define SCAN_ALL 0x001 /* Includes files that begin with "." */ #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */ #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */ #define SCAN_MTIME 0x008 /* Populate mtime column */ #define SCAN_SIZE 0x010 /* Populate size column */ #endif /* INTERFACE */ /* ** Load into table SFILE the name of every ordinary file in ** the directory pPath. Omit the first nPrefix characters of ** of pPath when inserting into the SFILE table. ** ** Subdirectories are scanned recursively. ** Omit files named in VFILE. ** ** Files whose names begin with "." are omitted unless the SCAN_ALL ** flag is set. ** ** Any files or directories that match the glob patterns pIgnore* ** are excluded from the scan. Name matching occurs after the ** first nPrefix characters are elided from the filename. */ void vfile_scan( Blob *pPath, /* Directory to be scanned */ int nPrefix, /* Number of bytes in directory name */ unsigned scanFlags, /* Zero or more SCAN_xxx flags */ Glob *pIgnore1, /* Do not add files that match this GLOB */ Glob *pIgnore2 /* Omit files matching this GLOB too */ ){ DIR *d; int origSize; struct dirent *pEntry; int skipAll = 0; static Stmt ins; static int depth = 0; void *zNative; origSize = blob_size(pPath); if( pIgnore1 || pIgnore2 ){ blob_appendf(pPath, "/"); if( glob_match(pIgnore1, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1; if( glob_match(pIgnore2, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1; blob_resize(pPath, origSize); } if( skipAll ) return; if( depth==0 ){ db_prepare(&ins, "INSERT OR IGNORE INTO sfile(pathname%s%s) SELECT :file%s%s" " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE" " pathname=:file %s)", scanFlags & SCAN_MTIME ? ", mtime" : "", scanFlags & SCAN_SIZE ? ", size" : "", scanFlags & SCAN_MTIME ? ", :mtime" : "", scanFlags & SCAN_SIZE ? ", :size" : "", filename_collation() ); } depth++; zNative = fossil_utf8_to_path(blob_str(pPath), 1); d = opendir(zNative); if( d ){ while( (pEntry=readdir(d))!=0 ){ |
︙ | ︙ | |||
526 527 528 529 530 531 532 | blob_appendf(pPath, "/%s", zUtf8); zPath = blob_str(pPath); if( glob_match(pIgnore1, &zPath[nPrefix+1]) || glob_match(pIgnore2, &zPath[nPrefix+1]) ){ /* do nothing */ #ifdef _DIRENT_HAVE_D_TYPE }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) | | | | | | < < < | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | blob_appendf(pPath, "/%s", zUtf8); zPath = blob_str(pPath); if( glob_match(pIgnore1, &zPath[nPrefix+1]) || glob_match(pIgnore2, &zPath[nPrefix+1]) ){ /* do nothing */ #ifdef _DIRENT_HAVE_D_TYPE }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) ? (file_isdir(zPath, RepoFILE)==1) : (pEntry->d_type==DT_DIR) ){ #else }else if( file_isdir(zPath, RepoFILE)==1 ){ #endif if( !vfile_top_of_checkout(zPath) ){ vfile_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2); } #ifdef _DIRENT_HAVE_D_TYPE }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) ? (file_isfile_or_link(zPath)) : (pEntry->d_type==DT_REG) ){ #else }else if( file_isfile_or_link(zPath) ){ #endif if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){ db_bind_text(&ins, ":file", &zPath[nPrefix+1]); if( scanFlags & SCAN_MTIME ){ db_bind_int(&ins, ":mtime", file_mtime(zPath, RepoFILE)); } if( scanFlags & SCAN_SIZE ){ db_bind_int(&ins, ":size", file_size(zPath, RepoFILE)); } db_step(&ins); db_reset(&ins); } } fossil_path_free(zUtf8); blob_resize(pPath, origSize); |
︙ | ︙ | |||
589 590 591 592 593 594 595 | ** Returns the total number of files found. */ int vfile_dir_scan( Blob *pPath, /* Base directory to be scanned */ int nPrefix, /* Number of bytes in base directory name */ unsigned scanFlags, /* Zero or more SCAN_xxx flags */ Glob *pIgnore1, /* Do not add directories that match this GLOB */ | | < | 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | ** Returns the total number of files found. */ int vfile_dir_scan( Blob *pPath, /* Base directory to be scanned */ int nPrefix, /* Number of bytes in base directory name */ unsigned scanFlags, /* Zero or more SCAN_xxx flags */ Glob *pIgnore1, /* Do not add directories that match this GLOB */ Glob *pIgnore2 /* Omit directories matching this GLOB too */ ){ int result = 0; DIR *d; int origSize; struct dirent *pEntry; int skipAll = 0; static Stmt ins; |
︙ | ︙ | |||
650 651 652 653 654 655 656 | blob_appendf(pPath, "/%s", zUtf8); zPath = blob_str(pPath); if( glob_match(pIgnore1, &zPath[nPrefix+1]) || glob_match(pIgnore2, &zPath[nPrefix+1]) ){ /* do nothing */ #ifdef _DIRENT_HAVE_D_TYPE }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) | | | | | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 | blob_appendf(pPath, "/%s", zUtf8); zPath = blob_str(pPath); if( glob_match(pIgnore1, &zPath[nPrefix+1]) || glob_match(pIgnore2, &zPath[nPrefix+1]) ){ /* do nothing */ #ifdef _DIRENT_HAVE_D_TYPE }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) ? (file_isdir(zPath, RepoFILE)==1) : (pEntry->d_type==DT_DIR) ){ #else }else if( file_isdir(zPath, RepoFILE)==1 ){ #endif if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){ char *zSavePath = mprintf("%s", zPath); int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2); db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]); db_bind_int(&ins, ":count", count); db_step(&ins); db_reset(&ins); fossil_free(zSavePath); result += count; /* found X normal files? */ } |
︙ | ︙ | |||
753 754 755 756 757 758 759 | md5sum_step_text(" 0\n", -1); continue; } fseek(in, 0L, SEEK_END); sqlite3_snprintf(sizeof(zBuf), zBuf, " %ld\n", ftell(in)); fseek(in, 0L, SEEK_SET); md5sum_step_text(zBuf, -1); | | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | md5sum_step_text(" 0\n", -1); continue; } fseek(in, 0L, SEEK_END); sqlite3_snprintf(sizeof(zBuf), zBuf, " %ld\n", ftell(in)); fseek(in, 0L, SEEK_SET); md5sum_step_text(zBuf, -1); /*printf("%s %s %s",md5sum_current_state(),zName,zBuf); fflush(stdout);*/ for(;;){ int n; n = fread(zBuf, 1, sizeof(zBuf), in); if( n<=0 ) break; md5sum_step_text(zBuf, n); } fclose(in); |
︙ | ︙ | |||
974 975 976 977 978 979 980 | vfile_aggregate_checksum_repository(vid, &hash); printf("archive: %s\n", blob_str(&hash)); blob_reset(&hash); vfile_aggregate_checksum_manifest(vid, &hash, &hash2); printf("manifest: %s\n", blob_str(&hash)); printf("recorded: %s\n", blob_str(&hash2)); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 964 965 966 967 968 969 970 | vfile_aggregate_checksum_repository(vid, &hash); printf("archive: %s\n", blob_str(&hash)); blob_reset(&hash); vfile_aggregate_checksum_manifest(vid, &hash, &hash2); printf("manifest: %s\n", blob_str(&hash)); printf("recorded: %s\n", blob_str(&hash2)); } |
Added src/webmail.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | /* ** Copyright (c) 2018 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Implementation of web pages for managing the email storage tables ** (if they exist): ** ** emailbox ** emailblob ** emailroute */ #include "config.h" #include "webmail.h" #include <assert.h> #if INTERFACE /* Recognized content encodings */ #define EMAILENC_NONE 0 /* No encoding */ #define EMAILENC_B64 1 /* Base64 encoded */ #define EMAILENC_QUOTED 2 /* Quoted printable */ /* An instance of the following object records the location of important ** attributes on a single element in a multipart email message body. */ struct EmailBody { char zMimetype[32]; /* Mimetype */ u8 encoding; /* Type of encoding */ char *zFilename; /* From content-disposition: */ char *zContent; /* Content. \0 terminator inserted */ }; /* ** An instance of the following object describes the struture of ** an rfc-2822 email message. */ struct EmailToc { int nHdr; /* Number of header lines */ int nHdrAlloc; /* Number of header lines allocated */ char **azHdr; /* Pointer to header line. \0 terminator inserted */ int nBody; /* Number of body segments */ int nBodyAlloc; /* Number of body segments allocated */ EmailBody *aBody; /* Location of body information */ }; #endif /* ** Free An EmailToc object */ void emailtoc_free(EmailToc *p){ int i; fossil_free(p->azHdr); for(i=0; i<p->nBody; i++){ fossil_free(p->aBody[i].zFilename); } fossil_free(p->aBody); fossil_free(p); } /* ** Allocate a new EmailToc object */ EmailToc *emailtoc_alloc(void){ EmailToc *p = fossil_malloc( sizeof(*p) ); memset(p, 0, sizeof(*p)); return p; } /* ** Add a new body element to an EmailToc. */ EmailBody *emailtoc_new_body(EmailToc *p){ EmailBody *pNew; p->nBody++; if( p->nBody>p->nBodyAlloc ){ p->nBodyAlloc = (p->nBodyAlloc+1)*2; p->aBody = fossil_realloc(p->aBody, sizeof(p->aBody[0])*p->nBodyAlloc); } pNew = &p->aBody[p->nBody-1]; memset(pNew, 0, sizeof(*pNew)); return pNew; } /* ** Add a new header line to the EmailToc. */ void emailtoc_new_header_line(EmailToc *p, char *z){ p->nHdr++; if( p->nHdr>p->nHdrAlloc ){ p->nHdrAlloc = (p->nHdrAlloc+1)*2; p->azHdr = fossil_realloc(p->azHdr, sizeof(p->azHdr[0])*p->nHdrAlloc); } p->azHdr[p->nHdr-1] = z; } /* ** Return the length of a line in an email header. Continuation lines ** are included. Hence, this routine returns the number of bytes up to ** and including the first \n character that is followed by something ** other than whitespace. */ static int email_line_length(const char *z){ int i; for(i=0; z[i] && (z[i]!='\n' || z[i+1]==' ' || z[i+1]=='\t'); i++){} if( z[i]=='\n' ) i++; return i; } /* ** Look for a parameter of the form NAME=VALUE in the given email ** header line. Return a copy of VALUE in space obtained from ** fossil_malloc(). Or return NULL if there is no such parameter. */ static char *email_hdr_value(const char *z, const char *zName){ int nName = (int)strlen(zName); int i; const char *z2 = strstr(z, zName); if( z2==0 ) return 0; z2 += nName; if( z2[0]!='=' ) return 0; z2++; if( z2[0]=='"' ){ z2++; for(i=0; z2[i] && z2[i]!='"'; i++){} if( z2[i]!='"' ) return 0; }else{ for(i=0; z2[i] && !fossil_isspace(z2[i]); i++){} } return mprintf("%.*s", i, z2); } /* ** Return a pointer to the first non-whitespace character in z */ static const char *firstToken(const char *z){ while( fossil_isspace(*z) ){ z++; } return z; } /* ** The n-bytes of content in z is a single multipart mime segment ** with its own header and body. Decode this one segment and add it to p; ** ** Rows of the header of the segment are added to p if bAddHeader is ** true. */ LOCAL void emailtoc_add_multipart_segment( EmailToc *p, /* Append the segments here */ char *z, /* The body component */ int bAddHeader /* True to add header lines to p */ ){ int i, j; int n; int multipartBody = 0; EmailBody *pBody = emailtoc_new_body(p); i = 0; while( z[i] ){ n = email_line_length(&z[i]); if( (n==2 && z[i]=='\r' && z[i+1]=='\n') || z[i]=='\n' || n==0 ){ /* This is the blank line at the end of the header */ i += n; break; } for(j=i+n; j>i && fossil_isspace(z[j-1]); j--){} z[j] = 0; if( sqlite3_strnicmp(z+i, "Content-Type:", 13)==0 ){ const char *z2 = firstToken(z+i+13); if( z2 && strncmp(z2, "multipart/", 10)==0 ){ multipartBody = 1; }else{ int j; for(j=0; z2[j]=='/' || fossil_isalnum(z2[j]); j++){} if( j>=sizeof(pBody->zMimetype) ) j = sizeof(pBody->zMimetype); memcpy(pBody->zMimetype, z2, j); pBody->zMimetype[j] = 0; } } /* 123456789 123456789 123456 */ if( sqlite3_strnicmp(z+i, "Content-Transfer-Encoding:", 26)==0 ){ const char *z2 = firstToken(z+(i+26)); if( z2 && sqlite3_strnicmp(z2, "base64", 6)==0 ){ pBody->encoding = EMAILENC_B64; /* 123456789 123456 */ }else if( sqlite3_strnicmp(z2, "quoted-printable", 16)==0 ){ pBody->encoding = EMAILENC_QUOTED; }else{ pBody->encoding = EMAILENC_NONE; } } if( bAddHeader ){ emailtoc_new_header_line(p, z+i); }else if( sqlite3_strnicmp(z+i, "Content-Disposition:", 20)==0 ){ /* 123456789 123456789 */ fossil_free(pBody->zFilename); pBody->zFilename = email_hdr_value(z+i, "filename"); } i += n; } if( multipartBody ){ p->nBody--; emailtoc_add_multipart(p, z+i); }else{ pBody->zContent = z+i; } } /* ** The n-bytes of content in z are a multipart/ body component for ** an email message. Decode this into its individual segments. ** ** The component should start and end with a boundary line. There ** may be additional boundary lines in the middle. */ LOCAL void emailtoc_add_multipart( EmailToc *p, /* Append the segments here */ char *z /* The body component. zero-terminated */ ){ int nB; /* Size of the boundary string */ int iStart; /* Start of the coding region past boundary mark */ int i; /* Loop index */ char *zBoundary = 0; /* Boundary marker */ /* Skip forward to the beginning of the boundary mark. The boundary ** mark always begins with "--" */ while( z[0]!='-' || z[1]!='-' ){ while( z[0] && z[0]!='\n' ) z++; if( z[0]==0 ) return; z++; } /* Find the length of the boundary mark. */ zBoundary = z; for(nB=0; z[nB] && !fossil_isspace(z[nB]); nB++){} if( nB==0 ) return; z += nB; while( fossil_isspace(z[0]) ) z++; zBoundary[nB] = 0; for(i=iStart=0; z[i]; i++){ if( z[i]=='\n' && strncmp(z+i+1, zBoundary, nB)==0 ){ z[i+1] = 0; emailtoc_add_multipart_segment(p, z+iStart, 0); iStart = i+nB; if( z[iStart]=='-' && z[iStart+1]=='-' ) return; while( fossil_isspace(z[iStart]) ) iStart++; i = iStart; } } } /* ** Compute a table-of-contents (EmailToc) for the email message ** provided on the input. ** ** This routine will cause pEmail to become zero-terminated if it is ** not already. It will also insert zero characters into parts of ** the message, to delimit the various components. */ EmailToc *emailtoc_from_email(Blob *pEmail){ char *z; EmailToc *p = emailtoc_alloc(); blob_terminate(pEmail); z = blob_buffer(pEmail); emailtoc_add_multipart_segment(p, z, 1); return p; } /* ** Inplace-unfolding of an email header line. ** ** Actually - this routine works by converting all contiguous sequences ** of whitespace into a single space character. */ static void email_hdr_unfold(char *z){ int i, j; char c; for(i=j=0; (c = z[i])!=0; i++){ if( fossil_isspace(c) ){ c = ' '; if( j && z[j-1]==' ' ) continue; } z[j++] = c; } z[j] = 0; } /* ** COMMAND: test-decode-email ** ** Usage: %fossil test-decode-email FILE ** ** Read an rfc-2822 formatted email out of FILE, then write a decoding ** to stdout. Use for testing and validating the email decoder. */ void test_email_decode_cmd(void){ Blob email; EmailToc *p; int i; verify_all_options(); if( g.argc!=3 ) usage("FILE"); blob_read_from_file(&email, g.argv[2], ExtFILE); p = emailtoc_from_email(&email); fossil_print("%d header line and %d content segments\n", p->nHdr, p->nBody); for(i=0; i<p->nHdr; i++){ email_hdr_unfold(p->azHdr[i]); fossil_print("%3d: %s\n", i, p->azHdr[i]); } for(i=0; i<p->nBody; i++){ fossil_print("\nBODY %d mime \"%s\" encoding %d", i, p->aBody[i].zMimetype, p->aBody[i].encoding); if( p->aBody[i].zFilename ){ fossil_print(" filename \"%s\"", p->aBody[i].zFilename); } fossil_print("\n"); if( strncmp(p->aBody[i].zMimetype,"text/",5)!=0 ) continue; switch( p->aBody[i].encoding ){ case EMAILENC_B64: { int n = 0; decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent); fossil_print("%s", p->aBody[i].zContent); if( n && p->aBody[i].zContent[n-1]!='\n' ) fossil_print("\n"); break; } case EMAILENC_QUOTED: { int n = 0; decodeQuotedPrintable(p->aBody[i].zContent, &n); fossil_print("%s", p->aBody[i].zContent); if( n && p->aBody[i].zContent[n-1]!='\n' ) fossil_print("\n"); break; } default: { fossil_print("%s\n", p->aBody[i].zContent); break; } } } emailtoc_free(p); blob_reset(&email); } /* ** Add the select/option box to the timeline submenu that shows ** the various email message formats. */ static void webmail_f_submenu(void){ static const char *az[] = { "0", "Normal", "1", "Decoded", "2", "Raw", }; style_submenu_multichoice("f", sizeof(az)/(2*sizeof(az[0])), az, 0); } /* ** If the first N characters of z[] are the name of a header field ** that should be shown in "Normal" mode, then return 1. */ static int webmail_normal_header(const char *z, int N){ static const char *az[] = { "To", "Cc", "Bcc", "Date", "From", "Subject", }; int i; for(i=0; i<sizeof(az)/sizeof(az[0]); i++){ if( sqlite3_strnicmp(z, az[i], N)==0 ) return 1; } return 0; } /* ** Paint a page showing a single email message */ static void webmail_show_one_message( HQuery *pUrl, /* Calling context */ int emailid, /* emailbox.ebid to display */ const char *zUser /* User who owns it, or NULL if does not matter */ ){ Blob sql; Stmt q; int eState = -1; int eTranscript = 0; char zENum[30]; style_submenu_element("Index", "%s", url_render(pUrl,"id",0,0,0)); webmail_f_submenu(); blob_init(&sql, 0, 0); db_begin_transaction(); blob_append_sql(&sql, "SELECT decompress(etxt), estate, emailblob.ets" " FROM emailblob, emailbox" " WHERE emailid=emsgid AND ebid=%d", emailid ); if( zUser ) blob_append_sql(&sql, " AND euser=%Q", zUser); db_prepare_blob(&q, &sql); blob_reset(&sql); style_header("Message %d",emailid); if( db_step(&q)==SQLITE_ROW ){ Blob msg = db_column_text_as_blob(&q, 0); int eFormat = atoi(PD("f","0")); eState = db_column_int(&q, 1); eTranscript = db_column_int(&q, 2); if( eFormat==2 ){ @ <pre>%h(db_column_text(&q, 0))</pre> }else{ EmailToc *p = emailtoc_from_email(&msg); int i, j; @ <p> for(i=0; i<p->nHdr; i++){ char *z = p->azHdr[i]; email_hdr_unfold(z); for(j=0; z[j] && z[j]!=':'; j++){} if( eFormat==0 && !webmail_normal_header(z, j) ) continue; if( z[j]!=':' ){ @ %h(z)<br> }else{ z[j] = 0; @ <b>%h(z):</b> %h(z+j+1)<br> } } for(i=0; i<p->nBody; i++){ @ <hr><b>Messsage Body #%d(i): %h(p->aBody[i].zMimetype) \ if( p->aBody[i].zFilename ){ @ "%h(p->aBody[i].zFilename)" } @ </b> if( eFormat==0 ){ if( strncmp(p->aBody[i].zMimetype, "text/plain", 10)!=0 ) continue; if( p->aBody[i].zFilename ) continue; }else{ if( strncmp(p->aBody[i].zMimetype, "text/", 5)!=0 ) continue; } switch( p->aBody[i].encoding ){ case EMAILENC_B64: { int n = 0; decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent); break; } case EMAILENC_QUOTED: { int n = 0; decodeQuotedPrintable(p->aBody[i].zContent, &n); break; } } @ <pre>%h(p->aBody[i].zContent)</pre> } } } db_finalize(&q); /* Optionally show the SMTP transcript */ if( eTranscript>0 && db_exists("SELECT 1 FROM emailblob WHERE emailid=%d", eTranscript) ){ if( P("ts")==0 ){ sqlite3_snprintf(sizeof(zENum), zENum, "%d", emailid); style_submenu_element("SMTP Transcript","%s", url_render(pUrl, "ts", "1", "id", zENum)); }else{ db_prepare(&q, "SELECT decompress(etxt) FROM emailblob WHERE emailid=%d", eTranscript ); if( db_step(&q)==SQLITE_ROW ){ const char *zTranscript = db_column_text(&q, 0); @ <hr> @ <pre>%h(zTranscript)</pre> } db_finalize(&q); } } if( eState==0 ){ /* If is message is currently Unread, change it to Read */ blob_append_sql(&sql, "UPDATE emailbox SET estate=1 " " WHERE estate=0 AND ebid=%d", emailid ); if( zUser ) blob_append_sql(&sql, " AND euser=%Q", zUser); db_multi_exec("%s", blob_sql_text(&sql)); blob_reset(&sql); eState = 1; } url_add_parameter(pUrl, "id", 0); sqlite3_snprintf(sizeof(zENum), zENum, "e%d", emailid); if( eState==2 ){ style_submenu_element("Undelete","%s", url_render(pUrl,"read","1",zENum,"1")); } if( eState==1 ){ style_submenu_element("Delete", "%s", url_render(pUrl,"trash","1",zENum,"1")); style_submenu_element("Mark As Unread", "%s", url_render(pUrl,"unread","1",zENum,"1")); } if( eState==3 ){ style_submenu_element("Delete", "%s", url_render(pUrl,"trash","1",zENum,"1")); } db_end_transaction(0); style_footer(); return; } /* ** Scan the query parameters looking for parameters with name of the ** form "eN" where N is an integer. For all such integers, change ** the state of every emailbox entry with ebid==N to eStateNew provided ** that either zUser is NULL or matches. ** ** Or if eNewState==99, then delete the entries. */ static void webmail_change_state(int eNewState, const char *zUser){ Blob sql; int sep = '('; int i; const char *zName; int n; if( !cgi_csrf_safe(0) ) return; blob_init(&sql, 0, 0); if( eNewState==99 ){ blob_append_sql(&sql, "DELETE FROM emailbox WHERE estate==2 AND ebid IN "); }else{ blob_append_sql(&sql, "UPDATE emailbox SET estate=%d WHERE ebid IN ", eNewState); } for(i=0; (zName = cgi_parameter_name(i))!=0; i++){ if( zName[0]!='e' ) continue; if( !fossil_isdigit(zName[1]) ) continue; n = atoi(zName+1); blob_append_sql(&sql, "%c%d", sep, n); sep = ','; } if( zUser ){ blob_append_sql(&sql, ") AND euser=%Q", zUser); }else{ blob_append_sql(&sql, ")"); } if( sep==',' ){ db_multi_exec("%s", blob_sql_text(&sql)); } blob_reset(&sql); } /* ** Add the select/option box to the timeline submenu that shows ** which messages to include in the index. */ static void webmail_d_submenu(void){ static const char *az[] = { "0", "InBox", "1", "Unread", "2", "Trash", "3", "Sent", "4", "Everything", }; style_submenu_multichoice("d", sizeof(az)/(2*sizeof(az[0])), az, 0); } /* ** WEBPAGE: webmail ** ** This page can be used to read content from the EMAILBOX table ** that contains email received by the "fossil smtpd" command. ** ** Query parameters: ** ** id=N Show a single email entry emailbox.ebid==N ** f=N Display format. 0: decoded 1: raw ** user=USER Show mailbox for USER (admin only). ** user=* Show mailbox for all users (admin only). ** d=N 0: inbox+unread 1: unread-only 2: trash 3: all ** eN Select email entry emailbox.ebid==N ** trash Move selected entries to trash (estate=2) ** read Mark selected entries as read (estate=1) ** unread Mark selected entries as unread (estate=0) ** */ void webmail_page(void){ int emailid; Stmt q; Blob sql; int showAll = 0; const char *zUser = 0; int d = 0; /* Display mode. 0..3. d= query parameter */ int pg = 0; /* Page number */ int N = 50; /* Results per page */ int got; /* Number of results on this page */ char zPPg[30]; /* Previous page */ char zNPg[30]; /* Next page */ HQuery url; login_check_credentials(); if( !login_is_individual() ){ login_needed(0); return; } if( !db_table_exists("repository","emailbox") ){ style_header("Webmail Not Available"); @ <p>This repository is not configured to provide webmail</p> style_footer(); return; } add_content_sql_commands(g.db); emailid = atoi(PD("id","0")); url_initialize(&url, "webmail"); if( g.perm.Admin ){ zUser = PD("user",g.zLogin); if( zUser ){ url_add_parameter(&url, "user", zUser); if( fossil_strcmp(zUser,"*")==0 ){ showAll = 1; zUser = 0; } } }else{ zUser = g.zLogin; } if( P("d") ) url_add_parameter(&url, "d", P("d")); if( emailid>0 ){ webmail_show_one_message(&url, emailid, zUser); return; } style_header("Webmail"); webmail_d_submenu(); db_begin_transaction(); if( P("trash")!=0 ) webmail_change_state(2,zUser); if( P("unread")!=0 ) webmail_change_state(0,zUser); if( P("read")!=0 ) webmail_change_state(1,zUser); if( P("purge")!=0 ) webmail_change_state(99,zUser); blob_init(&sql, 0, 0); blob_append_sql(&sql, "CREATE TEMP TABLE tmbox AS " "SELECT ebid," /* 0 */ " efrom," /* 1 */ " datetime(edate,'unixepoch')," /* 2 */ " estate," /* 3 */ " esubject," /* 4 */ " euser" /* 5 */ " FROM emailbox" ); d = atoi(PD("d","0")); switch( d ){ case 0: { /* Show unread and read */ blob_append_sql(&sql, " WHERE estate<=1"); break; } case 1: { /* Unread messages only */ blob_append_sql(&sql, " WHERE estate=0"); break; } case 2: { /* Trashcan only */ blob_append_sql(&sql, " WHERE estate=2"); break; } case 3: { /* Outgoing email only */ blob_append_sql(&sql, " WHERE estate=3"); break; } case 4: { /* Everything */ blob_append_sql(&sql, " WHERE 1"); break; } } if( showAll ){ style_submenu_element("My Emails", "%s", url_render(&url,"user",0,0,0)); }else if( zUser!=0 ){ style_submenu_element("All Users", "%s", url_render(&url,"user","*",0,0)); if( fossil_strcmp(zUser, g.zLogin)!=0 ){ style_submenu_element("My Emails", "%s", url_render(&url,"user",0,0,0)); } if( zUser ){ blob_append_sql(&sql, " AND euser=%Q", zUser); }else{ blob_append_sql(&sql, " AND euser=%Q", g.zLogin); } }else{ if( g.perm.Admin ){ style_submenu_element("All Users", "%s", url_render(&url,"user","*",0,0)); } blob_append_sql(&sql, " AND euser=%Q", g.zLogin); } pg = atoi(PD("pg","0")); blob_append_sql(&sql, " ORDER BY edate DESC limit %d offset %d", N+1, pg*N); db_multi_exec("%s", blob_sql_text(&sql)); got = db_int(0, "SELECT count(*) FROM tmbox"); db_prepare(&q, "SELECT * FROM tmbox LIMIT %d", N); blob_reset(&sql); @ <form action="%R/webmail" method="POST"> @ <input type="hidden" name="d" value="%d(d)"> @ <input type="hidden" name="user" value="%h(zUser?zUser:"*")"> @ <table border="0" width="100%%"> @ <tr><td align="left"> if( d==2 ){ @ <input type="submit" name="read" value="Undelete"> @ <input type="submit" name="purge" value="Delete Permanently"> }else{ @ <input type="submit" name="trash" value="Delete"> if( d!=1 ){ @ <input type="submit" name="unread" value="Mark as unread"> } @ <input type="submit" name="read" value="Mark as read"> } @ <button onclick="webmailSelectAll(); return false;">Select All</button> @ <a href="%h(url_render(&url,0,0,0,0))">refresh</a> @ </td><td align="right"> if( pg>0 ){ sqlite3_snprintf(sizeof(zPPg), zPPg, "%d", pg-1); @ <a href="%s(url_render(&url,"pg",zPPg,0,0))">< Newer</a> } if( got>50 ){ sqlite3_snprintf(sizeof(zNPg),zNPg,"%d",pg+1); @ <a href="%s(url_render(&url,"pg",zNPg,0,0))">Older ></a></td> } @ </table> @ <table> while( db_step(&q)==SQLITE_ROW ){ const char *zId = db_column_text(&q,0); const char *zFrom = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); const char *zSubject = db_column_text(&q, 4); if( zSubject==0 || zSubject[0]==0 ) zSubject = "(no subject)"; @ <tr> @ <td><input type="checkbox" class="webmailckbox" name="e%s(zId)"></td> @ <td>%h(zFrom)</td> @ <td><a href="%h(url_render(&url,"id",zId,0,0))">%h(zSubject)</a> \ @ %s(zDate)</td> if( showAll ){ const char *zTo = db_column_text(&q,5); @ <td><a href="%h(url_render(&url,"user",zTo,0,0))">%h(zTo)</a></td> } @ </tr> } db_finalize(&q); @ </table> @ </form> @ <script> @ function webmailSelectAll(){ @ var x = document.getElementsByClassName("webmailckbox"); @ for(i=0; i<x.length; i++){ @ x[i].checked = true; @ } @ } @ </script> style_footer(); db_end_transaction(0); } /* ** WEBPAGE: emailblob ** ** This page, accessible only to administrators, allows easy viewing of ** the emailblob table - the table that contains the text of email messages ** both inbound and outbound, and transcripts of SMTP sessions. ** ** id=N Show the text of emailblob with emailid==N ** */ void webmail_emailblob_page(void){ int id = atoi(PD("id","0")); Stmt q; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } add_content_sql_commands(g.db); style_header("emailblob table"); if( id>0 ){ style_submenu_element("Index", "%R/emailblob"); @ <ul> db_prepare(&q, "SELECT emailid FROM emailblob WHERE ets=%d", id); while( db_step(&q)==SQLITE_ROW ){ int id = db_column_int(&q, 0); @ <li> <a href="%R/emailblob?id=%d(id)">emailblob entry %d(id)</a> } db_finalize(&q); db_prepare(&q, "SELECT euser, estate FROM emailbox WHERE emsgid=%d", id); while( db_step(&q)==SQLITE_ROW ){ const char *zUser = db_column_text(&q, 0); int e = db_column_int(&q, 1); @ <li> emailbox for %h(zUser) state %d(e) } db_finalize(&q); db_prepare(&q, "SELECT efrom, eto FROM emailoutq WHERE emsgid=%d", id); while( db_step(&q)==SQLITE_ROW ){ const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); @ <li> emailoutq message body from %h(zFrom) to %h(zTo) } db_finalize(&q); db_prepare(&q, "SELECT efrom, eto FROM emailoutq WHERE ets=%d", id); while( db_step(&q)==SQLITE_ROW ){ const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); @ <li> emailoutq transcript from %h(zFrom) to %h(zTo) } db_finalize(&q); @ </ul> @ <hr> db_prepare(&q, "SELECT decompress(etxt) FROM emailblob WHERE emailid=%d", id); while( db_step(&q)==SQLITE_ROW ){ const char *zContent = db_column_text(&q, 0); @ <pre>%h(zContent)</pre> } db_finalize(&q); }else{ style_submenu_element("emailoutq table","%R/emailoutq"); db_prepare(&q, "SELECT emailid, enref, ets, datetime(etime,'unixepoch'), esz," " length(etxt)" " FROM emailblob ORDER BY etime DESC, emailid DESC"); @ <table border="1" cellpadding="5" cellspacing="0" class="sortable" \ @ data-column-types='nnntkk'> @ <thead><tr><th> emailid <th> enref <th> ets <th> etime \ @ <th> uncompressed <th> compressed </tr></thead><tbody> while( db_step(&q)==SQLITE_ROW ){ int id = db_column_int(&q, 0); int nref = db_column_int(&q, 1); int ets = db_column_int(&q, 2); const char *zDate = db_column_text(&q, 3); int sz = db_column_int(&q,4); int csz = db_column_int(&q,5); @ <tr> @ <td align="right"><a href="%R/emailblob?id=%d(id)">%d(id)</a> @ <td align="right">%d(nref)</td> if( ets>0 ){ @ <td align="right">%d(ets)</td> }else{ @ <td> </td> } @ <td>%h(zDate)</td> @ <td align="right" data-sortkey='%08x(sz)'>%,d(sz)</td> @ <td align="right" data-sortkey='%08x(csz)'>%,d(csz)</td> @ </tr> } @ </tbody></table> db_finalize(&q); style_table_sorter(); } style_footer(); } /* ** WEBPAGE: emailoutq ** ** This page, accessible only to administrators, allows easy viewing of ** the emailoutq table - the table that contains the email messages ** that are queued for transmission via SMTP. */ void webmail_emailoutq_page(void){ Stmt q; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } add_content_sql_commands(g.db); style_header("emailoutq table"); style_submenu_element("emailblob table","%R/emailblob"); db_prepare(&q, "SELECT edomain, efrom, eto, emsgid, " " datetime(ectime,'unixepoch')," " datetime(nullif(emtime,0),'unixepoch')," " ensend, ets" " FROM emailoutq" ); @ <table border="1" cellpadding="5" cellspacing="0" class="sortable" \ @ data-column-types='tttnttnn'> @ <thead><tr><th> edomain <th> efrom <th> eto <th> emsgid \ @ <th> ectime <th> emtime <th> ensend <th> ets </tr></thead><tbody> while( db_step(&q)==SQLITE_ROW ){ const char *zDomain = db_column_text(&q, 0); const char *zFrom = db_column_text(&q, 1); const char *zTo = db_column_text(&q, 2); int emsgid = db_column_int(&q, 3); const char *zCTime = db_column_text(&q, 4); const char *zMTime = db_column_text(&q, 5); int ensend = db_column_int(&q, 6); int ets = db_column_int(&q, 7); @ <tr> @ <td>%h(zDomain) @ <td>%h(zFrom) @ <td>%h(zTo) @ <td align="right"><a href="%R/emailblob?id=%d(emsgid)">%d(emsgid)</a> @ <td>%h(zCTime) @ <td>%h(zMTime) @ <td align="right">%d(ensend) if( ets>0 ){ @ <td align="right"><a href="%R/emailblob?id=%d(ets)">%d(ets)</a></td> }else{ @ <td> </td> } } @ </tbody></table> db_finalize(&q); style_table_sorter(); style_footer(); } |
Changes to src/wiki.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 | /* ** Check a wiki name. If it is not well-formed, then issue an error ** and return true. If it is well-formed, return false. */ static int check_name(const char *z){ if( !wiki_name_is_wellformed((const unsigned char *)z) ){ | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | 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 | /* ** Check a wiki name. If it is not well-formed, then issue an error ** and return true. If it is well-formed, return false. */ static int check_name(const char *z){ if( !wiki_name_is_wellformed((const unsigned char *)z) ){ style_header("Wiki Page Name Error"); @ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed. @ Rules for wiki page names: well_formed_wiki_name_rules(); style_footer(); return 1; } return 0; } /* ** WEBPAGE: home ** WEBPAGE: index ** WEBPAGE: not_found ** ** The /home, /index, and /not_found pages all redirect to the homepage ** configured by the administrator. */ void home_page(void){ char *zPageName = db_get("project-name",0); char *zIndexPage = db_get("index-page",0); login_check_credentials(); if( zIndexPage ){ const char *zPathInfo = P("PATH_INFO"); while( zIndexPage[0]=='/' ) zIndexPage++; while( zPathInfo[0]=='/' ) zPathInfo++; if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0; } if( zIndexPage ){ cgi_redirectf("%s/%s", g.zTop, zIndexPage); } if( !g.perm.RdWiki ){ cgi_redirectf("%s/login?g=%s/home", g.zTop, g.zTop); } if( zPageName ){ login_check_credentials(); g.zExtra = zPageName; cgi_set_parameter_nocopy("name", g.zExtra, 1); g.isHome = 1; wiki_page(); return; } style_header("Home"); @ <p>This is a stub home-page for the project. @ To fill in this page, first go to @ %z(href("%R/setup_config"))setup/config</a> @ and establish a "Project Name". Then create a @ wiki page with that name. The content of that wiki page @ will be displayed in place of this message.</p> style_footer(); } /* ** Return true if the given pagename is the name of the sandbox */ static int is_sandbox(const char *zPagename){ return fossil_stricmp(zPagename,"sandbox")==0 || |
︙ | ︙ | |||
187 188 189 190 191 192 193 | } /* ** Render wiki text according to its mimetype. ** ** text/x-fossil-wiki Fossil wiki ** text/x-markdown Markdown | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < < < < < < < < < < < < < | 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 | } /* ** Render wiki text according to its mimetype. ** ** text/x-fossil-wiki Fossil wiki ** text/x-markdown Markdown ** anything else... Plain text */ void wiki_render_by_mimetype(Blob *pWiki, const char *zMimetype){ if( zMimetype==0 || fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){ wiki_convert(pWiki, 0, 0); }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){ Blob tail = BLOB_INITIALIZER; markdown_to_html(pWiki, 0, &tail); @ %s(blob_str(&tail)) blob_reset(&tail); }else{ @ <pre class='textPlain'> @ %h(blob_str(pWiki)) @ </pre> } } /* ** WEBPAGE: md_rules ** ** Show a summary of the Markdown wiki formatting rules. */ void markdown_rules_page(void){ Blob x; int fTxt = P("txt")!=0; style_header("Markdown Formatting Rules"); if( fTxt ){ style_submenu_element("Formatted", "%R/md_rules"); }else{ style_submenu_element("Plain-Text", "%R/md_rules?txt=1"); } blob_init(&x, builtin_text("markdown.md"), -1); wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown"); blob_reset(&x); style_footer(); } /* ** WEBPAGE: wiki_rules ** ** Show a summary of the wiki formatting rules. */ void wiki_rules_page(void){ Blob x; int fTxt = P("txt")!=0; style_header("Wiki Formatting Rules"); if( fTxt ){ style_submenu_element("Formatted", "%R/wiki_rules"); }else{ style_submenu_element("Plain-Text", "%R/wiki_rules?txt=1"); } blob_init(&x, builtin_text("wiki.wiki"), -1); wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki"); blob_reset(&x); style_footer(); } /* ** Returns non-zero if moderation is required for wiki changes and wiki ** attachments. */ int wiki_need_moderation( |
︙ | ︙ | |||
342 343 344 345 346 347 348 349 | } if( (ok & W_HELP)!=0 ){ style_submenu_element("Help", "%R/wikihelp"); } if( (ok & W_NEW)!=0 && g.anon.NewWiki ){ style_submenu_element("New", "%R/wikinew"); } if( (ok & W_SANDBOX)!=0 ){ | > > > | < > > > > > > > > > > > > | | | < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < > | < < < < | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | } if( (ok & W_HELP)!=0 ){ style_submenu_element("Help", "%R/wikihelp"); } if( (ok & W_NEW)!=0 && g.anon.NewWiki ){ style_submenu_element("New", "%R/wikinew"); } #if 0 if( (ok & W_BLOG)!=0 #endif if( (ok & W_SANDBOX)!=0 ){ style_submenu_element("Sandbox", "%R/wiki?name=Sandbox"); } } /* ** WEBPAGE: wikihelp ** A generic landing page for wiki. */ void wiki_helppage(void){ login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } style_header("Wiki Help"); wiki_standard_submenu(W_ALL_BUT(W_HELP)); @ <h2>Wiki Links</h2> @ <ul> { char *zWikiHomePageName = db_get("index-page",0); if( zWikiHomePageName ){ @ <li> %z(href("%R%s",zWikiHomePageName)) @ %h(zWikiHomePageName)</a> wiki home page.</li> } } { char *zHomePageName = db_get("project-name",0); if( zHomePageName ){ @ <li> %z(href("%R/wiki?name=%t",zHomePageName)) @ %h(zHomePageName)</a> project home page.</li> } } @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li> @ <li> Formatting rules for %z(href("%R/wiki_rules"))Fossil Wiki</a> and for @ %z(href("%R/md_rules"))Markdown Wiki</a>.</li> @ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a> @ to experiment.</li> if( g.anon.NewWiki ){ @ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li> if( g.anon.Write ){ @ <li> Create a %z(href("%R/technoteedit"))new tech-note</a>.</li> } } @ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a> @ available on this server.</li> if( g.anon.ModWiki ){ @ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li> } if( search_restrict(SRCH_WIKI)!=0 ){ @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key @ words</li> } @ </ul> style_footer(); return; } /* ** WEBPAGE: wikisrch ** Usage: /wikisrch?s=PATTERN ** ** Full-text search of all current wiki text */ void wiki_srchpage(void){ login_check_credentials(); style_header("Wiki Search"); wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX); search_screen(SRCH_WIKI, 0); style_footer(); } /* ** WEBPAGE: wiki ** URL: /wiki?name=PAGENAME */ void wiki_page(void){ char *zTag; int rid = 0; int isSandbox; char *zUuid; unsigned submenuFlags = W_ALL; Blob wiki; Manifest *pWiki = 0; const char *zPageName; const char *zMimetype = 0; char *zBody = mprintf("%s","<i>Empty Page</i>"); login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } zPageName = P("name"); if( zPageName==0 ){ if( search_restrict(SRCH_WIKI)!=0 ){ wiki_srchpage(); }else{ wiki_helppage(); } return; |
︙ | ︙ | |||
591 592 593 594 595 596 597 | pWiki = manifest_get(rid, CFTYPE_WIKI, 0); if( pWiki ){ zBody = pWiki->zWiki; zMimetype = pWiki->zMimetype; } } zMimetype = wiki_filter_mimetypes(zMimetype); | | > > > > > | | < | > > > > > | | > > > > > > | > < | | < | < < < < < | < | | < > < < < < < < < | < | | < < < | < < < | | | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | > | < | < < < | < < < < | < < | > | | | | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < | < > > > > > > > | | > | | | < < | < < < < < < < < | | < | < < < < < < < < < < < | > | | < < < | | < | < < < < < < < < < < < < < < < | < | < < < < < < < < > > | < < < < < < | | > | | | < | < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < < < | < < < < < < < < | > | < < | | < < < < < < | < < < < | < | < < < < < < < < < < < < < | < < < < | < | | < < < < < | < < < < < < < < < < | < < < | | < < < > | < < | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < | < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < > > | | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | < < < | < < < < < < < < < < < | | | | < < < < < | | < < < | < < < < | | < | < < < > | < < > > | < < < < < < < < < < < < < < < < < < < | < < > > > | < < < < < < | < < | < < < < < < < < < < < < < | < | < < > > > > | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | | < < < < < < < | < < | < < < | < < < < > | | < | < < < < < < > | < < < > | < < < < < < < < < < < | | | < < < < < < | < < < < < < < < < < < < < < < < < < < < | < < | < | < < < < < < < < < < > > | < > > | < < | > > > > > | | < > | | | | | | | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 | pWiki = manifest_get(rid, CFTYPE_WIKI, 0); if( pWiki ){ zBody = pWiki->zWiki; zMimetype = pWiki->zMimetype; } } zMimetype = wiki_filter_mimetypes(zMimetype); if( !g.isHome ){ if( rid ){ style_submenu_element("Diff", "%R/wdiff?name=%T&a=%d", zPageName, rid); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); style_submenu_element("Details", "%R/info/%s", zUuid); } if( (rid && g.anon.WrWiki) || (!rid && g.anon.NewWiki) ){ if( db_get_boolean("wysiwyg-wiki", 0) ){ style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1", g.zTop, zPageName); }else{ style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName); } } if( rid && g.anon.ApndWiki && g.anon.Attach ){ style_submenu_element("Attach", "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", g.zTop, zPageName, g.zTop, zPageName); } if( rid && g.anon.ApndWiki ){ style_submenu_element("Append", "%s/wikiappend?name=%T&mimetype=%s", g.zTop, zPageName, zMimetype); } if( g.perm.Hyperlink ){ style_submenu_element("History", "%s/whistory?name=%T", g.zTop, zPageName); } } style_set_current_page("%T?name=%T", g.zPath, zPageName); style_header("%s", zPageName); wiki_standard_submenu(submenuFlags); blob_init(&wiki, zBody, -1); wiki_render_by_mimetype(&wiki, zMimetype); blob_reset(&wiki); attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>"); manifest_destroy(pWiki); style_footer(); } /* ** Write a wiki artifact into the repository */ int wiki_put(Blob *pWiki, int parent, int needMod){ int nrid; if( !needMod ){ nrid = content_put_ex(pWiki, 0, 0, 0, 0); if( parent) content_deltify(parent, &nrid, 1, 0); }else{ nrid = content_put_ex(pWiki, 0, 0, 0, 1); moderation_table_create(); db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid); } db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid); manifest_crosslink(nrid, pWiki, MC_NONE); return nrid; } /* ** Output a selection box from which the user can select the ** wiki mimetype. */ void mimetype_option_menu(const char *zMimetype){ unsigned i; @ <select name="mimetype" size="1"> for(i=0; i<count(azStyles); i+=3){ if( fossil_strcmp(zMimetype,azStyles[i])==0 ){ @ <option value="%s(azStyles[i])" selected>%s(azStyles[i+1])</option> }else{ @ <option value="%s(azStyles[i])">%s(azStyles[i+1])</option> } } @ </select> } /* ** Given a mimetype, return its common name. */ static const char *mimetype_common_name(const char *zMimetype){ int i; for(i=4; i>=2; i-=2){ if( zMimetype && fossil_strcmp(zMimetype, azStyles[i])==0 ){ return azStyles[i+1]; } } return azStyles[1]; } /* ** WEBPAGE: wikiedit ** URL: /wikiedit?name=PAGENAME ** ** Edit a wiki page. */ void wikiedit_page(void){ char *zTag; int rid = 0; int isSandbox; Blob wiki; Manifest *pWiki = 0; const char *zPageName; int n; const char *z; char *zBody = (char*)P("w"); const char *zMimetype = wiki_filter_mimetypes(P("mimetype")); int isWysiwyg = P("wysiwyg")!=0; int goodCaptcha = 1; if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; } if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; } if( zBody ){ if( isWysiwyg ){ Blob body; blob_zero(&body); htmlTidy(zBody, &body); zBody = blob_str(&body); }else{ zBody = mprintf("%s", zBody); } } login_check_credentials(); zPageName = PD("name",""); if( check_name(zPageName) ) return; isSandbox = is_sandbox(zPageName); if( isSandbox ){ if( !g.perm.WrWiki ){ login_needed(g.anon.WrWiki); return; } if( zBody==0 ){ zBody = db_get("sandbox",""); zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki"); } }else{ zTag = mprintf("wiki-%s", zPageName); rid = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); free(zTag); if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki); return; } if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){ zBody = pWiki->zWiki; zMimetype = pWiki->zMimetype; } } if( P("submit")!=0 && zBody!=0 && (goodCaptcha = captcha_is_correct(0)) ){ char *zDate; Blob cksum; blob_zero(&wiki); db_begin_transaction(); if( isSandbox ){ db_set("sandbox",zBody,0); db_set("sandbox-mimetype",zMimetype,0); }else{ login_verify_csrf_secret(); zDate = date_in_standard_format("now"); blob_appendf(&wiki, "D %s\n", zDate); free(zDate); blob_appendf(&wiki, "L %F\n", zPageName); if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){ blob_appendf(&wiki, "N %s\n", zMimetype); } if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } if( !login_is_nobody() ){ blob_appendf(&wiki, "U %F\n", login_name()); } blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody); md5sum_blob(&wiki, &cksum); blob_appendf(&wiki, "Z %b\n", &cksum); blob_reset(&cksum); wiki_put(&wiki, 0, wiki_need_moderation(0)); } db_end_transaction(0); cgi_redirectf("wiki?name=%T", zPageName); } if( P("cancel")!=0 ){ cgi_redirectf("wiki?name=%T", zPageName); return; } if( zBody==0 ){ zBody = mprintf("<i>Empty Page</i>"); } style_set_current_page("%T?name=%T", g.zPath, zPageName); style_header("Edit: %s", zPageName); if( !goodCaptcha ){ @ <p class="generalError">Error: Incorrect security code.</p> } blob_zero(&wiki); blob_append(&wiki, zBody, -1); if( P("preview")!=0 ){ @ Preview:<hr /> wiki_render_by_mimetype(&wiki, zMimetype); @ <hr /> blob_reset(&wiki); } for(n=2, z=zBody; z[0]; z++){ if( z[0]=='\n' ) n++; } if( n<20 ) n = 20; if( n>30 ) n = 30; if( !isWysiwyg ){ /* Traditional markup-only editing */ form_begin(0, "%R/wikiedit"); @ <div>Markup style: mimetype_option_menu(zMimetype); @ <br /><textarea name="w" class="wikiedit" cols="80" @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea> @ <br /> if( db_get_boolean("wysiwyg-wiki", 0) ){ @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor" @ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' /> } @ <input type="submit" name="preview" value="Preview Your Changes" /> }else{ /* Wysiwyg editing */ Blob html, temp; form_begin("", "%R/wikiedit"); @ <div> @ <input type="hidden" name="wysiwyg" value="1" /> blob_zero(&temp); wiki_convert(&wiki, &temp, 0); blob_zero(&html); htmlTidy(blob_str(&temp), &html); blob_reset(&temp); wysiwygEditor("w", blob_str(&html), 60, n); blob_reset(&html); @ <br /> @ <input type="submit" name="edit-markup" value="Markup Editor" @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' /> } login_insert_csrf_secret(); @ <input type="submit" name="submit" value="Apply These Changes" /> @ <input type="hidden" name="name" value="%h(zPageName)" /> @ <input type="submit" name="cancel" value="Cancel" @ onclick='confirm("Abandon your changes?")' /> @ </div> captcha_generate(0); @ </form> manifest_destroy(pWiki); blob_reset(&wiki); style_footer(); } /* ** WEBPAGE: wikinew ** URL /wikinew ** ** Prompt the user to enter the name of a new wiki page. Then redirect ** to the wikiedit screen for that new page. */ void wikinew_page(void){ const char *zName; const char *zMimetype; login_check_credentials(); if( !g.perm.NewWiki ){ login_needed(g.anon.NewWiki); return; } zName = PD("name",""); zMimetype = wiki_filter_mimetypes(P("mimetype")); if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){ if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 && db_get_boolean("wysiwyg-wiki", 0) ){ cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName); }else{ cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype); } } style_header("Create A New Wiki Page"); wiki_standard_submenu(W_ALL_BUT(W_NEW)); @ <p>Rules for wiki page names:</p> well_formed_wiki_name_rules(); form_begin(0, "%R/wikinew"); @ <p>Name of new wiki page: @ <input style="width: 35;" type="text" name="name" value="%h(zName)" /><br /> @ Markup style: mimetype_option_menu("text/x-fossil-wiki"); @ <br /><input type="submit" value="Create" /> @ </p></form> if( zName[0] ){ @ <p><span class="wikiError"> @ "%h(zName)" is not a valid wiki page name!</span></p> } style_footer(); } /* ** Append the wiki text for an remark to the end of the given BLOB. */ static void appendRemark(Blob *p, const char *zMimetype){ char *zDate; const char *zUser; const char *zRemark; char *zId; zDate = db_text(0, "SELECT datetime('now')"); zRemark = PD("r",""); zUser = PD("u",g.zLogin); if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){ zId = db_text(0, "SELECT lower(hex(randomblob(8)))"); blob_appendf(p, "\n\n<hr /><div id=\"%s\"><i>On %s UTC %h", zId, zDate, login_name()); if( zUser[0] && fossil_strcmp(zUser,login_name()) ){ blob_appendf(p, " (claiming to be %h)", zUser); } blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId); }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){ blob_appendf(p, "\n\n------\n*On %s UTC %h", zDate, login_name()); if( zUser[0] && fossil_strcmp(zUser,login_name()) ){ blob_appendf(p, " (claiming to be %h)", zUser); } blob_appendf(p, " added:*\n\n%s\n", zRemark); }else{ |
︙ | ︙ | |||
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | ** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE ** ** Append text to the end of a wiki page. */ void wikiappend_page(void){ char *zTag; int rid = 0; const char *zPageName; const char *zUser; const char *zMimetype; int goodCaptcha = 1; const char *zFormat; | > < < < < < < | < | > | < > > | < > > > > > > > > > | > > | | | | | | | | | | | | | | | | | | | | | | | < > < | < < < < < < | | < | > | | | | | | | | > > | > > > > | > > > > > > > > < < < < < < < | < | | | < < < < < | > | < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | > | < < < < < < < < < | | < | > | < | | > > | > > > > > > | > < | < < < < < < < | < < < < < < < < < < < < < < < < < < | < | > > | | | | < < < < > | > | | < | | < < < < < | < < < | < > | < < < < < | | < < < < < < < < < < < < | < < < < < < < < > | < | < < < < < | < < < < < < < < < < < < < | | < | < < < < < < | < < < < | | < < | | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 | ** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE ** ** Append text to the end of a wiki page. */ void wikiappend_page(void){ char *zTag; int rid = 0; int isSandbox; const char *zPageName; const char *zUser; const char *zMimetype; int goodCaptcha = 1; const char *zFormat; login_check_credentials(); zPageName = PD("name",""); zMimetype = wiki_filter_mimetypes(P("mimetype")); if( check_name(zPageName) ) return; isSandbox = is_sandbox(zPageName); if( !isSandbox ){ zTag = mprintf("wiki-%s", zPageName); rid = db_int(0, "SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" " ORDER BY mtime DESC", zTag ); free(zTag); if( !rid ){ fossil_redirect_home(); return; } } if( !g.perm.ApndWiki ){ login_needed(g.anon.ApndWiki); return; } if( P("submit")!=0 && P("r")!=0 && P("u")!=0 && (goodCaptcha = captcha_is_correct(0)) ){ char *zDate; Blob cksum; Blob body; Blob wiki; Manifest *pWiki = 0; blob_zero(&body); if( isSandbox ){ blob_append(&body, db_get("sandbox",""), -1); appendRemark(&body, zMimetype); db_set("sandbox", blob_str(&body), 0); }else{ login_verify_csrf_secret(); pWiki = manifest_get(rid, CFTYPE_WIKI, 0); if( pWiki ){ blob_append(&body, pWiki->zWiki, -1); manifest_destroy(pWiki); } blob_zero(&wiki); db_begin_transaction(); zDate = date_in_standard_format("now"); blob_appendf(&wiki, "D %s\n", zDate); blob_appendf(&wiki, "L %F\n", zPageName); if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")!=0 ){ blob_appendf(&wiki, "N %s\n", zMimetype); } if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); blob_appendf(&wiki, "P %s\n", zUuid); free(zUuid); } if( !login_is_nobody() ){ blob_appendf(&wiki, "U %F\n", login_name()); } appendRemark(&body, zMimetype); blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body)); md5sum_blob(&wiki, &cksum); blob_appendf(&wiki, "Z %b\n", &cksum); blob_reset(&cksum); wiki_put(&wiki, rid, wiki_need_moderation(0)); db_end_transaction(0); } cgi_redirectf("wiki?name=%T", zPageName); } if( P("cancel")!=0 ){ cgi_redirectf("wiki?name=%T", zPageName); return; } style_set_current_page("%T?name=%T", g.zPath, zPageName); style_header("Append Comment To: %s", zPageName); if( !goodCaptcha ){ @ <p class="generalError">Error: Incorrect security code.</p> } if( P("preview")!=0 ){ Blob preview; blob_zero(&preview); appendRemark(&preview, zMimetype); @ Preview:<hr /> wiki_render_by_mimetype(&preview, zMimetype); @ <hr /> blob_reset(&preview); } zUser = PD("u", g.zLogin); form_begin(0, "%R/wikiappend"); login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zPageName)" /> @ <input type="hidden" name="mimetype" value="%h(zMimetype)" /> @ Your Name: @ <input type="text" name="u" size="20" value="%h(zUser)" /><br /> zFormat = mimetype_common_name(zMimetype); @ Comment to append (formatted as %s(zFormat)):<br /> @ <textarea name="r" class="wikiedit" cols="80" @ rows="10" wrap="virtual">%h(PD("r",""))</textarea> @ <br /> @ <input type="submit" name="preview" value="Preview Your Comment" /> @ <input type="submit" name="submit" value="Append Your Changes" /> @ <input type="submit" name="cancel" value="Cancel" /> captcha_generate(0); @ </form> style_footer(); } /* ** Name of the wiki history page being generated */ static const char *zWikiPageName; /* ** Function called to output extra text at the end of each line in ** a wiki history listing. */ static void wiki_history_extra(int rid){ if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){ @ %z(href("%R/wdiff?name=%t&a=%d",zWikiPageName,rid))[diff]</a> } } /* ** WEBPAGE: whistory ** URL: /whistory?name=PAGENAME ** ** Show the complete change history for a single wiki page. */ void whistory_page(void){ Stmt q; const char *zPageName; login_check_credentials(); if( !g.perm.Hyperlink ){ login_needed(g.anon.Hyperlink); return; } zPageName = PD("name",""); style_header("History Of %s", zPageName); db_prepare(&q, "%s AND event.objid IN " " (SELECT rid FROM tagxref WHERE tagid=" "(SELECT tagid FROM tag WHERE tagname='wiki-%q')" " UNION SELECT attachid FROM attachment" " WHERE target=%Q)" "ORDER BY mtime DESC", timeline_query_for_www(), zPageName, zPageName); zWikiPageName = zPageName; www_print_timeline(&q, TIMELINE_ARTID, 0, 0, 0, wiki_history_extra); db_finalize(&q); style_footer(); } /* ** WEBPAGE: wdiff ** URL: /whistory?name=PAGENAME&a=RID1&b=RID2 ** ** Show the difference between two wiki pages. */ void wdiff_page(void){ int rid1, rid2; const char *zPageName; Manifest *pW1, *pW2 = 0; Blob w1, w2, d; u64 diffFlags; login_check_credentials(); rid1 = atoi(PD("a","0")); if( !g.perm.Hyperlink ){ login_needed(g.anon.Hyperlink); return; } if( rid1==0 ) fossil_redirect_home(); rid2 = atoi(PD("b","0")); zPageName = PD("name",""); style_header("Changes To %s", zPageName); if( rid2==0 ){ rid2 = db_int(0, "SELECT objid FROM event JOIN tagxref ON objid=rid AND tagxref.tagid=" "(SELECT tagid FROM tag WHERE tagname='wiki-%q')" " WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)" " ORDER BY event.mtime DESC LIMIT 1", zPageName, rid1 ); } pW1 = manifest_get(rid1, CFTYPE_WIKI, 0); if( pW1==0 ) fossil_redirect_home(); blob_init(&w1, pW1->zWiki, -1); blob_zero(&w2); if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI, 0))!=0 ){ blob_init(&w2, pW2->zWiki, -1); } blob_zero(&d); diffFlags = construct_diff_flags(1); text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO); @ <pre class="udiff"> @ %s(blob_str(&d)) @ <pre> manifest_destroy(pW1); manifest_destroy(pW2); style_footer(); } /* ** prepare()s pStmt with a query requesting: ** ** - wiki page name ** - tagxref (whatever that really is!) ** ** Used by wcontent_page() and the JSON wiki code. */ void wiki_prepare_page_list( Stmt * pStmt ){ db_prepare(pStmt, "SELECT" " substr(tagname, 6) as name," " (SELECT value FROM tagxref WHERE tagid=tag.tagid" " ORDER BY mtime DESC) as tagXref" " FROM tag WHERE tagname GLOB 'wiki-*'" " ORDER BY lower(tagname) /*sort*/" ); } /* ** WEBPAGE: wcontent ** ** all=1 Show deleted pages ** ** List all available wiki pages with date created and last modified. */ void wcontent_page(void){ Stmt q; int showAll = P("all")!=0; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } style_header("Available Wiki Pages"); if( showAll ){ style_submenu_element("Active", "%s/wcontent", g.zTop); }else{ style_submenu_element("All", "%s/wcontent?all=1", g.zTop); } wiki_standard_submenu(W_ALL_BUT(W_LIST)); @ <ul> wiki_prepare_page_list(&q); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); int size = db_column_int(&q, 1); if( size>0 ){ @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li> }else if( showAll ){ @ <li>%z(href("%R/wiki?name=%T",zName))<s>%h(zName)</s></a></li> } } db_finalize(&q); @ </ul> style_footer(); } /* ** WEBPAGE: wfind ** ** URL: /wfind?title=TITLE ** List all wiki pages whose titles contain the search text */ void wfind_page(void){ Stmt q; const char *zTitle; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } zTitle = PD("title","*"); style_header("Wiki Pages Found"); @ <ul> db_prepare(&q, "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'" " ORDER BY lower(tagname) /*sort*/" , zTitle); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li> } db_finalize(&q); @ </ul> style_footer(); } /* ** Add a new wiki page to the repository. The page name is ** given by the zPageName parameter. rid must be zero to create ** a new page otherwise the page identified by rid is updated. ** |
︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 | db_begin_transaction(); wiki_put(&wiki, 0, wiki_need_moderation(localUser)); db_end_transaction(0); return 1; } /* | | | | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | db_begin_transaction(); wiki_put(&wiki, 0, wiki_need_moderation(localUser)); db_end_transaction(0); return 1; } /* ** Determine the rid for a tech note given either its id or its ** timestamp. Returns 0 if there is no such item and -1 if the details ** are ambiguous and could refer to multiple items. */ int wiki_technote_to_rid(const char *zETime) { int rid=0; /* Artifact ID of the tech note */ int nETime = strlen(zETime); Stmt q; if( nETime>=4 && nETime<=HNAME_MAX && validate16(zETime, nETime) ){ |
︙ | ︙ | |||
2132 2133 2134 2135 2136 2137 2138 | " WHERE datetime(mtime)=datetime('%q')" " AND type='e'" " AND tagid IS NOT NULL" " ORDER BY objid DESC LIMIT 1", zETime); } } | < < < < < < < < < < < < < < < < < < < < < | | | | < < | < | < < < | < < < < < | < < < | | | | | | < | < < | | < | | | < < < < < < < < < < < | | | | < < < < < < < < < < | > > > | < | < < | | < < | < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < > > > | > > > > | | | < | < < < < < < < < | | > | | < < < < < | | | | | < | 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 | " WHERE datetime(mtime)=datetime('%q')" " AND type='e'" " AND tagid IS NOT NULL" " ORDER BY objid DESC LIMIT 1", zETime); } } return rid; } /* ** COMMAND: wiki* ** ** Usage: %fossil wiki (export|create|commit|list) WikiName ** ** Run various subcommands to work with wiki entries or tech notes. ** ** %fossil wiki export PAGENAME ?FILE? ** %fossil wiki export ?FILE? -t|--technote DATETIME|TECHNOTE-ID ** ** Sends the latest version of either a wiki page or of a tech note ** to the given file or standard output. ** If PAGENAME is provided, the wiki page will be output. For ** a tech note either DATETIME or TECHNOTE-ID must be specified. If ** DATETIME is used, the most recently modified tech note with that ** DATETIME will be sent. ** ** %fossil wiki (create|commit) PAGENAME ?FILE? ?OPTIONS? ** ** Create a new or commit changes to an existing wiki page or ** technote from FILE or from standard input. PAGENAME is the ** name of the wiki entry or the timeline comment of the ** technote. ** ** Options: ** -M|--mimetype TEXT-FORMAT The mime type of the update. ** Defaults to the type used by ** the previous version of the ** page, or text/x-fossil-wiki. ** Valid values are: text/x-fossil-wiki, ** text/markdown and text/plain. fossil, ** markdown or plain can be specified as ** synonyms of these values. ** -t|--technote DATETIME Specifies the timestamp of ** the technote to be created or ** updated. When updating a tech note ** the most recently modified tech note ** with the specified timestamp will be ** updated. ** -t|--technote TECHNOTE-ID Specifies the technote to be ** updated by its technote id. ** --technote-tags TAGS The set of tags for a technote. ** --technote-bgcolor COLOR The color used for the technote ** on the timeline. ** ** %fossil wiki list ?OPTIONS? ** %fossil wiki ls ?OPTIONS? ** ** Lists all wiki entries, one per line, ordered ** case-insensitively by name. ** ** Options: ** -t|--technote Technotes will be listed instead of ** pages. The technotes will be in order ** of timestamp with the most recent ** first. ** -s|--show-technote-ids The id of the tech note will be listed ** along side the timestamp. The tech note ** id will be the first word on each line. ** This option only applies if the ** --technote option is also specified. ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. ** */ void wiki_cmd(void){ int n; db_find_and_open_repository(0, 0); if( g.argc<3 ){ goto wiki_cmd_usage; } n = strlen(g.argv[2]); if( n==0 ){ goto wiki_cmd_usage; } if( strncmp(g.argv[2],"export",n)==0 ){ const char *zPageName; /* Name of the wiki page to export */ const char *zFile; /* Name of the output file (0=stdout) */ const char *zETime; /* The name of the technote to export */ int rid; /* Artifact ID of the wiki page */ int i; /* Loop counter */ char *zBody = 0; /* Wiki page content */ Blob body; /* Wiki page content */ Manifest *pWiki = 0; /* Parsed wiki page content */ zETime = find_option("technote","t",1); if( !zETime ){ if( (g.argc!=4) && (g.argc!=5) ){ usage("export PAGENAME ?FILE?"); } zPageName = g.argv[3]; rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" " ORDER BY x.mtime DESC LIMIT 1", zPageName ); if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){ zBody = pWiki->zWiki; } if( zBody==0 ){ fossil_fatal("wiki page [%s] not found",zPageName); } zFile = (g.argc==4) ? "-" : g.argv[4]; }else{ if( (g.argc!=3) && (g.argc!=4) ){ usage("export ?FILE? --technote DATETIME|TECHNOTE-ID"); } rid = wiki_technote_to_rid(zETime); if ( rid==-1 ){ fossil_fatal("ambiguous tech note id: %s", zETime); } if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){ zBody = pWiki->zWiki; } if( zBody==0 ){ fossil_fatal("technote [%s] not found",zETime); } zFile = (g.argc==3) ? "-" : g.argv[3]; } for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){} zBody[i] = 0; blob_init(&body, zBody, -1); blob_append(&body, "\n", 1); blob_write_to_file(&body, zFile); blob_reset(&body); manifest_destroy(pWiki); return; }else if( strncmp(g.argv[2],"commit",n)==0 || strncmp(g.argv[2],"create",n)==0 ){ const char *zPageName; /* page name */ Blob content; /* Input content */ int rid = 0; Manifest *pWiki = 0; /* Parsed wiki page content */ const char *zMimeType = find_option("mimetype", "M", 1); const char *zETime = find_option("technote", "t", 1); const char *zTags = find_option("technote-tags", NULL, 1); const char *zClr = find_option("technote-bgcolor", NULL, 1); if( g.argc!=4 && g.argc!=5 ){ usage("commit|create PAGENAME ?FILE? [--mimetype TEXT-FORMAT]" " [--technote DATETIME] [--technote-tags TAGS]" " [--technote-bgcolor COLOR]"); } zPageName = g.argv[3]; if( g.argc==4 ){ blob_read_from_channel(&content, stdin, -1); }else{ blob_read_from_file(&content, g.argv[4], ExtFILE); } if( !zMimeType || !*zMimeType ){ /* Try to deduce the mime type based on the prior version. */ if ( !zETime ){ rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" " ORDER BY x.mtime DESC LIMIT 1", zPageName ); if( rid>0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 && (pWiki->zMimetype && *pWiki->zMimetype) ){ zMimeType = pWiki->zMimetype; } }else{ rid = wiki_technote_to_rid(zETime); if( rid>0 && (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 && (pWiki->zMimetype && *pWiki->zMimetype) ){ zMimeType = pWiki->zMimetype; } } }else{ zMimeType = wiki_filter_mimetypes(zMimeType); } if( g.argv[2][1]=='r' && rid>0 ){ if ( !zETime ){ fossil_fatal("wiki page %s already exists", zPageName); }else{ /* Creating a tech note with same timestamp is permitted and should create a new tech note */ rid = 0; } }else if( g.argv[2][1]=='o' && rid == 0 ){ if ( !zETime ){ fossil_fatal("no such wiki page: %s", zPageName); }else{ fossil_fatal("no such tech note: %s", zETime); } } if( !zETime ){ wiki_cmd_commit(zPageName, rid, &content, zMimeType, 1); if( g.argv[2][1]=='r' ){ fossil_print("Created new wiki page %s.\n", zPageName); }else{ fossil_print("Updated wiki page %s.\n", zPageName); } }else{ if( rid != -1 ){ char *zMETime; /* Normalized, mutable version of zETime */ zMETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); event_cmd_commit(zMETime, rid, &content, zMimeType, zPageName, |
︙ | ︙ | |||
2459 2460 2461 2462 2463 2464 2465 | }else{ fossil_fatal("ambiguous tech note id: %s", zETime); } } manifest_destroy(pWiki); blob_reset(&content); }else if( strncmp(g.argv[2],"delete",n)==0 ){ | | < | | < | | > > > > | > < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < | | < < < < < < < < < < < | < < < < < | < < < < | < < < < < < < | < < | < < < < < < < < | | | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 | }else{ fossil_fatal("ambiguous tech note id: %s", zETime); } } manifest_destroy(pWiki); blob_reset(&content); }else if( strncmp(g.argv[2],"delete",n)==0 ){ if( g.argc!=5 ){ usage("delete PAGENAME"); } fossil_fatal("delete not yet implemented."); }else if(( strncmp(g.argv[2],"list",n)==0 ) || ( strncmp(g.argv[2],"ls",n)==0 )){ Stmt q; int showIds = 0; if ( !find_option("technote","t",0) ){ db_prepare(&q, "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'" " ORDER BY lower(tagname) /*sort*/" ); }else{ showIds = find_option("show-technote-ids","s",0)!=0; db_prepare(&q, "SELECT datetime(e.mtime), substr(t.tagname,7)" " FROM event e, tag t" " WHERE e.type='e'" " AND e.tagid IS NOT NULL" " AND t.tagid=e.tagid" " ORDER BY e.mtime DESC /*sort*/" ); } while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); if( showIds ){ const char *zUuid = db_column_text(&q, 1); fossil_print("%s ",zUuid); } fossil_print( "%s\n",zName); } db_finalize(&q); }else{ goto wiki_cmd_usage; } return; wiki_cmd_usage: usage("export|create|commit|list ..."); } /* ** COMMAND: test-markdown-render ** ** Usage: %fossil test-markdown-render FILE ** ** Render markdown wiki from FILE to stdout. ** */ void test_markdown_render(void){ Blob in, out; verify_all_options(); if( g.argc!=3 ) usage("FILE"); blob_zero(&out); blob_read_from_file(&in, g.argv[2], ExtFILE); markdown_to_html(&in, 0, &out); blob_write_to_file(&out, "-"); } |
Changes to src/wiki.wiki.
1 2 3 4 5 6 7 8 | <h2>Wiki Formatting Rule Summary</h2> # Blank lines are paragraph breaks # Bullets are "*" surrounded by two spaces at the beginning of a line # Enumeration items are "#" or a digit and a "." surrounded by two spaces at the beginning of a line # Indented paragraphs begin with a tab or two spaces # Hyperlinks are contained within square brackets: | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <h2>Wiki Formatting Rule Summary</h2> # Blank lines are paragraph breaks # Bullets are "*" surrounded by two spaces at the beginning of a line # Enumeration items are "#" or a digit and a "." surrounded by two spaces at the beginning of a line # Indented paragraphs begin with a tab or two spaces # Hyperlinks are contained within square brackets: <nowiki>"[target]" or "[target|label]"</nowiki> # Most ordinary HTML works # <verbatim> and <nowiki> We call the first five rules above the "wiki" formatting rules. The last two rules are the HTML formatting rules. <h2>Formatting Rule Details</h2> |
︙ | ︙ | |||
30 31 32 33 34 35 36 | 3. <b>Enumeration Lists.</b> An enumeration list item is a line that begins with a single "#" character surrounded on both sides by two or more spaces or by a tab. Or it can be a number and a "." (ex: "5.") surrounded on both sides by two spaces or a tab. Only a single level of enumeration list is supported by wiki. For nested lists or for enumerations that count using letters or | | | < < | < < < < < < < < < | 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 | 3. <b>Enumeration Lists.</b> An enumeration list item is a line that begins with a single "#" character surrounded on both sides by two or more spaces or by a tab. Or it can be a number and a "." (ex: "5.") surrounded on both sides by two spaces or a tab. Only a single level of enumeration list is supported by wiki. For nested lists or for enumerations that count using letters or roman numerials, use HTML. 4. <b>Indented Paragraphs.</b> Any paragraph that begins with two or more spaces or a tab and which is not a bullet or enumeration list item is rendered indented. Only a single level of indentation is supported by wiki. Use HTML for deeper indentation. 5. <b>Hyperlinks.</b> Text within square brackets <nowiki>("[...]")</nowiki> becomes a hyperlink. The target can be a wiki page name, the artifact ID of a check-in or ticket, the name of an image, or a URL. By default, the target is displayed as the text of the hyperlink. But you can specify alternative text after the target name separated by a "|" character. You can also link to internal anchor names using <nowiki>[#anchor-name],</nowiki> providing you have added the necessary "<a name='anchor-name'></a>" tag to your wiki page. 6. <b>HTML.</b> The following standard HTML elements may be used: <a> <address> <article> <aside> <b> <big> <blockquote> <br> <center> <cite> <code> <col> <colgroup> <dd> <dfn> <div> <dl> <dt> <em> <font> <footer> <h1> <h2> <h3> <h4> <h5> <h6> <header> <hr> <i> <img> <kbd> <li> <nav> <nobr> <nowiki> <ol> <p> <pre> <s> <samp> <section> <small> <span> <strike> <strong> <sub> <sup> <table> <tbody> <td> <tfoot> <th> <thead> <title> <tr> <tt> <u> <ul> <var> <verbatim>. There are two non-standard elements available: <verbatim> and <nowiki>. No other elements are allowed. All attributes are checked and only a few benign attributes are allowed on each element. In particular, any attributes that specify javascript or CSS are elided. 7. <b>Special Markup.</b> The <nowiki> tag disables all wiki formatting rules through the matching </nowiki> element. The <verbatim> tag works like <pre> with the addition that it also disables all wiki and HTML markup through the matching </verbatim>. |
Changes to src/wikiformat.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | */ #define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */ #define WIKI_INLINE 0x002 /* Do not surround with <p>..</p> */ #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */ #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */ #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */ #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ | < < < < < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | */ #define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */ #define WIKI_INLINE 0x002 /* Do not surround with <p>..</p> */ #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */ #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */ #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */ #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */ #endif /* ** These are the only markup attributes allowed. */ enum allowed_attr_t { |
︙ | ︙ | |||
63 64 65 66 67 68 69 | ATTR_NAME, ATTR_ROWSPAN, ATTR_SIZE, ATTR_SRC, ATTR_START, ATTR_STYLE, ATTR_TARGET, | < > | | | | | | | | | | | | | < | 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 | ATTR_NAME, ATTR_ROWSPAN, ATTR_SIZE, ATTR_SRC, ATTR_START, ATTR_STYLE, ATTR_TARGET, ATTR_TYPE, ATTR_VALIGN, ATTR_VALUE, ATTR_VSPACE, ATTR_WIDTH }; enum amsk_t { AMSK_ALIGN = 0x00000001, AMSK_ALT = 0x00000002, AMSK_BGCOLOR = 0x00000004, AMSK_BORDER = 0x00000008, AMSK_CELLPADDING = 0x00000010, AMSK_CELLSPACING = 0x00000020, AMSK_CLASS = 0x00000040, AMSK_CLEAR = 0x00000080, AMSK_COLOR = 0x00000100, AMSK_COLSPAN = 0x00000200, AMSK_COMPACT = 0x00000400, /* re-use = 0x00000800, */ AMSK_FACE = 0x00001000, AMSK_HEIGHT = 0x00002000, AMSK_HREF = 0x00004000, AMSK_HSPACE = 0x00008000, AMSK_ID = 0x00010000, AMSK_LINKS = 0x00020000, AMSK_NAME = 0x00040000, AMSK_ROWSPAN = 0x00080000, AMSK_SIZE = 0x00100000, AMSK_SRC = 0x00200000, AMSK_START = 0x00400000, AMSK_STYLE = 0x00800000, AMSK_TARGET = 0x01000000, AMSK_TYPE = 0x02000000, AMSK_VALIGN = 0x04000000, AMSK_VALUE = 0x08000000, AMSK_VSPACE = 0x10000000, AMSK_WIDTH = 0x20000000 }; |
︙ | ︙ | |||
136 137 138 139 140 141 142 | { "name", AMSK_NAME }, { "rowspan", AMSK_ROWSPAN }, { "size", AMSK_SIZE }, { "src", AMSK_SRC }, { "start", AMSK_START }, { "style", AMSK_STYLE }, { "target", AMSK_TARGET }, | < | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | { "name", AMSK_NAME }, { "rowspan", AMSK_ROWSPAN }, { "size", AMSK_SIZE }, { "src", AMSK_SRC }, { "start", AMSK_START }, { "style", AMSK_STYLE }, { "target", AMSK_TARGET }, { "type", AMSK_TYPE }, { "valign", AMSK_VALIGN }, { "value", AMSK_VALUE }, { "vspace", AMSK_VSPACE }, { "width", AMSK_WIDTH }, }; |
︙ | ︙ | |||
173 174 175 176 177 178 179 | /* ** Allowed markup. ** ** Except for MARKUP_INVALID, this must all be in alphabetical order ** and in numerical sequence. The first markup type must be zero. ** The value for MARKUP_XYZ must correspond to the <xyz> entry | | < | | < | | | | | | | | | | | | | < < | | | | | | | | | | | | | | | > < | < | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | < < < < | < < < | | > < < < | > > | > < | | < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | /* ** Allowed markup. ** ** Except for MARKUP_INVALID, this must all be in alphabetical order ** and in numerical sequence. The first markup type must be zero. ** The value for MARKUP_XYZ must correspond to the <xyz> entry ** in aAllowedMarkup[]. */ #define MARKUP_INVALID 0 #define MARKUP_A 1 #define MARKUP_ADDRESS 2 #define MARKUP_HTML5_ARTICLE 3 #define MARKUP_HTML5_ASIDE 4 #define MARKUP_B 5 #define MARKUP_BIG 6 #define MARKUP_BLOCKQUOTE 7 #define MARKUP_BR 8 #define MARKUP_CENTER 9 #define MARKUP_CITE 10 #define MARKUP_CODE 11 #define MARKUP_COL 12 #define MARKUP_COLGROUP 13 #define MARKUP_DD 14 #define MARKUP_DFN 15 #define MARKUP_DIV 16 #define MARKUP_DL 17 #define MARKUP_DT 18 #define MARKUP_EM 19 #define MARKUP_FONT 20 #define MARKUP_HTML5_FOOTER 21 #define MARKUP_H1 22 #define MARKUP_H2 23 #define MARKUP_H3 24 #define MARKUP_H4 25 #define MARKUP_H5 26 #define MARKUP_H6 27 #define MARKUP_HTML5_HEADER 28 #define MARKUP_HR 29 #define MARKUP_I 30 #define MARKUP_IMG 31 #define MARKUP_KBD 32 #define MARKUP_LI 33 #define MARKUP_HTML5_NAV 34 #define MARKUP_NOBR 35 #define MARKUP_NOWIKI 36 #define MARKUP_OL 37 #define MARKUP_P 38 #define MARKUP_PRE 39 #define MARKUP_S 40 #define MARKUP_SAMP 41 #define MARKUP_HTML5_SECTION 42 #define MARKUP_SMALL 43 #define MARKUP_SPAN 44 #define MARKUP_STRIKE 45 #define MARKUP_STRONG 46 #define MARKUP_SUB 47 #define MARKUP_SUP 48 #define MARKUP_TABLE 49 #define MARKUP_TBODY 50 #define MARKUP_TD 51 #define MARKUP_TFOOT 52 #define MARKUP_TH 53 #define MARKUP_THEAD 54 #define MARKUP_TITLE 55 #define MARKUP_TR 56 #define MARKUP_TT 57 #define MARKUP_U 58 #define MARKUP_UL 59 #define MARKUP_VAR 60 #define MARKUP_VERBATIM 61 /* ** The various markup is divided into the following types: */ #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */ #define MUTYPE_BLOCK 0x0002 /* Forms a new paragraph. ex: <p>, <h2> */ #define MUTYPE_FONT 0x0004 /* Font changes. ex: <b>, <font>, <sub> */ #define MUTYPE_LIST 0x0010 /* Lists. <ol>, <ul>, or <dl> */ #define MUTYPE_LI 0x0020 /* List items. <li>, <dd>, <dt> */ #define MUTYPE_TABLE 0x0040 /* <table> */ #define MUTYPE_TR 0x0080 /* <tr> */ #define MUTYPE_TD 0x0100 /* <td> or <th> */ #define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */ #define MUTYPE_HYPERLINK 0x0400 /* <a> */ /* ** These markup types must have an end tag. */ #define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE) /* ** This markup types are allowed for "inline" text. */ #define MUTYPE_INLINE (MUTYPE_FONT | MUTYPE_HYPERLINK) static const struct AllowedMarkup { const char *zName; /* Name of the markup */ char iCode; /* The MARKUP_* code */ short int iType; /* The MUTYPE_* code */ int allowedAttr; /* Allowed attributes on this markup */ } aMarkup[] = { { 0, MARKUP_INVALID, 0, 0 }, { "a", MARKUP_A, MUTYPE_HYPERLINK, AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE }, { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE }, { "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "b", MARKUP_B, MUTYPE_FONT, AMSK_STYLE }, { "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE }, { "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE }, { "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR }, { "center", MARKUP_CENTER, MUTYPE_BLOCK, AMSK_STYLE }, { "cite", MARKUP_CITE, MUTYPE_FONT, AMSK_STYLE }, { "code", MARKUP_CODE, MUTYPE_FONT, AMSK_STYLE }, { "col", MARKUP_COL, MUTYPE_SINGLE, AMSK_ALIGN|AMSK_CLASS|AMSK_COLSPAN|AMSK_WIDTH|AMSK_STYLE }, { "colgroup", MARKUP_COLGROUP, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_COLSPAN|AMSK_WIDTH|AMSK_STYLE}, { "dd", MARKUP_DD, MUTYPE_LI, AMSK_STYLE }, { "dfn", MARKUP_DFN, MUTYPE_FONT, AMSK_STYLE }, { "div", MARKUP_DIV, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "dl", MARKUP_DL, MUTYPE_LIST, AMSK_COMPACT|AMSK_STYLE }, { "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE }, { "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE }, { "font", MARKUP_FONT, MUTYPE_FONT, AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE }, { "footer", MARKUP_HTML5_FOOTER, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "h1", MARKUP_H1, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h2", MARKUP_H2, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h3", MARKUP_H3, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h4", MARKUP_H4, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h5", MARKUP_H5, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "h6", MARKUP_H6, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "header", MARKUP_HTML5_HEADER, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "hr", MARKUP_HR, MUTYPE_SINGLE, AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH| AMSK_STYLE|AMSK_CLASS }, { "i", MARKUP_I, MUTYPE_FONT, AMSK_STYLE }, { "img", MARKUP_IMG, MUTYPE_SINGLE, AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT| AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE }, { "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE }, { "li", MARKUP_LI, MUTYPE_LI, AMSK_TYPE|AMSK_VALUE|AMSK_STYLE }, { "nav", MARKUP_HTML5_NAV, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 }, { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 }, { "ol", MARKUP_OL, MUTYPE_LIST, AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE }, { "p", MARKUP_P, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "pre", MARKUP_PRE, MUTYPE_BLOCK, AMSK_STYLE }, { "s", MARKUP_S, MUTYPE_FONT, AMSK_STYLE }, { "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE }, { "section", MARKUP_HTML5_SECTION, MUTYPE_BLOCK, AMSK_ID|AMSK_CLASS|AMSK_STYLE }, { "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE }, { "span", MARKUP_SPAN, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, { "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE }, { "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE }, { "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE }, { "sup", MARKUP_SUP, MUTYPE_FONT, AMSK_STYLE }, { "table", MARKUP_TABLE, MUTYPE_TABLE, AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING| AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE|AMSK_CLASS| AMSK_STYLE }, { "tbody", MARKUP_TBODY, MUTYPE_BLOCK, AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE }, |
︙ | ︙ | |||
458 459 460 461 462 463 464 | int state; /* Flag that govern rendering */ unsigned renderFlags; /* Flags from the client */ int wikiList; /* Current wiki list type */ int inVerbatim; /* True in <verbatim> mode */ int preVerbState; /* Value of state prior to verbatim */ int wantAutoParagraph; /* True if a <p> is desired */ int inAutoParagraph; /* True if within an automatic paragraph */ | < | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | int state; /* Flag that govern rendering */ unsigned renderFlags; /* Flags from the client */ int wikiList; /* Current wiki list type */ int inVerbatim; /* True in <verbatim> mode */ int preVerbState; /* Value of state prior to verbatim */ int wantAutoParagraph; /* True if a <p> is desired */ int inAutoParagraph; /* True if within an automatic paragraph */ const char *zVerbatimId; /* The id= attribute of <verbatim> */ int nStack; /* Number of elements on the stack */ int nAlloc; /* Space allocated for aStack */ struct sStack { short iCode; /* Markup code */ short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ const char *zId; /* ID attribute or NULL */ |
︙ | ︙ | |||
488 489 490 491 492 493 494 | /* ** z points to a "<" character. Check to see if this is the start of ** a valid markup. If it is, return the total number of characters in ** the markup including the initial "<" and the terminating ">". If ** it is not well-formed markup, return 0. */ | | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | /* ** z points to a "<" character. Check to see if this is the start of ** a valid markup. If it is, return the total number of characters in ** the markup including the initial "<" and the terminating ">". If ** it is not well-formed markup, return 0. */ int htmlTagLength(const char *z){ int n = 1; int inparen = 0; int c; if( z[n]=='/' ){ n++; } if( !fossil_isalpha(z[n]) ) return 0; while( fossil_isalnum(z[n]) || z[n]=='-' ){ n++; } c = z[n]; |
︙ | ︙ | |||
546 547 548 549 550 551 552 | ** \n ** [ ** ** The "[" is only considered if flags contain ALLOW_LINKS or ALLOW_WIKI. ** The "\n" is only considered interesting if the flags constains ALLOW_WIKI. */ static int textLength(const char *z, int flags){ | > > | | > > | | > > > > | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | ** \n ** [ ** ** The "[" is only considered if flags contain ALLOW_LINKS or ALLOW_WIKI. ** The "\n" is only considered interesting if the flags constains ALLOW_WIKI. */ static int textLength(const char *z, int flags){ int n = 0; int c, x1, x2; if( flags & ALLOW_WIKI ){ x1 = '['; x2 = '\n'; }else if( flags & ALLOW_LINKS ){ x1 = '['; x2 = 0; }else{ x1 = x2 = 0; } while( (c = z[0])!=0 && c!='<' && c!='&' && c!=x1 && c!=x2 ){ n++; z++; } return n; } /* ** Return true if z[] begins with an HTML character element. */ static int isElement(const char *z){ int i; |
︙ | ︙ | |||
598 599 600 601 602 603 604 | n++; } if( i<2 || fossil_isspace(z[n]) ) return 0; return n; } /* | | | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | n++; } if( i<2 || fossil_isspace(z[n]) ) return 0; return n; } /* ** Check to see if the z[] string is the beginning of a enumeration value. ** If it is, return the length of the bullet text. Otherwise return 0. ** ** Syntax: ** * a tab or two or more spaces ** * one or more digits ** * optional "." ** * another tab or two ore more spaces. |
︙ | ︙ | |||
675 676 677 678 679 680 681 | ** ** z points to the start of a token. Return the number of ** characters in that token. Write the token type into *pTokenType. */ static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){ int n; if( z[0]=='<' ){ | | | | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | ** ** z points to the start of a token. Return the number of ** characters in that token. Write the token type into *pTokenType. */ static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){ int n; if( z[0]=='<' ){ n = htmlTagLength(z); if( n>0 ){ *pTokenType = TOKEN_MARKUP; return n; }else{ *pTokenType = TOKEN_CHARACTER; return 1; } } if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){ *pTokenType = TOKEN_CHARACTER; return 1; } if( (p->state & ALLOW_WIKI)!=0 ){ if( z[0]=='\n' ){ n = paragraphBreakLength(z); if( n>0 ){ *pTokenType = TOKEN_PARAGRAPH; return n; }else if( fossil_isspace(z[1]) ){ *pTokenType = TOKEN_NEWLINE; return 1; } } if( (p->state & AT_NEWLINE)!=0 && fossil_isspace(z[0]) ){ n = listItemLength(z, '*'); if( n>0 ){ |
︙ | ︙ | |||
791 792 793 794 795 796 797 | i = 2; }else{ p->endTag = 0; i = 1; } j = 0; while( fossil_isalnum(z[i]) ){ | | | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | i = 2; }else{ p->endTag = 0; i = 1; } j = 0; while( fossil_isalnum(z[i]) ){ if( j<sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]); i++; } zTag[j] = 0; p->iCode = findTag(zTag); p->iType = aMarkup[p->iCode].iType; p->nAttr = 0; c = 0; |
︙ | ︙ | |||
814 815 816 817 818 819 820 | if( c=='>' ) return 0; } while( fossil_isspace(z[i]) ){ i++; } while( c!='>' && p->nAttr<8 && fossil_isalpha(z[i]) ){ int attrOk; /* True to preserve attribute. False to ignore it */ j = 0; while( fossil_isalnum(z[i]) ){ | | | 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | if( c=='>' ) return 0; } while( fossil_isspace(z[i]) ){ i++; } while( c!='>' && p->nAttr<8 && fossil_isalpha(z[i]) ){ int attrOk; /* True to preserve attribute. False to ignore it */ j = 0; while( fossil_isalnum(z[i]) ){ if( j<sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]); i++; } zTag[j] = 0; p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag); attrOk = iACode!=0 && (seen & aAttribute[iACode].iMask)==0; while( fossil_isspace(z[i]) ){ z++; } if( z[i]!='=' ){ |
︙ | ︙ | |||
838 839 840 841 842 843 844 | while( z[i] && z[i]!='"' ){ i++; } }else if( z[i]=='\'' ){ i++; zValue = &z[i]; while( z[i] && z[i]!='\'' ){ i++; } }else{ zValue = &z[i]; | | < < < < < < | < | | | | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | while( z[i] && z[i]!='"' ){ i++; } }else if( z[i]=='\'' ){ i++; zValue = &z[i]; while( z[i] && z[i]!='\'' ){ i++; } }else{ zValue = &z[i]; while( !fossil_isspace(z[i]) && z[i]!='>' ){ z++; } } if( attrOk ){ p->aAttr[p->nAttr].zValue = zValue; p->aAttr[p->nAttr].cTerm = c = z[i]; z[i] = 0; } i++; } if( attrOk ){ seen |= aAttribute[iACode].iMask; p->nAttr++; } while( fossil_isspace(z[i]) ){ i++; } if( z[i]=='>' || (z[i]=='/' && z[i+1]=='>') ) break; } return seen; } /* ** Render markup on the given blob. */ static void renderMarkup(Blob *pOut, ParsedMarkup *p){ int i; if( p->endTag ){ blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName); }else{ blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName); for(i=0; i<p->nAttr; i++){ blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iACode].zName); if( p->aAttr[i].zValue ){ const char *zVal = p->aAttr[i].zValue; if( p->aAttr[i].iACode==ATTR_SRC && zVal[0]=='/' ){ blob_appendf(pOut, "=\"%s%s\"", g.zTop, zVal); }else{ blob_appendf(pOut, "=\"%s\"", zVal); } } } if (p->iType & MUTYPE_SINGLE){ blob_append(pOut, " /", 2); } blob_append(pOut, ">", 1); } } /* ** When the markup was parsed, some "\000" may have been inserted. ** This routine restores to those "\000" values back to their ** original content. |
︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 | /* ** Begin a new paragraph if that something that is needed. */ static void startAutoParagraph(Renderer *p){ if( p->wantAutoParagraph==0 ) return; if( p->state & WIKI_LINKSONLY ) return; if( p->wikiList==MARKUP_OL || p->wikiList==MARKUP_UL ) return; | | | 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 | /* ** Begin a new paragraph if that something that is needed. */ static void startAutoParagraph(Renderer *p){ if( p->wantAutoParagraph==0 ) return; if( p->state & WIKI_LINKSONLY ) return; if( p->wikiList==MARKUP_OL || p->wikiList==MARKUP_UL ) return; blob_append(p->pOut, "<p>", -1); p->wantAutoParagraph = 0; p->inAutoParagraph = 1; } /* ** End a paragraph if we are in one. */ |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 | int n; char zU2[HNAME_MAX+1]; db_static_prepare(&q, "SELECT 1 FROM blob WHERE uuid>=:u AND uuid<:u2" ); db_bind_text(&q, ":u", zUuid); n = (int)strlen(zUuid); | | | > | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < > > | | | < | | < < < < < < < < < < < | | | | | < | | | | | < < < < < < < < < < < < < < < < < < < | | > > | < > | > > > > | | > < > < < | | < < | < | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | int n; char zU2[HNAME_MAX+1]; db_static_prepare(&q, "SELECT 1 FROM blob WHERE uuid>=:u AND uuid<:u2" ); db_bind_text(&q, ":u", zUuid); n = (int)strlen(zUuid); if( n>=sizeof(zU2) ) n = sizeof(zU2)-1; memcpy(zU2, zUuid, n); zU2[n-1]++; zU2[n] = 0; db_bind_text(&q, ":u2", zU2); rc = db_step(&q); db_reset(&q); return rc==SQLITE_ROW; } /* ** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket. ** If it is, store in *pClosed a true or false depending on whether or not ** the ticket is closed and return true. If zTarget ** is not the UUID of a ticket, return false. */ static int is_ticket( const char *zTarget, /* Ticket UUID */ int *pClosed /* True if the ticket is closed */ ){ static Stmt q; static int once = 1; int n; int rc; char zLower[HNAME_MAX+1]; char zUpper[HNAME_MAX+1]; n = strlen(zTarget); memcpy(zLower, zTarget, n+1); canonical16(zLower, n+1); memcpy(zUpper, zLower, n+1); zUpper[n-1]++; if( once ){ const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); db_static_prepare(&q, "SELECT %s FROM ticket " " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", zClosedExpr /*safe-for-%s*/ ); once = 0; } db_bind_text(&q, ":lwr", zLower); db_bind_text(&q, ":upr", zUpper); if( db_step(&q)==SQLITE_ROW ){ rc = 1; *pClosed = db_column_int(&q, 0); }else{ rc = 0; } db_reset(&q); return rc; } /* ** Return a pointer to the name part of zTarget (skipping the "wiki:" prefix ** if there is one) if zTarget is a valid wiki page name. Return NULL if ** zTarget names a page that does not exist. */ static const char *validWikiPageName(Renderer *p, const char *zTarget){ if( strncmp(zTarget, "wiki:", 5)==0 && wiki_name_is_wellformed((const unsigned char*)zTarget) ){ return zTarget+5; } if( strcmp(zTarget, "Sandbox")==0 ) return zTarget; if( wiki_name_is_wellformed((const unsigned char *)zTarget) && ((p->state & WIKI_NOBADLINKS)==0 || db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'" " AND (SELECT value FROM tagxref WHERE tagid=tag.tagid" " ORDER BY mtime DESC LIMIT 1) > 0", zTarget)) ){ return zTarget; } return 0; } /* ** Resolve a hyperlink. The zTarget argument is the content of the [...] ** in the wiki. Append to the output string whatever text is appropriate ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will ** close the markup. ** ** If this routine determines that no hyperlink should be generated, then ** set zClose[0] to 0. ** ** Actually, this routine might or might not append the hyperlink, depending ** on current rendering rules: specifically does the current user have ** "History" permission. ** ** [http://www.fossil-scm.org/] ** [https://www.fossil-scm.org/] ** [ftp://www.fossil-scm.org/] ** [mailto:fossil-users@lists.fossil-scm.org] ** ** [/path] ** ** [./relpath] ** ** [WikiPageName] ** [wiki:WikiPageName] ** ** [0123456789abcdef] ** ** [#fragment] ** ** [2010-02-27 07:13] */ static void openHyperlink( Renderer *p, /* Rendering context */ const char *zTarget, /* Hyperlink target; text within [...] */ char *zClose, /* Write hyperlink closing text here */ int nClose, /* Bytes available in zClose[] */ const char *zOrig /* Complete document text */ ){ const char *zTerm = "</a>"; const char *z; assert( nClose>=20 ); if( strncmp(zTarget, "http:", 5)==0 || strncmp(zTarget, "https:", 6)==0 || strncmp(zTarget, "ftp:", 4)==0 || strncmp(zTarget, "mailto:", 7)==0 ){ blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); }else if( zTarget[0]=='/' ){ blob_appendf(p->pOut, "<a href=\"%R%h\">", zTarget); }else if( zTarget[0]=='.' && (zTarget[1]=='/' || (zTarget[1]=='.' && zTarget[2]=='/')) && (p->state & WIKI_LINKSONLY)==0 ){ blob_appendf(p->pOut, "<a href=\"%h\">", zTarget); }else if( zTarget[0]=='#' ){ blob_appendf(p->pOut, "<a href=\"%h\">", zTarget); }else if( is_valid_hname(zTarget) ){ int isClosed = 0; if( strlen(zTarget)<=HNAME_MAX && is_ticket(zTarget, &isClosed) ){ /* Special display processing for tickets. Display the hyperlink ** as crossed out if the ticket is closed. */ if( isClosed ){ if( g.perm.Hyperlink ){ blob_appendf(p->pOut, "%z<span class=\"wikiTagCancelled\">[", href("%R/info/%s",zTarget) ); zTerm = "]</span></a>"; }else{ blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">["); zTerm = "]</span>"; } }else{ if( g.perm.Hyperlink ){ blob_appendf(p->pOut,"%z[", href("%R/info/%s", zTarget)); zTerm = "]</a>"; }else{ blob_appendf(p->pOut, "["); zTerm = "]"; } } }else if( !in_this_repo(zTarget) ){ if( (p->state & (WIKI_LINKSONLY|WIKI_NOBADLINKS))!=0 ){ zTerm = ""; }else{ blob_appendf(p->pOut, "<span class=\"brokenlink\">["); zTerm = "]</span>"; } }else if( g.perm.Hyperlink ){ blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget)); zTerm = "]</a>"; }else{ zTerm = ""; } }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget); }else if( (z = validWikiPageName(p, zTarget))!=0 ){ blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", z); }else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){ /* Probably an array subscript in code */ zTerm = ""; }else if( (p->state & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){ zTerm = ""; }else{ blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]", zTarget); zTerm = "</span>"; } assert( strlen(zTerm)<nClose ); sqlite3_snprintf(nClose, zClose, "%s", zTerm); } /* ** Check to see if the given parsed markup is the correct ** </verbatim> tag. */ static int endVerbatim(Renderer *p, ParsedMarkup *pMarkup){ char *z; assert( p->inVerbatim ); if( pMarkup->iCode!=MARKUP_VERBATIM ) return 0; if( !pMarkup->endTag ) return 0; if( p->zVerbatimId==0 ) return 1; if( pMarkup->nAttr!=1 ) return 0; z = pMarkup->aAttr[0].zValue; return fossil_strcmp(z, p->zVerbatimId)==0; } /* ** Return the MUTYPE for the top of the stack. */ static int stackTopType(Renderer *p){ if( p->nStack<=0 ) return 0; return aMarkup[p->aStack[p->nStack-1].iCode].iType; } |
︙ | ︙ | |||
1467 1468 1469 1470 1471 1472 1473 | }else{ n = nextWikiToken(z, p, &tokenType); } p->state &= ~(AT_NEWLINE|AT_PARAGRAPH); switch( tokenType ){ case TOKEN_PARAGRAPH: { if( inlineOnly ){ | | | | < < < | < | | | | | | | | | | | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | }else{ n = nextWikiToken(z, p, &tokenType); } p->state &= ~(AT_NEWLINE|AT_PARAGRAPH); switch( tokenType ){ case TOKEN_PARAGRAPH: { if( inlineOnly ){ /* blob_append(p->pOut, " ¶ ", -1); */ blob_append(p->pOut, " ", -1); }else{ if( p->wikiList ){ popStackToTag(p, p->wikiList); p->wikiList = 0; } endAutoParagraph(p); blob_append(p->pOut, "\n\n", 1); p->wantAutoParagraph = 1; } p->state |= AT_PARAGRAPH|AT_NEWLINE; break; } case TOKEN_NEWLINE: { blob_append(p->pOut, "\n", 1); p->state |= AT_NEWLINE; break; } case TOKEN_BUL_LI: { if( inlineOnly ){ blob_append(p->pOut, " • ", -1); }else{ if( p->wikiList!=MARKUP_UL ){ if( p->wikiList ){ popStackToTag(p, p->wikiList); } endAutoParagraph(p); pushStack(p, MARKUP_UL); blob_append(p->pOut, "<ul>", 4); p->wikiList = MARKUP_UL; } popStackToTag(p, MARKUP_LI); startAutoParagraph(p); pushStack(p, MARKUP_LI); blob_append(p->pOut, "<li>", 4); } break; } case TOKEN_NUM_LI: { if( inlineOnly ){ blob_append(p->pOut, " # ", -1); }else{ if( p->wikiList!=MARKUP_OL ){ if( p->wikiList ){ popStackToTag(p, p->wikiList); } endAutoParagraph(p); pushStack(p, MARKUP_OL); blob_append(p->pOut, "<ol>", 4); p->wikiList = MARKUP_OL; } popStackToTag(p, MARKUP_LI); startAutoParagraph(p); pushStack(p, MARKUP_LI); blob_append(p->pOut, "<li>", 4); } break; } case TOKEN_ENUM: { if( inlineOnly ){ blob_appendf(p->pOut, " (%d) ", atoi(z)); }else{ if( p->wikiList!=MARKUP_OL ){ if( p->wikiList ){ popStackToTag(p, p->wikiList); } endAutoParagraph(p); pushStack(p, MARKUP_OL); blob_append(p->pOut, "<ol>", 4); p->wikiList = MARKUP_OL; } popStackToTag(p, MARKUP_LI); startAutoParagraph(p); pushStack(p, MARKUP_LI); blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z)); } break; } case TOKEN_INDENT: { if( !inlineOnly ){ assert( p->wikiList==0 ); pushStack(p, MARKUP_BLOCKQUOTE); blob_append(p->pOut, "<blockquote>", -1); p->wantAutoParagraph = 0; p->wikiList = MARKUP_BLOCKQUOTE; } break; } case TOKEN_CHARACTER: { startAutoParagraph(p); if( z[0]=='<' ){ blob_append(p->pOut, "<", 4); }else if( z[0]=='&' ){ blob_append(p->pOut, "&", 5); } break; } case TOKEN_LINK: { char *zTarget; char *zDisplay = 0; int i, j; |
︙ | ︙ | |||
1591 1592 1593 1594 1595 1596 1597 | iS1 = j; cS1 = z[j]; z[j] = 0; } } z[i] = 0; if( zDisplay==0 ){ | | < | | 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 | iS1 = j; cS1 = z[j]; z[j] = 0; } } z[i] = 0; if( zDisplay==0 ){ zDisplay = zTarget; }else{ while( fossil_isspace(*zDisplay) ) zDisplay++; } openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig); if( linksOnly || zClose[0]==0 || p->inVerbatim ){ if( cS1 ) z[iS1] = cS1; if( zClose[0]!=']' ){ blob_appendf(p->pOut, "[%h]%s", zTarget, zClose); }else{ blob_appendf(p->pOut, "%h%s", zTarget, zClose); } |
︙ | ︙ | |||
1654 1655 1656 1657 1658 1659 1660 | if( markup.iCode==MARKUP_DIV && markup.endTag && (zId = markupId(&markup))!=0 && (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0 ){ if( p->inVerbatim ){ p->inVerbatim = 0; p->state = p->preVerbState; | | | | | | 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 | if( markup.iCode==MARKUP_DIV && markup.endTag && (zId = markupId(&markup))!=0 && (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0 ){ if( p->inVerbatim ){ p->inVerbatim = 0; p->state = p->preVerbState; blob_append(p->pOut, "</pre>", 6); } while( p->nStack>iDiv+1 ) popStack(p); if( p->aStack[iDiv].allowWiki ){ p->state |= ALLOW_WIKI; }else{ p->state &= ~ALLOW_WIKI; } assert( p->nStack==iDiv+1 ); p->nStack--; }else /* If within <verbatim id=ID> ignore everything other than ** </verbatim id=ID> and the </dev id=ID2> above. */ if( p->inVerbatim ){ if( endVerbatim(p, &markup) ){ p->inVerbatim = 0; p->state = p->preVerbState; blob_append(p->pOut, "</pre>", 6); }else{ unparseMarkup(&markup); blob_append(p->pOut, "<", 4); n = 1; } }else /* Render invalid markup literally. The markup appears in the ** final output as plain text. */ if( markup.iCode==MARKUP_INVALID ){ unparseMarkup(&markup); startAutoParagraph(p); blob_append(p->pOut, "<", 4); n = 1; }else /* If the markup is not font-change markup ignore it if the ** font-change-only flag is set. */ if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){ |
︙ | ︙ | |||
1729 1730 1731 1732 1733 1734 1735 | }else /* Enter <verbatim> processing. With verbatim enabled, all other ** markup other than the corresponding end-tag with the same ID is ** ignored. */ if( markup.iCode==MARKUP_VERBATIM ){ | | < > | > > | < | < < < < < < < < | | < | 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 | }else /* Enter <verbatim> processing. With verbatim enabled, all other ** markup other than the corresponding end-tag with the same ID is ** ignored. */ if( markup.iCode==MARKUP_VERBATIM ){ int ii, vAttrDidAppend=0; p->zVerbatimId = 0; p->inVerbatim = 1; p->preVerbState = p->state; p->state &= ~ALLOW_WIKI; for(ii=0; ii<markup.nAttr; ii++){ if( markup.aAttr[ii].iACode == ATTR_ID ){ p->zVerbatimId = markup.aAttr[ii].zValue; }else if( markup.aAttr[ii].iACode==ATTR_TYPE ){ blob_appendf(p->pOut, "<pre name='code' class='%s'>", markup.aAttr[ii].zValue); vAttrDidAppend=1; }else if( markup.aAttr[ii].iACode==ATTR_LINKS && !is_false(markup.aAttr[ii].zValue) ){ p->state |= ALLOW_LINKS; } } if( !vAttrDidAppend ) { endAutoParagraph(p); blob_append(p->pOut, "<pre class='verbatim'>",-1); } p->wantAutoParagraph = 0; }else if( markup.iType==MUTYPE_LI ){ if( backupToType(p, MUTYPE_LIST)==0 ){ endAutoParagraph(p); pushStack(p, MARKUP_UL); blob_append(p->pOut, "<ul>", 4); } pushStack(p, MARKUP_LI); renderMarkup(p->pOut, &markup); }else if( markup.iType==MUTYPE_TR ){ if( backupToType(p, MUTYPE_TABLE) ){ pushStack(p, MARKUP_TR); renderMarkup(p->pOut, &markup); } }else if( markup.iType==MUTYPE_TD ){ if( backupToType(p, MUTYPE_TABLE|MUTYPE_TR) ){ if( stackTopType(p)==MUTYPE_TABLE ){ pushStack(p, MARKUP_TR); blob_append(p->pOut, "<tr>", 4); } pushStack(p, markup.iCode); renderMarkup(p->pOut, &markup); } }else if( markup.iType==MUTYPE_HYPERLINK ){ if( !isButtonHyperlink(p, &markup, z, &n) ){ popStackToTag(p, markup.iCode); |
︙ | ︙ | |||
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 | */ void wiki_convert(Blob *pIn, Blob *pOut, int flags){ Renderer renderer; memset(&renderer, 0, sizeof(renderer)); renderer.renderFlags = flags; renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags; if( flags & WIKI_INLINE ){ renderer.wantAutoParagraph = 0; }else{ renderer.wantAutoParagraph = 1; } if( wikiUsesHtml() ){ renderer.state |= WIKI_HTMLONLY; } if( pOut ){ renderer.pOut = pOut; }else{ renderer.pOut = cgi_output_blob(); } blob_to_utf8_no_bom(pIn, 0); wiki_render(&renderer, blob_str(pIn)); endAutoParagraph(&renderer); while( renderer.nStack ){ popStack(&renderer); } | > > > | > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 | */ void wiki_convert(Blob *pIn, Blob *pOut, int flags){ Renderer renderer; memset(&renderer, 0, sizeof(renderer)); renderer.renderFlags = flags; renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags; if( flags & WIKI_NOBLOCK ){ renderer.state |= INLINE_MARKUP_ONLY; } if( flags & WIKI_INLINE ){ renderer.wantAutoParagraph = 0; }else{ renderer.wantAutoParagraph = 1; } if( wikiUsesHtml() ){ renderer.state |= WIKI_HTMLONLY; } if( pOut ){ renderer.pOut = pOut; }else{ renderer.pOut = cgi_output_blob(); } blob_to_utf8_no_bom(pIn, 0); wiki_render(&renderer, blob_str(pIn)); endAutoParagraph(&renderer); while( renderer.nStack ){ popStack(&renderer); } blob_append(renderer.pOut, "\n", 1); free(renderer.aStack); } /* ** Send a string as wiki to CGI output. */ void wiki_write(const char *zIn, int flags){ Blob in; blob_init(&in, zIn, -1); wiki_convert(&in, 0, flags); blob_reset(&in); } /* ** COMMAND: test-wiki-render ** ** Usage: %fossil test-wiki-render FILE [OPTIONS] ** ** Options: ** --buttons Set the WIKI_BUTTONS flag ** --htmlonly Set the WIKI_HTMLONLY flag ** --linksonly Set the WIKI_LINKSONLY flag ** --nobadlinks Set the WIKI_NOBADLINKS flag ** --inline Set the WIKI_INLINE flag ** --noblock Set the WIKI_NOBLOCK flag */ void test_wiki_render(void){ Blob in, out; int flags = 0; if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS; if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY; if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY; if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS; if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE; if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK; verify_all_options(); if( g.argc!=3 ) usage("FILE"); blob_zero(&out); blob_read_from_file(&in, g.argv[2], ExtFILE); wiki_convert(&in, &out, flags); blob_write_to_file(&out, "-"); } /* ** Search for a <title>...</title> at the beginning of a wiki page. ** Return true (nonzero) if a title is found. Return zero if there is ** not title. ** ** If a title is found, initialize the pTitle blob to be the content ** of the title and initialize pTail to be the text that follows the |
︙ | ︙ | |||
1991 1992 1993 1994 1995 1996 1997 | ** ** Where "target" can be either an artifact ID prefix or a wiki page ** name. For each such hyperlink found, add an entry to the ** backlink table. */ void wiki_extract_links( char *z, /* The wiki text from which to extract links */ | | > > > > > > > | > > > > | > > > > > > > | 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 | ** ** Where "target" can be either an artifact ID prefix or a wiki page ** name. For each such hyperlink found, add an entry to the ** backlink table. */ void wiki_extract_links( char *z, /* The wiki text from which to extract links */ int srcid, /* srcid field for new BACKLINK table entries */ int srctype, /* srctype field for new BACKLINK table entries */ double mtime, /* mtime field for new BACKLINK table entries */ int replaceFlag, /* True first delete prior BACKLINK entries */ int flags /* wiki parsing flags */ ){ Renderer renderer; int tokenType; ParsedMarkup markup; int n; int inlineOnly; int wikiHtmlOnly = 0; memset(&renderer, 0, sizeof(renderer)); renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; if( flags & WIKI_NOBLOCK ){ renderer.state |= INLINE_MARKUP_ONLY; } if( wikiUsesHtml() ){ renderer.state |= WIKI_HTMLONLY; wikiHtmlOnly = 1; } inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0; if( replaceFlag ){ db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d", srctype, srcid); } while( z[0] ){ if( wikiHtmlOnly ){ n = nextRawToken(z, &renderer, &tokenType); }else{ n = nextWikiToken(z, &renderer, &tokenType); } switch( tokenType ){ case TOKEN_LINK: { char *zTarget; int i, c; char zLink[HNAME_MAX+4]; zTarget = &z[1]; for(i=0; zTarget[i] && zTarget[i]!='|' && zTarget[i]!=']'; i++){} while(i>1 && zTarget[i-1]==' '){ i--; } c = zTarget[i]; zTarget[i] = 0; if( is_valid_hname(zTarget) ){ memcpy(zLink, zTarget, i+1); canonical16(zLink, i); db_multi_exec( "REPLACE INTO backlink(target,srctype,srcid,mtime)" "VALUES(%Q,%d,%d,%g)", zLink, srctype, srcid, mtime ); } zTarget[i] = c; break; } case TOKEN_MARKUP: { const char *zId; int iDiv; parseMarkup(&markup, z); |
︙ | ︙ | |||
2142 2143 2144 2145 2146 2147 2148 | } z += n; } free(renderer.aStack); } /* | | > > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 | } z += n; } free(renderer.aStack); } /* ** Get the next HTML token. ** ** z points to the start of a token. Return the number of ** characters in that token. */ static int nextHtmlToken(const char *z){ int n; char c; if( (c=z[0])=='<' ){ n = htmlTagLength(z); if( n<=0 ) n = 1; }else if( fossil_isspace(c) ){ for(n=1; z[n] && fossil_isspace(z[n]); n++){} }else if( c=='&' ){ n = z[1]=='#' ? 2 : 1; while( fossil_isalnum(z[n]) ) n++; if( z[n]==';' ) n++; }else{ n = 1; for(n=1; 1; n++){ if( (c = z[n]) > '<' ) continue; if( c=='<' || c=='&' || fossil_isspace(c) || c==0 ) break; } } return n; } /* ** Attempt to reformat messy HTML to be easily readable by humans. ** ** * Try to keep lines less than 80 characters in length ** * Collapse white space into a single space ** * Put a blank line before: ** <blockquote><center><code><hN><p><pre><table> |
︙ | ︙ | |||
2289 2290 2291 2292 2293 2294 2295 | void htmlTidy(const char *zIn, Blob *pOut){ int n; int nPre = 0; int iCur = 0; int wantSpace = 0; int omitSpace = 1; while( zIn[0] ){ | | | | | | | | | | | | | | | | | 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 | void htmlTidy(const char *zIn, Blob *pOut){ int n; int nPre = 0; int iCur = 0; int wantSpace = 0; int omitSpace = 1; while( zIn[0] ){ n = nextHtmlToken(zIn); if( zIn[0]=='<' && n>1 ){ int i, j; int isCloseTag; int eTag; int eType; char zTag[32]; isCloseTag = zIn[1]=='/'; for(i=0, j=1+isCloseTag; i<30 && fossil_isalnum(zIn[j]); i++, j++){ zTag[i] = fossil_tolower(zIn[j]); } zTag[i] = 0; eTag = findTag(zTag); eType = aMarkup[eTag].iType; if( eTag==MARKUP_PRE ){ if( isCloseTag ){ nPre--; blob_append(pOut, zIn, n); zIn += n; if( nPre==0 ){ blob_append(pOut, "\n", 1); iCur = 0; } continue; }else{ if( iCur && nPre==0 ){ blob_append(pOut, "\n", 1); iCur = 0; } nPre++; } }else if( eType & (MUTYPE_BLOCK|MUTYPE_TABLE) ){ if( !isCloseTag && nPre==0 && blob_size(pOut)>0 ){ blob_append(pOut, "\n\n", 1 + (iCur>0)); iCur = 0; } wantSpace = 0; omitSpace = 1; }else if( (eType & (MUTYPE_LIST|MUTYPE_LI|MUTYPE_TR|MUTYPE_TD))!=0 || eTag==MARKUP_HR ){ if( nPre==0 && (!isCloseTag || (eType&MUTYPE_LIST)!=0) && iCur>0 ){ blob_append(pOut, "\n", 1); iCur = 0; } wantSpace = 0; omitSpace = 1; } if( wantSpace && nPre==0 ){ if( iCur+n+1>=80 ){ blob_append(pOut, "\n", 1); iCur = 0; }else{ blob_append(pOut, " ", 1); iCur++; } } blob_append(pOut, zIn, n); iCur += n; wantSpace = 0; if( eTag==MARKUP_BR || eTag==MARKUP_HR ){ blob_append(pOut, "\n", 1); iCur = 0; } }else if( fossil_isspace(zIn[0]) ){ if( nPre ){ blob_append(pOut, zIn, n); }else{ wantSpace = !omitSpace; } }else{ if( wantSpace && nPre==0 ){ if( iCur+n+1>=80 ){ blob_append(pOut, "\n", 1); iCur = 0; }else{ blob_append(pOut, " ", 1); iCur++; } } blob_append(pOut, zIn, n); iCur += n; wantSpace = omitSpace = 0; } zIn += n; } if( iCur ) blob_append(pOut, "\n", 1); } /* ** COMMAND: test-html-tidy ** ** Run the htmlTidy() routine on the content of all files named on ** the command-line and write the results to standard output. */ void test_html_tidy(void){ Blob in, out; int i; for(i=2; i<g.argc; i++){ blob_read_from_file(&in, g.argv[i], ExtFILE); blob_zero(&out); htmlTidy(blob_str(&in), &out); blob_reset(&in); fossil_puts(blob_str(&out), 0); blob_reset(&out); } } /* ** Remove all HTML markup from the input text. The output written into ** pOut is pure text. ** ** Put the title on the first line, if there is any <title> markup. ** If there is no <title>, then create a blank first line. */ void html_to_plaintext(const char *zIn, Blob *pOut){ int n; int i, j; int inTitle = 0; /* True between <title>...</title> */ int seenText = 0; /* True after first non-whitespace seen */ int nNL = 0; /* Number of \n characters at the end of pOut */ int nWS = 0; /* True if pOut ends with whitespace */ while( fossil_isspace(zIn[0]) ) zIn++; while( zIn[0] ){ n = nextHtmlToken(zIn); if( zIn[0]=='<' && n>1 ){ int isCloseTag; int eTag; int eType; char zTag[32]; isCloseTag = zIn[1]=='/'; for(i=0, j=1+isCloseTag; i<30 && fossil_isalnum(zIn[j]); i++, j++){ zTag[i] = fossil_tolower(zIn[j]); } zTag[i] = 0; eTag = findTag(zTag); eType = aMarkup[eTag].iType; if( eTag==MARKUP_INVALID && fossil_strnicmp(zIn,"<style",6)==0 ){ zIn += n; while( zIn[0] ){ n = nextHtmlToken(zIn); if( fossil_strnicmp(zIn, "</style",7)==0 ) break; zIn += n; } if( zIn[0]=='<' ) zIn += n; continue; } if( eTag==MARKUP_TITLE ){ inTitle = !isCloseTag; } if( !isCloseTag && seenText && (eType & (MUTYPE_BLOCK|MUTYPE_TABLE))!=0 ){ if( nNL==0 ){ blob_append(pOut, "\n", 1); nNL++; } nWS = 1; } }else if( fossil_isspace(zIn[0]) ){ if( seenText ){ nNL = 0; if( !inTitle ){ /* '\n' -> ' ' within <title> */ for(i=0; i<n; i++) if( zIn[i]=='\n' ) nNL++; } if( !nWS ){ blob_append(pOut, nNL ? "\n" : " ", 1); nWS = 1; } } }else if( zIn[0]=='&' ){ char c = '?'; if( zIn[1]=='#' ){ int x = atoi(&zIn[1]); |
︙ | ︙ | |||
2473 2474 2475 2476 2477 2478 2479 | if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){ c = aEntity[jj].c; break; } } } if( fossil_isspace(c) ){ | | | | | | | 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 | if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){ c = aEntity[jj].c; break; } } } if( fossil_isspace(c) ){ if( nWS==0 && seenText ) blob_append(pOut, &c, 1); nWS = 1; nNL = c=='\n'; }else{ if( !seenText && !inTitle ) blob_append(pOut, "\n", 1); seenText = 1; nNL = nWS = 0; blob_append(pOut, &c, 1); } }else{ if( !seenText && !inTitle ) blob_append(pOut, "\n", 1); seenText = 1; nNL = nWS = 0; blob_append(pOut, zIn, n); } zIn += n; } if( nNL==0 ) blob_append(pOut, "\n", 1); } /* ** COMMAND: test-html-to-text ** ** Usage: %fossil test-html-to-text FILE ... ** |
︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 | int i; for(i=2; i<g.argc; i++){ blob_read_from_file(&in, g.argv[i], ExtFILE); blob_zero(&out); html_to_plaintext(blob_str(&in), &out); blob_reset(&in); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 | int i; for(i=2; i<g.argc; i++){ blob_read_from_file(&in, g.argv[i], ExtFILE); blob_zero(&out); html_to_plaintext(blob_str(&in), &out); blob_reset(&in); fossil_puts(blob_str(&out), 0); blob_reset(&out); } } |
Changes to src/winfile.c.
︙ | ︙ | |||
280 281 282 283 284 285 286 | ** characters are converted to '/'. */ void win32_getcwd(char *zBuf, int nBuf){ int i; char *zUtf8; wchar_t *zWide = fossil_malloc( sizeof(wchar_t)*nBuf ); if( GetCurrentDirectoryW(nBuf, zWide)==0 ){ | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | ** characters are converted to '/'. */ void win32_getcwd(char *zBuf, int nBuf){ int i; char *zUtf8; wchar_t *zWide = fossil_malloc( sizeof(wchar_t)*nBuf ); if( GetCurrentDirectoryW(nBuf, zWide)==0 ){ fossil_panic("cannot find current working directory."); } zUtf8 = fossil_path_to_utf8(zWide); fossil_free(zWide); for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/'; strncpy(zBuf, zUtf8, nBuf); fossil_path_free(zUtf8); } |
︙ | ︙ |
Changes to src/winhttp.c.
︙ | ︙ | |||
201 202 203 204 205 206 207 | }; /* ** Accepts connections on DualSocket. */ static void DualSocket_accept(DualSocket* pListen, DualSocket* pClient, DualAddr* pClientAddr){ | | | | | | | 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 | }; /* ** Accepts connections on DualSocket. */ static void DualSocket_accept(DualSocket* pListen, DualSocket* pClient, DualAddr* pClientAddr){ fd_set rs; int rs_count = 0; assert( pListen!=NULL && pClient!=NULL && pClientAddr!= NULL ); DualSocket_init(pClient); DualAddr_init(pClientAddr); FD_ZERO(&rs); if( pListen->s4!=INVALID_SOCKET ){ FD_SET(pListen->s4, &rs); ++rs_count; } if( pListen->s6!=INVALID_SOCKET ){ FD_SET(pListen->s6, &rs); ++rs_count; } if( select(rs_count, &rs, 0, 0, 0 /*blocking*/)==SOCKET_ERROR ){ return; } if( FD_ISSET(pListen->s4, &rs) ){ pClient->s4 = accept(pListen->s4, (struct sockaddr*)&pClientAddr->a4.addr, &pClientAddr->a4.len); } if( FD_ISSET(pListen->s6, &rs) ){ pClient->s6 = accept(pListen->s6, (struct sockaddr*)&pClientAddr->a6.addr, |
︙ | ︙ | |||
286 287 288 289 290 291 292 | ** Issue a fatal error. */ static NORETURN void winhttp_fatal( const char *zOp, const char *zService, const char *zErr ){ | | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | ** Issue a fatal error. */ static NORETURN void winhttp_fatal( const char *zOp, const char *zService, const char *zErr ){ fossil_panic("unable to %s service '%s': %s", zOp, zService, zErr); } /* ** Make sure the server stops as soon as possible after the stopper file ** is found. If there is no stopper file name, do nothing. */ static void win32_server_stopper(void *pAppData){ |
︙ | ︙ | |||
338 339 340 341 342 343 344 | static void win32_http_request(void *pAppData){ HttpRequest *p = (HttpRequest*)pAppData; FILE *in = 0, *out = 0, *aux = 0; int amt, got, i; int wanted = 0; char *z; char *zIp; | < | < < < < < < | < < < < < | | < | | | < < < < < | | < | | < < < < < | | < | | | | | | < < < < | < < < < < | < < < < < < < | | | < | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | static void win32_http_request(void *pAppData){ HttpRequest *p = (HttpRequest*)pAppData; FILE *in = 0, *out = 0, *aux = 0; int amt, got, i; int wanted = 0; char *z; char *zIp; char zCmdFName[MAX_PATH]; char zRequestFName[MAX_PATH]; char zReplyFName[MAX_PATH]; char zCmd[2000]; /* Command-line to process the request */ char zHdr[4000]; /* The HTTP request header */ sqlite3_snprintf(MAX_PATH, zCmdFName, "%s_%06d_cmd.txt", zTempPrefix, p->id); sqlite3_snprintf(MAX_PATH, zRequestFName, "%s_%06d_in.txt", zTempPrefix, p->id); sqlite3_snprintf(MAX_PATH, zReplyFName, "%s_%06d_out.txt", zTempPrefix, p->id); amt = 0; while( amt<sizeof(zHdr) ){ got = recv(p->s, &zHdr[amt], sizeof(zHdr)-1-amt, 0); if( got==SOCKET_ERROR ) goto end_request; if( got==0 ){ wanted = 0; break; } amt += got; zHdr[amt] = 0; z = strstr(zHdr, "\r\n\r\n"); if( z ){ wanted = find_content_length(zHdr) + (&z[4]-zHdr) - amt; break; } } if( amt>=sizeof(zHdr) ) goto end_request; out = fossil_fopen(zRequestFName, "wb"); if( out==0 ) goto end_request; fwrite(zHdr, 1, amt, out); while( wanted>0 ){ got = recv(p->s, zHdr, sizeof(zHdr), 0); if( got==SOCKET_ERROR ) goto end_request; if( got ){ fwrite(zHdr, 1, got, out); }else{ break; } wanted -= got; } /* ** The repository name is only needed if there was no open checkout. This ** is designed to allow the open checkout for the interactive user to work ** with the local Fossil server started via the "ui" command. */ zIp = SocketAddr_toString(&p->addr); if( (p->flags & HTTP_SERVER_HAD_CHECKOUT)==0 ){ assert( g.zRepositoryName && g.zRepositoryName[0] ); sqlite3_snprintf(sizeof(zCmd), zCmd, "%s--in %s\n--out %s\n--ipaddr %s\n%s", get_utf8_bom(0), zRequestFName, zReplyFName, zIp, g.zRepositoryName ); }else{ sqlite3_snprintf(sizeof(zCmd), zCmd, "%s--in %s\n--out %s\n--ipaddr %s", get_utf8_bom(0), zRequestFName, zReplyFName, zIp ); } fossil_free(zIp); aux = fossil_fopen(zCmdFName, "wb"); if( aux==0 ) goto end_request; fwrite(zCmd, 1, strlen(zCmd), aux); sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http -args \"%s\" --nossl%s", g.nameOfExe, zCmdFName, p->zOptions ); in = fossil_fopen(zReplyFName, "w+b"); fflush(out); fflush(aux); fossil_system(zCmd); if( in ){ while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ send(p->s, zHdr, got, 0); } } end_request: if( out ) fclose(out); if( aux ) fclose(aux); if( in ) fclose(in); /* Initiate shutdown prior to closing the socket */ if( shutdown(p->s,1)==0 ) shutdown(p->s,0); closesocket(p->s); /* Make multiple attempts to delete the temporary files. Sometimes AV ** software keeps the files open for a few seconds, preventing the file ** from being deleted on the first try. */ for(i=1; i<=10 && file_delete(zRequestFName); i++){ Sleep(1000*i); } for(i=1; i<=10 && file_delete(zCmdFName); i++){ Sleep(1000*i); } for(i=1; i<=10 && file_delete(zReplyFName); i++){ Sleep(1000*i); } fossil_free(p); } /* ** Process a single incoming SCGI request. */ static void win32_scgi_request(void *pAppData){ |
︙ | ︙ | |||
568 569 570 571 572 573 574 | HANDLE hStoppedEvent; WSADATA wd; DualSocket ds; int idCnt = 0; int iPort = mnPort; Blob options; wchar_t zTmpPath[MAX_PATH]; | < < < < < | < | < < < < < < < < < < < < < < < < < | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | HANDLE hStoppedEvent; WSADATA wd; DualSocket ds; int idCnt = 0; int iPort = mnPort; Blob options; wchar_t zTmpPath[MAX_PATH]; const char *zSkin; #if USE_SEE const char *zSavedKey = 0; size_t savedKeySize = 0; #endif blob_zero(&options); if( zBaseUrl ){ blob_appendf(&options, " --baseurl %s", zBaseUrl); } if( zNotFound ){ blob_appendf(&options, " --notfound %s", zNotFound); } if( zFileGlob ){ blob_appendf(&options, " --files-urlenc %T", zFileGlob); } if( g.useLocalauth ){ blob_appendf(&options, " --localauth"); } if( g.thTrace ){ blob_appendf(&options, " --th-trace"); } if( flags & HTTP_SERVER_REPOLIST ){ blob_appendf(&options, " --repolist"); } zSkin = skin_in_use(); if( zSkin ){ blob_appendf(&options, " --skin %s", zSkin); } #if USE_SEE zSavedKey = db_get_saved_encryption_key(); savedKeySize = db_get_saved_encryption_key_size(); if( zSavedKey!=0 && savedKeySize>0 ){ blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(), zSavedKey, savedKeySize); } #endif if( WSAStartup(MAKEWORD(2,0), &wd) ){ fossil_panic("unable to initialize winsock"); } |
︙ | ︙ | |||
650 651 652 653 654 655 656 | iPort++; continue; } } break; } if( iPort>mxPort ){ | < | | < < < < < < < < < | | < | < | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | iPort++; continue; } } break; } if( iPort>mxPort ){ if( mnPort==mxPort ){ fossil_panic("unable to open listening socket on port %d", mnPort); }else{ fossil_panic("unable to open listening socket on any" " port in the range %d..%d", mnPort, mxPort); } } if( !GetTempPathW(MAX_PATH, zTmpPath) ){ fossil_panic("unable to get path to the temporary directory."); } zTempPrefix = mprintf("%sfossil_server_P%d", fossil_unicode_to_utf8(zTmpPath), iPort); fossil_print("Temporary files: %s*\n", zTempPrefix); fossil_print("Listening for %s requests on TCP port %d\n", (flags&HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort); if( zBrowser ){ zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort); fossil_print("Launch webbrowser: %s\n", zBrowser); fossil_system(zBrowser); } fossil_print("Type Ctrl-C to stop the HTTP server\n"); /* Create an event used to signal when this server is exiting. */ |
︙ | ︙ | |||
937 938 939 940 941 942 943 | hsData.s = *pS; win32_report_service_status(SERVICE_RUNNING, NO_ERROR, 0); } } /* ** Try to start the http server as a windows service. If we are running in | | | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | hsData.s = *pS; win32_report_service_status(SERVICE_RUNNING, NO_ERROR, 0); } } /* ** Try to start the http server as a windows service. If we are running in ** a interactive console session, this routine fails and returns a non zero ** integer value. When running as service, this routine does not return until ** the service is stopped. In this case, the return value is zero. */ int win32_http_service( int nPort, /* TCP port number */ const char *zBaseUrl, /* The --baseurl option, or NULL */ const char *zNotFound, /* The --notfound option, or NULL */ |
︙ | ︙ | |||
966 967 968 969 970 971 972 | if( GetStdHandle(STD_INPUT_HANDLE)!=NULL ){ return 1; } /* Try to start the control dispatcher thread for the service. */ if( !StartServiceCtrlDispatcherW(ServiceTable) ){ if( GetLastError()==ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ){ return 1; }else{ | | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | if( GetStdHandle(STD_INPUT_HANDLE)!=NULL ){ return 1; } /* Try to start the control dispatcher thread for the service. */ if( !StartServiceCtrlDispatcherW(ServiceTable) ){ if( GetLastError()==ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ){ return 1; }else{ fossil_panic("error from StartServiceCtrlDispatcher()"); } } return 0; } /* Duplicate #ifdef needed for mkindex */ #ifdef _WIN32 |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | ** ** Sets the start type of the service. TYPE can be "manual", ** which means you need to start the service yourself with the ** 'fossil winsrv start' command or with the "net start" command ** from the operating system. If TYPE is set to "auto", the service ** will be started automatically by the system during startup. ** | | | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | ** ** Sets the start type of the service. TYPE can be "manual", ** which means you need to start the service yourself with the ** 'fossil winsrv start' command or with the "net start" command ** from the operating system. If TYPE is set to "auto", the service ** will be started automatically by the system during startup. ** ** -U|--username USERNAME ** ** Specifies the user account which will be used to run the ** service. The account needs the "Logon as a service" right ** enabled in its profile. Specify local accounts as follows: ** ".\\USERNAME". By default, the "LocalSystem" account will be ** used. ** |
︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 | ** Use URL as the base (useful for reverse proxies) ** ** -P|--port TCPPORT ** ** Specifies the TCP port (default port is 8080) on which the ** server should listen. ** | | | | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 | ** Use URL as the base (useful for reverse proxies) ** ** -P|--port TCPPORT ** ** Specifies the TCP port (default port is 8080) on which the ** server should listen. ** ** -R|--repository REPOSITORY ** ** Specifies the name of the repository to be served. ** The repository option may be omitted if the working directory ** is within an open checkout. ** The REPOSITORY can be a directory (aka folder) that contains ** one or more repositories with names ending in ".fossil". ** In that case, the first element of the URL is used to select ** among the various repositories. ** ** --notfound URL ** |
︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 | SC_HANDLE hSvc; SERVICE_DESCRIPTIONW svcDescr = {L"Fossil - Distributed Software Configuration Management"}; DWORD dwStartType = SERVICE_DEMAND_START; const char *zAltBase = find_option("baseurl", 0, 1); const char *zDisplay = find_option("display", "D", 1); const char *zStart = find_option("start", "S", 1); | | | 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 | SC_HANDLE hSvc; SERVICE_DESCRIPTIONW svcDescr = {L"Fossil - Distributed Software Configuration Management"}; DWORD dwStartType = SERVICE_DEMAND_START; const char *zAltBase = find_option("baseurl", 0, 1); const char *zDisplay = find_option("display", "D", 1); const char *zStart = find_option("start", "S", 1); const char *zUsername = find_option("username", "U", 1); const char *zPassword = find_option("password", "W", 1); const char *zPort = find_option("port", "P", 1); const char *zNotFound = find_option("notfound", 0, 1); const char *zFileGlob = find_option("files", 0, 1); const char *zLocalAuth = find_option("localauth", 0, 0); const char *zRepository = find_repository_option(); int useSCGI = find_option("scgi", 0, 0)!=0; |
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 | if( !hScm ) winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); if( !hSvc ) winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); QueryServiceStatus(hSvc, &sstat); if( sstat.dwCurrentState!=SERVICE_RUNNING ){ fossil_print("Starting service '%s'", zSvcName); | | | | | | | | 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | if( !hScm ) winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS); if( !hSvc ) winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); QueryServiceStatus(hSvc, &sstat); if( sstat.dwCurrentState!=SERVICE_RUNNING ){ fossil_print("Starting service '%s'", zSvcName); if( sstat.dwCurrentState!=SERVICE_START_PENDING ){ if( !StartServiceW(hSvc, 0, NULL) ){ winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); } QueryServiceStatus(hSvc, &sstat); } while( sstat.dwCurrentState==SERVICE_START_PENDING || sstat.dwCurrentState==SERVICE_STOPPED ){ Sleep(100); fossil_print("."); QueryServiceStatus(hSvc, &sstat); } if( sstat.dwCurrentState==SERVICE_RUNNING ){ |
︙ | ︙ |
Added src/wysiwyg.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | /* ** Copyright (c) 2012 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code that generates WYSIWYG text editors on ** web pages. */ #include "config.h" #include <assert.h> #include <ctype.h> #include "wysiwyg.h" /* ** Output code for a WYSIWYG editor. The caller must have already generated ** the <form> that will contain the editor, and the call must generate the ** corresponding </form> after this routine returns. The caller must include ** an onsubmit= attribute on the <form> element that invokes the ** wysiwygSubmit() function. ** ** There can only be a single WYSIWYG editor per frame. */ void wysiwygEditor( const char *zId, /* ID for this editor */ const char *zContent, /* Initial content (HTML) */ int w, int h /* Initial width and height */ ){ @ <style type="text/css"> @ .intLink { cursor: pointer; } @ img.intLink { border: 0; } @ #wysiwygBox { @ border: 1px #000000 solid; @ padding: 12px; @ } @ #editMode label { cursor: pointer; } @ </style> @ <input id="wysiwygValue" type="hidden" name="%s(zId)"> @ <div id="editModeDiv">Edit mode: @ <select id="editMode" size=1> @ <option value="0">WYSIWYG</option> @ <option value="1">Raw HTML</option> @ </select></div> @ <div id="toolBar1"> @ <select class="format" data-format="formatblock"> @ <option selected>- formatting -</option> @ <option value="h1">Title 1 <h1></option> @ <option value="h2">Title 2 <h2></option> @ <option value="h3">Title 3 <h3></option> @ <option value="h4">Title 4 <h4></option> @ <option value="h5">Title 5 <h5></option> @ <option value="h6">Subtitle <h6></option> @ <option value="p">Paragraph <p></option> @ <option value="pre">Preformatted <pre></option> @ </select> @ <select class="format" data-format="fontname"> @ <option class="heading" selected>- font -</option> @ <option>Arial</option> @ <option>Arial Black</option> @ <option>Courier New</option> @ <option>Times New Roman</option> @ </select> @ <select class="format" data-format="fontsize"> @ <option class="heading" selected>- size -</option> @ <option value="1">Very small</option> @ <option value="2">A bit small</option> @ <option value="3">Normal</option> @ <option value="4">Medium-large</option> @ <option value="5">Big</option> @ <option value="6">Very big</option> @ <option value="7">Maximum</option> @ </select> @ <select class="format" data-format="forecolor"> @ <option class="heading" selected>- color -</option> @ <option value="red">Red</option> @ <option value="blue">Blue</option> @ <option value="green">Green</option> @ <option value="black">Black</option> @ </select> @ </div> @ <div id="toolBar2"> @ <img class="intLink" title="Undo" data-format="undo" @ src="data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7 @ /I19DV3NHa7P///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq704680 @ 7TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfE @ whdRIH4fh/DZMICe3/C4nBQBADs="> @ <img class="intLink" title="Redo" data-format="redo" @ src="data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1/ @ ///yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9Na @ EDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw=="> @ <img class="intLink" title="Remove formatting" data-format="removeFormat" @ src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AA @ AABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwA @ AAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB5 @ 01ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqG @ Xz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMz @ deiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3//sf37/1/c02cCG1lB8f//f95 @ DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af///2ckaHBp7+7wmavP5n76+P2C @ lrLIYl8H9W36auJCbCxM4szMTJac7Kza////R3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tA @ wMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n @ 7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1 @ lsXc4Db7z8C3r8p7Qjf///2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj @ 5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwf @ fj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv//vPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrj @ b/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0////fv77//8nLy+7MCc @ XmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc66 @ 6s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7//8/4//9/pgOnH @ 6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg=="> @ <img class="intLink" title="Bold" data-format="bold" @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB @ YAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs=" /> @ <img class="intLink" title="Italic" data-format="italic" @ src="data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf///yH5BAEAAAMALA @ AAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw==" /> @ <img class="intLink" title="Underline" data-format="underline" @ src="data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vj////////yH5BAEAAAIALA @ AAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA @ 7" /> @ <img class="intLink" title="Left align" data-format="justifyleft" @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB @ YAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw==" /> @ <img class="intLink" title="Center align" data-format="justifycenter" @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB @ YAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7" /> @ <img class="intLink" title="Right align" data-format="justifyright" @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB @ YAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw==" /> @ <img class="intLink" title="Numbered list" @ data-format="insertorderedlist" @ src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P//// @ ///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEO @ zyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs=" /> @ <img class="intLink" title="Dotted list" @ data-format="insertunorderedlist" @ src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv//// @ ///yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud6 @ 4UwiuKnigGQliQuWOyKQykgAAOw==" /> @ <img class="intLink" title="Quote" data-format="formatblock" @ src="data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2 @ R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P///////// @ //////////////////////////yH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2Cekk @ ErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrT @ q/b7/i8fp8PAQA7" /> @ <img class="intLink" title="Delete indentation" data-format="outdent" @ src="data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P @ ///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMcz @ sYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs=" /> @ <img class="intLink" title="Add indentation" data-format="indent" @ src="data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3N @ Ha7P///////////////////////////////yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650 @ B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw=="> @ <img class="intLink" title="Hyperlink" data-format="createlink" @ src="data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb @ /I19Ha7Pv8/f///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq704682 @ 7/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghG @ i9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7" /> #if 0 /* Cut/Copy/Paste requires special browser permissions for security ** reasons. So omit these buttons */ @ <img class="intLink" title="Cut" data-format="cut" @ src="data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1 @ dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P///////////////////////////// @ //////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnE @ bGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9 @ ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw==" /> @ <img class="intLink" title="Copy" data-format="copy" @ src="data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31 @ iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OP @ s++bx/Pv8/f///////////////yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/ @ kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ @ ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA @ Grpy+wsbKzIiEAOw==" /> @ <img class="intLink" title="Paste" data-format="paste" @ src="data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp @ qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f///////////////////// @ //////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB @ SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ @ o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA @ MOaK+bLAOrtLUyt7i5uiUhADs=" /> #endif @ </div> @ <div id="wysiwygBox" @ style="resize:both;overflow:auto;width:95%%;min-height:%d(h)em;" @ contenteditable="true">%s(zContent)</div> @ <script nonce="%h(style_nonce())"> @ var oDoc; @ @ /* Initialize the document editor */ @ function initDoc() { @ initEventHandlers(); @ oDoc = document.getElementById("wysiwygBox"); @ if (!isWysiwyg()) { setDocMode(true); } @ } @ @ function initEventHandlers() { @ document.querySelector('form').onsubmit = wysiwygSubmit; @ document.querySelector('#editMode').onchange = function() { @ setDocMode(this.selectedIndex) @ }; @ var controls = document.querySelectorAll('select.format'); @ for(var i = 0; i < controls.length; i++) { @ controls[i].onchange = handleDropDown; @ } @ controls = document.querySelectorAll('.intLink'); @ for(i = 0; i < controls.length; i++) { @ controls[i].onclick = handleFormatButton; @ } @ @ function handleDropDown() { @ formatDoc(this.dataset.format,this[this.selectedIndex].value); @ this.selectedIndex = 0; @ } @ @ function handleFormatButton() { @ var extra; @ switch (this.dataset.format) { @ case 'createlink': @ var sLnk = prompt('Target URL:',''); @ if(sLnk && sLnk != '') @ { @ extra = sLnk; @ } @ break; @ case 'formatblock': @ extra = 'blockquote'; @ break; @ } @ formatDoc(this.dataset.format, extra); @ } @ } @ @ /* Return true if the document editor is in WYSIWYG mode. Return @ ** false if it is in Markup mode */ @ function isWysiwyg() { @ return document.getElementById("editMode").selectedIndex==0; @ } @ @ /* Invoke this routine prior to submitting the HTML content back @ ** to the server */ @ function wysiwygSubmit() { @ if(oDoc.style.whiteSpace=="pre-wrap"){setDocMode(0);} @ document.getElementById("wysiwygValue").value=oDoc.innerHTML; @ } @ @ /* Run the editing command if in WYSIWYG mode */ @ function formatDoc(sCmd, sValue) { @ if (isWysiwyg()){ @ try { @ // First, try the W3C draft standard way, which has @ // been working on all non-IE browsers for a while. @ // It is also supported by IE11 and higher. @ document.execCommand("styleWithCSS", false, false); @ } catch (e) { @ try { @ // For IE9 or IE10, this should work. @ document.execCommand("useCSS", 0, true); @ } catch (e) { @ // Ok, that apparently did not work, do nothing. @ } @ } @ document.execCommand(sCmd, false, sValue); @ oDoc.focus(); @ } @ } @ @ /* Change the editing mode. Convert to markup if the argument @ ** is true and wysiwyg if the argument is false. */ @ function setDocMode(bToMarkup) { @ var oContent; @ if (bToMarkup) { @ /* WYSIWYG -> Markup */ @ var linebreak = new RegExp("</p><p>","ig"); @ oContent = document.createTextNode( @ oDoc.innerHTML.replace(linebreak,"</p>\n\n<p>")); @ oDoc.innerHTML = ""; @ oDoc.style.whiteSpace = "pre-wrap"; @ oDoc.appendChild(oContent); @ document.getElementById("toolBar1").style.visibility="hidden"; @ document.getElementById("toolBar2").style.visibility="hidden"; @ } else { @ /* Markup -> WYSIWYG */ @ if (document.all) { @ oDoc.innerHTML = oDoc.innerText; @ } else { @ oContent = document.createRange(); @ oContent.selectNodeContents(oDoc.firstChild); @ oDoc.innerHTML = oContent.toString(); @ } @ oDoc.style.whiteSpace = "normal"; @ document.getElementById("toolBar1").style.visibility="visible"; @ document.getElementById("toolBar2").style.visibility="visible"; @ } @ oDoc.focus(); @ } @ initDoc(); @ </script> } |
Changes to src/xfer.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | Blob *pIn; /* Input text from the other side */ Blob *pOut; /* Compose our reply here */ Blob line; /* The current line of input */ Blob aToken[6]; /* Tokenized version of line */ Blob err; /* Error message text */ int nToken; /* Number of tokens in line */ int nIGotSent; /* Number of "igot" cards sent */ | < | < < | 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 | Blob *pIn; /* Input text from the other side */ Blob *pOut; /* Compose our reply here */ Blob line; /* The current line of input */ Blob aToken[6]; /* Tokenized version of line */ Blob err; /* Error message text */ int nToken; /* Number of tokens in line */ int nIGotSent; /* Number of "igot" cards sent */ int nGimmeSent; /* Number of gimme cards sent */ int nFileSent; /* Number of files sent */ int nDeltaSent; /* Number of deltas sent */ int nFileRcvd; /* Number of files received */ int nDeltaRcvd; /* Number of deltas received */ int nDanglingFile; /* Number of dangling deltas received */ int mxSend; /* Stop sending "file" when pOut reaches this size */ int resync; /* Send igot cards for all holdings */ u8 syncPrivate; /* True to enable syncing private content */ u8 nextIsPrivate; /* If true, next "file" received is a private */ u32 clientVersion; /* Version of the client software */ time_t maxTime; /* Time when this transfer should be finished */ }; /* ** The input blob contains an artifact. Convert it into a record ID. ** Create a phantom record if no prior record exists and |
︙ | ︙ | |||
95 96 97 98 99 100 101 | db_static_prepare(&q, "INSERT OR IGNORE INTO onremote VALUES(:r)"); db_bind_int(&q, ":r", rid); db_step(&q); db_reset(&q); } } | < < < < < < < < < < < < | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | db_static_prepare(&q, "INSERT OR IGNORE INTO onremote VALUES(:r)"); db_bind_int(&q, ":r", rid); db_step(&q); db_reset(&q); } } /* ** The aToken[0..nToken-1] blob array is a parse of a "file" line ** message. This routine finishes parsing that message and does ** a record insert of the file. ** ** The file line is in one of the following two forms: ** |
︙ | ︙ | |||
352 353 354 355 356 357 358 | goto end_accept_unversioned_file; } }else{ nullContent = 1; } /* The isWriter flag must be true in order to land the new file */ | < < | < | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | goto end_accept_unversioned_file; } }else{ nullContent = 1; } /* The isWriter flag must be true in order to land the new file */ if( !isWriter ) goto end_accept_unversioned_file; /* Make sure we have a valid g.rcvid marker */ content_rcvid_init(0); /* Check to see if current content really should be overwritten. Ideally, ** a uvfile card should never have been sent unless the overwrite should ** occur. But do not trust the sender. Double-check. |
︙ | ︙ | |||
451 452 453 454 455 456 457 | if( srcId>0 && (pXfer->syncPrivate || !content_is_private(srcId)) && content_get(srcId, &src) ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId); blob_delta_create(&src, pContent, &delta); size = blob_size(&delta); | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | if( srcId>0 && (pXfer->syncPrivate || !content_is_private(srcId)) && content_get(srcId, &src) ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId); blob_delta_create(&src, pContent, &delta); size = blob_size(&delta); if( size>=blob_size(pContent)-50 ){ size = 0; }else if( uuid_is_shunned(zUuid) ){ size = 0; }else{ if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size); blob_append(pXfer->pOut, blob_buffer(&delta), size); |
︙ | ︙ | |||
540 541 542 543 544 545 546 | ** this routine becomes a no-op. */ static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){ Blob content, uuid; int size = 0; int isPriv = content_is_private(rid); | | < < < < < < < < < < < < | | | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | ** this routine becomes a no-op. */ static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){ Blob content, uuid; int size = 0; int isPriv = content_is_private(rid); if( pXfer->syncPrivate==0 && isPriv ) return; if( db_exists("SELECT 1 FROM onremote WHERE rid=%d", rid) ){ return; } blob_zero(&uuid); db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d AND size>=0", rid); if( blob_size(&uuid)==0 ){ return; } if( blob_size(&uuid)>HNAME_LEN_SHA1 && pXfer->clientVersion<20000 ){ xfer_cannot_send_sha3_error(pXfer); return; } if( pUuid ){ if( blob_compare(pUuid, &uuid)!=0 ){ blob_reset(&uuid); return; } }else{ pUuid = &uuid; } if( uuid_is_shunned(blob_str(pUuid)) ){ blob_reset(&uuid); return; } if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) || pXfer->mxSend<=blob_size(pXfer->pOut) ){ const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n"; blob_appendf(pXfer->pOut, zFormat /*works-like:"%b"*/, pUuid); pXfer->nIGotSent++; blob_reset(&uuid); return; } if( nativeDelta ){ |
︙ | ︙ | |||
654 655 656 657 658 659 660 | zUuid = db_column_text(&q1, 0); szU = db_column_int(&q1, 1); szC = db_column_bytes(&q1, 2); zContent = db_column_raw(&q1, 2); srcIsPrivate = db_column_int(&q1, 3); zDelta = db_column_text(&q1, 4); if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); | | | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | zUuid = db_column_text(&q1, 0); szU = db_column_int(&q1, 1); szC = db_column_bytes(&q1, 2); zContent = db_column_raw(&q1, 2); srcIsPrivate = db_column_int(&q1, 3); zDelta = db_column_text(&q1, 4); if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); if( pXfer->clientVersion<20000 && db_column_bytes(&q1,0)!=HNAME_LEN_SHA1 ){ xfer_cannot_send_sha3_error(pXfer); db_reset(&q1); return; } blob_appendf(pXfer->pOut, "cfile %s ", zUuid); if( !isPrivate && srcIsPrivate ){ content_get(rid, &fullContent); |
︙ | ︙ | |||
702 703 704 705 706 707 708 | static void send_unversioned_file( Xfer *pXfer, /* Transfer context */ const char *zName, /* Name of unversioned file to be sent */ int noContent /* True to omit the content */ ){ Stmt q1; | | | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | static void send_unversioned_file( Xfer *pXfer, /* Transfer context */ const char *zName, /* Name of unversioned file to be sent */ int noContent /* True to omit the content */ ){ Stmt q1; if( blob_size(pXfer->pOut)>=pXfer->mxSend ) noContent = 1; if( noContent ){ db_prepare(&q1, "SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q", zName ); }else{ db_prepare(&q1, "SELECT mtime, hash, encoding, sz, content FROM unversioned" " WHERE name=%Q", zName ); } if( db_step(&q1)==SQLITE_ROW ){ sqlite3_int64 mtime = db_column_int64(&q1, 0); const char *zHash = db_column_text(&q1, 1); if( pXfer->clientVersion<20000 && db_column_bytes(&q1,1)>HNAME_LEN_SHA1 ){ xfer_cannot_send_sha3_error(pXfer); db_reset(&q1); return; } if( blob_size(pXfer->pOut)>=pXfer->mxSend ){ /* If we have already reached the send size limit, send a (short) ** uvigot card rather than a uvfile card. This only happens on the ** server side. The uvigot card will provoke the client to resend ** another uvgimme on the next cycle. */ blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n", zName, mtime, zHash, db_column_int(&q1,3)); }else{ |
︙ | ︙ | |||
762 763 764 765 766 767 768 | ** Except: do not request shunned artifacts. And do not request ** private artifacts if we are not doing a private transfer. */ static void request_phantoms(Xfer *pXfer, int maxReq){ Stmt q; db_prepare(&q, "SELECT uuid FROM phantom CROSS JOIN blob USING(rid) /*scan*/" | < | | 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 | ** Except: do not request shunned artifacts. And do not request ** private artifacts if we are not doing a private transfer. */ static void request_phantoms(Xfer *pXfer, int maxReq){ Stmt q; db_prepare(&q, "SELECT uuid FROM phantom CROSS JOIN blob USING(rid) /*scan*/" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s", (pXfer->syncPrivate ? "" : " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)") ); while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){ const char *zUuid = db_column_text(&q, 0); blob_appendf(pXfer->pOut, "gimme %s\n", zUuid); pXfer->nGimmeSent++; |
︙ | ︙ | |||
799 800 801 802 803 804 805 | ** Check the signature on an application/x-fossil payload received by ** the HTTP server. The signature is a line of the following form: ** ** login LOGIN NONCE SIGNATURE ** ** The NONCE is the SHA1 hash of the remainder of the input. ** SIGNATURE is the SHA1 checksum of the NONCE concatenated | | < < | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | ** Check the signature on an application/x-fossil payload received by ** the HTTP server. The signature is a line of the following form: ** ** login LOGIN NONCE SIGNATURE ** ** The NONCE is the SHA1 hash of the remainder of the input. ** SIGNATURE is the SHA1 checksum of the NONCE concatenated ** with the users password. ** ** The parameters to this routine are ephemeral blobs holding the ** LOGIN, NONCE and SIGNATURE. ** ** This routine attempts to locate the user and verify the signature. ** If everything checks out, the USER.CAP column for the USER table ** is consulted to set privileges in the global g variable. ** ** If anything fails to check out, no changes are made to privileges. ** ** Signature generation on the client side is handled by the ** http_exchange() routine. ** ** Return non-zero for a login failure and zero for success. */ int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ Stmt q; int rc = -1; char *zLogin = blob_terminate(pLogin); defossilize(zLogin); if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 |
︙ | ︙ | |||
987 988 989 990 991 992 993 | } return cnt; } /* ** Send an igot message for every entry in unclustered table. ** Return the number of cards sent. | < < < < < < < < < < < < < < < < < | | | | < | | 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 | } return cnt; } /* ** Send an igot message for every entry in unclustered table. ** Return the number of cards sent. */ static int send_unclustered(Xfer *pXfer){ Stmt q; int cnt = 0; if( pXfer->resync ){ db_prepare(&q, "SELECT uuid, rid FROM blob" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)" " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)" " AND blob.rid<=%d" " ORDER BY blob.rid DESC", pXfer->resync ); }else{ db_prepare(&q, "SELECT uuid FROM unclustered JOIN blob USING(rid)" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)" " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)" ); } while( db_step(&q)==SQLITE_ROW ){ blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0)); cnt++; if( pXfer->resync && pXfer->mxSend<blob_size(pXfer->pOut) ){ pXfer->resync = db_column_int(&q, 1)-1; } } db_finalize(&q); if( cnt==0 ) pXfer->resync = 0; return cnt; } |
︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 | ** pXfer is a "pragma uv-hash HASH" card. ** ** If HASH is different from the unversioned content hash on this server, ** then send a bunch of uvigot cards, one for each entry unversioned file ** on this server. */ static void send_unversioned_catalog(Xfer *pXfer){ | < > > > | | | | | | | | > | | | | | > | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | ** pXfer is a "pragma uv-hash HASH" card. ** ** If HASH is different from the unversioned content hash on this server, ** then send a bunch of uvigot cards, one for each entry unversioned file ** on this server. */ static void send_unversioned_catalog(Xfer *pXfer){ unversioned_schema(); if( !blob_eq(&pXfer->aToken[2], unversioned_content_hash(0)) ){ int nUvIgot = 0; Stmt uvq; db_prepare(&uvq, "SELECT name, mtime, hash, sz FROM unversioned" ); while( db_step(&uvq)==SQLITE_ROW ){ const char *zName = db_column_text(&uvq,0); sqlite3_int64 mtime = db_column_int64(&uvq,1); const char *zHash = db_column_text(&uvq,2); int sz = db_column_int(&uvq,3); nUvIgot++; if( zHash==0 ){ sz = 0; zHash = "-"; } blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n", zName, mtime, zHash, sz); } db_finalize(&uvq); } } /* ** Called when there is an attempt to transfer private content to and ** from a server without authorization. */ static void server_private_xfer_not_authorized(void){ |
︙ | ︙ | |||
1152 1153 1154 1155 1156 1157 1158 | ** set common_done 1 ** } */ int xfer_run_common_script(void){ return xfer_run_script(xfer_common_code(), 0, 0); } | < < < < < < < < < < < < < < < < < < < < < < | | 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | ** set common_done 1 ** } */ int xfer_run_common_script(void){ return xfer_run_script(xfer_common_code(), 0, 0); } /* ** If this variable is set, disable login checks. Used for debugging ** only. */ static int disableLogin = 0; /* ** The CGI/HTTP preprocessor always redirects requests with a content-type ** of application/x-fossil or application/x-fossil-debug to this page, ** regardless of what path was specified in the HTTP header. This allows ** clone clients to specify a URL that omits default pathnames, such ** as "http://fossil-scm.org/" instead of "http://fossil-scm.org/index.cgi". ** ** WEBPAGE: xfer ** ** This is the transfer handler on the server side. The transfer ** message has been uncompressed and placed in the g.cgiIn blob. ** Process this message and form an appropriate reply. */ void page_xfer(void){ int isPull = 0; |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 | int rc; const char *zScript = 0; char *zUuidList = 0; int nUuidList = 0; char **pzUuidList = 0; int *pnUuidList = 0; int uvCatalogSent = 0; | < < | < | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | int rc; const char *zScript = 0; char *zUuidList = 0; int nUuidList = 0; char **pzUuidList = 0; int *pnUuidList = 0; int uvCatalogSent = 0; if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ fossil_redirect_home(); } g.zLogin = "anonymous"; login_set_anon_nobody_capabilities(); login_check_credentials(); memset(&xfer, 0, sizeof(xfer)); blobarray_zero(xfer.aToken, count(xfer.aToken)); cgi_set_content_type(g.zContentType); cgi_reset_content(); if( db_schema_is_outofdate() ){ @ error database\sschema\sis\sout-of-date\son\sthe\sserver. return; } blob_zero(&xfer.err); xfer.pIn = &g.cgiIn; xfer.pOut = cgi_output_blob(); xfer.mxSend = db_get_int("max-download", 5000000); xfer.maxTime = db_get_int("max-download-time", 30); if( xfer.maxTime<1 ) xfer.maxTime = 1; xfer.maxTime += time(NULL); g.xferPanic = 1; db_begin_transaction(); db_multi_exec( "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" ); manifest_crosslink_begin(); rc = xfer_run_common_script(); if( rc==TH_ERROR ){ cgi_reset_content(); @ error common\sscript\sfailed:\s%F(g.zErrMsg) nErr++; |
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | if( blob_buffer(&xfer.line)[0]=='#' ) continue; if( blob_size(&xfer.line)==0 ) continue; xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); /* file HASH SIZE \n CONTENT ** file HASH DELTASRC SIZE \n CONTENT ** | | | | < | < | | < < < | < < < | < < < < < < < < < < < < | < < < | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | if( blob_buffer(&xfer.line)[0]=='#' ) continue; if( blob_size(&xfer.line)==0 ) continue; xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); /* file HASH SIZE \n CONTENT ** file HASH DELTASRC SIZE \n CONTENT ** ** Accept a file from the client. */ if( blob_eq(&xfer.aToken[0], "file") ){ if( !isPush ){ cgi_reset_content(); @ error not\sauthorized\sto\swrite nErr++; break; } xfer_accept_file(&xfer, 0, pzUuidList, pnUuidList); if( blob_size(&xfer.err) ){ cgi_reset_content(); @ error %T(blob_str(&xfer.err)) nErr++; break; } }else /* cfile HASH USIZE CSIZE \n CONTENT ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT ** ** Accept a file from the client. */ if( blob_eq(&xfer.aToken[0], "cfile") ){ if( !isPush ){ cgi_reset_content(); @ error not\sauthorized\sto\swrite nErr++; break; } xfer_accept_compressed_file(&xfer, pzUuidList, pnUuidList); if( blob_size(&xfer.err) ){ cgi_reset_content(); @ error %T(blob_str(&xfer.err)) nErr++; break; } }else /* uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT ** ** Accept an unversioned file from the client. */ if( blob_eq(&xfer.aToken[0], "uvfile") ){ xfer_accept_unversioned_file(&xfer, g.perm.WrUnver); if( blob_size(&xfer.err) ){ cgi_reset_content(); @ error %T(blob_str(&xfer.err)) nErr++; break; } }else /* gimme HASH ** ** Client is requesting a file. Send it. */ if( blob_eq(&xfer.aToken[0], "gimme") && xfer.nToken==2 && blob_is_hname(&xfer.aToken[1]) ){ nGimme++; if( isPull ){ int rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid ){ send_file(&xfer, rid, &xfer.aToken[1], deltaFlag); } } }else /* uvgimme NAME ** ** Client is requesting an unversioned file. Send it. */ if( blob_eq(&xfer.aToken[0], "uvgimme") && xfer.nToken==2 && blob_is_filename(&xfer.aToken[1]) ){ send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0); }else /* igot HASH ?ISPRIVATE? ** ** Client announces that it has a particular file. If the ISPRIVATE ** argument exists and is non-zero, then the file is a private file. */ if( xfer.nToken>=2 && blob_eq(&xfer.aToken[0], "igot") && blob_is_hname(&xfer.aToken[1]) ){ if( isPush ){ if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){ rid_from_uuid(&xfer.aToken[1], 1, 0); }else if( g.perm.Private ){ rid_from_uuid(&xfer.aToken[1], 1, 1); }else{ server_private_xfer_not_authorized(); } } }else /* pull SERVERCODE PROJECTCODE ** push SERVERCODE PROJECTCODE |
︙ | ︙ | |||
1460 1461 1462 1463 1464 1465 1466 | ){ int seqno, max; if( iVers>=3 ){ cgi_set_content_type("application/x-fossil-uncompressed"); } blob_is_int(&xfer.aToken[2], &seqno); max = db_int(0, "SELECT max(rid) FROM blob"); | | < | | 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 | ){ int seqno, max; if( iVers>=3 ){ cgi_set_content_type("application/x-fossil-uncompressed"); } blob_is_int(&xfer.aToken[2], &seqno); max = db_int(0, "SELECT max(rid) FROM blob"); while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){ if( time(NULL) >= xfer.maxTime ) break; if( iVers>=3 ){ send_compressed_file(&xfer, seqno); }else{ send_file(&xfer, seqno, 0, 1); } seqno++; } if( seqno>max ) seqno = 0; @ clone_seqno %d(seqno) }else{ isClone = 1; isPull = 1; deltaFlag = 1; } @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x")) }else /* login USER NONCE SIGNATURE ** ** Check for a valid login. This has to happen before anything else. ** The client can send multiple logins. Permissions are cumulative. */ if( blob_eq(&xfer.aToken[0], "login") && xfer.nToken==4 ){ if( disableLogin ){ g.perm.Read = g.perm.Write = g.perm.Private = g.perm.Admin = 1; |
︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 | break; } } }else /* reqconfig NAME ** | | | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 | break; } } }else /* reqconfig NAME ** ** Request a configuration value */ if( blob_eq(&xfer.aToken[0], "reqconfig") && xfer.nToken==2 ){ if( g.perm.Read ){ char *zName = blob_str(&xfer.aToken[1]); if( zName[0]=='/' ){ /* New style configuration transfer */ int groupMask = configure_name_to_mask(&zName[1], 0); if( !g.perm.Admin ) groupMask &= ~(CONFIGSET_USER|CONFIGSET_SCRIBER); if( !g.perm.RdAddr ) groupMask &= ~CONFIGSET_ADDR; configure_send_group(xfer.pOut, groupMask, 0); } } }else /* config NAME SIZE \n CONTENT ** ** Receive a configuration value from the client. This is only ** permitted for high-privilege users. */ if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 && blob_is_int(&xfer.aToken[2], &size) ){ const char *zName = blob_str(&xfer.aToken[1]); Blob content; blob_zero(&content); blob_extract(xfer.pIn, size, &content); |
︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 | blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT ** | | | 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 | blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT ** ** A cookie contains a arbitrary-length argument that is server-defined. ** The argument must be encoded so as not to contain any whitespace. ** The server can optionally send a cookie to the client. The client ** might then return the same cookie back to the server on its next ** communication. The cookie might record information that helps ** the server optimize a push or pull. ** ** The client is not required to return a cookie. So the server |
︙ | ︙ | |||
1568 1569 1570 1571 1572 1573 1574 | if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){ /* Process the cookie */ }else /* private ** | | | < < < > | < < < | > | | < < | < < < < < | < | < < < | > < | > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 | if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){ /* Process the cookie */ }else /* private ** ** This card indicates that the next "file" or "cfile" will contain ** private content. */ if( blob_eq(&xfer.aToken[0], "private") ){ if( !g.perm.Private ){ server_private_xfer_not_authorized(); }else{ xfer.nextIsPrivate = 1; } }else /* pragma NAME VALUE... ** ** The client issue pragmas to try to influence the behavior of the ** server. These are requests only. Unknown pragmas are silently ** ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ /* pragma send-private ** ** If the user has the "x" privilege (which must be set explicitly - ** it is not automatic with "a" or "s") then this pragma causes ** private information to be pulled in addition to public records. */ if( blob_eq(&xfer.aToken[1], "send-private") ){ login_check_credentials(); if( !g.perm.Private ){ server_private_xfer_not_authorized(); }else{ xfer.syncPrivate = 1; } } /* pragma send-catalog ** ** Send igot cards for all known artifacts. */ if( blob_eq(&xfer.aToken[1], "send-catalog") ){ xfer.resync = 0x7fffffff; } /* pragma client-version VERSION ** ** Let the server know what version of Fossil is running on the client. */ if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){ xfer.clientVersion = atoi(blob_str(&xfer.aToken[2])); } /* pragma uv-hash HASH ** ** The client wants to make sure that unversioned files are all synced. ** If the HASH does not match, send a complete catalog of ** "uvigot" cards. */ if( blob_eq(&xfer.aToken[1], "uv-hash") && blob_is_hname(&xfer.aToken[2]) ){ if( !uvCatalogSent ){ if( g.perm.Read && g.perm.WrUnver ){ @ pragma uv-push-ok send_unversioned_catalog(&xfer); }else if( g.perm.Read ){ @ pragma uv-pull-only send_unversioned_catalog(&xfer); } } uvCatalogSent = 1; } }else /* Unknown message */ { cgi_reset_content(); @ error bad\scommand:\s%F(blob_str(&xfer.line)) |
︙ | ︙ | |||
1798 1799 1800 1801 1802 1803 1804 | send_all(&xfer); if( xfer.syncPrivate ) send_private(&xfer); }else if( isPull ){ create_cluster(); send_unclustered(&xfer); if( xfer.syncPrivate ) send_private(&xfer); } | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < | | | < < | < | | < < > > | | < | < | < < < < < < < | | | | | | | < | | > | | < < < < < < | | | < < < < < < < < < < | < < < < < < < < < < < < < | | | < < < < < < | | < < < < < < < < < | | | < | < < | < < < < < < < < < < < < < < < < < < | | | > | | | | | < | 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 | send_all(&xfer); if( xfer.syncPrivate ) send_private(&xfer); }else if( isPull ){ create_cluster(); send_unclustered(&xfer); if( xfer.syncPrivate ) send_private(&xfer); } db_multi_exec("DROP TABLE onremote"); manifest_crosslink_end(MC_PERMIT_HOOKS); /* Send the server timestamp last, in case prior processing happened ** to use up a significant fraction of our time window. */ zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')"); @ # timestamp %s(zNow) free(zNow); db_end_transaction(0); configure_rebuild(); } /* ** COMMAND: test-xfer ** ** This command is used for debugging the server. There is a single ** argument which is the uncompressed content of an "xfer" message ** from client to server. This command interprets that message as ** if had been received by the server. ** ** On the client side, run: ** ** fossil push http://bogus/ --httptrace ** ** Or a similar command to provide the output. The content of the ** message will appear on standard output. Capture this message ** into a file named (for example) out.txt. Then run the ** server in gdb: ** ** gdb fossil ** r test-xfer out.txt */ void cmd_test_xfer(void){ db_find_and_open_repository(0,0); if( g.argc!=2 && g.argc!=3 ){ usage("?MESSAGEFILE?"); } blob_zero(&g.cgiIn); blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2], ExtFILE); disableLogin = 1; page_xfer(); fossil_print("%s\n", cgi_extract_content()); } /* ** Format strings for progress reporting. */ static const char zLabelFormat[] = "%-10s %10s %10s %10s %10s\n"; static const char zValueFormat[] = "\r%-10s %10d %10d %10d %10d\n"; static const char zBriefFormat[] = "Round-trips: %d Artifacts sent: %d received: %d\r"; #if INTERFACE /* ** Flag options for controlling client_sync() */ #define SYNC_PUSH 0x0001 /* push content client to server */ #define SYNC_PULL 0x0002 /* pull content server to client */ #define SYNC_CLONE 0x0004 /* clone the repository */ #define SYNC_PRIVATE 0x0008 /* Also transfer private content */ #define SYNC_VERBOSE 0x0010 /* Extra diagnostics */ #define SYNC_RESYNC 0x0020 /* --verily */ #define SYNC_UNVERSIONED 0x0040 /* Sync unversioned content */ #define SYNC_UV_REVERT 0x0080 /* Copy server unversioned to client */ #define SYNC_FROMPARENT 0x0100 /* Pull from the parent project */ #define SYNC_UV_TRACE 0x0200 /* Describe UV activities */ #define SYNC_UV_DRYRUN 0x0400 /* Do not actually exchange files */ #endif /* ** Floating-point absolute value */ static double fossil_fabs(double x){ return x>0.0 ? x : -x; } /* ** Sync to the host identified in g.url.name and g.url.path. This ** routine is called by the client. ** ** Records are pushed to the server if pushFlag is true. Records ** are pulled if pullFlag is true. A full sync occurs if both are ** true. */ int client_sync( unsigned syncFlags, /* Mask of SYNC_* flags */ unsigned configRcvMask, /* Receive these configuration items */ unsigned configSendMask /* Send these configuration items */ ){ int go = 1; /* Loop until zero */ int nCardSent = 0; /* Number of cards sent */ int nCardRcvd = 0; /* Number of cards received */ int nCycle = 0; /* Number of round trips to the server */ int size; /* Size of a config value or uvfile */ int origConfigRcvMask; /* Original value of configRcvMask */ int nFileRecv; /* Number of files received */ int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ const char *zCookie; /* Server cookie */ i64 nSent, nRcvd; /* Bytes sent and received (after compression) */ int cloneSeqno = 1; /* Sequence number for clones */ Blob send; /* Text we are sending to the server */ Blob recv; /* Reply we got back from the server */ Xfer xfer; /* Transfer data */ int pctDone; /* Percentage done with a message */ int lastPctDone = -1; /* Last displayed pctDone */ double rArrivalTime; /* Time at which a message arrived */ const char *zSCode = db_get("server-code", "x"); const char *zPCode = db_get("project-code", 0); int nErr = 0; /* Number of errors */ int nRoundtrip= 0; /* Number of HTTP requests */ int nArtifactSent = 0; /* Total artifacts sent */ int nArtifactRcvd = 0; /* Total artifacts received */ const char *zOpType = 0;/* Push, Pull, Sync, Clone */ double rSkew = 0.0; /* Maximum time skew */ int uvHashSent = 0; /* The "pragma uv-hash" message has been sent */ int uvDoPush = 0; /* Generate uvfile messages to send to server */ int nUvGimmeSent = 0; /* Number of uvgimme cards sent on this cycle */ int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */ sqlite3_int64 mtime; /* Modification time on a UV file */ if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH; if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0 && configRcvMask==0 && configSendMask==0 ) return 0; if( syncFlags & SYNC_FROMPARENT ){ configRcvMask = 0; configSendMask = 0; syncFlags &= ~(SYNC_PUSH); zPCode = db_get("parent-project-code", 0); if( zPCode==0 || db_get("parent-project-name",0)==0 ){ fossil_fatal("there is no parent project: set the 'parent-project-code'" " and 'parent-project-name' config parameters set in order" " to pull from a parent project"); } } transport_stats(0, 0, 1); socket_global_init(); memset(&xfer, 0, sizeof(xfer)); xfer.pIn = &recv; xfer.pOut = &send; xfer.mxSend = db_get_int("max-upload", 250000); xfer.maxTime = -1; xfer.clientVersion = RELEASE_VERSION_NUMBER; if( syncFlags & SYNC_PRIVATE ){ g.perm.Private = 1; xfer.syncPrivate = 1; } blobarray_zero(xfer.aToken, count(xfer.aToken)); blob_zero(&send); blob_zero(&recv); blob_zero(&xfer.err); blob_zero(&xfer.line); origConfigRcvMask = 0; /* Send the send-private pragma if we are trying to sync private data */ if( syncFlags & SYNC_PRIVATE ){ blob_append(&send, "pragma send-private\n", -1); } /* When syncing unversioned files, create a TEMP table in which to store ** the names of files that need to be sent from client to server. ** ** The initial assumption is that all unversioned files need to be sent ** to the other side. But "uvigot" cards received back from the remote ** side will normally cause many of these entries to be removed since they ** do not really need to be sent. */ if( (syncFlags & (SYNC_UNVERSIONED|SYNC_CLONE))!=0 ){ unversioned_schema(); db_multi_exec( "CREATE TEMP TABLE uv_tosend(" " name TEXT PRIMARY KEY," /* Name of file to send client->server */ " mtimeOnly BOOLEAN" /* True to only send mtime, not content */ ") WITHOUT ROWID;" "INSERT INTO uv_toSend(name,mtimeOnly)" " SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;" ); } /* ** Always begin with a clone, pull, or push message */ blob_appendf(&send, "pragma client-version %d\n", RELEASE_VERSION_NUMBER); if( syncFlags & SYNC_CLONE ){ blob_appendf(&send, "clone 3 %d\n", cloneSeqno); syncFlags &= ~(SYNC_PUSH|SYNC_PULL); nCardSent++; /* TBD: Request all transferable configuration values */ content_enable_dephantomize(0); zOpType = "Clone"; }else if( syncFlags & SYNC_PULL ){ blob_appendf(&send, "pull %s %s\n", zSCode, zPCode); nCardSent++; zOpType = (syncFlags & SYNC_PUSH)?"Sync":"Pull"; if( (syncFlags & SYNC_RESYNC)!=0 && nCycle<2 ){ blob_appendf(&send, "pragma send-catalog\n"); nCardSent++; } } if( syncFlags & SYNC_PUSH ){ blob_appendf(&send, "push %s %s\n", zSCode, zPCode); nCardSent++; if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push"; if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff; } if( syncFlags & SYNC_VERBOSE ){ fossil_print(zLabelFormat /*works-like:"%s%s%s%s%d"*/, "", "Bytes", "Cards", "Artifacts", "Deltas"); } while( go ){ int newPhantom = 0; char *zRandomness; db_begin_transaction(); db_record_repository_filename(0); db_multi_exec( "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" ); manifest_crosslink_begin(); /* Send back the most recently received cookie. Let the server ** figure out if this is a cookie that it cares about. */ zCookie = db_get("cookie", 0); if( zCookie ){ blob_appendf(&send, "cookie %s\n", zCookie); } /* Generate gimme cards for phantoms and leaf cards ** for all leaves. */ if( (syncFlags & SYNC_PULL)!=0 || ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1) ){ request_phantoms(&xfer, mxPhantomReq); } if( syncFlags & SYNC_PUSH ){ send_unsent(&xfer); nCardSent += send_unclustered(&xfer); if( syncFlags & SYNC_PRIVATE ) send_private(&xfer); } /* Send configuration parameter requests. On a clone, delay sending ** this until the second cycle since the login card might fail on ** the first cycle. */ if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){ const char *zName; if( zOpType==0 ) zOpType = "Pull"; zName = configure_first_name(configRcvMask); while( zName ){ blob_appendf(&send, "reqconfig %s\n", zName); zName = configure_next_name(configRcvMask); nCardSent++; } origConfigRcvMask = configRcvMask; configRcvMask = 0; } /* Send a request to sync unversioned files. On a clone, delay sending ** this until the second cycle since the login card might fail on ** the first cycle. */ if( (syncFlags & SYNC_UNVERSIONED)!=0 && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) && !uvHashSent ){ blob_appendf(&send, "pragma uv-hash %s\n", unversioned_content_hash(0)); nCardSent++; uvHashSent = 1; } /* Send configuration parameters being pushed */ if( configSendMask ){ if( zOpType==0 ) zOpType = "Push"; nCardSent += configure_send_group(xfer.pOut, configSendMask, 0); configSendMask = 0; } /* Send unversioned files present here on the client but missing or |
︙ | ︙ | |||
2234 2235 2236 2237 2238 2239 2240 | send_unversioned_file(&xfer, zName, db_column_int(&uvq,1)); nCardSent++; nArtifactSent++; db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName); if( syncFlags & SYNC_VERBOSE ){ fossil_print("\rUnversioned-file sent: %s\n", zName); } | | < < < < < < < < < < < < | | < < | < < < < < < < < < < < | < < < < < < < < < < | < < | < < | 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 | send_unversioned_file(&xfer, zName, db_column_int(&uvq,1)); nCardSent++; nArtifactSent++; db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName); if( syncFlags & SYNC_VERBOSE ){ fossil_print("\rUnversioned-file sent: %s\n", zName); } if( blob_size(xfer.pOut)>xfer.mxSend ) break; } db_finalize(&uvq); if( rc==SQLITE_DONE ) uvDoPush = 0; } } /* Append randomness to the end of the message. This makes all ** messages unique so that that the login-card nonce will always ** be unique. */ zRandomness = db_text(0, "SELECT hex(randomblob(20))"); blob_appendf(&send, "# %s\n", zRandomness); free(zRandomness); if( syncFlags & SYNC_VERBOSE ){ fossil_print("waiting for server..."); } fflush(stdout); /* Exchange messages with the server */ if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0, MAX_REDIRECTS) ){ nErr++; go = 2; break; } /* Output current stats */ if( syncFlags & SYNC_VERBOSE ){ fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Sent:", blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, xfer.nFileSent, xfer.nDeltaSent); }else{ nRoundtrip++; nArtifactSent += xfer.nFileSent + xfer.nDeltaSent; fossil_print(zBriefFormat /*works-like:"%d%d%d"*/, nRoundtrip, nArtifactSent, nArtifactRcvd); } nCardSent = 0; nCardRcvd = 0; xfer.nFileSent = 0; xfer.nDeltaSent = 0; xfer.nGimmeSent = 0; xfer.nIGotSent = 0; lastPctDone = -1; blob_reset(&send); blob_appendf(&send, "pragma client-version %d\n", RELEASE_VERSION_NUMBER); rArrivalTime = db_double(0.0, "SELECT julianday('now')"); /* Send the send-private pragma if we are trying to sync private data */ if( syncFlags & SYNC_PRIVATE ){ blob_append(&send, "pragma send-private\n", -1); } /* Begin constructing the next message (which might never be ** sent) by beginning with the pull or push cards */ if( syncFlags & SYNC_PULL ){ blob_appendf(&send, "pull %s %s\n", zSCode, zPCode); nCardSent++; } if( syncFlags & SYNC_PUSH ){ blob_appendf(&send, "push %s %s\n", zSCode, zPCode); nCardSent++; } go = 0; nUvGimmeSent = 0; nUvFileRcvd = 0; /* Process the reply that came back from the server */ while( blob_line(&recv, &xfer.line) ){ if( blob_buffer(&xfer.line)[0]=='#' ){ const char *zLine = blob_buffer(&xfer.line); if( memcmp(zLine, "# timestamp ", 12)==0 ){ char zTime[20]; |
︙ | ︙ | |||
2376 2377 2378 2379 2380 2381 2382 | fflush(stdout); } } /* file HASH SIZE \n CONTENT ** file HASH DELTASRC SIZE \n CONTENT ** | | | | | | | < < | 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 | fflush(stdout); } } /* file HASH SIZE \n CONTENT ** file HASH DELTASRC SIZE \n CONTENT ** ** Receive a file transmitted from the server. */ if( blob_eq(&xfer.aToken[0],"file") ){ xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0); nArtifactRcvd++; }else /* cfile HASH USIZE CSIZE \n CONTENT ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT ** ** Receive a compressed file transmitted from the server. */ if( blob_eq(&xfer.aToken[0],"cfile") ){ xfer_accept_compressed_file(&xfer, 0, 0); nArtifactRcvd++; }else /* uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT ** ** Accept an unversioned file from the server. */ if( blob_eq(&xfer.aToken[0], "uvfile") ){ xfer_accept_unversioned_file(&xfer, 1); nArtifactRcvd++; nUvFileRcvd++; if( syncFlags & SYNC_VERBOSE ){ fossil_print("\rUnversioned-file received: %s\n", blob_str(&xfer.aToken[1])); } }else /* gimme HASH ** ** Server is requesting a file. If the file is a manifest, assume ** that the server will also want to know all of the content files ** associated with the manifest and send those too. */ if( blob_eq(&xfer.aToken[0], "gimme") && xfer.nToken==2 && blob_is_hname(&xfer.aToken[1]) ){ if( syncFlags & SYNC_PUSH ){ int rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0); } }else /* igot HASH ?PRIVATEFLAG? |
︙ | ︙ | |||
2445 2446 2447 2448 2449 2450 2451 | && blob_eq(&xfer.aToken[0], "igot") && blob_is_hname(&xfer.aToken[1]) ){ int rid; int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1"); rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid>0 ){ | < < < | < | 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 | && blob_eq(&xfer.aToken[0], "igot") && blob_is_hname(&xfer.aToken[1]) ){ int rid; int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1"); rid = rid_from_uuid(&xfer.aToken[1], 0, 0); if( rid>0 ){ if( !isPriv ) content_make_public(rid); }else if( isPriv && !g.perm.Private ){ /* ignore private files */ }else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){ rid = content_new(blob_str(&xfer.aToken[1]), isPriv); if( rid ) newPhantom = 1; } remote_has(rid); |
︙ | ︙ | |||
2521 2522 2523 2524 2525 2526 2527 | } }else if( iStatus==2 ){ db_multi_exec( "UPDATE unversioned SET mtime=%lld WHERE name=%Q", mtime, zName ); db_unset("uv-hash", 0); } | < < < < < < < < | | | | 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 | } }else if( iStatus==2 ){ db_multi_exec( "UPDATE unversioned SET mtime=%lld WHERE name=%Q", mtime, zName ); db_unset("uv-hash", 0); } if( iStatus<=3 ){ db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName); }else if( iStatus==4 ){ db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q",zName); }else if( iStatus==5 ){ db_multi_exec("REPLACE INTO uv_tosend(name,mtimeOnly) VALUES(%Q,0)", zName); } }else /* push SERVERCODE PRODUCTCODE ** ** Should only happen in response to a clone. This message tells ** the client what product to use for the new database. */ if( blob_eq(&xfer.aToken[0],"push") && xfer.nToken==3 && (syncFlags & SYNC_CLONE)!=0 && blob_is_hname(&xfer.aToken[2]) ){ if( zPCode==0 ){ zPCode = mprintf("%b", &xfer.aToken[2]); db_set("project-code", zPCode, 0); } if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno); nCardSent++; }else /* config NAME SIZE \n CONTENT ** ** Receive a configuration value from the server. ** ** The received configuration setting is silently ignored if it was ** not requested by a prior "reqconfig" sent from client to server. */ if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 && blob_is_int(&xfer.aToken[2], &size) ){ const char *zName = blob_str(&xfer.aToken[1]); |
︙ | ︙ | |||
2581 2582 2583 2584 2585 2586 2587 | blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT ** | | | | < | | 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 | blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT ** ** The server might include a cookie in its reply. The client ** should remember this cookie and send it back to the server ** in its next query. ** ** Each cookie received overwrites the prior cookie from the ** same server. */ if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){ db_set("cookie", blob_str(&xfer.aToken[1]), 0); }else /* private ** ** This card indicates that the next "file" or "cfile" will contain ** private content. */ if( blob_eq(&xfer.aToken[0], "private") ){ xfer.nextIsPrivate = 1; }else /* clone_seqno N ** ** When doing a clone, the server tries to send all of its artifacts ** in sequence. This card indicates the sequence number of the next ** blob that needs to be sent. If N<=0 that indicates that all blobs ** have been sent. */ if( blob_eq(&xfer.aToken[0], "clone_seqno") && xfer.nToken==2 ){ blob_is_int(&xfer.aToken[1], &cloneSeqno); }else /* message MESSAGE ** ** Print a message. Similar to "error" but does not stop processing. ** ** If the "login failed" message is seen, clear the sync password prior ** to the next cycle. */ if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ char *zMsg = blob_terminate(&xfer.aToken[1]); defossilize(zMsg); |
︙ | ︙ | |||
2643 2644 2645 2646 2647 2648 2649 | /* pragma NAME VALUE... ** ** The server can send pragmas to try to convey meta-information to ** the client. These are informational only. Unknown pragmas are ** silently ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ | < < < < < < < < < < < < < < < < < | < | < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < > | | < < < < < > > > > > > > > > > > > > > | | > | 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 | /* pragma NAME VALUE... ** ** The server can send pragmas to try to convey meta-information to ** the client. These are informational only. Unknown pragmas are ** silently ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ /* If the server is unwill to accept new unversioned content (because ** this client lacks the necessary permissions) then it sends a ** "uv-pull-only" pragma so that the client will know not to waste ** bandwidth trying to upload unversioned content. If the server ** does accept new unversioned content, it sends "uv-push-ok". */ if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){ if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1; }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){ uvDoPush = 1; } }else /* error MESSAGE ** ** Report an error and abandon the sync session. ** ** Except, when cloning we will sometimes get an error on the ** first message exchange because the project-code is unknown ** and so the login card on the request was invalid. The project-code ** is returned in the reply before the error card, so second and ** subsequent messages should be OK. Nevertheless, we need to ignore ** the error card on the first message of a clone. */ if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){ char *zMsg = blob_terminate(&xfer.aToken[1]); defossilize(zMsg); fossil_force_newline(); fossil_print("Error: %s\n", zMsg); if( fossil_strcmp(zMsg, "login failed")==0 ){ if( nCycle<2 ){ g.url.passwd = 0; go = 1; if( g.cgiOutput==0 ){ g.url.flags |= URL_PROMPT_PW; g.url.flags &= ~URL_PROMPTED; url_prompt_for_password(); url_remember(); } }else{ nErr++; } }else{ blob_appendf(&xfer.err, "server says: %s\n", zMsg); nErr++; } break; } }else /* Unknown message */ if( xfer.nToken>0 ){ if( blob_str(&xfer.aToken[0])[0]=='<' ){ |
︙ | ︙ | |||
2806 2807 2808 2809 2810 2811 2812 | fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Received:", blob_size(&recv), nCardRcvd, xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); }else{ fossil_print(zBriefFormat /*works-like:"%d%d%d"*/, nRoundtrip, nArtifactSent, nArtifactRcvd); } | < | | > | < < > | | < < | < < < < | | < > | > > | | | > > > > > > > > | > > | | < | < < < | < < < < < < < < | | < < < < < < < < | < < < < < < < < < | 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 | fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Received:", blob_size(&recv), nCardRcvd, xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); }else{ fossil_print(zBriefFormat /*works-like:"%d%d%d"*/, nRoundtrip, nArtifactSent, nArtifactRcvd); } blob_reset(&recv); nCycle++; /* If we received one or more files on the previous exchange but ** there are still phantoms, then go another round. */ nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){ go = 1; mxPhantomReq = nFileRecv*2; if( mxPhantomReq<200 ) mxPhantomReq = 200; }else if( (syncFlags & SYNC_CLONE)!=0 && nFileRecv>0 ){ go = 1; } nCardRcvd = 0; xfer.nFileRcvd = 0; xfer.nDeltaRcvd = 0; xfer.nDanglingFile = 0; /* If we have one or more files queued to send, then go ** another round */ if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){ go = 1; } /* If this is a clone, the go at least two rounds */ if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1; /* Stop the cycle if the server sends a "clone_seqno 0" card and ** we have gone at least two rounds. Always go at least two rounds ** on a clone in order to be sure to retrieve the configuration ** information which is only sent on the second round. */ if( cloneSeqno<=0 && nCycle>1 ) go = 0; /* Continue looping as long as new uvfile cards are being received ** and uvgimme cards are being sent. */ if( nUvGimmeSent>0 && (nUvFileRcvd>0 || nCycle<3) ) go = 1; db_multi_exec("DROP TABLE onremote"); if( go ){ manifest_crosslink_end(MC_PERMIT_HOOKS); }else{ manifest_crosslink_end(MC_PERMIT_HOOKS); content_enable_dephantomize(1); } db_end_transaction(0); }; transport_stats(&nSent, &nRcvd, 1); if( (rSkew*24.0*3600.0) > 10.0 ){ fossil_warning("*** time skew *** server is fast by %s", db_timespan_name(rSkew)); g.clockSkewSeen = 1; }else if( rSkew*24.0*3600.0 < -10.0 ){ fossil_warning("*** time skew *** server is slow by %s", db_timespan_name(-rSkew)); g.clockSkewSeen = 1; } fossil_force_newline(); fossil_print( "%s done, sent: %lld received: %lld ip: %s\n", zOpType, nSent, nRcvd, g.zIpAddr); transport_close(&g.url); transport_global_shutdown(&g.url); if( nErr && go==2 ){ db_multi_exec("DROP TABLE onremote"); manifest_crosslink_end(MC_PERMIT_HOOKS); content_enable_dephantomize(1); db_end_transaction(0); } if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){ fossil_warning("***** WARNING: a fork has occurred *****\n" "use \"fossil leaves -multiple\" for more details."); } return nErr; } |
Changes to src/xfersetup.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | "Specific TH1 code to run after \"push\" transfer requests."); setup_menu_entry("Commit", "xfersetup_commit", "Specific TH1 code to run after processing a commit."); setup_menu_entry("Ticket", "xfersetup_ticket", "Specific TH1 code to run after processing a ticket change."); @ </table> | | | | | | | | 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 | "Specific TH1 code to run after \"push\" transfer requests."); setup_menu_entry("Commit", "xfersetup_commit", "Specific TH1 code to run after processing a commit."); setup_menu_entry("Ticket", "xfersetup_ticket", "Specific TH1 code to run after processing a ticket change."); @ </table> url_parse(0, 0); if( g.url.protocol ){ unsigned syncFlags; const char *zButton; char *zWarning; if( db_get_boolean("dont-push", 0) ){ syncFlags = SYNC_PULL; zButton = "Pull"; zWarning = 0; }else{ syncFlags = SYNC_PUSH | SYNC_PULL; zButton = "Synchronize"; zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.", g.url.canonical); } @ <p>Press the <strong>%h(zButton)</strong> button below to @ synchronize with the <em>%h(g.url.canonical)</em> repository now.<br /> @ This may be useful when testing the various transfer scripts.</p> @ <p>You can use the <code>http -async</code> command in your scripts, but @ make sure the <code>th1-uri-regexp</code> setting is set first.</p> if( zWarning ){ @ @ <big><b>%h(zWarning)</b></big> free(zWarning); } @ @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> login_insert_csrf_secret(); @ <input type="submit" name="sync" value="%h(zButton)" /> @ </div></form> @ if( P("sync") ){ user_select(); url_enable_proxy(0); @ <pre class="xfersetup"> client_sync(syncFlags, 0, 0); @ </pre> } } style_footer(); } /* ** Common implementation for the transfer setup editor pages. */ static void xfersetup_generic( const char *zTitle, /* Page title */ |
︙ | ︙ | |||
114 115 116 117 118 119 120 | cgi_redirect("xfersetup"); } isSubmit = P("submit")!=0; z = P("x"); if( z==0 ){ z = db_get(zDbField, zDfltValue); } | < | > | | > | | | | | | | | 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 | cgi_redirect("xfersetup"); } isSubmit = P("submit")!=0; z = P("x"); if( z==0 ){ z = db_get(zDbField, zDfltValue); } style_header("Edit %s", zTitle); if( P("clear")!=0 ){ login_verify_csrf_secret(); db_unset(zDbField, 0); if( xRebuild ) xRebuild(); z = zDfltValue; }else if( isSubmit ){ char *zErr = 0; login_verify_csrf_secret(); if( xText && (zErr = xText(z))!=0 ){ @ <p class="xfersetupError">ERROR: %h(zErr)</p> }else{ db_set(zDbField, z, 0); if( xRebuild ) xRebuild(); cgi_redirect("xfersetup"); } } @ <form action="%s(g.zTop)/%s(g.zPath)" method="post"><div> login_insert_csrf_secret(); @ <p>%s(zDesc)</p> @ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea> @ <p> @ <input type="submit" name="submit" value="Apply Changes" /> @ <input type="submit" name="clear" value="Revert To Default" /> @ <input type="submit" name="setup" value="Cancel" /> @ </p> @ </div></form> if ( zDfltValue ){ @ <hr /> @ <h2>Default %s(zTitle)</h2> @ <blockquote><pre> @ %h(zDfltValue) @ </pre></blockquote> } style_footer(); } static const char *zDefaultXferCommon = 0; /* ** WEBPAGE: xfersetup_com ** View or edit the TH1 script that runs prior to receiving a |
︙ | ︙ |
Changes to src/zip.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** This file contains code used to generate ZIP and SQLAR archives. */ #include "config.h" #include <assert.h> | > > > > | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** ******************************************************************************* ** ** This file contains code used to generate ZIP and SQLAR archives. */ #include "config.h" #include <assert.h> #if defined(FOSSIL_ENABLE_MINIZ) # define MINIZ_HEADER_FILE_ONLY # include "miniz.c" #else # include <zlib.h> #endif #include "zip.h" /* ** Type of archive to build. */ #define ARCHIVE_ZIP 0 #define ARCHIVE_SQLAR 1 |
︙ | ︙ | |||
64 65 66 67 68 69 70 | sqlite3_vfs vfs; /* VFS object */ }; /* ** Ensure that blob pBlob is at least nMin bytes in size. */ static void zip_blob_minsize(Blob *pBlob, int nMin){ | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | sqlite3_vfs vfs; /* VFS object */ }; /* ** Ensure that blob pBlob is at least nMin bytes in size. */ static void zip_blob_minsize(Blob *pBlob, int nMin){ if( blob_size(pBlob)<nMin ){ blob_resize(pBlob, nMin); } } /************************************************************************* ** Implementation of "archive" VFS. A VFS designed to store the contents ** of a new database in a Blob. Used to construct sqlar archives in |
︙ | ︙ | |||
136 137 138 139 140 141 142 | return 512; } static int archiveDeviceCharacteristics(sqlite3_file *pFile){ return 0; } static int archiveOpen( | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | return 512; } static int archiveDeviceCharacteristics(sqlite3_file *pFile){ return 0; } static int archiveOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ static struct sqlite3_io_methods methods = { 1, /* iVersion */ archiveClose, archiveRead, archiveWrite, |
︙ | ︙ | |||
234 235 236 237 238 239 240 | /* ** Set the date and time from a julian day number. */ void zip_set_timedate(double rDate){ char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate); zip_set_timedate_from_str(zDate); fossil_free(zDate); | | | | | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | /* ** Set the date and time from a julian day number. */ void zip_set_timedate(double rDate){ char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate); zip_set_timedate_from_str(zDate); fossil_free(zDate); unixTime = (rDate - 2440587.5)*86400.0; } /* ** Append a single file to a growing ZIP archive. ** ** pFile is the file to be appended. zName is the name ** that the file should be saved as. */ static void zip_add_file_to_zip( Archive *p, const char *zName, const Blob *pFile, int mPerm ){ z_stream stream; int nameLen; int toOut = 0; int iStart; int iCRC = 0; int nByte = 0; int nByteCompr = 0; int nBlob; /* Size of the blob */ int iMethod; /* Compression method. */ int iMode = 0644; /* Access permissions */ char *z; char zHdr[30]; |
︙ | ︙ | |||
372 373 374 375 376 377 378 | put16(&zExTime[2], 5); blob_append(&toc, zExTime, 9); nEntry++; } static void zip_add_file_to_sqlar( Archive *p, | | | | | | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | put16(&zExTime[2], 5); blob_append(&toc, zExTime, 9); nEntry++; } static void zip_add_file_to_sqlar( Archive *p, const char *zName, const Blob *pFile, int mPerm ){ int nName = (int)strlen(zName); if( p->db==0 ){ assert( p->vfs.zName==0 ); p->vfs.zName = (const char*)mprintf("archivevfs%p", (void*)p); p->vfs.iVersion = 1; p->vfs.szOsFile = sizeof(ArchiveFile); p->vfs.mxPathname = 512; p->vfs.pAppData = (void*)p->pBlob; p->vfs.xOpen = archiveOpen; p->vfs.xDelete = archiveDelete; p->vfs.xAccess = archiveAccess; p->vfs.xFullPathname = archiveFullPathname; p->vfs.xRandomness = archiveRandomness; p->vfs.xSleep = archiveSleep; p->vfs.xCurrentTime = archiveCurrentTime; p->vfs.xGetLastError = archiveGetLastError; sqlite3_vfs_register(&p->vfs, 0); sqlite3_open_v2("file:xyz.db", &p->db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE, p->vfs.zName ); assert( p->db ); blob_zero(&p->tmp); sqlite3_exec(p->db, "PRAGMA page_size=512;" "PRAGMA journal_mode = off;" "PRAGMA cache_spill = off;" "BEGIN;" "CREATE TABLE sqlar(" "name TEXT PRIMARY KEY, -- name of the file\n" "mode INT, -- access permissions\n" "mtime INT, -- last modification time\n" "sz INT, -- original file size\n" "data BLOB -- compressed content\n" ");", 0, 0, 0 ); sqlite3_prepare(p->db, "INSERT INTO sqlar VALUES(?, ?, ?, ?, ?)", -1, &p->pInsert, 0 ); assert( p->pInsert ); sqlite3_bind_int64(p->pInsert, 3, unixTime); blob_zero(p->pBlob); } |
︙ | ︙ | |||
435 436 437 438 439 440 441 | sqlite3_bind_int(p->pInsert, 4, 0); sqlite3_bind_null(p->pInsert, 5); }else{ sqlite3_bind_text(p->pInsert, 1, zName, nName, SQLITE_STATIC); if( mPerm==PERM_LNK ){ sqlite3_bind_int(p->pInsert, 2, 0120755); sqlite3_bind_int(p->pInsert, 4, -1); | | | | | | | | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | sqlite3_bind_int(p->pInsert, 4, 0); sqlite3_bind_null(p->pInsert, 5); }else{ sqlite3_bind_text(p->pInsert, 1, zName, nName, SQLITE_STATIC); if( mPerm==PERM_LNK ){ sqlite3_bind_int(p->pInsert, 2, 0120755); sqlite3_bind_int(p->pInsert, 4, -1); sqlite3_bind_text(p->pInsert, 5, blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC ); }else{ int nIn = blob_size(pFile); unsigned long int nOut = nIn; sqlite3_bind_int(p->pInsert, 2, mPerm==PERM_EXE ? 0100755 : 0100644); sqlite3_bind_int(p->pInsert, 4, nIn); zip_blob_minsize(&p->tmp, nIn); compress( (unsigned char*) blob_buffer(&p->tmp), &nOut, (unsigned char*)blob_buffer(pFile), nIn ); if( nOut>=nIn ){ sqlite3_bind_blob(p->pInsert, 5, blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC ); }else{ sqlite3_bind_blob(p->pInsert, 5, blob_buffer(&p->tmp), nOut, SQLITE_STATIC ); } } } sqlite3_step(p->pInsert); sqlite3_reset(p->pInsert); } static void zip_add_file( Archive *p, const char *zName, const Blob *pFile, int mPerm ){ if( p->eType==ARCHIVE_ZIP ){ zip_add_file_to_zip(p, zName, pFile, mPerm); }else{ zip_add_file_to_sqlar(p, zName, pFile, mPerm); } |
︙ | ︙ | |||
585 586 587 588 589 590 591 | if( find_option("dereference","h",0)!=0 ){ eFType = ExtFILE; } zip_open(); for(i=3; i<g.argc; i++){ blob_zero(&file); blob_read_from_file(&file, g.argv[i], eFType); | | | 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | if( find_option("dereference","h",0)!=0 ){ eFType = ExtFILE; } zip_open(); for(i=3; i<g.argc; i++){ blob_zero(&file); blob_read_from_file(&file, g.argv[i], eFType); zip_add_file(&sArchive, g.argv[i], &file, file_perm(0,0)); blob_reset(&file); } zip_close(&sArchive); blob_write_to_file(&zip, g.argv[2]); } /* |
︙ | ︙ | |||
607 608 609 610 611 612 613 | ** If the RID object does not exist in the repository, then ** pZip is zeroed. ** ** zDir is a "synthetic" subdirectory which all zipped files get ** added to as part of the zip file. It may be 0 or an empty string, ** in which case it is ignored. The intention is to create a zip which ** politely expands into a subdir instead of filling your current dir | | | | < | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 | ** If the RID object does not exist in the repository, then ** pZip is zeroed. ** ** zDir is a "synthetic" subdirectory which all zipped files get ** added to as part of the zip file. It may be 0 or an empty string, ** in which case it is ignored. The intention is to create a zip which ** politely expands into a subdir instead of filling your current dir ** with source files. For example, pass a UUID or "ProjectName". ** */ static void zip_of_checkin( int eType, /* Type of archive (ZIP or SQLAR) */ int rid, /* The RID of the checkin to build the archive from */ Blob *pZip, /* Write the archive content into this blob */ const char *zDir, /* Top-level directory of the archive */ Glob *pInclude, /* Only include files that match this pattern */ Glob *pExclude /* Exclude files that match this pattern */ ){ Blob mfile, hash, file; Manifest *pManifest; ManifestFile *pFile; Blob filename; int nPrefix; Archive sArchive; memset(&sArchive, 0, sizeof(Archive)); sArchive.eType = eType; sArchive.pBlob = pZip; blob_zero(&sArchive.tmp); blob_zero(pZip); content_get(rid, &mfile); if( blob_size(&mfile)==0 ){ return; } blob_set_dynamic(&hash, rid_to_uuid(rid)); blob_zero(&filename); zip_open(); if( zDir && zDir[0] ){ blob_appendf(&filename, "%s/", zDir); } nPrefix = blob_size(&filename); pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0); |
︙ | ︙ | |||
672 673 674 675 676 677 678 | && (flg & MFESTFLG_TAGS) ){ eflg |= MFESTFLG_TAGS; } if( eflg & MFESTFLG_RAW ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); | < < | > | < < < | | | < > > > < < < < < | | | < | > < < < | | | < < | < < < < < < < < | < < | | < < < < < < < | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | && (flg & MFESTFLG_TAGS) ){ eflg |= MFESTFLG_TAGS; } if( eflg & MFESTFLG_RAW ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); zip_add_folders(&sArchive, zName); sterilize_manifest(&mfile); zip_add_file(&sArchive, zName, &mfile, 0); } if( eflg & MFESTFLG_UUID ){ blob_append(&hash, "\n", 1); blob_resize(&filename, nPrefix); blob_append(&filename, "manifest.uuid", -1); zName = blob_str(&filename); zip_add_folders(&sArchive, zName); zip_add_file(&sArchive, zName, &hash, 0); } if( eflg & MFESTFLG_TAGS ){ Blob tagslist; blob_zero(&tagslist); get_checkin_taglist(rid, &tagslist); blob_resize(&filename, nPrefix); blob_append(&filename, "manifest.tags", -1); zName = blob_str(&filename); zip_add_folders(&sArchive, zName); zip_add_file(&sArchive, zName, &tagslist, 0); blob_reset(&tagslist); } } manifest_file_rewind(pManifest); zip_add_file(&sArchive, "", 0, 0); while( (pFile = manifest_file_next(pManifest,0))!=0 ){ int fid; if( pInclude!=0 && !glob_match(pInclude, pFile->zName) ) continue; if( glob_match(pExclude, pFile->zName) ) continue; fid = uuid_to_rid(pFile->zUuid, 0); if( fid ){ content_get(fid, &file); blob_resize(&filename, nPrefix); blob_append(&filename, pFile->zName, -1); zName = blob_str(&filename); zip_add_folders(&sArchive, zName); zip_add_file(&sArchive, zName, &file, manifest_file_mperm(pFile)); blob_reset(&file); } } } blob_reset(&mfile); manifest_destroy(pManifest); blob_reset(&filename); blob_reset(&hash); zip_close(&sArchive); } /* ** Implementation of zip_cmd and sqlar_cmd. */ static void archive_cmd(int eType){ int rid; Blob zip; const char *zName; Glob *pInclude = 0; Glob *pExclude = 0; const char *zInclude; const char *zExclude; zName = find_option("name", 0, 1); zExclude = find_option("exclude", "X", 1); if( zExclude ) pExclude = glob_create(zExclude); zInclude = find_option("include", 0, 1); if( zInclude ) pInclude = glob_create(zInclude); db_find_and_open_repository(0, 0); /* We should be done with options.. */ verify_all_options(); if( g.argc!=4 ){ usage("VERSION OUTPUTFILE"); } g.zOpenRevision = g.argv[2]; rid = name_to_typed_rid(g.argv[2], "ci"); if( rid==0 ){ fossil_fatal("Check-in not found: %s", g.argv[2]); return; } if( zName==0 ){ zName = db_text("default-name", "SELECT replace(%Q,' ','_') " " || strftime('_%%Y-%%m-%%d_%%H%%M%%S_', event.mtime) " " || substr(blob.uuid, 1, 10)" " FROM event, blob" " WHERE event.objid=%d" " AND blob.rid=%d", db_get("project-name", "unnamed"), rid, rid ); } zip_of_checkin(eType, rid, &zip, zName, pInclude, pExclude); glob_free(pInclude); glob_free(pExclude); blob_write_to_file(&zip, g.argv[3]); blob_reset(&zip); } /* ** COMMAND: zip* ** ** Usage: %fossil zip VERSION OUTPUTFILE [OPTIONS] ** ** Generate a ZIP archive for a check-in. If the --name option is ** used, its argument becomes the name of the top-level directory in the ** resulting ZIP archive. If --name is omitted, the top-level directory ** name is derived from the project name, the check-in date and time, and ** the artifact ID of the check-in. ** ** The GLOBLIST argument to --exclude and --include can be a comma-separated ** list of glob patterns, where each glob pattern may optionally be enclosed ** in "..." or '...' so that it may contain commas. If a file matches both ** --include and --exclude then it is excluded. ** ** Options: ** -X|--exclude GLOBLIST Comma-separated list of GLOBs of files to exclude ** --include GLOBLIST Comma-separated list of GLOBs of files to include ** --name DIRECTORYNAME The name of the top-level directory in the archive ** -R REPOSITORY Specify a Fossil repository */ void zip_cmd(void){ archive_cmd(ARCHIVE_ZIP); } |
︙ | ︙ | |||
842 843 844 845 846 847 848 | ** the artifact ID of the check-in. ** ** The GLOBLIST argument to --exclude and --include can be a comma-separated ** list of glob patterns, where each glob pattern may optionally be enclosed ** in "..." or '...' so that it may contain commas. If a file matches both ** --include and --exclude then it is excluded. ** | < < < < < < < < < < < | | < < > > | | | | | | | | < < < | | < | | | | < | | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | ** the artifact ID of the check-in. ** ** The GLOBLIST argument to --exclude and --include can be a comma-separated ** list of glob patterns, where each glob pattern may optionally be enclosed ** in "..." or '...' so that it may contain commas. If a file matches both ** --include and --exclude then it is excluded. ** ** Options: ** -X|--exclude GLOBLIST Comma-separated list of GLOBs of files to exclude ** --include GLOBLIST Comma-separated list of GLOBs of files to include ** --name DIRECTORYNAME The name of the top-level directory in the archive ** -R REPOSITORY Specify a Fossil repository */ void sqlar_cmd(void){ archive_cmd(ARCHIVE_SQLAR); } /* ** WEBPAGE: sqlar ** WEBPAGE: zip ** ** Generate a ZIP or SQL archive for the check-in specified by the "r" ** query parameter. Return the archive as the HTTP reply content. ** ** If the NAME contains one "/" then the part before the "/" is taken ** as the TAG and the part after the "/" becomes the true name. Hence, ** the following URLs are all equivalent: ** ** /sqlar/508c42a6398f8/download.sqlar ** /sqlar?r=508c42a6398f8&name=download.sqlar ** /sqlar/download.sqlar?r=508c42a6398f8 ** /sqlar?name=508c42a6398f8/download.sqlar ** ** Query parameters: ** ** name=NAME The base name of the output file. The default ** value is a configuration parameter in the project ** settings. A prefix of the name, omitting the ** extension, is used as the top-most directory name. ** ** r=TAG The check-in that is turned into a ZIP archive. ** Defaults to "trunk". This query parameter used to ** be called "uuid" and the older "uuid" name is still ** accepted for backwards compatibility. If this ** query parameter is omitted, the latest "trunk" ** check-in is used. ** ** in=PATTERN Only include files that match the comma-separate ** list of GLOB patterns in PATTERN, as with ex= ** ** ex=PATTERN Omit any file that match PATTERN. PATTERN is a ** comma-separated list of GLOB patterns, where each ** pattern can optionally be quoted using ".." or '..'. |
︙ | ︙ | |||
929 930 931 932 933 934 935 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ eType = ARCHIVE_SQLAR; zType = "SQL"; }else{ eType = ARCHIVE_ZIP; zType = "ZIP"; } | | < < < | | | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ eType = ARCHIVE_SQLAR; zType = "SQL"; }else{ eType = ARCHIVE_ZIP; zType = "ZIP"; } load_control(); zName = fossil_strdup(PD("name","")); z = P("r"); if( z==0 ) z = P("uuid"); if( z==0 ) z = tar_uuid_from_name(&zName); if( z==0 ) z = "trunk"; nName = strlen(zName); g.zOpenRevision = zRid = fossil_strdup(z); nRid = strlen(zRid); zInclude = P("in"); if( zInclude ) pInclude = glob_create(zInclude); zExclude = P("ex"); if( zExclude ) pExclude = glob_create(zExclude); if( eType==ARCHIVE_ZIP && nName>4 && fossil_strcmp(&zName[nName-4], ".zip")==0 ){ /* Special case: Remove the ".zip" suffix. */ nName -= 4; zName[nName] = 0; }else if( eType==ARCHIVE_SQLAR && nName>6 && fossil_strcmp(&zName[nName-6], ".sqlar")==0 ){ /* Special case: Remove the ".sqlar" suffix. */ nName -= 6; zName[nName] = 0; }else{ |
︙ | ︙ | |||
986 987 988 989 990 991 992 | blob_appendf(&cacheKey, "/%s/%z", g.zPath, rid_to_uuid(rid)); blob_appendf(&cacheKey, "/%q", zName); if( zInclude ) blob_appendf(&cacheKey, ",in=%Q", zInclude); if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude); zKey = blob_str(&cacheKey); etag_check(ETAG_HASH, zKey); | < | | | | | | | < | < | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | blob_appendf(&cacheKey, "/%s/%z", g.zPath, rid_to_uuid(rid)); blob_appendf(&cacheKey, "/%q", zName); if( zInclude ) blob_appendf(&cacheKey, ",in=%Q", zInclude); if( zExclude ) blob_appendf(&cacheKey, ",ex=%Q", zExclude); zKey = blob_str(&cacheKey); etag_check(ETAG_HASH, zKey); if( P("debug")!=0 ){ style_header("%s Archive Generator Debug Screen", zType); @ zName = "%h(zName)"<br /> @ rid = %d(rid)<br /> if( zInclude ){ @ zInclude = "%h(zInclude)"<br /> } if( zExclude ){ @ zExclude = "%h(zExclude)"<br /> } @ zKey = "%h(zKey)" style_footer(); return; } if( referred_from_login() ){ style_header("%s Archive Download", zType); @ <form action='%R/%s(g.zPath)/%h(zName).%s(g.zPath)'> cgi_query_parameters_to_hidden(); @ <p>%s(zType) Archive named <b>%h(zName).%s(g.zPath)</b> @ holding the content of check-in <b>%h(zRid)</b>: @ <input type="submit" value="Download" /> @ </form> style_footer(); return; } blob_zero(&zip); if( cache_read(&zip, zKey)==0 ){ zip_of_checkin(eType, rid, &zip, zName, pInclude, pExclude); cache_write(&zip, zKey); } glob_free(pInclude); glob_free(pExclude); fossil_free(zName); fossil_free(zRid); blob_reset(&cacheKey); cgi_set_content(&zip); if( eType==ARCHIVE_ZIP ){ cgi_set_content_type("application/zip"); }else{ cgi_set_content_type("application/sqlar"); } } |
Changes to test/amend.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 | } proc manifest_comment {comment} { string map [list { } {\\s} \n {\\n} \r {\\r}] $comment } proc uuid_from_commit {res var} { | | | | | | | | | | | | | | 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 | } proc manifest_comment {comment} { string map [list { } {\\s} \n {\\n} \r {\\r}] $comment } proc uuid_from_commit {res var} { upvar $var UUID regexp {^New_Version: ([0-9a-f]{40})[0-9a-f]*$} $res m UUID } proc uuid_from_branch {res var} { upvar $var UUID regexp {^New branch: ([0-9a-f]{40})[0-9a-f]*$} $res m UUID } proc uuid_from_checkout {var} { global RESULT upvar $var UUID fossil status regexp {checkout:\s+([0-9a-f]{40})} $RESULT m UUID } # Make sure we are not in an open repository and initialize new repository test_setup ######################################## # Setup: Add file and commit # ######################################## if {![uuid_from_checkout UUIDINIT]} { test amend-checkout-failure false test_cleanup_then_return } write_file datafile "data" fossil add datafile fossil commit -m "c1" if {![uuid_from_commit $RESULT UUID]} { test amend-setup-failure false test_cleanup_then_return } ######################################## # Test: -branch # ######################################## set UUIDB UUIDB write_file datafile "data.file" fossil commit -m "c2" if {![uuid_from_commit $RESULT UUIDB]} { test amend-branch.setup false } fossil amend $UUIDB -branch amended-branch test amend-branch-1.1 {[regexp {tags:\s+amended-branch} $RESULT]} fossil branch ls test amend-branch-1.2 {[string first "* amended-branch" $RESULT] != -1} fossil tag list test amend-branch-1.3 {[string first amended-branch $RESULT] != -1} fossil tag list --raw $UUIDB test amend-branch-1.4 {[string first "branch=amended-branch" $RESULT] != -1} test amend-branch-1.5 {[string first "sym-amended-branch" $RESULT] != -1} fossil timeline -n 1 test amend-branch-1.6 {[string match {*Move*to*branch*amended-branch*} $RESULT]} ######################################## # Test: -bgcolor # |
︙ | ︙ | |||
100 101 102 103 104 105 106 | acf #acf 123 #123 #1234 #1234 1234 1234 123456 #123456 } { incr tc | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | acf #acf 123 #123 #1234 #1234 1234 1234 123456 #123456 } { incr tc fossil amend $UUID -bgcolor $color test amend-bgcolor-1.$tc.a {[string match "*uuid:*$UUID*" $RESULT]} fossil tag list --raw $UUID test amend-bgcolor-1.$tc.b {[string first "bgcolor=$result" $RESULT] != -1} fossil timeline -n 1 test amend-bgcolor-1.$tc.c { [string match "*Change*background*color*to*\"$result\"*" $RESULT] } if {[artifact_from_timeline $RESULT artid]} { fossil artifact $artid test amend-bgcolor-1.$tc.d { [string match "*T +bgcolor $UUID* $result*" $RESULT] } } else { if {$VERBOSE} { protOut "No artifact found in timeline output" } test amend-bgcolor-1.$tc.d false } } fossil amend $UUID -bgcolor {} test amend-bgcolor-2.1 {[string match "*uuid:*$UUID*" $RESULT]} fossil tag list --raw $UUID test amend-bgcolor-2.2 { [string first "bgcolor=" $RESULT] == -1 && [string first "bgcolor" $RESULT] != -1 } fossil timeline -n 1 test amend-bgcolor-2.3 {[string match "*Cancel*background*color.*" $RESULT]} if {[artifact_from_timeline $RESULT artid]} { fossil artifact $artid test amend-bgcolor-2.4 {[string match "*T -bgcolor $UUID*" $RESULT]} } else { if {$VERBOSE} { protOut "No artifact found in timeline output" } test amend-bgcolor-2.4 false } ######################################## # Test: -branchcolor # ######################################## set UUID2 UUID2 fossil branch new brclr $UUID if {![uuid_from_branch $RESULT UUID2]} { test amend-branchcolor.setup false } fossil update $UUID2 fossil amend $UUID2 -branchcolor yellow test amend-branchcolor-1.1 {[string match "*uuid:*$UUID2*" $RESULT]} fossil tag ls --raw $UUID2 test amend-branchcolor-1.2 {[string first "bgcolor=yellow" $RESULT] != -1} fossil timeline -n 1 test amend-branchcolor-1.3 { [string match {*Change*branch*background*color*to*"yellow".*} $RESULT] } if {[regexp {(?x)[0-9]{2}(?::[0-9]{2}){2}\s+\[([0-9a-f]+)]} $RESULT m artid]} { fossil artifact $artid test amend-branchcolor-1.4 { [string match "*T \*bgcolor $UUID2* yellow*" $RESULT] } } else { if {$VERBOSE} { protOut "No artifact found in timeline output" } test amend-branchcolor-1.4 false } set UUIDN UUIDN write_file datafile "brclr" fossil commit -m "brclr" if {![uuid_from_commit $RESULT UUIDN]} { test amend-branchcolor-propagating.setup false } write_file datafile "bc1" fossil commit -m "mc1" write_file datafile "bc2" fossil commit -m "mc2" fossil amend $UUIDN -branchcolor deadbe test amend-branchcolor-2.1 {[string match "*uuid:*$UUIDN*" $RESULT]} fossil tag ls --raw current test amend-branchcolor-2.2 {[string first "bgcolor=#deadbe" $RESULT] != -1} fossil timeline -n 1 test amend-branchcolor-2.3 { [string match {*Change*branch*background*color*to*"#deadbe".*} $RESULT] } ######################################## # Test: -author # ######################################## fossil amend $UUID -author author-test test amend-author-1.1 {[string match {*comment:*(user:*author-test)*} $RESULT]} fossil tag ls --raw $UUID test amend-author-1.2 {[string first "user=author-test" $RESULT] != -1} fossil timeline -n 1 test amend-author-1.3 {[string match {*Change*user*to*"author-test".*} $RESULT]} ######################################## # Test: -date # ######################################## set timestamp [clock scan yesterday] set date [clock format $timestamp -format "%Y-%m-%d" -gmt 1] set time [clock format $timestamp -format "%H:%M:%S" -gmt 1] set datetime "$date $time" fossil amend $UUIDINIT -date $datetime test amend-date-1.1 {[string match "*uuid:*$UUIDINIT*$datetime*" $RESULT]} fossil tag ls --raw $UUIDINIT test amend-date-1.2 {[string first "date=$datetime" $RESULT] != -1} fossil timeline -n 1 test amend-date-1.3 {[string match "*Timestamp*$date*$time*" $RESULT]} set badformats { "%+" "%Y-%m-%d %H:%M%:%S %Z" "%d/%m/%Y %H:%M%:%S %Z" "%d/%m/%Y %H:%M%:%S" "%d/%m/%Y" } set sc 0 foreach badformat $badformats { incr sc set datetime [clock format $timestamp -format $badformat -gmt 1] fossil amend $UUIDINIT -date $datetime -expectError test amend-date-2.$sc {[string first "YYYY-MM-DD HH:MM:SS" $RESULT] != -1} } ######################################## # Test: -hide # ######################################## set UUIDH UUIDH fossil revert fossil update trunk fossil branch new tohide current if {![uuid_from_branch $RESULT UUIDH]} { test amend-hide-setup false } fossil amend $UUIDH -hide test amend-hide-1.1 {[string match "*uuid:*$UUIDH*" $RESULT]} fossil tag ls --raw $UUIDH test amend-hide-1.2 {[string first "hidden" $RESULT] != -1} fossil timeline -n 1 test amend-hide-1.3 {[string match {*Add*propagating*"hidden".*} $RESULT]} ######################################## # Test: -close # ######################################## set UUIDC UUIDC fossil branch new cllf $UUID if {![uuid_from_branch $RESULT UUIDC]} { test amend-close.setup false } fossil update $UUIDC fossil amend $UUIDC -close test amend-close-1.1.a {[string match "*uuid:*$UUIDC*" $RESULT]} test amend-close-1.1.b { [string match "*comment:*Create*new*branch*named*\"cllf\"*" $RESULT] } fossil tag ls --raw $UUIDC test amend-close-1.2 {[string first "closed" $RESULT] != -1} fossil timeline -n 1 test amend-close-1.3 {[string match {*Mark*"Closed".*} $RESULT]} write_file datafile "cllf" fossil commit -m "should fail" -expectError test amend-close-2 {[string first "closed leaf" $RESULT] != -1} set UUID3 UUID3 fossil revert fossil update trunk write_file datafile "cb" fossil commit -m "closed-branch" --branch "closebranch" if {![uuid_from_commit $RESULT UUID3]} { test amend-close-3.setup false } write_file datafile "b1" fossil commit -m "m1" write_file datafile "b2" fossil commit -m "m2" fossil amend $UUID3 --close test amend-close-3.1 {[string match "*uuid:*$UUID3*" $RESULT]} fossil tag ls --raw current test amend-close-3.2 {[string first "closed" $RESULT] != -1} fossil timeline -n 1 test amend-close-3.3 { [string match "*Add*propagating*\"closed\".*" $RESULT] } write_file datafile "changed" |
︙ | ︙ | |||
294 295 296 297 298 299 300 | {000000 lower Upper alpha 0alpha} {000000 0alpha Upper alpha lower} } set tc 0 foreach {tagt result} $tagtests { incr tc set tags {} set cancels {} | | > > < < < | | | | | | | | | | | | | | | | | | | | | | > > > | | | | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | {000000 lower Upper alpha 0alpha} {000000 0alpha Upper alpha lower} } set tc 0 foreach {tagt result} $tagtests { incr tc set tags {} set cancels {} set t1exp "" set t2exp "*" set t3exp "*" set t5exp "*" foreach tag $tagt { lappend tags -tag $tag lappend cancels -cancel $tag } foreach res $result { append t1exp ", $res" append t2exp "sym-$res*" append t3exp "Add*tag*\"$res\".*" append t5exp "Cancel*tag*\"$res\".*" } eval fossil amend $UUID $tags test amend-tag-$tc.1 {[string match "*uuid:*$UUID*tags:*$t1exp*" $RESULT]} fossil tag ls --raw $UUID test amend-tag-$tc.2 {[string match $t2exp $RESULT]} fossil timeline -n 1 test amend-tag-$tc.3 {[string match $t3exp $RESULT]} eval fossil amend $UUID $cancels test amend-tag-$tc.4 {![string match "*tags:*$t1exp*" $RESULT]} fossil timeline -n 1 test amend-tag-$tc.5 {[string match $t5exp $RESULT]} } ######################################## # Test: -comment # ######################################## proc prep-test {comment content} { global UUID RESULT fossil revert fossil update trunk write_file datafile $comment fossil commit -m $content if {![uuid_from_commit $RESULT UUID]} { set UUID "" } } proc test-comment {name UUID comment} { global VERBOSE RESULT test amend-comment-$name.1 { [string match "*uuid:*$UUID*comment:*$comment*" $RESULT] } fossil timeline -n 1 if {[artifact_from_timeline $RESULT artid]} { fossil artifact $artid test amend-comment-$name.2 { [string match "*T +comment $UUID* *[manifest_comment $comment]*" $RESULT] } } else { if {$VERBOSE} { protOut "No artifact found in timeline output: $RESULT" } test amend-comment-$name.2 false } fossil timeline -n 1 test amend-comment-$name.3 { [string match "*[short_uuid $UUID]*Edit*check-in*comment.*" $RESULT] } fossil info $UUID test amend-comment-$name.4 { [string match "*uuid:*$UUID*comment:*$comment*" $RESULT] } } prep-test "revision 1" "revision 1" fossil amend $UUID -comment "revised revision 1" test-comment 1 $UUID "revised revision 1" prep-test "revision 2" "revision 2" fossil amend $UUID -m "revised revision 2 with -m" test-comment 2 $UUID "revised revision 2 with -m" prep-test "revision 3" "revision 3" write_file commitmsg "revision 3 revised" fossil amend $UUID -message-file commitmsg test-comment 3 $UUID "revision 3 revised" prep-test "revision 4" "revision 4" write_file commitmsg "revision 4 revised with -M" fossil amend $UUID -M commitmsg test-comment 4 $UUID "revision 4 revised with -M" prep-test "final comment" "final content" if {[catch {exec which ed} result]} { if {$VERBOSE} { protOut "Install ed for interactive comment test: $result" } test-comment 5 $UUID "ed required for interactive edit" } else { fossil settings editor "ed -s" set comment "interactive edited comment" fossil_maybe_answer "a\n$comment\n.\nw\nq\n" amend $UUID --edit-comment test-comment 5 $UUID $comment } ######################################## # Test: NULL UUID # ######################################## fossil amend {} -close -expectError test amend-null-uuid {$CODE && [string first "no such check-in" $RESULT] != -1} ############################################################################### test_cleanup |
Changes to test/cmdline.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Test command line parsing # test_setup "" | | < < < < < < < < | < < < | < < | < < < < < | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ############################################################################ # # Test command line parsing # test_setup "" proc cmd-line {testname args} { set i 1 foreach {cmdline result} $args { fossil test-echo $cmdline test cmd-line-$testname.$i {[lrange [split $::RESULT \n] 3 end]=="\{argv\[2\] = \[$result\]\}"} incr i } } cmd-line 100 abc abc a\"bc a\"bc \"abc\" \"abc\" cmd-line 101 * * *.* *.* ############################################################################### test_cleanup |
Changes to test/commit-warning.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 | write_file line-0064 "$a6\n" set a7 $a6$a6 set a8 $a7$a7 set a9 $a8$a8 set a10 $a9$a9 write_file line-1024 "$a10\n" set a11 $a10$a10 | < < < | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | write_file line-0064 "$a6\n" set a7 $a6$a6 set a8 $a7$a7 set a9 $a8$a8 set a10 $a9$a9 write_file line-1024 "$a10\n" set a11 $a10$a10 set a12 $a11$a11 write_file line-4096 "$a12\n" set a13 $a12$a12 write_file line-8192 "$a13\n" set a14 $a13$a13 set a15 $a14$a14 set a16 $a15$a15 write_file line-64K "$a16\n" # UTF-8 extends 7-bit ASCII using bytes 80 and above to encode # larger character codes. Unicode uses U+0 through U+10FFFF only, # with U+D800 through U+DFFF reserved for surrogate pairs. # UTF-8 is valid if it is the shortest possible coding, encodes a |
︙ | ︙ | |||
119 120 121 122 123 124 125 | 1\tbinary\tbinary data 1\tcr-lf-crlf.txt\tmixed line endings 1\tcr-only.txt\tCR line endings 1\tcrlf.txt\tCR/LF line endings 0\tempty\t 0\tline-0064\t 0\tline-1024\t | < < < | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 1\tbinary\tbinary data 1\tcr-lf-crlf.txt\tmixed line endings 1\tcr-only.txt\tCR line endings 1\tcrlf.txt\tCR/LF line endings 0\tempty\t 0\tline-0064\t 0\tline-1024\t 0\tline-4096\t 1\tline-64K\tlong lines 1\tline-8192\tlong lines 0\tplain.txt\t 1\tutf-16be-bombe-hello\tUnicode 1\tutf-16be-bomle-hello\tUnicode 1\tutf-16be-hello\tbinary data 1\tutf-16be.txt\tUnicode 1\tutf-16le-bombe-hello\tUnicode 1\tutf-16le-bomle-hello\tUnicode |
︙ | ︙ | |||
170 171 172 173 174 175 176 | # of source files that MUST NEVER BE TEXT. # test_block_in_checkout pre-commit-warnings-fossil-1 { fossil test-commit-warning --no-settings } { test pre-commit-warnings-fossil-1 {[normalize_result] eq \ [subst -nocommands -novariables [string trim { | > > > | | | | | | | | | | | | | | | | | > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < | | | | | | | > > > > | | > > > > > | | | | | | > > | > > > > > > | > | | | | | | | | | | | | | | < < < < | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | # of source files that MUST NEVER BE TEXT. # test_block_in_checkout pre-commit-warnings-fossil-1 { fossil test-commit-warning --no-settings } { test pre-commit-warnings-fossil-1 {[normalize_result] eq \ [subst -nocommands -novariables [string trim { 1\tart/branching.odp\tbinary data 1\tart/concept1.dia\tbinary data 1\tart/concept2.dia\tbinary data 1\tcompat/zlib/contrib/blast/test.pk\tbinary data 1\tcompat/zlib/contrib/dotzlib/DotZLib.build\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/DotZLib.chm\tbinary data 1\tcompat/zlib/contrib/dotzlib/DotZLib.sln\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/Deflater.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/Inflater.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/LICENSE_1_0.txt\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/gcc_gvmat64/gvmat64.S\tCR/LF line endings 1\tcompat/zlib/contrib/masmx64/bld_ml64.bat\tCR/LF line endings 1\tcompat/zlib/contrib/masmx64/gvmat64.asm\tCR/LF line endings 1\tcompat/zlib/contrib/masmx64/inffas8664.c\tCR/LF line endings 1\tcompat/zlib/contrib/masmx64/inffasx64.asm\tCR/LF line endings 1\tcompat/zlib/contrib/masmx64/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/masmx86/bld_ml32.bat\tCR/LF line endings 1\tcompat/zlib/contrib/masmx86/inffas32.asm\tCR/LF line endings 1\tcompat/zlib/contrib/masmx86/match686.asm\tCR/LF line endings 1\tcompat/zlib/contrib/masmx86/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/puff/zeros.raw\tbinary data 1\tcompat/zlib/contrib/testzlib/testzlib.c\tCR/LF line endings 1\tcompat/zlib/contrib/testzlib/testzlib.txt\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlib.rc\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.sln\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/miniunz.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/minizip.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/testzlib.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/testzlibdll.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/zlib.rc\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/zlibstat.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.sln\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc11/zlibvc.vcxproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc12/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc14/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/miniunz.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/minizip.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/testzlib.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/testzlibdll.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlib.rc\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibstat.vcproj\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.def\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.sln\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.vcproj\tCR/LF line endings 1\tcompat/zlib/win32/zlib.def\tCR/LF line endings 1\tcompat/zlib/zlib.3.pdf\tbinary data 1\tcompat/zlib/zlib.map\tCR/LF line endings 1\tsetup/fossil.iss\tCR/LF line endings 1\tskins/blitz/arrow_project.png\tbinary data 1\tskins/blitz/dir.png\tbinary data 1\tskins/blitz/file.png\tbinary data 1\tskins/blitz/fossil_100.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan_text.png\tbinary data 1\tskins/blitz/rss_20.png\tbinary data 1\tskins/bootstrap/css.txt\tlong lines 1\ttest/th1-docs-input.txt\tCR/LF line endings 1\ttest/th1-hooks-input.txt\tCR/LF line endings 1\ttest/utf16be.txt\tUnicode 1\ttest/utf16le.txt\tUnicode 1\twin/buildmsvc.bat\tCR/LF line endings 1\twin/fossil.ico\tbinary data 1\twin/fossil.rc\tinvalid UTF-8 1\twww/CollRev1.gif\tbinary data 1\twww/CollRev2.gif\tbinary data 1\twww/CollRev3.gif\tbinary data 1\twww/CollRev4.gif\tbinary data 1\twww/apple-touch-icon.png\tbinary data 1\twww/background.jpg\tbinary data 1\twww/branch01.gif\tbinary data 1\twww/branch02.gif\tbinary data 1\twww/branch03.gif\tbinary data 1\twww/branch04.gif\tbinary data 1\twww/branch05.gif\tbinary data 1\twww/build-icons/linux.gif\tbinary data 1\twww/build-icons/linux64.gif\tbinary data 1\twww/build-icons/mac.gif\tbinary data 1\twww/build-icons/openbsd.gif\tbinary data 1\twww/build-icons/src.gif\tbinary data 1\twww/build-icons/win32.gif\tbinary data 1\twww/concept1.gif\tbinary data 1\twww/concept2.gif\tbinary data 1\twww/copyright-release.pdf\tbinary data 1\twww/delta1.gif\tbinary data 1\twww/delta2.gif\tbinary data 1\twww/delta3.gif\tbinary data 1\twww/delta4.gif\tbinary data 1\twww/delta5.gif\tbinary data 1\twww/delta6.gif\tbinary data 1\twww/encode1.gif\tbinary data 1\twww/encode10.gif\tbinary data 1\twww/encode2.gif\tbinary data 1\twww/encode3.gif\tbinary data 1\twww/encode4.gif\tbinary data 1\twww/encode5.gif\tbinary data 1\twww/encode6.gif\tbinary data 1\twww/encode7.gif\tbinary data 1\twww/encode8.gif\tbinary data 1\twww/encode9.gif\tbinary data 1\twww/fossil.gif\tbinary data 1\twww/fossil2.gif\tbinary data 1\twww/fossil3.gif\tbinary data 1\twww/fossil_logo_small.gif\tbinary data 1\twww/fossil_logo_small2.gif\tbinary data 1\twww/fossil_logo_small3.gif\tbinary data 1\twww/xkcd-git.gif\tbinary data 1}]]} } ############################################################################### test_cleanup |
Deleted test/csp1.html.
|
| < < < < < < < < < < < < < < < < < < |
Changes to test/delta1.test.
︙ | ︙ | |||
23 24 25 26 27 28 29 | # Use test script files as the basis for this test. # # For each test, copy the file intact to "./t1". Make # some random changes in "./t2". Then call test-delta on the # two files to make sure that deltas between these two files # work properly. # | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # Use test script files as the basis for this test. # # For each test, copy the file intact to "./t1". Make # some random changes in "./t2". Then call test-delta on the # two files to make sure that deltas between these two files # work properly. # set filelist [glob $testdir/*] foreach f $filelist { if {[file isdir $f]} continue set base [file root [file tail $f]] set f1 [read_file $f] write_file t1 $f1 for {set i 0} {$i<100} {incr i} { write_file t2 [random_changes $f1 1 1 0 0.1] |
︙ | ︙ |
Changes to test/diff-test-1.wiki.
︙ | ︙ | |||
18 19 20 21 22 23 24 | * <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113" target="testwindow">Column alignment with multibyte characters.</a> The edit of a line with multibyte characters is the first chunk. * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6" target="testwindow">Large diff of sqlite3.c</a>. This diff was very slow prior to the performance enhancement change [9e15437e97]. * <a href="../../../info/bda00cbada#chunk49" target="testwindow"> | | < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | * <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113" target="testwindow">Column alignment with multibyte characters.</a> The edit of a line with multibyte characters is the first chunk. * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6" target="testwindow">Large diff of sqlite3.c</a>. This diff was very slow prior to the performance enhancement change [9e15437e97]. * <a href="../../../info/bda00cbada#chunk49" target="testwindow"> A difficult indentation change.</a> * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13" target="testwindow">Another tricky indentation.</a> Notice especially lines 59398 and 59407 on the left. * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13" target="testwindow">Inverse of the previous.</a> * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk24" target="testwindow">A complex change</a> that is difficult to align, and |
︙ | ︙ |
Changes to test/diff.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | file mkdir .fossil-settings write_file [file join .fossil-settings binary-glob] "*" write_file file0.dat ""; # no content. write_file file1.dat "test file 1 (one line no term)." write_file file2.dat "test file 2 (NUL character).\0" | | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | file mkdir .fossil-settings write_file [file join .fossil-settings binary-glob] "*" write_file file0.dat ""; # no content. write_file file1.dat "test file 1 (one line no term)." write_file file2.dat "test file 2 (NUL character).\0" write_file file3.dat "test file 3 (long line).[string repeat x 16384]" write_file file4.dat "test file 4 (long line).[string repeat y 16384]\ntwo" write_file file5.dat "[string repeat z 16384]\ntest file 5 (long line)." fossil add $rootDir fossil commit -m "c1" ############################################################################### fossil ls |
︙ | ︙ | |||
54 55 56 57 58 59 60 | ================================================================== --- file0.dat +++ file0.dat cannot compute difference between binary files}} ############################################################################### | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ================================================================== --- file0.dat +++ file0.dat cannot compute difference between binary files}} ############################################################################### write_file file1.dat [string repeat z 16384] fossil diff file1.dat test diff-file1-1 {[normalize_result] eq {Index: file1.dat ================================================================== --- file1.dat +++ file1.dat cannot compute difference between binary files}} |
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 | test diff-file5-1 {[normalize_result] eq {Index: file5.dat ================================================================== --- file5.dat +++ file5.dat cannot compute difference between binary files}} ############################################################################### | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 107 108 109 110 111 112 113 114 115 116 | test diff-file5-1 {[normalize_result] eq {Index: file5.dat ================================================================== --- file5.dat +++ file5.dat cannot compute difference between binary files}} ############################################################################### test_cleanup |
Changes to test/fake-editor.tcl.
︙ | ︙ | |||
48 49 50 51 52 53 54 | return "" } ############################################################################### set fileName [lindex $argv 0] | < < < < < | | | 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 | return "" } ############################################################################### set fileName [lindex $argv 0] if {[file exists $fileName]} then { set data [readFile $fileName] } else { set data "" } ############################################################################### if {[info exists env(FAKE_EDITOR_SCRIPT)]} { # # NOTE: If an error is caught while evaluating this script, catch # it and return, which will also skip writing the (possibly # modified) content back to the original file. # set script $env(FAKE_EDITOR_SCRIPT) set code [catch $script error] if {$code != 0} then { if {[info exists env(FAKE_EDITOR_VERBOSE)]} { if {[info exists errorInfo]} { puts stdout "ERROR ($code): $errorInfo" } else { puts stdout "ERROR ($code): $error" } } |
︙ | ︙ |
Changes to test/fileStat.th1.
︙ | ︙ | |||
58 59 60 61 62 63 64 | proc getLatestTrunkCheckIn {} { tclEval { # # NOTE: Get the unique Id of the latest check-in on trunk. # return [lindex [regexp -line -inline -nocase -- \ | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | proc getLatestTrunkCheckIn {} { tclEval { # # NOTE: Get the unique Id of the latest check-in on trunk. # return [lindex [regexp -line -inline -nocase -- \ {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ $repository "" info trunk]]] end] } } proc theSumOfAllFiles { id } { # # NOTE: Copy check-in Id value to the Tcl interpreter. |
︙ | ︙ |
Changes to test/graph-test-1.wiki.
︙ | ︙ | |||
76 77 78 79 80 81 82 | * <a href="../../../timeline?a=2bc3cfeb&n=5" target="testwindow">Branch risers comes from the bottom of the screen, not from the andygoth-crlf branch.</a> * <a href="../../../timeline?a=b8c7af5b&n=12" target="testwindow">Check-in 2de15c8e has merge arrows from two different trunk check-ins. One of the merge risers also branches to check-in ea7f3297</a> | < < < < < < < < < < < < < < < < < < < < < < < | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | * <a href="../../../timeline?a=2bc3cfeb&n=5" target="testwindow">Branch risers comes from the bottom of the screen, not from the andygoth-crlf branch.</a> * <a href="../../../timeline?a=b8c7af5b&n=12" target="testwindow">Check-in 2de15c8e has merge arrows from two different trunk check-ins. One of the merge risers also branches to check-in ea7f3297</a> External: * <a href="http://www.sqlite.org/src/timeline?c=2010-09-29&nd" target="testwindow">Timewarp due to a mis-configured system clock.</a> * <a href="http://core.tcl.tk/tk/finfo?name=tests/id.test" target="testwindow">Show all three separate deletions of "id.test". (Scroll down for the third deletion.) * <a href='http://core.tcl.tk/tk/timeline?y=ci&b=2015-03-07' target='testwindow'>Merge arrows to the left and to the right</a> * <a href='http://core.tcl.tk/tk/timeline?y=ci&b=2015-03-07&railpitch=13' target='testwindow'>Previous, with a scrunched graph</a> * <a href='http://core.tcl.tk/tk/timeline?y=ci&b=2015-03-07&railpitch=11' target='testwindow'>Previous, with a severely scrunched graph</a> |
Deleted test/graph-test-2.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/json.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 | # Make sure we have a build with the json command at all and that it # is not stubbed out. This assumes the current (as of 2016-01-27) # practice of eliminating all trace of the fossil json command when # not configured. If that changes, these conditions might not prevent # the rest of this file from running. fossil test-th-eval "hasfeature json" | | | < < < < < < | | 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 | # Make sure we have a build with the json command at all and that it # is not stubbed out. This assumes the current (as of 2016-01-27) # practice of eliminating all trace of the fossil json command when # not configured. If that changes, these conditions might not prevent # the rest of this file from running. fossil test-th-eval "hasfeature json" if {[normalize_result] ne "1"} then { puts "Fossil was not compiled with JSON support." test_cleanup_then_return } # We need a JSON parser to effectively test the JSON produced by # fossil. It looks like the one from tcllib is exactly what we need. # On ActiveTcl, add it with teacup. On other platforms, YMMV. # teacup install json # teacup install json::write package require json proc json2dict {txt} { set rc [catch {::json::json2dict $txt} result options] if {$rc != 0} { protOut "JSON ERROR: $result" return {} } return $result } # and that the json itself smells ok and has the expected API error code in it fossil json -expectError set JR [json2dict $RESULT] if {$JR eq ""} { puts "Fossil was not compiled with JSON support (bad JSON)." test_cleanup_then_return } test json-1 {[dict exists $JR resultCode] && [dict get $JR resultCode] eq "FOSSIL-4102"} # Use the CLI interface to execute a JSON command. Sets the global # RESULT to the response text, and JR to a Tcl dict conversion of the # response body. # # Returns "200" or "500". proc fossil_json {args} { |
︙ | ︙ | |||
78 79 80 81 82 83 84 | # RESULT to the HTTP response body, and JR to a Tcl dict conversion of # the response body. # # Returns the status code from the HTTP header. proc fossil_http_json {url {cookie "Muppet=Monster"} args} { global RESULT JR set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" | | < | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | # RESULT to the HTTP response body, and JR to a Tcl dict conversion of # the response body. # # Returns the status code from the HTTP header. proc fossil_http_json {url {cookie "Muppet=Monster"} args} { global RESULT JR set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" set RESULT [fossil_maybe_answer $request http {*}$args] regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg if {$status eq "200"} { set JR [json2dict $body] } return $status } |
︙ | ︙ | |||
120 121 122 123 124 125 126 | \r }] } # handle the actual request flush stdout #exec $fossilexe | | < | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | \r }] } # handle the actual request flush stdout #exec $fossilexe set RESULT [fossil_maybe_answer $request http {*}$args] # separate HTTP headers from body regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg if {$status eq "200"} { if {[string length $body] > 0} { set JR [json2dict $body] } else { set JR "" |
︙ | ︙ | |||
175 176 177 178 179 180 181 | proc test_json_payload {testname okfields badfields} { test_dict_keys $testname [dict get $::JR payload] $okfields $badfields } #### VERSION AKA HAI # The JSON API generally assumes we have a respository, so let it have one. | < < < < < < < < < < < | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | proc test_json_payload {testname okfields badfields} { test_dict_keys $testname [dict get $::JR payload] $okfields $badfields } #### VERSION AKA HAI # The JSON API generally assumes we have a respository, so let it have one. test_setup # Check for basic envelope fields in the result with an error fossil_json -expectError test_json_envelope json-enverr [concat resultCode fossil timestamp \ resultText command procTimeUs procTimeMs] {} test json-enverr-rc-1 {[dict get $JR resultCode] eq "FOSSIL-3002"} |
︙ | ︙ | |||
282 283 284 285 286 287 288 | test_json_payload json-login-a {authToken name capabilities loginCookieName} {} set AuthAnon [dict get $JR payload] proc test_hascaps {testname need caps} { foreach n [split $need {}] { test $testname-$n {[string first $n $caps] >= 0} } } | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | test_json_payload json-login-a {authToken name capabilities loginCookieName} {} set AuthAnon [dict get $JR payload] proc test_hascaps {testname need caps} { foreach n [split $need {}] { test $testname-$n {[string first $n $caps] >= 0} } } test_hascaps json-login-c "hmnc" [dict get $AuthAnon capabilities] fossil user new U1 User-1 Uone fossil user capabilities U1 s write_file u1 { { "command":"login", "payload":{ |
︙ | ︙ | |||
324 325 326 327 328 329 330 | test json-cap-CLI {[dict get $JR payload permissionFlags setup]} # json cap via POST with authToken in request envelope set anon2 [read_file anon-2] fossil_post_json "/json/cap" $anon2 test json-cap-POSTenv-env-0 {[string length $JR] > 0} test_json_envelope_ok json-cap-POSTenv-env | < | < < < | < < | < < | | | < < | < < | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | test json-cap-CLI {[dict get $JR payload permissionFlags setup]} # json cap via POST with authToken in request envelope set anon2 [read_file anon-2] fossil_post_json "/json/cap" $anon2 test json-cap-POSTenv-env-0 {[string length $JR] > 0} test_json_envelope_ok json-cap-POSTenv-env test json-cap-POSTenv-name {[dict get $JR payload name] eq "anonymous"} knownBug test json-cap-POSTenv-notsetup {![dict get $JR payload permissionFlags setup]} # json cap via GET with authToken in Cookie header fossil_post_json "/json/cap" {} $AnonCookie test json-cap-GETcookie-env-0 {[string length $JR] > 0} test_json_envelope_ok json-cap-GETcookie-env test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} # json cap via GET with authToken in a parameter fossil_post_json "/json/cap?authToken=[dict get $AuthAnon authToken]" {} test json-cap-GETcookie-env-0 {[string length $JR] > 0} test_json_envelope_ok json-cap-GETcookie-env test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} # whoami # via CLI with no auth token supplied fossil_json whoami test_json_envelope_ok json-whoami-cli-env test_json_payload json-whoami-cli {name capabilities} {} |
︙ | ︙ | |||
704 705 706 707 708 709 710 | # which writes something (timeline creates a temp table). The "repo # is not writable" error comes back as HTML. i don't know if the # error happens before we have made the determination that the app is # in JSON mode or if the error handling is incorrectly not # recognizing JSON mode. # #test_setup x.fossil | > | | < < | < < > | | | < | < < < | < < | < | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | # which writes something (timeline creates a temp table). The "repo # is not writable" error comes back as HTML. i don't know if the # error happens before we have made the determination that the app is # in JSON mode or if the error handling is incorrectly not # recognizing JSON mode. # #test_setup x.fossil #catch {exec chmod 444 .rep.fossil}; # Unix. What about Win? fossil_http_json /json/timeline/checkin $U1Cookie test json-ROrepo-1-1 {$CODE == 0} test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]} test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} test_json_envelope_ok json-http-timeline1 protOut "chmod 444 repo" catch {exec chmod 444 .rep.fossil}; # Unix catch {exec attrib +r .rep.fossil}; # Windows fossil_http_json /json/timeline/checkin $U1Cookie -expectError test json-ROrepo-2-1 {$CODE != 0} test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} knownBug test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} knownBug #test_json_envelope_ok json-http-timeline2 catch {exec attrib -r .rep.fossil}; # Windows catch {exec chmod 666 .rep.fossil}; # Unix #### Result Codes # Test cases designed to stimulate each (documented) error code. # FOSSIL-0000 # Not returned by any command. We generally verify that in the # test_json_envelope_ok command by verifying that the resultCode |
︙ | ︙ | |||
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 | # Fossil repository db file could not be found. fossil close fossil_json HAI -expectError test json-RC-4102-CLI-exit {$CODE != 0} test_json_envelope json-RC-4102-CLI-exit {fossil timestamp command procTimeUs \ procTimeMs resultCode resultText} {payload} test json-RC-4102 {[dict get $JR resultCode] eq "FOSSIL-4102"} # FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID # Fossil repository db file is not valid. write_file nope.fossil { This is not a fossil repo. It ought to be a SQLite db with a well-known schema, but it is actually just a block of text. } fossil_json HAI -R nope.fossil -expectError test json-RC-4103-CLI-exit {$CODE != 0} if { $JR ne "" } { test_json_envelope json-RC-4103-CLI {fossil timestamp command procTimeUs \ procTimeMs resultCode resultText} {payload} test json-RC-4103 {[dict get $JR resultCode] eq "FOSSIL-4103"} } else { test json-RC-4103 0 knownBug } ############################################################################### test_cleanup | > < < < < < < | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 | # Fossil repository db file could not be found. fossil close fossil_json HAI -expectError test json-RC-4102-CLI-exit {$CODE != 0} test_json_envelope json-RC-4102-CLI-exit {fossil timestamp command procTimeUs \ procTimeMs resultCode resultText} {payload} test json-RC-4102 {[dict get $JR resultCode] eq "FOSSIL-4102"} fossil open .rep.fossil # FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID # Fossil repository db file is not valid. write_file nope.fossil { This is not a fossil repo. It ought to be a SQLite db with a well-known schema, but it is actually just a block of text. } fossil_json HAI -R nope.fossil -expectError test json-RC-4103-CLI-exit {$CODE != 0} if { $JR ne "" } { test_json_envelope json-RC-4103-CLI {fossil timestamp command procTimeUs \ procTimeMs resultCode resultText} {payload} test json-RC-4103 {[dict get $JR resultCode] eq "FOSSIL-4103"} } else { test json-RC-4103 0 knownBug } ############################################################################### test_cleanup |
Deleted test/markdown-test2.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/markdown-test3.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/merge1.test.
︙ | ︙ | |||
71 72 73 74 75 76 77 | 111 - This is line one OF the demo program - 1111 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t23 { | | | | | | | | | | | | 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 | 111 - This is line one OF the demo program - 1111 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t23 { <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< 111 - This is line ONE of the demo program - 1111 ======= COMMON ANCESTOR content follows ============================ 111 - This is line one of the demo program - 1111 ======= MERGED IN content follows ================================== 111 - This is line one OF the demo program - 1111 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t32 { <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< 111 - This is line one OF the demo program - 1111 ======= COMMON ANCESTOR content follows ============================ 111 - This is line one of the demo program - 1111 ======= MERGED IN content follows ================================== 111 - This is line ONE of the demo program - 1111 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } fossil 3-way-merge t1 t3 t2 a32 test merge1-2.1 {[same_file t32 a32]} fossil 3-way-merge t1 t2 t3 a23 test merge1-2.2 {[same_file t23 a23]} write_file_indented t1 { 111 - This is line one of the demo program - 1111 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 |
︙ | ︙ | |||
156 157 158 159 160 161 162 | write_file_indented t3 { 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t32 { | | | | | | | | | | | | 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 | write_file_indented t3 { 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t32 { <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< ======= COMMON ANCESTOR content follows ============================ 111 - This is line one of the demo program - 1111 ======= MERGED IN content follows ================================== 000 - Zero lines added to the beginning of - 0000 111 - This is line one of the demo program - 1111 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t23 { <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< 000 - Zero lines added to the beginning of - 0000 111 - This is line one of the demo program - 1111 ======= COMMON ANCESTOR content follows ============================ 111 - This is line one of the demo program - 1111 ======= MERGED IN content follows ================================== >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } fossil 3-way-merge t1 t3 t2 a32 test merge1-4.1 {[same_file t32 a32]} fossil 3-way-merge t1 t2 t3 a23 test merge1-4.2 {[same_file t23 a23]} write_file_indented t1 { 111 - This is line one of the demo program - 1111 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 |
︙ | ︙ | |||
295 296 297 298 299 300 301 | KLMN OPQR STUV XYZ. } write_file_indented t23 { abcd | | | | | | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | KLMN OPQR STUV XYZ. } write_file_indented t23 { abcd <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< efgh 2 ijkl 2 mnop 2 qrst uvwx yzAB 2 CDEF 2 GHIJ 2 ======= COMMON ANCESTOR content follows ============================ efgh ijkl mnop qrst uvwx yzAB CDEF GHIJ ======= MERGED IN content follows ================================== efgh ijkl mnop 3 qrst 3 uvwx 3 yzAB 3 CDEF GHIJ >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KLMN OPQR STUV XYZ. } fossil 3-way-merge t1 t2 t3 a23 test merge1-7.1 {[same_file t23 a23]} write_file_indented t2 { abcd efgh 2 ijkl 2 mnop |
︙ | ︙ | |||
363 364 365 366 367 368 369 | KLMN OPQR STUV XYZ. } write_file_indented t23 { abcd | | | | | | | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 | KLMN OPQR STUV XYZ. } write_file_indented t23 { abcd <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< efgh 2 ijkl 2 mnop qrst uvwx yzAB 2 CDEF 2 GHIJ 2 ======= COMMON ANCESTOR content follows ============================ efgh ijkl mnop qrst uvwx yzAB CDEF GHIJ ======= MERGED IN content follows ================================== efgh ijkl mnop 3 qrst 3 uvwx 3 yzAB 3 CDEF GHIJ >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KLMN OPQR STUV XYZ. } fossil 3-way-merge t1 t2 t3 a23 test merge1-7.2 {[same_file t23 a23]} ############################################################################### test_cleanup |
Changes to test/merge2.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Tests of the delta mechanism. # test_setup "" | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ############################################################################ # # Tests of the delta mechanism. # test_setup "" set filelist [glob $testdir/*] foreach f $filelist { if {[file isdir $f]} continue set base [file root [file tail $f]] if {[string match "utf16*" $base]} continue set f1 [read_file $f] write_file t1 $f1 for {set i 0} {$i<100} {incr i} { |
︙ | ︙ |
Changes to test/merge3.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Tests of the 3-way merge # test_setup "" | | | < | | < | < < | < < | < | 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 | ############################################################################ # # Tests of the 3-way merge # test_setup "" proc merge-test {testid basis v1 v2 result} { write_file t1 [join [string trim $basis] \n]\n write_file t2 [join [string trim $v1] \n]\n write_file t3 [join [string trim $v2] \n]\n fossil 3-way-merge t1 t2 t3 t4 set x [read_file t4] regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \ {MINE:} x regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x set x [split [string trim $x] \n] set result [string trim $result] if {$x!=$result} { protOut " Expected \[$result\]" protOut " Got \[$x\]" test merge3-$testid 0 } else { |
︙ | ︙ | |||
72 73 74 75 76 77 78 | 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6 7 8 9 } { 1 2 3 4 5c 6 7 8 9 } { 1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9 | < > < > < > < > < > < > | 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 | 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6 7 8 9 } { 1 2 3 4 5c 6 7 8 9 } { 1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9 } merge-test 4 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8 9 } { 1 2 3 4 5c 6 7 8 9 } { 1 2 MINE: 3b 4b 5b 6b COM: 3 4 5 6 YOURS: 3 4 5c 6 END 7 8 9 } merge-test 5 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8 9 } { 1 2 3 4 5c 6c 7c 8 9 } { 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8 9 } merge-test 6 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8b 9 } { 1 2 3 4 5c 6c 7c 8 9 } { 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8b 9 } merge-test 7 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8b 9 } { 1 2 3 4 5c 6c 7c 8c 9 } { 1 2 MINE: 3b 4b 5b 6b 7 8b COM: 3 4 5 6 7 8 YOURS: 3 4 5c 6c 7c 8c END 9 } merge-test 8 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8b 9b } { 1 2 3 4 5c 6c 7c 8c 9 } { 1 2 MINE: 3b 4b 5b 6b 7 8b 9b COM: 3 4 5 6 7 8 9 YOURS: 3 4 5c 6c 7c 8c 9 END } merge-test 9 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5 6 7 8b 9b } { 1 2 3 4 5c 6c 7c 8 9 } { |
︙ | ︙ | |||
145 146 147 148 149 150 151 | 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5 6 7 8b 9b } { 1 2 3b 4c 5 6c 7c 8 9 } { 1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b | < > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5 6 7 8b 9b } { 1 2 3b 4c 5 6c 7c 8 9 } { 1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b } merge-test 12 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b4b 5 6 7 8b 9b } { 1 2 3b4b 5 6c 7c 8 9 } { |
︙ | ︙ | |||
200 201 202 203 204 205 206 | 1 2 3 4 5 6 7 8 9 } { 1 6 7 8 9 } { 1 2 3 4 9 } { 1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 | < > < > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | 1 2 3 4 5 6 7 8 9 } { 1 6 7 8 9 } { 1 2 3 4 9 } { 1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 } merge-test 25 { 1 2 3 4 5 6 7 8 9 } { 1 7 8 9 } { 1 2 3 9 } { 1 MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 } merge-test 30 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 6 7 9 } { 1 3 4 5 6 7 8 9 |
︙ | ︙ | |||
255 256 257 258 259 260 261 | 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 9 } { 1 6 7 8 9 } { 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9 | < > < > | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 9 } { 1 6 7 8 9 } { 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9 } merge-test 35 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 9 } { 1 7 8 9 } { 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END 9 } merge-test 40 { 2 3 4 5 6 7 8 } { 3 4 5 6 7 8 } { 2 3 4 5 6 7 |
︙ | ︙ | |||
310 311 312 313 314 315 316 | 2 3 4 5 6 7 8 } { 6 7 8 } { 2 3 4 } { MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END | < > < > | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | 2 3 4 5 6 7 8 } { 6 7 8 } { 2 3 4 } { MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END } merge-test 45 { 2 3 4 5 6 7 8 } { 7 8 } { 2 3 } { MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END } merge-test 50 { 2 3 4 5 6 7 8 } { 2 3 4 5 6 7 } { 3 4 5 6 7 8 |
︙ | ︙ | |||
364 365 366 367 368 369 370 | 2 3 4 5 6 7 8 } { 2 3 4 } { 6 7 8 } { MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END | < > < > | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | 2 3 4 5 6 7 8 } { 2 3 4 } { 6 7 8 } { MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END } merge-test 55 { 2 3 4 5 6 7 8 } { 2 3 } { 7 8 } { MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END } merge-test 60 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3 4 5 6 7 8 9 } { 1 2 3 4 5 6 7 9 |
︙ | ︙ | |||
419 420 421 422 423 424 425 | 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4b 5b 6 7 8 9 } { 1 2 3 4 9 } { 1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 | < > < > | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4b 5b 6 7 8 9 } { 1 2 3 4 9 } { 1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 } merge-test 65 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4b 5b 6b 7 8 9 } { 1 2 3 9 } { 1 MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 } merge-test 70 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 6 7 9 } { 1 2b 3 4 5 6 7 8 9 |
︙ | ︙ | |||
474 475 476 477 478 479 480 | 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 9 } { 1 2b 3b 4b 5b 6 7 8 9 } { 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9 | < > < > | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 9 } { 1 2b 3b 4b 5b 6 7 8 9 } { 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9 } merge-test 75 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 9 } { 1 2b 3b 4b 5b 6b 7 8 9 } { 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END 9 } merge-test 80 { 2 3 4 5 6 7 8 } { 2b 3 4 5 6 7 8 } { 2 3 4 5 6 7 |
︙ | ︙ | |||
529 530 531 532 533 534 535 | 2 3 4 5 6 7 8 } { 2b 3b 4b 5b 6 7 8 } { 2 3 4 } { MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END | < > < > | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | 2 3 4 5 6 7 8 } { 2b 3b 4b 5b 6 7 8 } { 2 3 4 } { MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END } merge-test 85 { 2 3 4 5 6 7 8 } { 2b 3b 4b 5b 6b 7 8 } { 2 3 } { MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END } merge-test 90 { 2 3 4 5 6 7 8 } { 2 3 4 5 6 7 } { 2b 3 4 5 6 7 8 |
︙ | ︙ | |||
584 585 586 587 588 589 590 | 2 3 4 5 6 7 8 } { 2 3 4 } { 2b 3b 4b 5b 6 7 8 } { MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END | < > < > | 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | 2 3 4 5 6 7 8 } { 2 3 4 } { 2b 3b 4b 5b 6 7 8 } { MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END } merge-test 95 { 2 3 4 5 6 7 8 } { 2 3 } { 2b 3b 4b 5b 6b 7 8 } { MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END } merge-test 100 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3 4 5 7 8 9 a b c d e } { 1 2b 3 4 5 7 8 9 a b c d e |
︙ | ︙ | |||
630 631 632 633 634 635 636 | 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 7 8 9b } { 1 2 3 4 5 7 8 9b a b c d e } { 1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END | < > < > | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 7 8 9b } { 1 2 3 4 5 7 8 9b a b c d e } { 1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END } merge-test 104 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 7 8 9b a b c d e } { 1 2 3 4 5 7 8 9b } { 1 2 3 4 5 7 8 MINE: 9b a b c d e COM: 9 YOURS: 9b END } ############################################################################### test_cleanup |
Changes to test/merge4.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Tests of the 3-way merge # test_setup "" | | | | | | | | | | | < > | 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 | ############################################################################ # # Tests of the 3-way merge # test_setup "" proc merge-test {testid basis v1 v2 result1 result2} { write_file t1 [join [string trim $basis] \n]\n write_file t2 [join [string trim $v1] \n]\n write_file t3 [join [string trim $v2] \n]\n fossil 3-way-merge t1 t2 t3 t4 fossil 3-way-merge t1 t3 t2 t5 set x [read_file t4] regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x regsub -all {=======.*=======} $x {=} x regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x set x [split [string trim $x] \n] set y [read_file t5] regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $y {>} y regsub -all {=======.*=======} $y {=} y regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y set y [split [string trim $y] \n] set result1 [string trim $result1] if {$x!=$result1} { protOut " Expected \[$result1\]" protOut " Got \[$x\]" test merge3-$testid 0 } else { set result2 [string trim $result2] if {$y!=$result2} { protOut " Expected \[$result2\]" protOut " Got \[$y\]" test merge3-$testid 0 } else { test merge3-$testid 1 } } } merge-test 1000 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4b 5 6b 7b 8b 9 } { 1 2 3 4c 5c 6c 7 8 9 } { 1 > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < 9 } { 1 > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < 9 } merge-test 1001 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4 5 6 7b 8b 9 } { 1 2 3 4c 5c 6c 7 8 9 } { |
︙ | ︙ | |||
81 82 83 84 85 86 87 | 2b 3b 4b 5 6b 7b 8b } { 2 3 4c 5c 6c 7 8 } { > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < } { > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < | < > | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 2b 3b 4b 5 6b 7b 8b } { 2 3 4c 5c 6c 7 8 } { > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < } { > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < } merge-test 1003 { 2 3 4 5 6 7 8 } { 2b 3b 4 5 6 7b 8b } { 2 3 4c 5c 6c 7 8 } { |
︙ | ︙ |
Changes to test/merge5.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # http://www.hwaci.com/drh/ # ############################################################################ # # Tests of the "merge" command # | < | < | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # http://www.hwaci.com/drh/ # ############################################################################ # # Tests of the "merge" command # puts "Skipping Merge5 tests" protOut { fossil sqlite3 --no-repository reacts badly to SQL dumped from repositories created from fossil older than version 2.0. } test merge5-sqlite3-issue false knownBug test_cleanup_then_return # Verify the results of a check-out # proc checkout-test {testid expected_content} { set flist {} foreach {status filename} [exec $::fossilexe ls -l] { |
︙ | ︙ |
Changes to test/merge_renames.test.
︙ | ︙ | |||
260 261 262 263 264 265 266 | fossil update trunk write_file f1 "f1.2" fossil add f1 fossil commit -b b2 -m "add f1" fossil update trunk fossil merge b1 | | < | | < | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | fossil update trunk write_file f1 "f1.2" fossil add f1 fossil commit -b b2 -m "add f1" fossil update trunk fossil merge b1 fossil merge b2 test_status_list merge_renames-8-1 $RESULT { WARNING: no common ancestor for f1 } fossil revert fossil merge --integrate b1 fossil merge b2 test_status_list merge_renames-8-2 $RESULT { WARNING: no common ancestor for f1 } ############################################# # Test 9 # # Merging a delete/rename/add combination # ############################################# |
︙ | ︙ | |||
308 309 310 311 312 313 314 | ADDED f1 } test_status_list merge_renames-9-1 $RESULT $expectedMerge fossil changes test_status_list merge_renames-9-2 $RESULT " MERGED_WITH [commit_id b] ADDED_BY_MERGE f1 | | | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | ADDED f1 } test_status_list merge_renames-9-1 $RESULT $expectedMerge fossil changes test_status_list merge_renames-9-2 $RESULT " MERGED_WITH [commit_id b] ADDED_BY_MERGE f1 RENAMED f2 DELETED f2 (overwritten by rename) " test_file_contents merge_renames-9-3 f1 "f1.1" test_file_contents merge_renames-9-4 f2 "f1" # Undo and ensure a dry run merge results in no changes fossil undo test_status_list merge_renames-9-5 $RESULT { UNDO f1 UNDO f2 } fossil merge -n b test_status_list merge_renames-9-6 $RESULT " $expectedMerge REMINDER: this was a dry run - no files were actually changed. " test merge_renames-9-7 {[fossil changes] eq ""} ################################################################### |
︙ | ︙ | |||
368 369 370 371 372 373 374 | test_status_list merge_renames-10-4 $RESULT { RENAME f1 -> f2 RENAME f2 -> f1 } test_file_contents merge_renames-10-5 f1 "f1" test_file_contents merge_renames-10-6 f2 "f2" test_status_list merge_renames-10-7 [fossil changes] " | | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | test_status_list merge_renames-10-4 $RESULT { RENAME f1 -> f2 RENAME f2 -> f1 } test_file_contents merge_renames-10-5 f1 "f1" test_file_contents merge_renames-10-6 f2 "f2" test_status_list merge_renames-10-7 [fossil changes] " RENAMED f1 RENAMED f2 BACKOUT [commit_id trunk] " fossil commit -m "swap back" ;# V fossil merge b test_status_list merge_renames-10-8 $RESULT { UPDATE f1 |
︙ | ︙ | |||
495 496 497 498 499 500 501 | ADD f2 } fossil merge trunk fossil commit -m "merge trunk" --tag c4 fossil mv --hard f2 f2n test_status_list merge_renames-13-3 $RESULT " RENAME f2 f2n | | | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | ADD f2 } fossil merge trunk fossil commit -m "merge trunk" --tag c4 fossil mv --hard f2 f2n test_status_list merge_renames-13-3 $RESULT " RENAME f2 f2n MOVED_FILE $repoDir/f2 " fossil commit -m "renamed f2->f2n" --tag c5 fossil update trunk fossil merge b test_status_list merge_renames-13-4 $RESULT {ADDED f2n} fossil commit -m "merge f2n" --tag m1 --tag c6 |
︙ | ︙ | |||
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | write_file f1 "line1\nline3\nline4" fossil commit -m "edit f1 on b" --tag c10 fossil update m1 fossil merge b test_status_list merge_renames-13-6 $RESULT { UPDATE f1 } test_file_contents merge_renames-13-7 f2n "line1" fossil revert test_status_list merge_renames-13-8 $RESULT { REVERT f1 } fossil update trunk fossil merge --integrate b test_status_list merge_renames-13-9 $RESULT { UPDATE f1 } test_file_contents merge_renames-13-10 f2n "line1" fossil revert test_status_list merge_renames-13-11 $RESULT { REVERT f1 } ###################################### # # Tests for troubles not specifically linked with renames but that I'd like to # write: # [c26c63eb1b] - 'merge --backout' does not handle conflicts properly # [953031915f] - Lack of warning when overwriting extra files # [4df5f38f1e] - Troubles merging a file delete with a file change ############################################################################### test_cleanup | > > > > > > | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | write_file f1 "line1\nline3\nline4" fossil commit -m "edit f1 on b" --tag c10 fossil update m1 fossil merge b test_status_list merge_renames-13-6 $RESULT { UPDATE f1 DELETE f2n ADDED f2n } test_file_contents merge_renames-13-7 f2n "line1" fossil revert test_status_list merge_renames-13-8 $RESULT { REVERT f1 REVERT f2n } fossil update trunk fossil merge --integrate b test_status_list merge_renames-13-9 $RESULT { UPDATE f1 DELETE f2n ADDED f2n } test_file_contents merge_renames-13-10 f2n "line1" fossil revert test_status_list merge_renames-13-11 $RESULT { REVERT f1 REVERT f2n } ###################################### # # Tests for troubles not specifically linked with renames but that I'd like to # write: # [c26c63eb1b] - 'merge --backout' does not handle conflicts properly # [953031915f] - Lack of warning when overwriting extra files # [4df5f38f1e] - Troubles merging a file delete with a file change ############################################################################### test_cleanup |
Deleted test/merge_renames_2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/merge_warn.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 | write_file f4 "f4" fossil add f4 fossil commit -m "add f4" fossil update trunk write_file f1 "f1.1" write_file f3 "f3.1" | | < | | | | > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | write_file f4 "f4" fossil add f4 fossil commit -m "add f4" fossil update trunk write_file f1 "f1.1" write_file f3 "f3.1" fossil merge --integrate mrg test_status_list merge_warn-1 $RESULT { WARNING: no common ancestor for f2 DELETE f1 WARNING: local edits lost for f1 ADDED f3 (overwrites an unmanaged file) WARNING: 1 merge conflicts WARNING: 1 unmanaged files were overwritten } test merge_warn-2 { [string first "ignoring --integrate: mrg is not a leaf" $RESULT]>=0 } ############################################################################### |
︙ | ︙ |
Changes to test/mv-rm.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 | write_file [file join $rootDir subdirB f9] "f9" file mkdir [file join $rootDir subdirC] write_file [file join $rootDir subdirC f10] "f10" write_file [file join $rootDir subdirC f11] "f11" write_file f12 "f12" | < < < < | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | write_file [file join $rootDir subdirB f9] "f9" file mkdir [file join $rootDir subdirC] write_file [file join $rootDir subdirC f10] "f10" write_file [file join $rootDir subdirC f11] "f11" write_file f12 "f12" fossil add f1 f2 f3 f4 f5 f6 f7 f8 subdirB/f9 subdirC/f10 subdirC/f11 f12 fossil commit -m "c1" ######################################## # Test 1: Soft Move Relative Directory # ######################################## file mkdir [file join $rootDir subdir1] |
︙ | ︙ | |||
415 416 417 418 419 420 421 | ############################################ # Test 18: Move Directory to New Directory # ############################################ fossil mv --hard subdirC subdirD test mv-file-new-directory-7 { | | | < < < < < < < < < < < < < < < < < < < < < < < < < < | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | ############################################ # Test 18: Move Directory to New Directory # ############################################ fossil mv --hard subdirC subdirD test mv-file-new-directory-7 { [normalize_result] eq "RENAME subdirC subdirD\nMOVED_FILE ${rootDir}/subdirC" } test mv-file-new-directory-8 {[file size subdirD/f10] == 3} test mv-file-new-directory-9 {[read_file subdirD/f10] eq "f10"} test mv-file-new-directory-10 {[file size subdirD/f11] == 3} test mv-file-new-directory-11 {[read_file subdirD/f11] eq "f11"} fossil revert test mv-file-new-directory-12 { [normalize_result] eq "REVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" } test mv-file-new-directory-13 {[file size subdirC/f10] == 3} test mv-file-new-directory-14 {[read_file subdirC/f10] eq "f10"} test mv-file-new-directory-15 {[file size subdirC/f11] == 3} test mv-file-new-directory-16 {[read_file subdirC/f11] eq "f11"} cd $rootDir ############################################################################### test_cleanup |
Changes to test/release-checklist.wiki.
1 2 3 4 5 6 | <title>Release Checklist</title> This file describes the testing procedures for Fossil prior to an official release. <ol> | < < < < < < < < < < < < < < < > | | | 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 | <title>Release Checklist</title> This file describes the testing procedures for Fossil prior to an official release. <ol> <li><p> From a private directory (not the source tree) run "<b>tclsh $SRC/test/tester.tcl $FOSSIL</b>" where $FOSSIL is the name of the executable under test and $SRC is the source tree. Verify that there are no errors. <li><p> Click on each of the links in in the [./graph-test-1.wiki] document and verify that all graphs are rendered correctly. <li><p> Click on each of the links in in the [./diff-test-1.wiki] document and verify that all diffs are rendered correctly. <li><p> Click on the following link to verify that it works: [./test-page%2b%2b.wiki | ./test-page++.wiki] (NB: Many web servers automatically block or rewrite URLs that contain "+" characters, even when those "+" characters are encoded as "%2B". On such web servers, the URL above will not work. This test is only guaranteed to work when running "fossil ui".) <li><p> Shift-click on each of the links in [./fileage-test-1.wiki] and verify correct operation of the file-age computation. <li><p> Verify correct name-change tracking behavior (no net changes) for: <blockquote><b> fossil test-name-changes --debug b120bc8b262ac 374920b20944b </b></blockquote> <li><p> Compile for all of the following platforms: <ol type="a"> <li> Linux x86 <li> Linux x86_64 <li> Mac x86 |
︙ | ︙ | |||
72 73 74 75 76 77 78 | <li> <b>fossil sync</b> <li> <b>fossil test-integrity</b> </ol> <li><p> Run the following commands on Linux and verify no major memory leaks and no run-time errors or warnings (except for the well-known jump on an | | < < < < | | < < < < < < < | 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 | <li> <b>fossil sync</b> <li> <b>fossil test-integrity</b> </ol> <li><p> Run the following commands on Linux and verify no major memory leaks and no run-time errors or warnings (except for the well-known jump on an uninitialized value that occurs within zlib). <ol type="a"> <li> <b>valgrind fossil rebuild</b> <li> <b>valgrind fossil sync</b> </ol> <li><p> Inspect [http://www.fossil-scm.org/index.html/vdiff?from=release&to=trunk&sbs=1|all code changes since the previous release], paying particular attention to the following details: <ol type="a"> <li> Can a malicious HTTP request cause a buffer overrun. <li> Can a malicious HTTP request expose privileged information to unauthorized users. </ol> <li><p> Use the release candidate version of fossil in production on the [http://www.fossil-scm.org/] website for at least 48 hours (without incident) prior to making the release official. <li><p> Verify that the [../www/changes.wiki | Change Log] is correct and up-to-date. </ol> <hr> Upon successful completion of all tests above, tag the release candidate with the "release" tag and set its background color to "#d0c0ff". Update the www/changes.wiki file to show the date of the release. |
Deleted test/reserved-names.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/revert.test.
︙ | ︙ | |||
96 97 98 99 100 101 102 | # Test with a single filename argument # revert-test 1-2 f0 { UNMANAGE f0 } -changes { DELETED f1 EDITED f2 | | | | | 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 | # Test with a single filename argument # revert-test 1-2 f0 { UNMANAGE f0 } -changes { DELETED f1 EDITED f2 RENAMED f3n } -addremove { ADDED f0 } -exists {f0 f2 f3n} -notexists f3 revert-test 1-3 f1 { REVERT f1 } -changes { ADDED f0 EDITED f2 RENAMED f3n } -exists {f0 f1 f2 f3n} -notexists f3 revert-test 1-4 f2 { REVERT f2 } -changes { ADDED f0 DELETED f1 RENAMED f3n } -exists {f0 f2 f3n} -notexists {f1 f3} # Both files involved in a rename are reverted regardless of which filename # is used as an argument to 'fossil revert' # revert-test 1-5 f3 { REVERT f3 |
︙ | ︙ | |||
184 185 186 187 188 189 190 191 | fossil mv --soft f1 f1new test 3-mv-1 {[file exists f1]} test 3-mv-2 {![file exists f1new]} revert-test 3-1 {} { REVERT f1 DELETE f1new } -exists {f1} -notexists {f1n} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 184 185 186 187 188 189 190 191 192 193 194 | fossil mv --soft f1 f1new test 3-mv-1 {[file exists f1]} test 3-mv-2 {![file exists f1new]} revert-test 3-1 {} { REVERT f1 DELETE f1new } -exists {f1} -notexists {f1n} ############################################################################### test_cleanup |
Deleted test/rewrite-test-output.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/set-manifest.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # drh@hwaci.com # http://www.hwaci.com/drh/ # ############################################################################ # # Test manifest setting # proc file_contains {fname match} { set fp [open $fname r] set contents [read $fp] close $fp set lines [split $contents "\n"] foreach line $lines { if {[regexp $match $line]} { return 1 } } return 0 } | > > > > > > < < < < < < < < < | | | 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 | # drh@hwaci.com # http://www.hwaci.com/drh/ # ############################################################################ # # Test manifest setting # # We need SHA1 to effectively test the manifest files produced by # fossil. It looks like the one from tcllib is exactly what we need. # On ActiveTcl, add it with teacup. On other platforms, YMMV. # teacup install sha1 package require sha1 proc file_contains {fname match} { set fp [open $fname r] set contents [read $fp] close $fp set lines [split $contents "\n"] foreach line $lines { if {[regexp $match $line]} { return 1 } } return 0 } # We need a respository, so let it have one. test_setup #### Verify classic behavior of the manifest setting # Setting is off by default, and there are no extra files. fossil settings manifest test "set-manifest-1" {[regexp {^manifest *$} $RESULT]} set filelist [glob -nocomplain manifest*] test "set-manifest-1-n" {[llength $filelist] == 0} # Classic behavior: TRUE value creates manifest and manifest.uuid set truths [list true on 1] foreach v $truths { fossil settings manifest $v test "set-manifest-2-$v" {$RESULT eq ""} fossil settings manifest test "set-manifest-2-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]} set filelist [glob manifest*] test "set-manifest-2-$v-n" {[llength $filelist] == 2} foreach f $filelist { test "set-manifest-2-$v-f-$f" {[file isfile $f]} } } # ... and manifest.uuid is the checkout's hash |
︙ | ︙ | |||
86 87 88 89 90 91 92 | # Classic behavior: FALSE value removes manifest and manifest.uuid set falses [list false off 0] foreach v $falses { fossil settings manifest $v test "set-manifest-3-$v" {$RESULT eq ""} fossil settings manifest test "set-manifest-3-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]} | | | | | 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 | # Classic behavior: FALSE value removes manifest and manifest.uuid set falses [list false off 0] foreach v $falses { fossil settings manifest $v test "set-manifest-3-$v" {$RESULT eq ""} fossil settings manifest test "set-manifest-3-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]} set filelist [glob -nocomplain manifest*] test "set-manifest-3-$v-n" {[llength $filelist] == 0} } # Classic behavior: unset removes manifest and manifest.uuid fossil unset manifest test "set-manifest-4" {$RESULT eq ""} fossil settings manifest test "set-manifest-4-a" {[regexp {^manifest *$} $RESULT]} set filelist [glob -nocomplain manifest*] test "set-manifest-4-n" {[llength $filelist] == 0} ##### Tags Manifest feature extends the manifest setting # Manifest Tags: use letters r, u, and t to select each of manifest, # manifest.uuid, and manifest.tags files. set truths [list r u t ru ut rt rut] foreach v $truths { fossil settings manifest $v test "set-manifest-5-$v" {$RESULT eq ""} fossil settings manifest test "set-manifest-5-$v-a" {[regexp "^manifest\\s+\\(local\\)\\s+$v\\s*$" $RESULT]} set filelist [glob manifest*] test "set-manifest-5-$v-n" {[llength $filelist] == [string length $v]} foreach f $filelist { test "set-manifest-5-$v-f-$f" {[file isfile $f]} } } # Quick check for tags applied in trunk |
︙ | ︙ |
Changes to test/settings-repo.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 | set all_settings [get_all_settings] foreach name $all_settings { # # HACK: Make 100% sure that there are no non-default setting values # present anywhere. # | < < < | < | | | | | | | | | 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 | set all_settings [get_all_settings] foreach name $all_settings { # # HACK: Make 100% sure that there are no non-default setting values # present anywhere. # fossil unset $name --exact --global fossil unset $name --exact # # NOTE: Query for the hard-coded default value of this setting and # save it. # fossil test-th-eval "setting $name" set defaults($name) [normalize_result] } ############################################################################### fossil settings bad-setting some_value test settings-set-bad-local { [normalize_result] eq "no such setting: bad-setting" } fossil settings bad-setting some_value --global test settings-set-bad-global { [normalize_result] eq "no such setting: bad-setting" } ############################################################################### fossil unset bad-setting test settings-unset-bad-local { [normalize_result] eq "no such setting: bad-setting" } fossil unset bad-setting --global test settings-unset-bad-global { [normalize_result] eq "no such setting: bad-setting" } ############################################################################### fossil settings ssl some_value test settings-set-ambiguous-local { [normalize_result] eq "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" } fossil settings ssl some_value --global test settings-set-ambiguous-global { [normalize_result] eq "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" } ############################################################################### fossil unset ssl test settings-unset-ambiguous-local { [normalize_result] eq "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" } fossil unset ssl --global test settings-unset-ambiguous-global { [normalize_result] eq "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" } ############################################################################### |
︙ | ︙ | |||
244 245 246 247 248 249 250 | [regexp -- [string map [list %name% $name] $pattern(5)] $data] } fossil test-th-eval --open-config "setting $name" set data [normalize_result] test settings-set-check2-versionable-$name { | | | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | [regexp -- [string map [list %name% $name] $pattern(5)] $data] } fossil test-th-eval --open-config "setting $name" set data [normalize_result] test settings-set-check2-versionable-$name { $data eq $value } file delete $fileName fossil settings $name --exact set data [normalize_result] |
︙ | ︙ |
Changes to test/settings.test.
︙ | ︙ | |||
37 38 39 40 41 42 43 | # letter. It also assumes that any output lines that start with a # lowercase letter contain a setting name starting at that same point. # proc extract_setting_names { data } { set names [list] foreach {dummy name} [regexp \ | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | # letter. It also assumes that any output lines that start with a # lowercase letter contain a setting name starting at that same point. # proc extract_setting_names { data } { set names [list] foreach {dummy name} [regexp \ -all -line -inline -- {^([a-z][a-z0-9\-]*) } $data] { lappend names $name } return $names } ############################################################################### |
︙ | ︙ | |||
90 91 92 93 94 95 96 | set data [normalize_result] test settings-query-local-$name { [regexp -- [string map [list %name% $name] $pattern(1)] $data] || [regexp -- [string map [list %name% $name] $pattern(2)] $data] } | < < < | < | | | 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 | set data [normalize_result] test settings-query-local-$name { [regexp -- [string map [list %name% $name] $pattern(1)] $data] || [regexp -- [string map [list %name% $name] $pattern(2)] $data] } fossil settings $name --exact --global set data [normalize_result] if {$name eq "manifest"} { test settings-query-global-$name { $data eq "cannot set 'manifest' globally" } } else { test settings-query-global-$name { [regexp -- [string map [list %name% $name] $pattern(1)] $data] || [regexp -- [string map [list %name% $name] $pattern(2)] $data] } } } ############################################################################### fossil settings bad-setting test settings-query-bad-local { [normalize_result] eq "no such setting: bad-setting" } fossil settings bad-setting --global test settings-query-bad-global { [normalize_result] eq "no such setting: bad-setting" } ############################################################################### test_cleanup |
Changes to test/stash.test.
︙ | ︙ | |||
139 140 141 142 143 144 145 | test stash-1-list-1 {[regexp {^1: \[[0-9a-z]+\] on } [first_data_line]]} test stash-1-list-2 {[regexp {^\s+stash 1\s*$} [second_data_line]]} set diff_stash_1 {DELETE f1 Index: f1 ================================================================== --- f1 | | | | | | | | | | | | | | | 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 | test stash-1-list-1 {[regexp {^1: \[[0-9a-z]+\] on } [first_data_line]]} test stash-1-list-2 {[regexp {^\s+stash 1\s*$} [second_data_line]]} set diff_stash_1 {DELETE f1 Index: f1 ================================================================== --- f1 +++ f1 @@ -1,1 +0,0 @@ -f1 CHANGED f2 --- f2 +++ f2 @@ -1,1 +1,1 @@ -f2 +f2.1 CHANGED f3n --- f3n +++ f3n ADDED f0 Index: f0 ================================================================== --- f0 +++ f0 @@ -0,0 +1,1 @@ +f0} ######## # fossil stash show|cat ?STASHID? ?DIFF-OPTIONS? # fossil stash [g]diff ?STASHID? ?DIFF-OPTIONS? fossil stash show test stash-1-show {[normalize_result] eq $diff_stash_1} fossil stash diff test stash-1-diff {[normalize_result] eq $diff_stash_1} knownBug ######## # fossil stash pop stash-test 2 pop { DELETE f1 UPDATE f2 UPDATE f3n ADDED f0 } -changes { ADDED f0 MISSING f1 EDITED f2 RENAMED f3n } -addremove { DELETED f1 } -exists {f0 f2 f3n} -notexists {f1 f3} # Confirm there is no longer a stash saved fossil stash list test stash-2-list {[first_data_line] eq "empty stash"} # Test stashed mv without touching the file system # Issue reported by email to fossil-users # from Warren Young, dated Tue, 9 Feb 2016 01:22:54 -0700 # with checkin [b8c7af5bd9] plus a local patch on CentOS 5 # 64 bit intel, 8-byte pointer, 4-byte integer # Stashed renamed file said: # fossil: ./src/delta.c:231: checksum: Assertion '...' failed. # Should be triggered by this stash-WY-1 test. fossil checkout --force c1 fossil clean fossil mv --soft f1 f1new stash-test WY-1 {save -m "Reported 2016-02-09"} { REVERT f1 DELETE f1new } -changes { } -addremove { } -exists {f1 f2 f3} -notexists {f1new} -knownbugs {-code -result} # TODO: add tests that verify the saved stash is sensible. Possibly # by applying it and checking results. But until the SQLITE_CONSTRAINT # error is fixed, there is nothing stashed to test. # Test stashing the combination of a renamed file and an added file that |
︙ | ︙ | |||
263 264 265 266 267 268 269 | ADDED f3 } -exists {f1 f2 f3} -notexists {} #fossil status fossil stash show test stash-3-1-show {[normalize_result] eq {ADDED f3 Index: f3 ================================================================== | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | ADDED f3 } -exists {f1 f2 f3} -notexists {} #fossil status fossil stash show test stash-3-1-show {[normalize_result] eq {ADDED f3 Index: f3 ================================================================== --- f3 +++ f3 @@ -0,0 +1,1 @@ +f3}} stash-test 3-1-pop {pop} { ADDED f3 } -changes { ADDED f3 |
︙ | ︙ | |||
290 291 292 293 294 295 296 | fossil commit -m "baseline" fossil mv --hard f2 f2n test_result_state stash-3-2-mv "mv --hard f2 f2n" [concat { RENAME f2 f2n MOVED_FILE} [file normalize f2] { }] -changes { | | < | | | | | | | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | fossil commit -m "baseline" fossil mv --hard f2 f2n test_result_state stash-3-2-mv "mv --hard f2 f2n" [concat { RENAME f2 f2n MOVED_FILE} [file normalize f2] { }] -changes { RENAMED f2n } -addremove { } -exists {f1 f2n} -notexists {f2} stash-test 3-2 {save -m f2n} { REVERT f2 DELETE f2n } -exists {f1 f2} -notexists {f2n} -knownbugs {-result} fossil stash show test stash-3-2-show-1 {![regexp {\sf1} $RESULT]} knownBug test stash-3-2-show-2 {[regexp {\sf2n} $RESULT]} stash-test 3-2-pop {pop} { UPDATE f1 UPDATE f2n } -changes { RENAMED f2n } -addremove { } -exists {f1 f2n} -notexists {f2} ######## # fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? |
︙ | ︙ | |||
367 368 369 370 371 372 373 | file rename -force f3 f3n fossil mv f3 f3n stash-test 4-3 {snapshot -m "snap 3"} { } -changes { ADDED f0 DELETED f1 EDITED f2 | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | file rename -force f3 f3n fossil mv f3 f3n stash-test 4-3 {snapshot -m "snap 3"} { } -changes { ADDED f0 DELETED f1 EDITED f2 RENAMED f3n } -addremove { } -exists {f0 f2 f3n} -notexists {f1 f3} fossil stash diff test stash-4-3-diff-CODE {!$::CODE} knownBug fossil stash show test stash-4-3-show-1 {[regexp {DELETE f1} $RESULT]} test stash-4-3-show-2 {[regexp {CHANGED f2} $RESULT]} |
︙ | ︙ |
Deleted test/subdir with spaces/filename with spaces.txt.
|
| < < |
Changes to test/symlinks.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Symbolic link tests. # set path [file dirname [info script]] | | > > > > > > > < < < | 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 | ############################################################################ # # Symbolic link tests. # set path [file dirname [info script]] if {$tcl_platform(platform) eq "windows"} { puts "Symlinks are not supported on Windows." test_cleanup_then_return } fossil test-th-eval --open-config "setting allow-symlinks" if {![string is true -strict [normalize_result]]} { puts "Symlinks are not enabled." test_cleanup_then_return } require_no_open_checkout ############################################################################### test_setup; set rootDir [file normalize [pwd]] fossil test-th-eval --open-config {repository} set repository [normalize_result] if {[string length $repository] == 0} { puts "Detection of the open repository file failed." test_cleanup_then_return } |
︙ | ︙ | |||
56 57 58 59 60 61 62 | test symlinks-dir-1 {[file exists [file join $rootDir subdirA f1.txt]] eq 1} test symlinks-dir-2 {[file exists [file join $rootDir symdirA f1.txt]] eq 1} test symlinks-dir-3 {[file exists [file join $rootDir subdirA f2.txt]] eq 1} test symlinks-dir-4 {[file exists [file join $rootDir symdirA f2.txt]] eq 1} fossil add [file join $rootDir symdirA f1.txt] | < < < | < < < | | | | | | 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 | test symlinks-dir-1 {[file exists [file join $rootDir subdirA f1.txt]] eq 1} test symlinks-dir-2 {[file exists [file join $rootDir symdirA f1.txt]] eq 1} test symlinks-dir-3 {[file exists [file join $rootDir subdirA f2.txt]] eq 1} test symlinks-dir-4 {[file exists [file join $rootDir symdirA f2.txt]] eq 1} fossil add [file join $rootDir symdirA f1.txt] fossil commit -m "c1" ############################################################################### fossil ls test symlinks-dir-5 {[normalize_result] eq "symdirA/f1.txt"} ############################################################################### fossil extras test symlinks-dir-6 {[normalize_result] eq \ "subdirA/f1.txt\nsubdirA/f2.txt\nsymdirA/f2.txt"} ############################################################################### fossil close file delete [file join $rootDir subdirA f1.txt] test symlinks-dir-7 {[file exists [file join $rootDir subdirA f1.txt]] eq 0} test symlinks-dir-8 {[file exists [file join $rootDir symdirA f1.txt]] eq 0} test symlinks-dir-9 {[file exists [file join $rootDir subdirA f2.txt]] eq 1} test symlinks-dir-10 {[file exists [file join $rootDir symdirA f2.txt]] eq 1} ############################################################################### fossil open $repository set code [catch {file readlink [file join $rootDir symdirA]} result] test symlinks-dir-11 {$code == 0} test symlinks-dir-12 {$result eq [file join $rootDir subdirA]} test symlinks-dir-13 {[file exists [file join $rootDir subdirA f1.txt]] eq 1} test symlinks-dir-14 {[file exists [file join $rootDir symdirA f1.txt]] eq 1} test symlinks-dir-15 {[file exists [file join $rootDir subdirA f2.txt]] eq 1} test symlinks-dir-16 {[file exists [file join $rootDir symdirA f2.txt]] eq 1} ############################################################################### # # TODO: Add tests for symbolic links as files here, including tests with the # "allow-symlinks" setting on and off. # ############################################################################### test_cleanup |
Changes to test/tester.tcl.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # This is the main test script. To run a regression test, do this: # # tclsh ../test/tester.tcl ../bld/fossil # # Where ../test/tester.tcl is the name of this file and ../bld/fossil # is the name of the executable to be tested. # | < < < < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # This is the main test script. To run a regression test, do this: # # tclsh ../test/tester.tcl ../bld/fossil # # Where ../test/tester.tcl is the name of this file and ../bld/fossil # is the name of the executable to be tested. # # We use some things introduced in 8.6 such as lmap. auto.def should # have found us a suitable Tcl installation. package require Tcl 8.6 set testfiledir [file normalize [file dirname [info script]]] set testrundir [pwd] set testdir [file normalize [file dirname $argv0]] set fossilexe [file normalize [lindex $argv 0]] set is_windows [expr {$::tcl_platform(platform) eq "windows"}] if {$::is_windows} { if {[string length [file extension $fossilexe]] == 0} { append fossilexe .exe } set outside_fossil_repo [expr ![file exists "$::testfiledir\\..\\_FOSSIL_"]] } else { |
︙ | ︙ | |||
174 175 176 177 178 179 180 | } set keepNewline 0 set index [lsearch -exact $args -keepNewline] if {$index != -1} { set keepNewline 1 set args [lreplace $args $index $index] } | < < < < < < < < < < | | | | < | | > | > | | < | < | | > | < < < < < < < | | | | < | 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 | } set keepNewline 0 set index [lsearch -exact $args -keepNewline] if {$index != -1} { set keepNewline 1 set args [lreplace $args $index $index] } foreach a $args { lappend cmd $a } protOut $cmd flush stdout if {[string length $answer] > 0} { protOut $answer set prompt_file [file join $::tempPath fossil_prompt_answer] write_file $prompt_file $answer\n if {$keepNewline} { set rc [catch {eval exec -keepnewline $cmd <$prompt_file} result] } else { set rc [catch {eval exec $cmd <$prompt_file} result] } file delete $prompt_file } else { if {$keepNewline} { set rc [catch {eval exec -keepnewline $cmd} result] } else { set rc [catch {eval exec $cmd} result] } } global RESULT CODE set CODE $rc if {($rc && !$expectError) || (!$rc && $expectError)} { protOut "ERROR: $result" 1 } elseif {$::VERBOSE} { protOut "RESULT: $result" } set RESULT $result } # Read a file into memory. # proc read_file {filename} { |
︙ | ︙ | |||
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | # proc get_versionable_settings {} { # # TODO: If the list of supported versionable settings in "db.c" is modified, # this list (and procedure) most likely needs to be modified as well. # set result [list \ binary-glob \ clean-glob \ crlf-glob \ crnl-glob \ dotfiles \ empty-dirs \ encoding-glob \ ignore-glob \ keep-glob \ | > | > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | # proc get_versionable_settings {} { # # TODO: If the list of supported versionable settings in "db.c" is modified, # this list (and procedure) most likely needs to be modified as well. # set result [list \ allow-symlinks \ binary-glob \ clean-glob \ crlf-glob \ crnl-glob \ dotfiles \ empty-dirs \ encoding-glob \ ignore-glob \ keep-glob \ manifest \ th1-setup \ th1-uri-regexp] fossil test-th-eval "hasfeature tcl" if {[normalize_result] eq "1"} { lappend result tcl-setup } return [lsort -dictionary $result] } # Returns the list of all supported settings. # proc get_all_settings {} { # # TODO: If the list of supported settings in "db.c" is modified, this list # (and procedure) most likely needs to be modified as well. # set result [list \ access-log \ admin-log \ allow-symlinks \ auto-captcha \ auto-hyperlink \ auto-shun \ autosync \ autosync-tries \ binary-glob \ case-sensitive \ clean-glob \ clearsign \ crlf-glob \ crnl-glob \ default-perms \ diff-binary \ diff-command \ dont-push \ dotfiles \ editor \ empty-dirs \ encoding-glob \ exec-rel-paths \ gdiff-command \ gmerge-command \ hash-digits \ http-port \ https-login \ ignore-glob \ keep-glob \ localauth \ main-branch \ manifest \ max-loadavg \ max-upload \ mtime-changes \ pgp-command \ proxy \ relative-paths \ repo-cksum \ self-register \ ssh-command \ ssl-ca-location \ ssl-identity \ th1-setup \ th1-uri-regexp \ uv-sync \ web-browser] fossil test-th-eval "hasfeature legacyMvRm" if {[normalize_result] eq "1"} { lappend result mv-rm-files |
︙ | ︙ | |||
406 407 408 409 410 411 412 | # Return true if two files are the same # proc same_file {a b} { set x [read_file $a] regsub -all { +\n} $x \n x set y [read_file $b] regsub -all { +\n} $y \n y | < | < < < < < < < | | < < | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | # Return true if two files are the same # proc same_file {a b} { set x [read_file $a] regsub -all { +\n} $x \n x set y [read_file $b] regsub -all { +\n} $y \n y return [expr {$x==$y}] } # Return true if two strings refer to the # same uuid. That is, the shorter is a prefix # of the longer. # proc same_uuid {a b} { set na [string length $a] set nb [string length $b] if {$na == $nb} { return [expr {$a eq $b}] } if {$na < $nb} then { return [string match "$a*" $b] } return [string match "$b*" $a] } # Return a prefix of a uuid, defaulting to 10 chars. # proc short_uuid {uuid {len 10}} { string range $uuid 0 $len-1 } proc require_no_open_checkout {} { if {[info exists ::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT)] && \ $::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT) eq "YES_DO_IT"} { return } catch {exec $::fossilexe info} res if {![regexp {use --repository} $res]} { set projectName <unknown> set localRoot <unknown> regexp -line -- {^project-name: (.*)$} $res dummy projectName set projectName [string trim $projectName] regexp -line -- {^local-root: (.*)$} $res dummy localRoot set localRoot [string trim $localRoot] error "Detected an open checkout of project \"$projectName\",\ |
︙ | ︙ | |||
486 487 488 489 490 491 492 | } after [expr {$try * 100}] } error "Could not delete \"$path\", error: $error" } proc test_cleanup_then_return {} { | < < | < < < < | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | } after [expr {$try * 100}] } error "Could not delete \"$path\", error: $error" } proc test_cleanup_then_return {} { uplevel 1 [list test_cleanup] return -code return } proc test_cleanup {} { if {$::KEEP} {return}; # All cleanup disabled? if {![info exists ::tempRepoPath]} {return} if {![file exists $::tempRepoPath]} {return} if {![file isdirectory $::tempRepoPath]} {return} set tempPathEnd [expr {[string length $::tempPath] - 1}] if {[string length $::tempPath] == 0 || \ [string range $::tempRepoPath 0 $tempPathEnd] ne $::tempPath} { error "Temporary repository path has wrong parent during cleanup." |
︙ | ︙ | |||
526 527 528 529 530 531 532 | # Finally, attempt to gracefully delete the temporary home directory, # unless forbidden by external forces. if {![info exists ::tempKeepHome]} {delete_temporary_home} } proc delete_temporary_home {} { if {$::KEEP} {return}; # All cleanup disabled? | | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | # Finally, attempt to gracefully delete the temporary home directory, # unless forbidden by external forces. if {![info exists ::tempKeepHome]} {delete_temporary_home} } proc delete_temporary_home {} { if {$::KEEP} {return}; # All cleanup disabled? if {$::is_windows} { robust_delete [file join $::tempHomePath _fossil] } else { robust_delete [file join $::tempHomePath .fossil] } robust_delete $::tempHomePath } |
︙ | ︙ | |||
637 638 639 640 641 642 643 | # # Be sure to adhere to the requirements of run_in_checkout! proc test_block_in_checkout { name rscript {tscript ""} } { if {$::outside_fossil_repo || $::dirty_ckout} { set $::CODE 0 set $::RESULT "" } else { | | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | # # Be sure to adhere to the requirements of run_in_checkout! proc test_block_in_checkout { name rscript {tscript ""} } { if {$::outside_fossil_repo || $::dirty_ckout} { set $::CODE 0 set $::RESULT "" } else { run_in_checkout $rscript if {[string length $tscript] == 0} { return "" } else { set code [catch { uplevel 1 $tscript } result] return -code $code $result |
︙ | ︙ | |||
853 854 855 856 857 858 859 | lappend bad_test $name if {$::HALT} {exit 1} } } } set bad_test {} set ignored_test {} | < | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 | lappend bad_test $name if {$::HALT} {exit 1} } } } set bad_test {} set ignored_test {} # Return a random string N characters long. # set vocabulary 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" append vocabulary " ()*^!.eeeeeeeeaaaaattiioo " set nvocabulary [string length $vocabulary] proc rand_str {N} { |
︙ | ︙ | |||
1016 1017 1018 1019 1020 1021 1022 | proc test_fossil_http { repository dataFileName url } { set suffix [appendArgs [pid] - [getSeqNo] - [clock seconds] .txt] set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] set data [subst [read_file $dataFileName]] write_file $inFileName $data | < < | < | 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | proc test_fossil_http { repository dataFileName url } { set suffix [appendArgs [pid] - [getSeqNo] - [clock seconds] .txt] set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] set data [subst [read_file $dataFileName]] write_file $inFileName $data fossil http $inFileName $outFileName 127.0.0.1 $repository --localauth set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}] if {1} { catch {file delete $inFileName} catch {file delete $outFileName} } |
︙ | ︙ | |||
1095 1096 1097 1098 1099 1100 1101 | } error] != 0} { error "Could not write file \"$tempFile\" in directory \"$tempPath\",\ please set TEMP variable in environment, error: $error" } set tempHomePath [file join $tempPath home_[pid]] | < < < < < < < < < < < < < < < < < < < < < < < < < < | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | } error] != 0} { error "Could not write file \"$tempFile\" in directory \"$tempPath\",\ please set TEMP variable in environment, error: $error" } set tempHomePath [file join $tempPath home_[pid]] if {[catch { file mkdir $tempHomePath } error] != 0} { error "Could not make directory \"$tempHomePath\",\ please set TEMP variable in environment, error: $error" } protInit $fossilexe set ::tempKeepHome 1 foreach testfile $argv { protOut "***** $testfile ******" if { [catch {source $testdir/$testfile.test} testerror testopts] } { test test-framework-$testfile 0 protOut "!!!!! $testfile: $testerror" protOutDict $testopts" } else { test test-framework-$testfile 1 } protOut "***** End of $testfile: [llength $bad_test] errors so far ******" } unset ::tempKeepHome; delete_temporary_home set nErr [llength $bad_test] if {$nErr>0 || !$::QUIET} { protOut "***** Final results: $nErr errors out of $test_count tests" 1 } if {$nErr>0} { protOut "***** Considered failures: $bad_test" 1 } set nErr [llength $ignored_test] if {$nErr>0 || !$::QUIET} { protOut "***** Ignored results: $nErr ignored errors out of $test_count tests" 1 } if {$nErr>0} { protOut "***** Ignored failures: $ignored_test" 1 } |
Changes to test/th1-docs.test.
︙ | ︙ | |||
27 28 29 30 31 32 33 34 35 36 | fossil test-th-eval "hasfeature tcl" if {[normalize_result] ne "1"} { puts "Fossil was not compiled with Tcl support." test_cleanup_then_return } ############################################################################### | > > > > > > > > | > | > < < < < < < < < < > | | | > | | 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 | fossil test-th-eval "hasfeature tcl" if {[normalize_result] ne "1"} { puts "Fossil was not compiled with Tcl support." test_cleanup_then_return } if {$::outside_fossil_repo} { puts "Skipping th1-docs-* tests: not in Fossil repo checkout." test_cleanup_then_return } elseif ($::dirty_ckout) { puts "Skipping th1-docs-* tests: uncommitted changes in Fossil checkout." test_cleanup_then_return } ############################################################################### test_setup "" ############################################################################### set env(TH1_ENABLE_DOCS) 1; # TH1 docs must be enabled for this test. set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test. ############################################################################### run_in_checkout { set data [fossil info] } regexp -line -- {^repository: (.*)$} $data dummy repository if {[string length $repository] == 0 || ![file exists $repository]} { error "unable to locate repository" } set dataFileName [file join $::testdir th1-docs-input.txt] ############################################################################### run_in_checkout { set RESULT [test_fossil_http \ $repository $dataFileName /doc/trunk/test/fileStat.th1] } test th1-docs-1a {[regexp {<title>Fossil: test/fileStat.th1</title>} $RESULT]} test th1-docs-1b {[regexp {>\[[0-9a-f]{40,64}\]<} $RESULT]} test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]} ############################################################################### test_cleanup |
Changes to test/th1-hooks.test.
︙ | ︙ | |||
124 125 126 127 128 129 130 | error "unable to locate repository" } set dataFileName [file join $::testdir th1-hooks-input.txt] ############################################################################### | < | | | 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 | error "unable to locate repository" } set dataFileName [file join $::testdir th1-hooks-input.txt] ############################################################################### saveTh1SetupFile; writeTh1SetupFile $testTh1Setup ############################################################################### fossil timeline custom -expectError; # NOTE: Bad "WHEN" argument. test th1-cmd-hooks-1a {[normalize_result] eq \ {<h1><b>command_hook timeline CUSTOM TIMELINE</b></h1> unknown check-in or invalid date: custom}} ############################################################################### fossil timeline custom2; # NOTE: Bad "WHEN" argument. test th1-cmd-hooks-1b {[normalize_result] eq \ {<h1><b>command_hook timeline</b></h1> +++ some stuff here +++ <h1><b>command_hook timeline command_notify timeline</b></h1>}} ############################################################################### fossil timeline custom3; # NOTE: Bad "WHEN" argument. test th1-cmd-hooks-1c {[normalize_result] eq \ {<h1><b>command_hook timeline</b></h1> unknown check-in or invalid date: custom3}} ############################################################################### |
︙ | ︙ | |||
194 195 196 197 198 199 200 | fossil test3 test th1-custom-cmd-3a {[string trim $RESULT] eq \ {<h1><b>command_hook test3</b></h1>}} ############################################################################### | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | fossil test3 test th1-custom-cmd-3a {[string trim $RESULT] eq \ {<h1><b>command_hook test3</b></h1>}} ############################################################################### fossil test4 test th1-custom-cmd-4a {[first_data_line] eq \ {<h1><b>command_hook test4</b></h1>}} test th1-custom-cmd-4b {[regexp -- \ {: unknown command: test4$} [second_data_line]]} |
︙ | ︙ | |||
226 227 228 229 230 231 232 | test th1-custom-web-1a {[next_to_last_data_line] eq $repository} test th1-custom-web-1b {[last_data_line] eq \ {<h1><b>command_hook http webpage_hook test1 webpage_notify test1</b></h1>}} ############################################################################### | | | 225 226 227 228 229 230 231 232 233 234 235 236 | test th1-custom-web-1a {[next_to_last_data_line] eq $repository} test th1-custom-web-1b {[last_data_line] eq \ {<h1><b>command_hook http webpage_hook test1 webpage_notify test1</b></h1>}} ############################################################################### restoreTh1SetupFile ############################################################################### test_cleanup |
Changes to test/th1-tcl.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | } ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl3.txt]] | | | | | | | | | | < < < < < < < | | 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 | } ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl3.txt]] test th1-tcl-3 {$RESULT eq {<hr /><p class="thmainError">ERROR:\ invalid command name "bad_command"</p>}} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl4.txt]] test th1-tcl-4 {$RESULT eq {<hr /><p class="thmainError">ERROR:\ divide by zero</p>}} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl5.txt]] test th1-tcl-5 {$RESULT eq {<hr /><p class="thmainError">ERROR:\ Tcl command not found: bad_command</p>} || $RESULT eq {<hr /><p\ class="thmainError">ERROR: invalid command name "bad_command"</p>}} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl6.txt]] test th1-tcl-6 {$RESULT eq {<hr /><p class="thmainError">ERROR:\ no such command: bad_command</p>}} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl7.txt]] test th1-tcl-7 {$RESULT eq {<hr /><p class="thmainError">ERROR:\ syntax error in expression: "2**0"</p>}} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl8.txt]] test th1-tcl-8 {$RESULT eq {<hr /><p class="thmainError">ERROR:\ cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr /><p\ class="thmainError">ERROR: tailcall can only be called from a proc or\ lambda</p>} || $RESULT eq {<hr /><p class="thmainError">ERROR: This test\ requires Tcl 8.6 or higher.</p>}} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $path th1-tcl9.txt]] test th1-tcl-9 {[string trim $RESULT] eq [list [file tail $fossilexe] 3 \ [list test-th-render --open-config [file nativename [file join $path \ th1-tcl9.txt]]]]} ############################################################################### fossil test-th-eval "tclMakeSafe a" test th1-tcl-10 {[normalize_result] eq \ |
︙ | ︙ |
Changes to test/th1.test.
︙ | ︙ | |||
561 562 563 564 565 566 567 | puts "Skipping th1-anycap-*-1 perm tests: not in Fossil repo checkout." } elseif ($::dirty_ckout) { puts "Skipping th1-anycap-*-1 perm tests: uncommitted changes in Fossil checkout." } else { set skip_anycap 0 } | < < | < < < < > < < | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | puts "Skipping th1-anycap-*-1 perm tests: not in Fossil repo checkout." } elseif ($::dirty_ckout) { puts "Skipping th1-anycap-*-1 perm tests: uncommitted changes in Fossil checkout." } else { set skip_anycap 0 } foreach perm [list 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] { if {$perm eq "u"} continue; # NOTE: Skip "reader" meta-permission. if {$perm eq "v"} continue; # NOTE: Skip "developer" meta-permission. fossil test-th-eval "anycap $perm" test th1-anycap-no-$perm-1 {$RESULT eq {0}} fossil test-th-eval "hascap $perm" test th1-hascap-no-$perm-1 {$RESULT eq {0}} fossil test-th-eval "anoncap $perm" test th1-anoncap-no-$perm-1 {$RESULT eq {0}} if {$skip_anycap} { continue } run_in_checkout { fossil test-th-eval --set-user-caps "anycap $perm" test th1-anycap-yes-$perm-1 {$RESULT eq {1}} set ::env(TH1_TEST_USER_CAPS) 1; # NOTE: Bad permission. fossil test-th-eval --set-user-caps "anycap $perm" test th1-anycap-no-$perm-1 {$RESULT eq {0}} unset ::env(TH1_TEST_USER_CAPS) fossil test-th-eval --set-user-caps "hascap $perm" test th1-hascap-yes-$perm-1 {$RESULT eq {1}} set ::env(TH1_TEST_USER_CAPS) 1; # NOTE: Bad permission. fossil test-th-eval --set-user-caps "hascap $perm" test th1-hascap-no-$perm-1 {$RESULT eq {0}} unset ::env(TH1_TEST_USER_CAPS) fossil test-th-eval --set-anon-caps "anoncap $perm" test th1-anoncap-yes-$perm-1 {$RESULT eq {1}} set ::env(TH1_TEST_ANON_CAPS) 1; # NOTE: Bad permission. fossil test-th-eval --set-anon-caps "anoncap $perm" test th1-anoncap-no-$perm-1 {$RESULT eq {0}} unset ::env(TH1_TEST_ANON_CAPS) |
︙ | ︙ | |||
728 729 730 731 732 733 734 | ############################################################################### fossil test-th-eval "trace {}" test th1-trace-1 {$RESULT eq {}} ############################################################################### | | < < < < < | | | | | | < < < < < | | | | | < < < < < < < < < < < < < < | 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 | ############################################################################### fossil test-th-eval "trace {}" test th1-trace-1 {$RESULT eq {}} ############################################################################### fossil test-th-eval --th-trace "trace {}" if {$th1Hooks} { test th1-trace-2 {[normalize_result] eq \ {------------------ BEGIN TRACE LOG ------------------ th1-init 0x0 => 0x0<br /> ------------------- END TRACE LOG -------------------}} } else { test th1-trace-2 {[normalize_result] eq \ {------------------ BEGIN TRACE LOG ------------------ th1-init 0x0 => 0x0<br /> th1-setup {} => TH_OK<br /> ------------------- END TRACE LOG -------------------}} } ############################################################################### fossil test-th-eval "trace {this is a trace message.}" test th1-trace-3 {$RESULT eq {}} ############################################################################### fossil test-th-eval --th-trace "trace {this is a trace message.}" if {$th1Hooks} { test th1-trace-4 {[normalize_result] eq \ {------------------ BEGIN TRACE LOG ------------------ th1-init 0x0 => 0x0<br /> this is a trace message. ------------------- END TRACE LOG -------------------}} } else { test th1-trace-4 {[normalize_result] eq \ {------------------ BEGIN TRACE LOG ------------------ th1-init 0x0 => 0x0<br /> th1-setup {} => TH_OK<br /> this is a trace message. ------------------- END TRACE LOG -------------------}} } ############################################################################### fossil test-th-eval "styleHeader {Page Title Here}" test th1-header-1 {$RESULT eq {TH_ERROR: repository unavailable}} ############################################################################### |
︙ | ︙ | |||
815 816 817 818 819 820 821 | fossil test-th-eval --open-config "styleFooter" test th1-footer-2 {$RESULT eq {}} ############################################################################### fossil test-th-eval --open-config --cgi "styleHeader {}; styleFooter" | | | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | fossil test-th-eval --open-config "styleFooter" test th1-footer-2 {$RESULT eq {}} ############################################################################### fossil test-th-eval --open-config --cgi "styleHeader {}; styleFooter" test th1-footer-3 {[regexp -- {</body></html>} $RESULT]} ############################################################################### fossil test-th-eval "getParameter" test th1-get-parameter-1 {$RESULT eq \ {TH_ERROR: wrong # args: should be "getParameter NAME ?DEFAULT?"}} |
︙ | ︙ | |||
1021 1022 1023 1024 1025 1026 1027 | ############################################################################### fossil test-th-eval "globalState vfs" test th1-globalState-14 {[string length $RESULT] == 0} ############################################################################### | | | 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 | ############################################################################### fossil test-th-eval "globalState vfs" test th1-globalState-14 {[string length $RESULT] == 0} ############################################################################### if {$tcl_platform(platform) eq "windows"} { set altVfs win32-longpath } else { set altVfs unix-dotfile } ############################################################################### |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 | # NOTE: This test will fail if the command names are added to TH1, or # moved from Tcl builds to plain or the reverse. Sorting the # command lists eliminates a dependence on order. # fossil test-th-eval "info commands" set sorted_result [lsort $RESULT] protOut "Sorted: $sorted_result" | | < | | | < | | | | > | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | # NOTE: This test will fail if the command names are added to TH1, or # moved from Tcl builds to plain or the reverse. Sorting the # command lists eliminates a dependence on order. # fossil test-th-eval "info commands" set sorted_result [lsort $RESULT] protOut "Sorted: $sorted_result" set base_commands {anoncap anycap array artifact break breakpoint catch\ checkout combobox continue date decorate dir enable_output encode64\ error expr for getParameter glob_match globalState hascap hasfeature\ html htmlize http httpize if info insertCsrf lindex linecount list\ llength lsearch markdown proc puts query randhex redirect regexp\ reinitialize rename render repository return searchable set\ setParameter setting stime string styleFooter styleHeader tclReady\ trace unset unversioned uplevel upvar utime verifyCsrf wiki} set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe} if {$th1Tcl} { test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]} } else { test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]} } ############################################################################### fossil test-th-eval "info vars" if {$th1Hooks} { test th1-info-vars-1 {[lsort $RESULT] eq \ |
︙ | ︙ |
Changes to test/unversioned.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # The "unversioned" command. # set path [file dirname [info script]] | | < < < < < < < < < < | | | 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 | ############################################################################ # # The "unversioned" command. # set path [file dirname [info script]] if {[catch {package require sha1}] != 0} then { puts "The \"sha1\" package is not available." test_cleanup_then_return } require_no_open_checkout test_setup; set rootDir [file normalize [pwd]] fossil test-th-eval --open-config {repository} set repository [normalize_result] if {[string length $repository] == 0} { puts "Detection of the open repository file failed." test_cleanup_then_return } write_file unversioned1.txt "This is unversioned file #1." write_file unversioned2.txt " This is unversioned file #2. " write_file "unversioned space.txt" "\nThis is unversioned file #3.\n" write_file unversioned4.txt "This is unversioned file #4." write_file unversioned5.txt "This is unversioned file #5." set env(VISUAL) [appendArgs \ [info nameofexecutable] " " [file join $path fake-editor.tcl]] ############################################################################### fossil unversioned test unversioned-1 {[normalize_result] eq \ [string map [list %fossil% [file nativename $fossilexe]] {Usage: %fossil%\ unversioned add|cat|edit|export|list|revert|remove|sync|touch}]} ############################################################################### fossil unversioned list test unversioned-2 {[normalize_result] eq {}} |
︙ | ︙ | |||
127 128 129 130 131 132 133 | fossil unversioned ls --all test unversioned-13 {[normalize_result] eq {unversioned1.txt}} ############################################################################### fossil unversioned add "unversioned space.txt" -expectError test unversioned-14 {[normalize_result] eq \ | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | fossil unversioned ls --all test unversioned-13 {[normalize_result] eq {unversioned1.txt}} ############################################################################### fossil unversioned add "unversioned space.txt" -expectError test unversioned-14 {[normalize_result] eq \ {names of unversioned files may not contain whitespace}} ############################################################################### fossil unversioned add "unversioned space.txt" --as unversioned3.txt test unversioned-15 {[normalize_result] eq {}} ############################################################################### |
︙ | ︙ | |||
320 321 322 323 324 325 326 | fossil user new uvtester "Unversioned Test User" $password fossil user capabilities uvtester oy ############################################################################### foreach {pid port outTmpFile} [test_start_server $repository stopArg] {} | < | < < | < | | < | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | fossil user new uvtester "Unversioned Test User" $password fossil user capabilities uvtester oy ############################################################################### foreach {pid port outTmpFile} [test_start_server $repository stopArg] {} puts [appendArgs "Started Fossil server, pid \"" $pid \" ", port \"" $port \".] set remote [appendArgs http://uvtester: $password @localhost: $port /] ############################################################################### set clientDir [file join $tempPath [appendArgs \ uvtest_ [string trim [clock seconds] -] _ [getSeqNo]]] set savedPwd [pwd] file mkdir $clientDir; cd $clientDir puts [appendArgs "Now in client directory \"" [pwd] \".] write_file unversioned-client1.txt "This is unversioned client file #1." ############################################################################### fossil_maybe_answer y clone $remote uvrepo.fossil fossil open uvrepo.fossil ############################################################################### fossil unversioned list test unversioned-45 {[normalize_result] eq {}} ############################################################################### fossil_maybe_answer y unversioned sync $remote test unversioned-46 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 2 \n? done, sent: \d+ received: \d+ ip: 127.0.0.1} [normalize_result]]} ############################################################################### fossil unversioned ls test unversioned-47 {[normalize_result] eq {unversioned2.txt unversioned5.txt}} |
︙ | ︙ | |||
401 402 403 404 405 406 407 | fossil_maybe_answer y unversioned revert $remote test unversioned-52 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 2 | < | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | fossil_maybe_answer y unversioned revert $remote test unversioned-52 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 2 \n? done, sent: \d+ received: \d+ ip: 127.0.0.1} [normalize_result]]} ############################################################################### fossil unversioned list test unversioned-53 {[regexp \ {^[0-9a-f]{12} 2016-10-01 00:00:00 30 30\ unversioned2\.txt |
︙ | ︙ | |||
426 427 428 429 430 431 432 | fossil_maybe_answer y unversioned sync $remote test unversioned-55 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 1 received: 0 Round-trips: 2 Artifacts sent: 1 received: 0 | < | < | < < | < | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | fossil_maybe_answer y unversioned sync $remote test unversioned-55 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 1 received: 0 Round-trips: 2 Artifacts sent: 1 received: 0 \n? done, sent: \d+ received: \d+ ip: 127.0.0.1} [normalize_result]]} ############################################################################### fossil close test unversioned-56 {[normalize_result] eq {}} ############################################################################### cd $savedPwd; unset savedPwd file delete -force $clientDir puts [appendArgs "Now in server directory \"" [pwd] \".] ############################################################################### set stopped [test_stop_server $stopArg $pid $outTmpFile] puts [appendArgs \ [expr {$stopped ? "Stopped" : "Could not stop"}] \ " Fossil server, pid \"" $pid "\", using argument \"" \ $stopArg \".] ############################################################################### fossil unversioned list test unversioned-57 {[regexp \ {^[0-9a-f]{12} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 35 35\ unversioned-client1\.txt |
︙ | ︙ |
Deleted test/update.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/utf.test.
︙ | ︙ | |||
33 34 35 36 37 38 39 | proc utf-check {testname args} { global tempPath set i 1 foreach {fileName result} $args { set fileName [file join $tempPath $fileName] fossil test-looks-like-utf $fileName set result [string map [list %TEMP% $tempPath \r\n \n] $result] | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | proc utf-check {testname args} { global tempPath set i 1 foreach {fileName result} $args { set fileName [file join $tempPath $fileName] fossil test-looks-like-utf $fileName set result [string map [list %TEMP% $tempPath \r\n \n] $result] # if {$::RESULT ne $result} {puts stdout $::RESULT} test utf-check-$testname.$i {$::RESULT eq $result} incr i } } unset -nocomplain enc array set enc [list \ |
︙ | ︙ | |||
139 140 141 142 143 144 145 | 73 [appendArgs \x00 AB\x00\n] \ 74 [appendArgs \x00 ABC\x00\n] \ 75 [appendArgs \x00 ABCD\x00\n] \ 76 [appendArgs \x00 A\x00\r\n] \ 77 [appendArgs \x00 AB\x00\r\n] \ 78 [appendArgs \x00 ABC\x00\r\n] \ 79 [appendArgs \x00 ABCD\x00\r\n] \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | 73 [appendArgs \x00 AB\x00\n] \ 74 [appendArgs \x00 ABC\x00\n] \ 75 [appendArgs \x00 ABCD\x00\n] \ 76 [appendArgs \x00 A\x00\r\n] \ 77 [appendArgs \x00 AB\x00\r\n] \ 78 [appendArgs \x00 ABC\x00\r\n] \ 79 [appendArgs \x00 ABCD\x00\r\n] \ 80 [string repeat A 8193] \ 81 [string repeat A 8193]\r \ 82 [string repeat A 8193]\n \ 83 [string repeat A 8193]\r\n \ 84 [string repeat ABCD 2049] \ 85 [string repeat ABCD 2049]\r \ 86 [string repeat ABCD 2049]\n \ 87 [string repeat ABCD 2049]\r\n \ 88 \x00[string repeat A 8193] \ 89 \x00[string repeat A 8193]\r \ 90 \x00[string repeat A 8193]\n \ 91 \x00[string repeat A 8193]\r\n \ 92 \x00[string repeat ABCD 2049] \ 93 \x00[string repeat ABCD 2049]\r \ 94 \x00[string repeat ABCD 2049]\n \ 95 \x00[string repeat ABCD 2049]\r\n \ 96 [string repeat A 8193]\x00 \ 97 [string repeat A 8193]\x00\r \ 98 [string repeat A 8193]\x00\n \ 99 [string repeat A 8193]\x00\r\n \ 100 [string repeat ABCD 2049]\x00 \ 101 [string repeat ABCD 2049]\x00\r \ 102 [string repeat ABCD 2049]\x00\n \ 103 [string repeat ABCD 2049]\x00\r\n \ 104 \x00[string repeat A 8193]\x00 \ 105 \x00[string repeat A 8193]\x00\r \ 106 \x00[string repeat A 8193]\x00\n \ 107 \x00[string repeat A 8193]\x00\r\n \ 108 \x00[string repeat ABCD 2049]\x00 \ 109 \x00[string repeat ABCD 2049]\x00\r \ 110 \x00[string repeat ABCD 2049]\x00\n \ 111 \x00[string repeat ABCD 2049]\x00\r\n \ 112 \u000A\u000D \ 113 \u0A00\u0D00 \ 114 \u000D\u000A \ 115 \u0D00\u0A00 \ 116 \x00\u000A\u000D \ 117 \x00\u0A00\u0D00 \ 118 \x00\u000D\u000A \ |
︙ | ︙ | |||
2904 2905 2906 2907 2908 2909 2910 | Has flag LOOK_CRLF: yes Has flag LOOK_LONG: no Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 260 utf-check-260-0-80-0.jnk \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 | Has flag LOOK_CRLF: yes Has flag LOOK_LONG: no Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 260 utf-check-260-0-80-0.jnk \ {File "%TEMP%/utf-check-260-0-80-0.jnk" has 8193 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 261 utf-check-261-0-80-1.jnk \ {File "%TEMP%/utf-check-261-0-80-1.jnk" has 8194 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 262 utf-check-262-0-81-0.jnk \ {File "%TEMP%/utf-check-262-0-81-0.jnk" has 8194 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 263 utf-check-263-0-81-1.jnk \ {File "%TEMP%/utf-check-263-0-81-1.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 264 utf-check-264-0-82-0.jnk \ {File "%TEMP%/utf-check-264-0-82-0.jnk" has 8194 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 265 utf-check-265-0-82-1.jnk \ {File "%TEMP%/utf-check-265-0-82-1.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 266 utf-check-266-0-83-0.jnk \ {File "%TEMP%/utf-check-266-0-83-0.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 267 utf-check-267-0-83-1.jnk \ {File "%TEMP%/utf-check-267-0-83-1.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 268 utf-check-268-0-84-0.jnk \ {File "%TEMP%/utf-check-268-0-84-0.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 269 utf-check-269-0-84-1.jnk \ {File "%TEMP%/utf-check-269-0-84-1.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 270 utf-check-270-0-85-0.jnk \ {File "%TEMP%/utf-check-270-0-85-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 271 utf-check-271-0-85-1.jnk \ {File "%TEMP%/utf-check-271-0-85-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 272 utf-check-272-0-86-0.jnk \ {File "%TEMP%/utf-check-272-0-86-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 273 utf-check-273-0-86-1.jnk \ {File "%TEMP%/utf-check-273-0-86-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 274 utf-check-274-0-87-0.jnk \ {File "%TEMP%/utf-check-274-0-87-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 275 utf-check-275-0-87-1.jnk \ {File "%TEMP%/utf-check-275-0-87-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 276 utf-check-276-0-88-0.jnk \ {File "%TEMP%/utf-check-276-0-88-0.jnk" has 8194 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 277 utf-check-277-0-88-1.jnk \ {File "%TEMP%/utf-check-277-0-88-1.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 278 utf-check-278-0-89-0.jnk \ {File "%TEMP%/utf-check-278-0-89-0.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 279 utf-check-279-0-89-1.jnk \ {File "%TEMP%/utf-check-279-0-89-1.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 280 utf-check-280-0-90-0.jnk \ {File "%TEMP%/utf-check-280-0-90-0.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 281 utf-check-281-0-90-1.jnk \ {File "%TEMP%/utf-check-281-0-90-1.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 282 utf-check-282-0-91-0.jnk \ {File "%TEMP%/utf-check-282-0-91-0.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 283 utf-check-283-0-91-1.jnk \ {File "%TEMP%/utf-check-283-0-91-1.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 284 utf-check-284-0-92-0.jnk \ {File "%TEMP%/utf-check-284-0-92-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 285 utf-check-285-0-92-1.jnk \ {File "%TEMP%/utf-check-285-0-92-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 286 utf-check-286-0-93-0.jnk \ {File "%TEMP%/utf-check-286-0-93-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 287 utf-check-287-0-93-1.jnk \ {File "%TEMP%/utf-check-287-0-93-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 288 utf-check-288-0-94-0.jnk \ {File "%TEMP%/utf-check-288-0-94-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 289 utf-check-289-0-94-1.jnk \ {File "%TEMP%/utf-check-289-0-94-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 290 utf-check-290-0-95-0.jnk \ {File "%TEMP%/utf-check-290-0-95-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 291 utf-check-291-0-95-1.jnk \ {File "%TEMP%/utf-check-291-0-95-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 292 utf-check-292-0-96-0.jnk \ {File "%TEMP%/utf-check-292-0-96-0.jnk" has 8194 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 293 utf-check-293-0-96-1.jnk \ {File "%TEMP%/utf-check-293-0-96-1.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 294 utf-check-294-0-97-0.jnk \ {File "%TEMP%/utf-check-294-0-97-0.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 295 utf-check-295-0-97-1.jnk \ {File "%TEMP%/utf-check-295-0-97-1.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 296 utf-check-296-0-98-0.jnk \ {File "%TEMP%/utf-check-296-0-98-0.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 297 utf-check-297-0-98-1.jnk \ {File "%TEMP%/utf-check-297-0-98-1.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 298 utf-check-298-0-99-0.jnk \ {File "%TEMP%/utf-check-298-0-99-0.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 299 utf-check-299-0-99-1.jnk \ {File "%TEMP%/utf-check-299-0-99-1.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 300 utf-check-300-0-100-0.jnk \ {File "%TEMP%/utf-check-300-0-100-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 301 utf-check-301-0-100-1.jnk \ {File "%TEMP%/utf-check-301-0-100-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 302 utf-check-302-0-101-0.jnk \ {File "%TEMP%/utf-check-302-0-101-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 303 utf-check-303-0-101-1.jnk \ {File "%TEMP%/utf-check-303-0-101-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 304 utf-check-304-0-102-0.jnk \ {File "%TEMP%/utf-check-304-0-102-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 305 utf-check-305-0-102-1.jnk \ {File "%TEMP%/utf-check-305-0-102-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 306 utf-check-306-0-103-0.jnk \ {File "%TEMP%/utf-check-306-0-103-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 307 utf-check-307-0-103-1.jnk \ {File "%TEMP%/utf-check-307-0-103-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 308 utf-check-308-0-104-0.jnk \ {File "%TEMP%/utf-check-308-0-104-0.jnk" has 8195 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 309 utf-check-309-0-104-1.jnk \ {File "%TEMP%/utf-check-309-0-104-1.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 310 utf-check-310-0-105-0.jnk \ {File "%TEMP%/utf-check-310-0-105-0.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 311 utf-check-311-0-105-1.jnk \ {File "%TEMP%/utf-check-311-0-105-1.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 312 utf-check-312-0-106-0.jnk \ {File "%TEMP%/utf-check-312-0-106-0.jnk" has 8196 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 313 utf-check-313-0-106-1.jnk \ {File "%TEMP%/utf-check-313-0-106-1.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 314 utf-check-314-0-107-0.jnk \ {File "%TEMP%/utf-check-314-0-107-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 315 utf-check-315-0-107-1.jnk \ {File "%TEMP%/utf-check-315-0-107-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 316 utf-check-316-0-108-0.jnk \ {File "%TEMP%/utf-check-316-0-108-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 317 utf-check-317-0-108-1.jnk \ {File "%TEMP%/utf-check-317-0-108-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 318 utf-check-318-0-109-0.jnk \ {File "%TEMP%/utf-check-318-0-109-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 319 utf-check-319-0-109-1.jnk \ {File "%TEMP%/utf-check-319-0-109-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 320 utf-check-320-0-110-0.jnk \ {File "%TEMP%/utf-check-320-0-110-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 321 utf-check-321-0-110-1.jnk \ {File "%TEMP%/utf-check-321-0-110-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 322 utf-check-322-0-111-0.jnk \ {File "%TEMP%/utf-check-322-0-111-0.jnk" has 8200 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 323 utf-check-323-0-111-1.jnk \ {File "%TEMP%/utf-check-323-0-111-1.jnk" has 8201 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes |
︙ | ︙ | |||
9464 9465 9466 9467 9468 9469 9470 | Has flag LOOK_CRLF: yes Has flag LOOK_LONG: no Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 670 utf-check-670-1-80-0.jnk \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 | Has flag LOOK_CRLF: yes Has flag LOOK_LONG: no Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 670 utf-check-670-1-80-0.jnk \ {File "%TEMP%/utf-check-670-1-80-0.jnk" has 8196 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 671 utf-check-671-1-80-1.jnk \ {File "%TEMP%/utf-check-671-1-80-1.jnk" has 8197 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 672 utf-check-672-1-81-0.jnk \ {File "%TEMP%/utf-check-672-1-81-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 673 utf-check-673-1-81-1.jnk \ {File "%TEMP%/utf-check-673-1-81-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 674 utf-check-674-1-82-0.jnk \ {File "%TEMP%/utf-check-674-1-82-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 675 utf-check-675-1-82-1.jnk \ {File "%TEMP%/utf-check-675-1-82-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 676 utf-check-676-1-83-0.jnk \ {File "%TEMP%/utf-check-676-1-83-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 677 utf-check-677-1-83-1.jnk \ {File "%TEMP%/utf-check-677-1-83-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 678 utf-check-678-1-84-0.jnk \ {File "%TEMP%/utf-check-678-1-84-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 679 utf-check-679-1-84-1.jnk \ {File "%TEMP%/utf-check-679-1-84-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 680 utf-check-680-1-85-0.jnk \ {File "%TEMP%/utf-check-680-1-85-0.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 681 utf-check-681-1-85-1.jnk \ {File "%TEMP%/utf-check-681-1-85-1.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 682 utf-check-682-1-86-0.jnk \ {File "%TEMP%/utf-check-682-1-86-0.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 683 utf-check-683-1-86-1.jnk \ {File "%TEMP%/utf-check-683-1-86-1.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 684 utf-check-684-1-87-0.jnk \ {File "%TEMP%/utf-check-684-1-87-0.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 685 utf-check-685-1-87-1.jnk \ {File "%TEMP%/utf-check-685-1-87-1.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 686 utf-check-686-1-88-0.jnk \ {File "%TEMP%/utf-check-686-1-88-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 687 utf-check-687-1-88-1.jnk \ {File "%TEMP%/utf-check-687-1-88-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 688 utf-check-688-1-89-0.jnk \ {File "%TEMP%/utf-check-688-1-89-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 689 utf-check-689-1-89-1.jnk \ {File "%TEMP%/utf-check-689-1-89-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 690 utf-check-690-1-90-0.jnk \ {File "%TEMP%/utf-check-690-1-90-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 691 utf-check-691-1-90-1.jnk \ {File "%TEMP%/utf-check-691-1-90-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 692 utf-check-692-1-91-0.jnk \ {File "%TEMP%/utf-check-692-1-91-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 693 utf-check-693-1-91-1.jnk \ {File "%TEMP%/utf-check-693-1-91-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 694 utf-check-694-1-92-0.jnk \ {File "%TEMP%/utf-check-694-1-92-0.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 695 utf-check-695-1-92-1.jnk \ {File "%TEMP%/utf-check-695-1-92-1.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 696 utf-check-696-1-93-0.jnk \ {File "%TEMP%/utf-check-696-1-93-0.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 697 utf-check-697-1-93-1.jnk \ {File "%TEMP%/utf-check-697-1-93-1.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 698 utf-check-698-1-94-0.jnk \ {File "%TEMP%/utf-check-698-1-94-0.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 699 utf-check-699-1-94-1.jnk \ {File "%TEMP%/utf-check-699-1-94-1.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 700 utf-check-700-1-95-0.jnk \ {File "%TEMP%/utf-check-700-1-95-0.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 701 utf-check-701-1-95-1.jnk \ {File "%TEMP%/utf-check-701-1-95-1.jnk" has 8203 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 702 utf-check-702-1-96-0.jnk \ {File "%TEMP%/utf-check-702-1-96-0.jnk" has 8197 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 703 utf-check-703-1-96-1.jnk \ {File "%TEMP%/utf-check-703-1-96-1.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 704 utf-check-704-1-97-0.jnk \ {File "%TEMP%/utf-check-704-1-97-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 705 utf-check-705-1-97-1.jnk \ {File "%TEMP%/utf-check-705-1-97-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 706 utf-check-706-1-98-0.jnk \ {File "%TEMP%/utf-check-706-1-98-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 707 utf-check-707-1-98-1.jnk \ {File "%TEMP%/utf-check-707-1-98-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 708 utf-check-708-1-99-0.jnk \ {File "%TEMP%/utf-check-708-1-99-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 709 utf-check-709-1-99-1.jnk \ {File "%TEMP%/utf-check-709-1-99-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 710 utf-check-710-1-100-0.jnk \ {File "%TEMP%/utf-check-710-1-100-0.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 711 utf-check-711-1-100-1.jnk \ {File "%TEMP%/utf-check-711-1-100-1.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 712 utf-check-712-1-101-0.jnk \ {File "%TEMP%/utf-check-712-1-101-0.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 713 utf-check-713-1-101-1.jnk \ {File "%TEMP%/utf-check-713-1-101-1.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 714 utf-check-714-1-102-0.jnk \ {File "%TEMP%/utf-check-714-1-102-0.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 715 utf-check-715-1-102-1.jnk \ {File "%TEMP%/utf-check-715-1-102-1.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 716 utf-check-716-1-103-0.jnk \ {File "%TEMP%/utf-check-716-1-103-0.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 717 utf-check-717-1-103-1.jnk \ {File "%TEMP%/utf-check-717-1-103-1.jnk" has 8203 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 718 utf-check-718-1-104-0.jnk \ {File "%TEMP%/utf-check-718-1-104-0.jnk" has 8198 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 719 utf-check-719-1-104-1.jnk \ {File "%TEMP%/utf-check-719-1-104-1.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 720 utf-check-720-1-105-0.jnk \ {File "%TEMP%/utf-check-720-1-105-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 721 utf-check-721-1-105-1.jnk \ {File "%TEMP%/utf-check-721-1-105-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 722 utf-check-722-1-106-0.jnk \ {File "%TEMP%/utf-check-722-1-106-0.jnk" has 8199 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 723 utf-check-723-1-106-1.jnk \ {File "%TEMP%/utf-check-723-1-106-1.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 724 utf-check-724-1-107-0.jnk \ {File "%TEMP%/utf-check-724-1-107-0.jnk" has 8200 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 725 utf-check-725-1-107-1.jnk \ {File "%TEMP%/utf-check-725-1-107-1.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 726 utf-check-726-1-108-0.jnk \ {File "%TEMP%/utf-check-726-1-108-0.jnk" has 8201 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 727 utf-check-727-1-108-1.jnk \ {File "%TEMP%/utf-check-727-1-108-1.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 728 utf-check-728-1-109-0.jnk \ {File "%TEMP%/utf-check-728-1-109-0.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 729 utf-check-729-1-109-1.jnk \ {File "%TEMP%/utf-check-729-1-109-1.jnk" has 8203 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 730 utf-check-730-1-110-0.jnk \ {File "%TEMP%/utf-check-730-1-110-0.jnk" has 8202 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 731 utf-check-731-1-110-1.jnk \ {File "%TEMP%/utf-check-731-1-110-1.jnk" has 8203 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 732 utf-check-732-1-111-0.jnk \ {File "%TEMP%/utf-check-732-1-111-0.jnk" has 8203 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 733 utf-check-733-1-111-1.jnk \ {File "%TEMP%/utf-check-733-1-111-1.jnk" has 8204 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes |
︙ | ︙ | |||
16024 16025 16026 16027 16028 16029 16030 | Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1080 utf-check-1080-2-80-0.jnk \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 16024 16025 16026 16027 16028 16029 16030 16031 16032 16033 16034 16035 16036 16037 16038 16039 16040 16041 16042 16043 16044 16045 16046 16047 16048 16049 16050 16051 16052 16053 16054 16055 16056 16057 16058 16059 16060 16061 16062 16063 16064 16065 16066 16067 16068 16069 16070 16071 16072 16073 16074 16075 16076 16077 16078 16079 16080 16081 16082 16083 16084 16085 16086 16087 16088 16089 16090 16091 16092 16093 16094 16095 16096 16097 16098 16099 16100 16101 16102 16103 16104 16105 16106 16107 16108 16109 16110 16111 16112 16113 16114 16115 16116 16117 16118 16119 16120 16121 16122 16123 16124 16125 16126 16127 16128 16129 16130 16131 16132 16133 16134 16135 16136 16137 16138 16139 16140 16141 16142 16143 16144 16145 16146 16147 16148 16149 16150 16151 16152 16153 16154 16155 16156 16157 16158 16159 16160 16161 16162 16163 16164 16165 16166 16167 16168 16169 16170 16171 16172 16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191 16192 16193 16194 16195 16196 16197 16198 16199 16200 16201 16202 16203 16204 16205 16206 16207 16208 16209 16210 16211 16212 16213 16214 16215 16216 16217 16218 16219 16220 16221 16222 16223 16224 16225 16226 16227 16228 16229 16230 16231 16232 16233 16234 16235 16236 16237 16238 16239 16240 16241 16242 16243 16244 16245 16246 16247 16248 16249 16250 16251 16252 16253 16254 16255 16256 16257 16258 16259 16260 16261 16262 16263 16264 16265 16266 16267 16268 16269 16270 16271 16272 16273 16274 16275 16276 16277 16278 16279 16280 16281 16282 16283 16284 16285 16286 16287 16288 16289 16290 16291 16292 16293 16294 16295 16296 16297 16298 16299 16300 16301 16302 16303 16304 16305 16306 16307 16308 16309 16310 16311 16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 16324 16325 16326 16327 16328 16329 16330 16331 16332 16333 16334 16335 16336 16337 16338 16339 16340 16341 16342 16343 16344 16345 16346 16347 16348 16349 16350 16351 16352 16353 16354 16355 16356 16357 16358 16359 16360 16361 16362 16363 16364 16365 16366 16367 16368 16369 16370 16371 16372 16373 16374 16375 16376 16377 16378 16379 16380 16381 16382 16383 16384 16385 16386 16387 16388 16389 16390 16391 16392 16393 16394 16395 16396 16397 16398 16399 16400 16401 16402 16403 16404 16405 16406 16407 16408 16409 16410 16411 16412 16413 16414 16415 16416 16417 16418 16419 16420 16421 16422 16423 16424 16425 16426 16427 16428 16429 16430 16431 16432 16433 16434 16435 16436 16437 16438 16439 16440 16441 16442 16443 16444 16445 16446 16447 16448 16449 16450 16451 16452 16453 16454 16455 16456 16457 16458 16459 16460 16461 16462 16463 16464 16465 16466 16467 16468 16469 16470 16471 16472 16473 16474 16475 16476 16477 16478 16479 16480 16481 16482 16483 16484 16485 16486 16487 16488 16489 16490 16491 16492 16493 16494 16495 16496 16497 16498 16499 16500 16501 16502 16503 16504 16505 16506 16507 16508 16509 16510 16511 16512 16513 16514 16515 16516 16517 16518 16519 16520 16521 16522 16523 16524 16525 16526 16527 16528 16529 16530 16531 16532 16533 16534 16535 16536 16537 16538 16539 16540 16541 16542 16543 16544 16545 16546 16547 16548 16549 16550 16551 16552 16553 16554 16555 16556 16557 16558 16559 16560 16561 16562 16563 16564 16565 16566 16567 16568 16569 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 16580 16581 16582 16583 16584 16585 16586 16587 16588 16589 16590 16591 16592 16593 16594 16595 16596 16597 16598 16599 16600 16601 16602 16603 16604 16605 16606 16607 16608 16609 16610 16611 16612 16613 16614 16615 16616 16617 16618 16619 16620 16621 16622 16623 16624 16625 16626 16627 16628 16629 16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643 16644 16645 16646 16647 16648 16649 16650 16651 16652 16653 16654 16655 16656 16657 16658 16659 16660 16661 16662 16663 16664 16665 16666 16667 16668 16669 16670 16671 16672 16673 16674 16675 16676 16677 16678 16679 16680 16681 16682 16683 16684 16685 16686 16687 16688 16689 16690 16691 16692 16693 16694 16695 16696 16697 16698 16699 16700 16701 16702 16703 16704 16705 16706 16707 16708 16709 16710 16711 16712 16713 16714 16715 16716 16717 16718 16719 16720 16721 16722 16723 16724 16725 16726 16727 16728 16729 16730 16731 16732 16733 16734 16735 16736 16737 16738 16739 16740 16741 16742 16743 16744 16745 16746 16747 16748 16749 16750 16751 16752 16753 16754 16755 16756 16757 16758 16759 16760 16761 16762 16763 16764 16765 16766 16767 16768 16769 16770 16771 16772 16773 16774 16775 16776 16777 16778 16779 16780 16781 16782 16783 16784 16785 16786 16787 16788 16789 16790 16791 16792 16793 16794 16795 16796 16797 16798 16799 16800 16801 16802 16803 16804 16805 16806 16807 16808 16809 16810 16811 16812 16813 16814 16815 16816 16817 16818 16819 16820 16821 16822 16823 16824 16825 16826 16827 16828 16829 16830 16831 16832 16833 16834 16835 16836 16837 16838 16839 16840 16841 16842 16843 16844 16845 16846 16847 16848 16849 16850 16851 16852 16853 16854 16855 16856 16857 16858 16859 16860 16861 16862 16863 16864 16865 16866 16867 16868 16869 16870 16871 16872 16873 16874 16875 16876 16877 16878 16879 16880 16881 16882 16883 16884 16885 16886 16887 16888 16889 16890 16891 16892 16893 16894 16895 16896 16897 16898 16899 16900 16901 16902 16903 16904 16905 16906 16907 16908 16909 16910 16911 16912 16913 16914 16915 16916 16917 16918 16919 16920 16921 16922 16923 16924 16925 16926 16927 16928 16929 16930 16931 16932 16933 16934 16935 16936 16937 16938 16939 16940 16941 16942 16943 16944 16945 16946 16947 16948 16949 16950 16951 16952 16953 16954 16955 16956 16957 16958 16959 16960 16961 16962 16963 16964 16965 16966 16967 16968 16969 16970 16971 16972 16973 16974 16975 16976 16977 16978 16979 16980 16981 16982 16983 16984 16985 16986 16987 16988 16989 16990 16991 16992 16993 16994 16995 16996 16997 16998 16999 17000 17001 17002 17003 17004 17005 17006 17007 17008 17009 17010 17011 17012 17013 17014 17015 17016 17017 17018 17019 17020 17021 17022 17023 17024 17025 17026 17027 17028 17029 17030 17031 17032 17033 17034 17035 17036 17037 17038 17039 17040 17041 17042 17043 17044 17045 17046 | Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1080 utf-check-1080-2-80-0.jnk \ {File "%TEMP%/utf-check-1080-2-80-0.jnk" has 16388 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1081 utf-check-1081-2-80-1.jnk \ {File "%TEMP%/utf-check-1081-2-80-1.jnk" has 16389 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1082 utf-check-1082-2-81-0.jnk \ {File "%TEMP%/utf-check-1082-2-81-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1083 utf-check-1083-2-81-1.jnk \ {File "%TEMP%/utf-check-1083-2-81-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1084 utf-check-1084-2-82-0.jnk \ {File "%TEMP%/utf-check-1084-2-82-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1085 utf-check-1085-2-82-1.jnk \ {File "%TEMP%/utf-check-1085-2-82-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1086 utf-check-1086-2-83-0.jnk \ {File "%TEMP%/utf-check-1086-2-83-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1087 utf-check-1087-2-83-1.jnk \ {File "%TEMP%/utf-check-1087-2-83-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1088 utf-check-1088-2-84-0.jnk \ {File "%TEMP%/utf-check-1088-2-84-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1089 utf-check-1089-2-84-1.jnk \ {File "%TEMP%/utf-check-1089-2-84-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1090 utf-check-1090-2-85-0.jnk \ {File "%TEMP%/utf-check-1090-2-85-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1091 utf-check-1091-2-85-1.jnk \ {File "%TEMP%/utf-check-1091-2-85-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1092 utf-check-1092-2-86-0.jnk \ {File "%TEMP%/utf-check-1092-2-86-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1093 utf-check-1093-2-86-1.jnk \ {File "%TEMP%/utf-check-1093-2-86-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1094 utf-check-1094-2-87-0.jnk \ {File "%TEMP%/utf-check-1094-2-87-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1095 utf-check-1095-2-87-1.jnk \ {File "%TEMP%/utf-check-1095-2-87-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1096 utf-check-1096-2-88-0.jnk \ {File "%TEMP%/utf-check-1096-2-88-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1097 utf-check-1097-2-88-1.jnk \ {File "%TEMP%/utf-check-1097-2-88-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1098 utf-check-1098-2-89-0.jnk \ {File "%TEMP%/utf-check-1098-2-89-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1099 utf-check-1099-2-89-1.jnk \ {File "%TEMP%/utf-check-1099-2-89-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1100 utf-check-1100-2-90-0.jnk \ {File "%TEMP%/utf-check-1100-2-90-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1101 utf-check-1101-2-90-1.jnk \ {File "%TEMP%/utf-check-1101-2-90-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1102 utf-check-1102-2-91-0.jnk \ {File "%TEMP%/utf-check-1102-2-91-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1103 utf-check-1103-2-91-1.jnk \ {File "%TEMP%/utf-check-1103-2-91-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1104 utf-check-1104-2-92-0.jnk \ {File "%TEMP%/utf-check-1104-2-92-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1105 utf-check-1105-2-92-1.jnk \ {File "%TEMP%/utf-check-1105-2-92-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1106 utf-check-1106-2-93-0.jnk \ {File "%TEMP%/utf-check-1106-2-93-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1107 utf-check-1107-2-93-1.jnk \ {File "%TEMP%/utf-check-1107-2-93-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1108 utf-check-1108-2-94-0.jnk \ {File "%TEMP%/utf-check-1108-2-94-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1109 utf-check-1109-2-94-1.jnk \ {File "%TEMP%/utf-check-1109-2-94-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1110 utf-check-1110-2-95-0.jnk \ {File "%TEMP%/utf-check-1110-2-95-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1111 utf-check-1111-2-95-1.jnk \ {File "%TEMP%/utf-check-1111-2-95-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1112 utf-check-1112-2-96-0.jnk \ {File "%TEMP%/utf-check-1112-2-96-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1113 utf-check-1113-2-96-1.jnk \ {File "%TEMP%/utf-check-1113-2-96-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1114 utf-check-1114-2-97-0.jnk \ {File "%TEMP%/utf-check-1114-2-97-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1115 utf-check-1115-2-97-1.jnk \ {File "%TEMP%/utf-check-1115-2-97-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1116 utf-check-1116-2-98-0.jnk \ {File "%TEMP%/utf-check-1116-2-98-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1117 utf-check-1117-2-98-1.jnk \ {File "%TEMP%/utf-check-1117-2-98-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1118 utf-check-1118-2-99-0.jnk \ {File "%TEMP%/utf-check-1118-2-99-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1119 utf-check-1119-2-99-1.jnk \ {File "%TEMP%/utf-check-1119-2-99-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1120 utf-check-1120-2-100-0.jnk \ {File "%TEMP%/utf-check-1120-2-100-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1121 utf-check-1121-2-100-1.jnk \ {File "%TEMP%/utf-check-1121-2-100-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1122 utf-check-1122-2-101-0.jnk \ {File "%TEMP%/utf-check-1122-2-101-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1123 utf-check-1123-2-101-1.jnk \ {File "%TEMP%/utf-check-1123-2-101-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1124 utf-check-1124-2-102-0.jnk \ {File "%TEMP%/utf-check-1124-2-102-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1125 utf-check-1125-2-102-1.jnk \ {File "%TEMP%/utf-check-1125-2-102-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1126 utf-check-1126-2-103-0.jnk \ {File "%TEMP%/utf-check-1126-2-103-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: yes Has flag LOOK_LONG: yes Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1127 utf-check-1127-2-103-1.jnk \ {File "%TEMP%/utf-check-1127-2-103-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1128 utf-check-1128-2-104-0.jnk \ {File "%TEMP%/utf-check-1128-2-104-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1129 utf-check-1129-2-104-1.jnk \ {File "%TEMP%/utf-check-1129-2-104-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1130 utf-check-1130-2-105-0.jnk \ {File "%TEMP%/utf-check-1130-2-105-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1131 utf-check-1131-2-105-1.jnk \ {File "%TEMP%/utf-check-1131-2-105-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1132 utf-check-1132-2-106-0.jnk \ {File "%TEMP%/utf-check-1132-2-106-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1133 utf-check-1133-2-106-1.jnk \ {File "%TEMP%/utf-check-1133-2-106-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1134 utf-check-1134-2-107-0.jnk \ {File "%TEMP%/utf-check-1134-2-107-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1135 utf-check-1135-2-107-1.jnk \ {File "%TEMP%/utf-check-1135-2-107-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1136 utf-check-1136-2-108-0.jnk \ {File "%TEMP%/utf-check-1136-2-108-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1137 utf-check-1137-2-108-1.jnk \ {File "%TEMP%/utf-check-1137-2-108-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1138 utf-check-1138-2-109-0.jnk \ {File "%TEMP%/utf-check-1138-2-109-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1139 utf-check-1139-2-109-1.jnk \ {File "%TEMP%/utf-check-1139-2-109-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1140 utf-check-1140-2-110-0.jnk \ {File "%TEMP%/utf-check-1140-2-110-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1141 utf-check-1141-2-110-1.jnk \ {File "%TEMP%/utf-check-1141-2-110-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1142 utf-check-1142-2-111-0.jnk \ {File "%TEMP%/utf-check-1142-2-111-0.jnk" has 16402 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes Has flag LOOK_LONE_LF: yes Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1143 utf-check-1143-2-111-1.jnk \ {File "%TEMP%/utf-check-1143-2-111-1.jnk" has 16403 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes Has flag LOOK_LONE_CR: yes Has flag LOOK_LF: yes |
︙ | ︙ | |||
17607 17608 17609 17610 17611 17612 17613 | Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} | | | | | | | | | | | | | | | | | 17607 17608 17609 17610 17611 17612 17613 17614 17615 17616 17617 17618 17619 17620 17621 17622 17623 17624 17625 17626 17627 17628 17629 17630 17631 17632 17633 17634 17635 | Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1179 utf-check-1179-2-129-1.jnk \ {File "%TEMP%/utf-check-1179-2-129-1.jnk" has 7 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1180 utf-check-1180-2-130-0.jnk \ {File "%TEMP%/utf-check-1180-2-130-0.jnk" has 4 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: yes Has flag LOOK_NUL: no |
︙ | ︙ | |||
22584 22585 22586 22587 22588 22589 22590 | Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1490 utf-check-1490-3-80-0.jnk \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 22584 22585 22586 22587 22588 22589 22590 22591 22592 22593 22594 22595 22596 22597 22598 22599 22600 22601 22602 22603 22604 22605 22606 22607 22608 22609 22610 22611 22612 22613 22614 22615 22616 22617 22618 22619 22620 22621 22622 22623 22624 22625 22626 22627 22628 22629 22630 22631 22632 22633 22634 22635 22636 22637 22638 22639 22640 22641 22642 22643 22644 22645 22646 22647 22648 22649 22650 22651 22652 22653 22654 22655 22656 22657 22658 22659 22660 22661 22662 22663 22664 22665 22666 22667 22668 22669 22670 22671 22672 22673 22674 22675 22676 22677 22678 22679 22680 22681 22682 22683 22684 22685 22686 22687 22688 22689 22690 22691 22692 22693 22694 22695 22696 22697 22698 22699 22700 22701 22702 22703 22704 22705 22706 22707 22708 22709 22710 22711 22712 22713 22714 22715 22716 22717 22718 22719 22720 22721 22722 22723 22724 22725 22726 22727 22728 22729 22730 22731 22732 22733 22734 22735 22736 22737 22738 22739 22740 22741 22742 22743 22744 22745 22746 22747 22748 22749 22750 22751 22752 22753 22754 22755 22756 22757 22758 22759 22760 22761 22762 22763 22764 22765 22766 22767 22768 22769 22770 22771 22772 22773 22774 22775 22776 22777 22778 22779 22780 22781 22782 22783 22784 22785 22786 22787 22788 22789 22790 22791 22792 22793 22794 22795 22796 22797 22798 22799 22800 22801 22802 22803 22804 22805 22806 22807 22808 22809 22810 22811 22812 22813 22814 22815 22816 22817 22818 22819 22820 22821 22822 22823 22824 22825 22826 22827 22828 22829 22830 22831 22832 22833 22834 22835 22836 22837 22838 22839 22840 22841 22842 22843 22844 22845 22846 22847 22848 22849 22850 22851 22852 22853 22854 22855 22856 22857 22858 22859 22860 22861 22862 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880 22881 22882 22883 22884 22885 22886 22887 22888 22889 22890 22891 22892 22893 22894 22895 22896 22897 22898 22899 22900 22901 22902 22903 22904 22905 22906 22907 22908 22909 22910 22911 22912 22913 22914 22915 22916 22917 22918 22919 22920 22921 22922 22923 22924 22925 22926 22927 22928 22929 22930 22931 22932 22933 22934 22935 22936 22937 22938 22939 22940 22941 22942 22943 22944 22945 22946 22947 22948 22949 22950 22951 22952 22953 22954 22955 22956 22957 22958 22959 22960 22961 22962 22963 22964 22965 22966 22967 22968 22969 22970 22971 22972 22973 22974 22975 22976 22977 22978 22979 22980 22981 22982 22983 22984 22985 22986 22987 22988 22989 22990 22991 22992 22993 22994 22995 22996 22997 22998 22999 23000 23001 23002 23003 23004 23005 23006 23007 23008 23009 23010 23011 23012 23013 23014 23015 23016 23017 23018 23019 23020 23021 23022 23023 23024 23025 23026 23027 23028 23029 23030 23031 23032 23033 23034 23035 23036 23037 23038 23039 23040 23041 23042 23043 23044 23045 23046 23047 23048 23049 23050 23051 23052 23053 23054 23055 23056 23057 23058 23059 23060 23061 23062 23063 23064 23065 23066 23067 23068 23069 23070 23071 23072 23073 23074 23075 23076 23077 23078 23079 23080 23081 23082 23083 23084 23085 23086 23087 23088 23089 23090 23091 23092 23093 23094 23095 23096 23097 23098 23099 23100 23101 23102 23103 23104 23105 23106 23107 23108 23109 23110 23111 23112 23113 23114 23115 23116 23117 23118 23119 23120 23121 23122 23123 23124 23125 23126 23127 23128 23129 23130 23131 23132 23133 23134 23135 23136 23137 23138 23139 23140 23141 23142 23143 23144 23145 23146 23147 23148 23149 23150 23151 23152 23153 23154 23155 23156 23157 23158 23159 23160 23161 23162 23163 23164 23165 23166 23167 23168 23169 23170 23171 23172 23173 23174 23175 23176 23177 23178 23179 23180 23181 23182 23183 23184 23185 23186 23187 23188 23189 23190 23191 23192 23193 23194 23195 23196 23197 23198 23199 23200 23201 23202 23203 23204 23205 23206 23207 23208 23209 23210 23211 23212 23213 23214 23215 23216 23217 23218 23219 23220 23221 23222 23223 23224 23225 23226 23227 23228 23229 23230 23231 23232 23233 23234 23235 23236 23237 23238 23239 23240 23241 23242 23243 23244 23245 23246 23247 23248 23249 23250 23251 23252 23253 23254 23255 23256 23257 23258 23259 23260 23261 23262 23263 23264 23265 23266 23267 23268 23269 23270 23271 23272 23273 23274 23275 23276 23277 23278 23279 23280 23281 23282 23283 23284 23285 23286 23287 23288 23289 23290 23291 23292 23293 23294 23295 23296 23297 23298 23299 23300 23301 23302 23303 23304 23305 23306 23307 23308 23309 23310 23311 23312 23313 23314 23315 23316 23317 23318 23319 23320 23321 23322 23323 23324 23325 23326 23327 23328 23329 23330 23331 23332 23333 23334 23335 23336 23337 23338 23339 23340 23341 23342 23343 23344 23345 23346 23347 23348 23349 23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360 23361 23362 23363 23364 23365 23366 23367 23368 23369 23370 23371 23372 23373 23374 23375 23376 23377 23378 23379 23380 23381 23382 23383 23384 23385 23386 23387 23388 23389 23390 23391 23392 23393 23394 23395 23396 23397 23398 23399 23400 23401 23402 23403 23404 23405 23406 23407 23408 23409 23410 23411 23412 23413 23414 23415 23416 23417 23418 23419 23420 23421 23422 23423 23424 23425 23426 23427 23428 23429 23430 23431 23432 23433 23434 23435 23436 23437 23438 23439 23440 23441 23442 23443 23444 23445 23446 23447 23448 23449 23450 23451 23452 23453 23454 23455 23456 23457 23458 23459 23460 23461 23462 23463 23464 23465 23466 23467 23468 23469 23470 23471 23472 23473 23474 23475 23476 23477 23478 23479 23480 23481 23482 23483 23484 23485 23486 23487 23488 23489 23490 23491 23492 23493 23494 23495 23496 23497 23498 23499 23500 23501 23502 23503 23504 23505 23506 23507 23508 23509 23510 23511 23512 23513 23514 23515 23516 23517 23518 23519 23520 23521 23522 23523 23524 23525 23526 23527 23528 23529 23530 23531 23532 23533 23534 23535 23536 23537 23538 23539 23540 23541 23542 23543 23544 23545 23546 23547 23548 23549 23550 23551 23552 23553 23554 23555 23556 23557 23558 23559 23560 23561 23562 23563 23564 23565 23566 23567 23568 23569 23570 23571 23572 23573 23574 23575 23576 23577 23578 23579 23580 23581 23582 23583 23584 23585 23586 23587 23588 23589 23590 23591 23592 23593 23594 23595 23596 23597 23598 23599 23600 23601 23602 23603 23604 23605 23606 | Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1490 utf-check-1490-3-80-0.jnk \ {File "%TEMP%/utf-check-1490-3-80-0.jnk" has 16388 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1491 utf-check-1491-3-80-1.jnk \ {File "%TEMP%/utf-check-1491-3-80-1.jnk" has 16389 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1492 utf-check-1492-3-81-0.jnk \ {File "%TEMP%/utf-check-1492-3-81-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1493 utf-check-1493-3-81-1.jnk \ {File "%TEMP%/utf-check-1493-3-81-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1494 utf-check-1494-3-82-0.jnk \ {File "%TEMP%/utf-check-1494-3-82-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1495 utf-check-1495-3-82-1.jnk \ {File "%TEMP%/utf-check-1495-3-82-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1496 utf-check-1496-3-83-0.jnk \ {File "%TEMP%/utf-check-1496-3-83-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1497 utf-check-1497-3-83-1.jnk \ {File "%TEMP%/utf-check-1497-3-83-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1498 utf-check-1498-3-84-0.jnk \ {File "%TEMP%/utf-check-1498-3-84-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1499 utf-check-1499-3-84-1.jnk \ {File "%TEMP%/utf-check-1499-3-84-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1500 utf-check-1500-3-85-0.jnk \ {File "%TEMP%/utf-check-1500-3-85-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1501 utf-check-1501-3-85-1.jnk \ {File "%TEMP%/utf-check-1501-3-85-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1502 utf-check-1502-3-86-0.jnk \ {File "%TEMP%/utf-check-1502-3-86-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1503 utf-check-1503-3-86-1.jnk \ {File "%TEMP%/utf-check-1503-3-86-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1504 utf-check-1504-3-87-0.jnk \ {File "%TEMP%/utf-check-1504-3-87-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1505 utf-check-1505-3-87-1.jnk \ {File "%TEMP%/utf-check-1505-3-87-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1506 utf-check-1506-3-88-0.jnk \ {File "%TEMP%/utf-check-1506-3-88-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1507 utf-check-1507-3-88-1.jnk \ {File "%TEMP%/utf-check-1507-3-88-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1508 utf-check-1508-3-89-0.jnk \ {File "%TEMP%/utf-check-1508-3-89-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1509 utf-check-1509-3-89-1.jnk \ {File "%TEMP%/utf-check-1509-3-89-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1510 utf-check-1510-3-90-0.jnk \ {File "%TEMP%/utf-check-1510-3-90-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1511 utf-check-1511-3-90-1.jnk \ {File "%TEMP%/utf-check-1511-3-90-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1512 utf-check-1512-3-91-0.jnk \ {File "%TEMP%/utf-check-1512-3-91-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1513 utf-check-1513-3-91-1.jnk \ {File "%TEMP%/utf-check-1513-3-91-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1514 utf-check-1514-3-92-0.jnk \ {File "%TEMP%/utf-check-1514-3-92-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1515 utf-check-1515-3-92-1.jnk \ {File "%TEMP%/utf-check-1515-3-92-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1516 utf-check-1516-3-93-0.jnk \ {File "%TEMP%/utf-check-1516-3-93-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1517 utf-check-1517-3-93-1.jnk \ {File "%TEMP%/utf-check-1517-3-93-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1518 utf-check-1518-3-94-0.jnk \ {File "%TEMP%/utf-check-1518-3-94-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1519 utf-check-1519-3-94-1.jnk \ {File "%TEMP%/utf-check-1519-3-94-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1520 utf-check-1520-3-95-0.jnk \ {File "%TEMP%/utf-check-1520-3-95-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1521 utf-check-1521-3-95-1.jnk \ {File "%TEMP%/utf-check-1521-3-95-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1522 utf-check-1522-3-96-0.jnk \ {File "%TEMP%/utf-check-1522-3-96-0.jnk" has 16390 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1523 utf-check-1523-3-96-1.jnk \ {File "%TEMP%/utf-check-1523-3-96-1.jnk" has 16391 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1524 utf-check-1524-3-97-0.jnk \ {File "%TEMP%/utf-check-1524-3-97-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1525 utf-check-1525-3-97-1.jnk \ {File "%TEMP%/utf-check-1525-3-97-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1526 utf-check-1526-3-98-0.jnk \ {File "%TEMP%/utf-check-1526-3-98-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1527 utf-check-1527-3-98-1.jnk \ {File "%TEMP%/utf-check-1527-3-98-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1528 utf-check-1528-3-99-0.jnk \ {File "%TEMP%/utf-check-1528-3-99-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1529 utf-check-1529-3-99-1.jnk \ {File "%TEMP%/utf-check-1529-3-99-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1530 utf-check-1530-3-100-0.jnk \ {File "%TEMP%/utf-check-1530-3-100-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1531 utf-check-1531-3-100-1.jnk \ {File "%TEMP%/utf-check-1531-3-100-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1532 utf-check-1532-3-101-0.jnk \ {File "%TEMP%/utf-check-1532-3-101-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1533 utf-check-1533-3-101-1.jnk \ {File "%TEMP%/utf-check-1533-3-101-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1534 utf-check-1534-3-102-0.jnk \ {File "%TEMP%/utf-check-1534-3-102-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1535 utf-check-1535-3-102-1.jnk \ {File "%TEMP%/utf-check-1535-3-102-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1536 utf-check-1536-3-103-0.jnk \ {File "%TEMP%/utf-check-1536-3-103-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1537 utf-check-1537-3-103-1.jnk \ {File "%TEMP%/utf-check-1537-3-103-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1538 utf-check-1538-3-104-0.jnk \ {File "%TEMP%/utf-check-1538-3-104-0.jnk" has 16392 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1539 utf-check-1539-3-104-1.jnk \ {File "%TEMP%/utf-check-1539-3-104-1.jnk" has 16393 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1540 utf-check-1540-3-105-0.jnk \ {File "%TEMP%/utf-check-1540-3-105-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1541 utf-check-1541-3-105-1.jnk \ {File "%TEMP%/utf-check-1541-3-105-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1542 utf-check-1542-3-106-0.jnk \ {File "%TEMP%/utf-check-1542-3-106-0.jnk" has 16394 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1543 utf-check-1543-3-106-1.jnk \ {File "%TEMP%/utf-check-1543-3-106-1.jnk" has 16395 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1544 utf-check-1544-3-107-0.jnk \ {File "%TEMP%/utf-check-1544-3-107-0.jnk" has 16396 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1545 utf-check-1545-3-107-1.jnk \ {File "%TEMP%/utf-check-1545-3-107-1.jnk" has 16397 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1546 utf-check-1546-3-108-0.jnk \ {File "%TEMP%/utf-check-1546-3-108-0.jnk" has 16398 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1547 utf-check-1547-3-108-1.jnk \ {File "%TEMP%/utf-check-1547-3-108-1.jnk" has 16399 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1548 utf-check-1548-3-109-0.jnk \ {File "%TEMP%/utf-check-1548-3-109-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1549 utf-check-1549-3-109-1.jnk \ {File "%TEMP%/utf-check-1549-3-109-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1550 utf-check-1550-3-110-0.jnk \ {File "%TEMP%/utf-check-1550-3-110-0.jnk" has 16400 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1551 utf-check-1551-3-110-1.jnk \ {File "%TEMP%/utf-check-1551-3-110-1.jnk" has 16401 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1552 utf-check-1552-3-111-0.jnk \ {File "%TEMP%/utf-check-1552-3-111-0.jnk" has 16402 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: yes Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1553 utf-check-1553-3-111-1.jnk \ {File "%TEMP%/utf-check-1553-3-111-1.jnk" has 16403 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no |
︙ | ︙ | |||
24119 24120 24121 24122 24123 24124 24125 | Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 24119 24120 24121 24122 24123 24124 24125 24126 24127 24128 24129 24130 24131 24132 24133 24134 24135 24136 24137 24138 24139 24140 24141 24142 24143 24144 24145 24146 24147 24148 24149 24150 24151 24152 24153 24154 24155 24156 24157 24158 24159 24160 24161 24162 24163 | Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1586 utf-check-1586-3-128-0.jnk \ {File "%TEMP%/utf-check-1586-3-128-0.jnk" has 6 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1587 utf-check-1587-3-128-1.jnk \ {File "%TEMP%/utf-check-1587-3-128-1.jnk" has 7 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Has flag LOOK_LONE_CR: no Has flag LOOK_LF: no Has flag LOOK_LONE_LF: no Has flag LOOK_CRLF: no Has flag LOOK_LONG: no Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1588 utf-check-1588-3-129-0.jnk \ {File "%TEMP%/utf-check-1588-3-129-0.jnk" has 6 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes |
︙ | ︙ |
Changes to test/wiki.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################ # # Test wiki and attachment command Support # test_setup | < < < < < < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ############################################################################ # # Test wiki and attachment command Support # test_setup # Return true if two files are similar (i.e. not only compress trailing spaces # from a line, but remove any final LF from the file as well) proc similar_file {a b} { set x "" if {[file exists $a]} { set x [read_file $a] regsub -all { +\n} $x \n x |
︙ | ︙ | |||
49 50 51 52 53 54 55 | # "text/x-fossil-wiki" (the default mimetype for rendering) # if the N card is omitted in the manifest. # Note: Makes fossil calls, so $CODE and $RESULT will be corrupted proc get_mime_type {name} { global CODE RESULT fossil http << "GET /wiki?name=$name" if {$CODE != 0} { | | | | | | | | | | | | | 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 | # "text/x-fossil-wiki" (the default mimetype for rendering) # if the N card is omitted in the manifest. # Note: Makes fossil calls, so $CODE and $RESULT will be corrupted proc get_mime_type {name} { global CODE RESULT fossil http << "GET /wiki?name=$name" if {$CODE != 0} { return error: /wiki?name=$name $CODE $RESULT" } set CODE [regexp {href="/info/([0-9a-f]+)"} $RESULT match info] if {$CODE == 0} { return "error: No info link found for wiki page $name" } fossil http << "GET /artifact/$info" if {$CODE != 0} { return "error: /artifact/$info $CODE $RESULT" } set CODE [regexp {<pre>(.*)</pre>} $RESULT match pre] if {$CODE == 0} { return "error: No pre block in /artifact/$info" } set CODE [regexp -line {^N (.*)$} $pre match mimetype] if {$CODE == 0} { return "text/x-fossil-wiki" } return $mimetype } |
︙ | ︙ |
Deleted tools/co-rsync.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/codecheck1.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tools/email-sender.tcl.
︙ | ︙ | |||
19 20 21 22 23 24 25 | msg TXT ); } while {1} { db transaction immediate { set n 0 db eval {SELECT msg FROM email} { | < < < < | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | msg TXT ); } while {1} { db transaction immediate { set n 0 db eval {SELECT msg FROM email} { set out [open |$PIPE w] puts -nonewline $out $msg flush $out close $out incr n } if {$n>0} { db eval {DELETE FROM email} |
︙ | ︙ |
Deleted tools/emcc.sh.in.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tools/fossil-autocomplete.bash.
1 2 3 4 5 6 7 | # Command name completion for Fossil. # Mailing-list contribution by Stuart Rackham. function _fossil() { local cur commands cur=${COMP_WORDS[COMP_CWORD]} commands=$(fossil help --all) if [ $COMP_CWORD -eq 1 ] || [ ${COMP_WORDS[1]} = help ]; then | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # Command name completion for Fossil. # Mailing-list contribution by Stuart Rackham. function _fossil() { local cur commands cur=${COMP_WORDS[COMP_CWORD]} commands=$(fossil help --all) if [ $COMP_CWORD -eq 1 ] || [ ${COMP_WORDS[1]} = help ]; then # Command name completion for 1st argument or 2nd if help command. COMPREPLY=( $(compgen -W "$commands" $cur) ) else # File name completion for other arguments. COMPREPLY=( $(compgen -f $cur) ) fi } complete -o default -F _fossil fossil f |
Deleted tools/fossil-autocomplete.zsh.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/fossil-diff-log.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tools/fossil-stress.tcl.
︙ | ︙ | |||
13 14 15 16 17 18 19 | } if {$x=="-threads"} { incr i set nthread [lindex $argv $i] } elseif {[string index $x 0]=="-"} { error "unknown option \"$x\"" } elseif {[info exists url]} { | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | } if {$x=="-threads"} { incr i set nthread [lindex $argv $i] } elseif {[string index $x 0]=="-"} { error "unknown option \"$x\"" } elseif {[info exists url]} { error "unknown argment \"$x\"" } else { set url $x } } if {![info exists url]} { error "Usage: $argv0 [-threads N] URL" } |
︙ | ︙ |
Added tools/fossil_chat.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 | #!/home/drh/bin/tobe # # Simple chat client for Tcl/Tk. # package require Tk set SERVERHOST fossil-scm.hwaci.com # set SERVERHOST 127.0.0.1 #set SERVERHOST 64.5.53.192 set SERVERPORT 8615 # set to correct values if you have to use a proxy set PROXYHOST {} set PROXYPORT {} # Setup the user interface wm title . Fossil-Chat wm iconname . [wm title .] menu .mb -type menubar if {$tcl_platform(platform)=="unix" && $tcl_platform(os)!="Darwin"} { pack .mb -side top -fill x } else { . config -menu .mb } .mb add cascade -label File -underline 0 -menu .mb.file menu .mb.file -tearoff 0 .mb.file add command -label Send -command send_message .mb.file add command -label {Remove older messages} -command cleanup_record .mb.file add separator .mb.file add command -label {Exit} -command exit frame .who pack .who -side right -anchor n -fill y label .who.title -text {Users: } pack .who.title -side top -anchor nw label .who.list -anchor w -justify left -text {} pack .who.list -side top -anchor nw -expand 1 -padx 5 label .who.time -text {} -justify right proc update_time {} { after 1000 update_time set now [clock seconds] set time [clock format $now -format %H:%M -gmt 1] .who.time config -text "UTC: $time" } update_time pack .who.time -side bottom -anchor sw frame .input pack .input -side bottom -fill x text .input.t -bd 1 -relief sunken -bg white -fg black -width 60 -height 3 \ -wrap word -yscrollcommand [list .input.sb set] -takefocus 1 bind .input.t <Key-Return> {send_message; break} pack .input.t -side left -fill both -expand 1 scrollbar .input.sb -orient vertical -command [list .input.t yview] pack .input.sb -side left -fill y frame .msg pack .msg -side top -fill both -expand 1 text .msg.t -bd 1 -relief sunken -bg white -fg black -width 60 -height 20 \ -wrap word -yscrollcommand [list .msg.sb set] -takefocus 0 bindtags .msg.t [list .msg.t . all] .msg.t tag config error -foreground red .msg.t tag config meta -foreground forestgreen .msg.t tag config norm -foreground black pack .msg.t -side left -fill both -expand 1 scrollbar .msg.sb -orient vertical -command [list .msg.t yview] pack .msg.sb -side left -fill y update # Send periodic messages to keep the TCP/IP link up # proc keep_alive {} { global TIMER SOCKET catch {after cancel $TIMER} set TIMER [after 300000 keep_alive] catch {puts $SOCKET noop; flush $SOCKET} } # Connect to the server proc connect {} { global SOCKET tcl_platform catch {close $SOCKET} if {[catch { if {$::PROXYHOST ne {}} { set SOCKET [socket $::PROXYHOST $::PROXYPORT] puts $SOCKET "CONNECT $::SERVERHOST:$::SERVERPORT HTTP/1.1" puts $SOCKET "Host: $::SERVERHOST:$::SERVERPORT" puts $SOCKET "" } else { set SOCKET [socket $::SERVERHOST $::SERVERPORT] } fconfigure $SOCKET -translation binary -blocking 0 puts $SOCKET [list login $tcl_platform(user) fact,fuzz] flush $SOCKET fileevent $SOCKET readable handle_input keep_alive } errmsg]} { if {[tk_messageBox -icon error -type yesno -parent . -message \ "Unable to connect to server. $errmsg.\n\nTry again?"]=="yes"} { after 100 connect } } } connect # Send the message text contained in the .input.t widget to the server. # proc send_message {} { set txt [.input.t get 1.0 end] .input.t delete 1.0 end regsub -all "\[ \t\n\f\r\]+" [string trim $txt] { } txt if {$txt==""} return global SOCKET puts $SOCKET [list message $txt] flush $SOCKET } .mb add cascade -label "Transfer" -underline 0 -menu .mb.files menu .mb.files -tearoff 0 .mb.files add command -label "Send file..." -command send_file .mb.files add command -label "Delete files" -command delete_files \ -state disabled .mb.files add separator # Encode a string (possibly containing binary and \000 characters) into # single line of text. # proc encode {txt} { return [string map [list % %25 + %2b " " + \n %0a \t %09 \000 %00] $txt] } # Undo the work of encode. Convert an encoded string back into its original # form. # proc decode {txt} { return [string map [list %00 \000 %09 \t %0a \n + " " %2b + %25 %] $txt] } # Delete all of the downloaded files we are currently holding. # proc delete_files {} { global FILES .mb.files delete 3 end array unset FILES .mb.files entryconfigure 1 -state disabled } # Prompt the user to select a file from the disk. Then send that # file to all chat participants. # proc send_file {} { global SOCKET set openfile [tk_getOpenFile] if {$openfile==""} return set f [open $openfile] fconfigure $f -translation binary set data [read $f] close $f puts $SOCKET [list file [file tail $openfile] [encode $data]] flush $SOCKET set time [clock format [clock seconds] -format {%H:%M} -gmt 1] .msg.t insert end "\[$time\] sent file [file tail $openfile]\ - [string length $data] bytes\n" meta .msg.t see end } # Save the named file to the disk. # proc save_file {filename} { global FILES set savefile [tk_getSaveFile -initialfile $filename] if {$savefile==""} return set f [open $savefile w] fconfigure $f -translation binary puts -nonewline $f [decode $FILES($filename)] close $f } # Handle a "file" message from the chat server. # proc handle_file {from filename data} { global FILES foreach prior [array names FILES] { if {$filename==$prior} break } if {![info exists prior] || $filename!=$prior} { .mb.files add command -label "Save \"$filename\"" \ -command [list save_file $filename] } set FILES($filename) $data .mb.files entryconfigure 1 -state active set time [clock format [clock seconds] -format {%H:%M} -gmt 1] .msg.t insert end "\[$time $from\] " meta "File: \"$filename\"\n" norm .msg.t see end } # Handle input from the server # proc handle_input {} { global SOCKET if {[eof $SOCKET]} { disconnect return } set line [gets $SOCKET] if {$line==""} return set cmd [lindex $line 0] if {$cmd=="userlist"} { set ulist {} foreach u [lrange $line 1 end] { append ulist $u\n } .who.list config -text [string trim $ulist] } elseif {$cmd=="message"} { set time [clock format [clock seconds] -format {%H:%M} -gmt 1] set from [lindex $line 1] .msg.t insert end "\[$time $from\] " meta [lindex $line 2]\n norm .msg.t see end bell wm deiconify . update raise . } elseif {$cmd=="noop"} { # do nothing } elseif {$cmd=="meta"} { set now [clock seconds] set time [clock format $now -format {%H:%M} -gmt 1] .msg.t insert end "\[$time\] [lindex $line 1]\n" meta .msg.t see end } elseif {$cmd=="file"} { if {[info commands handle_file]=="handle_file"} { handle_file [lindex $line 1] [lindex $line 2] [lindex $line 3] } } } # Handle a broken socket connection # proc disconnect {} { global SOCKET close $SOCKET set q [tk_messageBox -icon error -type yesno -parent . -message \ "TCP/IP link lost. Try to reconnet?"] if {$q=="yes"} { connect } else { exit } } # Remove all but the most recent 100 message from the message log # proc cleanup_record {} { .msg.t delete 1.0 {end -100 lines} } |
Deleted tools/fslsrv.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/makeheaders.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/makeheaders.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/makemake.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/mkbuiltin.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/mkindex.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/mkversion.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/skintxt2config.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/sqlcompattest.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tools/translate.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added win/Makefile.PellesCGMake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # HowTo # ----- # # This is a Makefile to compile fossil with PellesC from # http://www.smorgasbordet.com/pellesc/index.htm # In addition to the Compiler envrionment, you need # gmake from http://sourceforge.net/projects/unxutils/, Pelles make version # couldn't handle the complex dependencies in this build # zlib sources # Then you do # 1. create a directory PellesC in the project root directory # 2. Change the variables PellesCDir/ZLIBSRCDIR to the path of your installation # 3. open a dos prompt window and change working directory into PellesC (step 1) # 4. run gmake -f ..\win\Makefile.PellesCGMake # # this file is tested with # PellesC 5.00.13 # gmake 3.80 # zlib sources 1.2.5 # Windows XP SP 2 # and # PellesC 6.00.4 # gmake 3.80 # zlib sources 1.2.5 # Windows 7 Home Premium # # PellesCDir=c:\Programme\PellesC # Select between 32/64 bit code, default is 32 bit #TARGETVERSION=64 ifeq ($(TARGETVERSION),64) # 64 bit version TARGETMACHINE_CC=amd64 TARGETMACHINE_LN=amd64 TARGETEXTEND=64 else # 32 bit version TARGETMACHINE_CC=x86 TARGETMACHINE_LN=ix86 TARGETEXTEND= endif # define the project directories B=.. SRCDIR=$(B)/src/ WINDIR=$(B)/win/ ZLIBSRCDIR=../../zlib/ # define linker command and options LINK=$(PellesCDir)/bin/polink.exe LINKFLAGS=-subsystem:console -machine:$(TARGETMACHINE_LN) /LIBPATH:$(PellesCDir)\lib\win$(TARGETEXTEND) /LIBPATH:$(PellesCDir)\lib kernel32.lib advapi32.lib delayimp$(TARGETEXTEND).lib Wsock32.lib dnsapi.lib Crtmt$(TARGETEXTEND).lib # define standard C-compiler and flags, used to compile # the fossil binary. Some special definitions follow for # special files follow CC=$(PellesCDir)\bin\pocc.exe DEFINES=-D_pgmptr=g.argv[0] CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) # define commands for building the windows resource files RESOURCE=fossil.res RC=$(PellesCDir)\bin\porc.exe RCFLAGS=$(INCLUDE) -D__POCC__=1 -D_M_X$(TARGETVERSION) # define the special utilities files, needed to generate # the automatically generated source files UTILS=translate.exe mkindex.exe makeheaders.exe mkbuiltin.exe UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the SQLite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_WIN32_NO_ANSI # define the SQLite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) SQLITESHELLDEFINES=-DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) # define the zlib files, needed by this compile ZLIBSRC=adler32.c compress.c crc32.c deflate.c gzclose.c gzlib.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c ORIGZLIBSRC=$(foreach sf,$(ZLIBSRC),$(ZLIBSRCDIR)$(sf)) ZLIBOBJ=$(foreach sf,$(ZLIBSRC),$(sf:.c=.obj)) # define all fossil sources, using the standard compile and # source generation. These are all files in SRCDIR, which are not # mentioned as special files above: ORIGSRC=$(filter-out $(UTILS_SRC) $(ORIGTHSRC) $(ORIGSQLITESRC) $(ORIGSQLITESHELLSRC),$(wildcard $(SRCDIR)*.c)) SRC=$(subst $(SRCDIR),,$(ORIGSRC)) TRANSLATEDSRC=$(SRC:.c=_.c) TRANSLATEDOBJ=$(TRANSLATEDSRC:.c=.obj) # main target file is the application APPLICATION=fossil.exe # define the standard make target .PHONY: default default: page_index.h builtin_data.h headers $(APPLICATION) # symbolic target to generate the source generate utils .PHONY: utils utils: $(UTILS) # link utils $(UTILS) version.exe: %.exe: %.obj $(LINK) $(LINKFLAGS) -out:"$@" $< # compiling standard fossil utils $(UTILS_OBJ): %.obj: $(SRCDIR)%.c $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" # compile special windows utils version.obj: $(SRCDIR)mkversion.c $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" # generate the translated c-source files $(TRANSLATEDSRC): %_.c: $(SRCDIR)%.c translate.exe translate.exe $< >$@ # generate the index source, containing all web references,.. page_index.h: $(TRANSLATEDSRC) mkindex.exe mkindex.exe $(TRANSLATEDSRC) >$@ builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ # extracting version info from manifest VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@ default_css.h: mkcss.exe default_css.txt mkcss.exe default_css.txt $@ # generate the simplified headers headers: makeheaders.exe page_index.h builtin_data.h default_css.h VERSION.h ../src/sqlite3.h ../src/th.h makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h echo Done >$@ # compile C sources with relevant options $(TRANSLATEDOBJ): %_.obj: %_.c %.h $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" $(SQLITEOBJ): %.obj: $(SRCDIR)%.c $(SRCDIR)%.h $(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@" $(SQLITESHELLOBJ): %.obj: $(SRCDIR)%.c $(CC) $(CCFLAGS) $(SQLITESHELLDEFINES) $(INCLUDE) "$<" -Fo"$@" $(THOBJ): %.obj: $(SRCDIR)%.c $(SRCDIR)th.h $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" $(ZLIBOBJ): %.obj: $(ZLIBSRCDIR)%.c $(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@" # create the windows resource with icon and version info $(RESOURCE): %.res: ../win/%.rc ../win/*.ico $(RC) $(RCFLAGS) $< -Fo"$@" # link the application $(APPLICATION): $(TRANSLATEDOBJ) $(SQLITEOBJ) $(SQLITESHELLOBJ) $(THOBJ) $(ZLIBOBJ) headers $(RESOURCE) $(LINK) $(LINKFLAGS) -out:"$@" $(TRANSLATEDOBJ) $(SQLITEOBJ) $(SQLITESHELLOBJ) $(THOBJ) $(ZLIBOBJ) $(RESOURCE) # cleanup .PHONY: clean clean: -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj -del /F $(TRANSLATEDSRC) -del /F *.h headers -del /F $(RESOURCE) .PHONY: clobber clobber: clean -del /F *.exe |
Changes to win/Makefile.dmc.
1 2 | # ############################################################################## | | < < | | | < < | | | | | | | | > > > | | | | > > > | > < < < < < < < < < < < < | 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 | # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # B = .. SRCDIR = $B\src OBJDIR = . O = .obj E = .exe # Maybe DMDIR, SSL or INCL needs adjustment DMDIR = c:\DM INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include #SSL = -DFOSSIL_ENABLE_SSL=1 SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen SRC = add_.c alerts_.c allrepo_.c attach_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c file_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OBJDIR)\add$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E codecheck1$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) codecheck1$E $(SRC) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res +echo add alerts allrepo attach backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd descendants diff diffcmd dispatch doc encode etag event export file finfo foci forum fshell fusefs glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ translate$E: $(SRCDIR)\translate.c $(BCC) -o$@ $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) -o$@ $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** mkbuiltin$E: $(SRCDIR)\mkbuiltin.c $(BCC) -o$@ $** mkversion$E: $(SRCDIR)\mkversion.c $(BCC) -o$@ $** mkcss$E: $(SRCDIR)\mkcss.c $(BCC) -o$@ $** codecheck1$E: $(SRCDIR)\codecheck1.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c $(TCC) -o$@ -c $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $** $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c $(TCC) -o$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** $(OBJDIR)\th$O : $(SRCDIR)\th.c $(TCC) -o$@ -c $** $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) -o$@ -c $** $(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h cp $@ $@ VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION +$** > $@ default_css.h : mkcss$E $B\src\default_css.txt +$** $B\src\default_css.txt $@ page_index.h: mkindex$E $(SRC) +$** > $@ builtin_data.h: mkbuiltin$E $(EXTRA_FILES) mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@ clean: -del $(OBJDIR)\*.obj -del *.obj *_.c *.h *.map realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E codecheck1$E mkbuiltin$E mkcss$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h $(OBJDIR)\add$O : add_.c add.h $(TCC) -o$@ -c add_.c add_.c : $(SRCDIR)\add.c +translate$E $** > $@ $(OBJDIR)\alerts$O : alerts_.c alerts.h $(TCC) -o$@ -c alerts_.c alerts_.c : $(SRCDIR)\alerts.c +translate$E $** > $@ $(OBJDIR)\allrepo$O : allrepo_.c allrepo.h $(TCC) -o$@ -c allrepo_.c allrepo_.c : $(SRCDIR)\allrepo.c +translate$E $** > $@ $(OBJDIR)\attach$O : attach_.c attach.h $(TCC) -o$@ -c attach_.c attach_.c : $(SRCDIR)\attach.c +translate$E $** > $@ $(OBJDIR)\backoffice$O : backoffice_.c backoffice.h $(TCC) -o$@ -c backoffice_.c backoffice_.c : $(SRCDIR)\backoffice.c +translate$E $** > $@ $(OBJDIR)\bag$O : bag_.c bag.h |
︙ | ︙ | |||
232 233 234 235 236 237 238 | $(OBJDIR)\cgi$O : cgi_.c cgi.h $(TCC) -o$@ -c cgi_.c cgi_.c : $(SRCDIR)\cgi.c +translate$E $** > $@ | < < < < < < | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | $(OBJDIR)\cgi$O : cgi_.c cgi.h $(TCC) -o$@ -c cgi_.c cgi_.c : $(SRCDIR)\cgi.c +translate$E $** > $@ $(OBJDIR)\checkin$O : checkin_.c checkin.h $(TCC) -o$@ -c checkin_.c checkin_.c : $(SRCDIR)\checkin.c +translate$E $** > $@ $(OBJDIR)\checkout$O : checkout_.c checkout.h |
︙ | ︙ | |||
262 263 264 265 266 267 268 | $(OBJDIR)\clone$O : clone_.c clone.h $(TCC) -o$@ -c clone_.c clone_.c : $(SRCDIR)\clone.c +translate$E $** > $@ | < < < < < < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | $(OBJDIR)\clone$O : clone_.c clone.h $(TCC) -o$@ -c clone_.c clone_.c : $(SRCDIR)\clone.c +translate$E $** > $@ $(OBJDIR)\comformat$O : comformat_.c comformat.h $(TCC) -o$@ -c comformat_.c comformat_.c : $(SRCDIR)\comformat.c +translate$E $** > $@ $(OBJDIR)\configure$O : configure_.c configure.h |
︙ | ︙ | |||
310 311 312 313 314 315 316 | $(OBJDIR)\deltacmd$O : deltacmd_.c deltacmd.h $(TCC) -o$@ -c deltacmd_.c deltacmd_.c : $(SRCDIR)\deltacmd.c +translate$E $** > $@ | < < < < < < | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | $(OBJDIR)\deltacmd$O : deltacmd_.c deltacmd.h $(TCC) -o$@ -c deltacmd_.c deltacmd_.c : $(SRCDIR)\deltacmd.c +translate$E $** > $@ $(OBJDIR)\descendants$O : descendants_.c descendants.h $(TCC) -o$@ -c descendants_.c descendants_.c : $(SRCDIR)\descendants.c +translate$E $** > $@ $(OBJDIR)\diff$O : diff_.c diff.h |
︙ | ︙ | |||
370 371 372 373 374 375 376 | $(OBJDIR)\export$O : export_.c export.h $(TCC) -o$@ -c export_.c export_.c : $(SRCDIR)\export.c +translate$E $** > $@ | < < < < < < < < < < < < | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | $(OBJDIR)\export$O : export_.c export.h $(TCC) -o$@ -c export_.c export_.c : $(SRCDIR)\export.c +translate$E $** > $@ $(OBJDIR)\file$O : file_.c file.h $(TCC) -o$@ -c file_.c file_.c : $(SRCDIR)\file.c +translate$E $** > $@ $(OBJDIR)\finfo$O : finfo_.c finfo.h $(TCC) -o$@ -c finfo_.c finfo_.c : $(SRCDIR)\finfo.c +translate$E $** > $@ $(OBJDIR)\foci$O : foci_.c foci.h |
︙ | ︙ | |||
418 419 420 421 422 423 424 | $(OBJDIR)\fusefs$O : fusefs_.c fusefs.h $(TCC) -o$@ -c fusefs_.c fusefs_.c : $(SRCDIR)\fusefs.c +translate$E $** > $@ | < < < < < < | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | $(OBJDIR)\fusefs$O : fusefs_.c fusefs.h $(TCC) -o$@ -c fusefs_.c fusefs_.c : $(SRCDIR)\fusefs.c +translate$E $** > $@ $(OBJDIR)\glob$O : glob_.c glob.h $(TCC) -o$@ -c glob_.c glob_.c : $(SRCDIR)\glob.c +translate$E $** > $@ $(OBJDIR)\graph$O : graph_.c graph.h |
︙ | ︙ | |||
448 449 450 451 452 453 454 | $(OBJDIR)\hname$O : hname_.c hname.h $(TCC) -o$@ -c hname_.c hname_.c : $(SRCDIR)\hname.c +translate$E $** > $@ | < < < < < < | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | $(OBJDIR)\hname$O : hname_.c hname.h $(TCC) -o$@ -c hname_.c hname_.c : $(SRCDIR)\hname.c +translate$E $** > $@ $(OBJDIR)\http$O : http_.c http.h $(TCC) -o$@ -c http_.c http_.c : $(SRCDIR)\http.c +translate$E $** > $@ $(OBJDIR)\http_socket$O : http_socket_.c http_socket.h |
︙ | ︙ | |||
490 491 492 493 494 495 496 | $(OBJDIR)\info$O : info_.c info.h $(TCC) -o$@ -c info_.c info_.c : $(SRCDIR)\info.c +translate$E $** > $@ | < < < < < < | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | $(OBJDIR)\info$O : info_.c info.h $(TCC) -o$@ -c info_.c info_.c : $(SRCDIR)\info.c +translate$E $** > $@ $(OBJDIR)\json$O : json_.c json.h $(TCC) -o$@ -c json_.c json_.c : $(SRCDIR)\json.c +translate$E $** > $@ $(OBJDIR)\json_artifact$O : json_artifact_.c json_artifact.h |
︙ | ︙ | |||
664 665 666 667 668 669 670 | $(OBJDIR)\name$O : name_.c name.h $(TCC) -o$@ -c name_.c name_.c : $(SRCDIR)\name.c +translate$E $** > $@ | < < < < < < < < < < < < | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | $(OBJDIR)\name$O : name_.c name.h $(TCC) -o$@ -c name_.c name_.c : $(SRCDIR)\name.c +translate$E $** > $@ $(OBJDIR)\path$O : path_.c path.h $(TCC) -o$@ -c path_.c path_.c : $(SRCDIR)\path.c +translate$E $** > $@ $(OBJDIR)\piechart$O : piechart_.c piechart.h $(TCC) -o$@ -c piechart_.c piechart_.c : $(SRCDIR)\piechart.c +translate$E $** > $@ $(OBJDIR)\pivot$O : pivot_.c pivot.h $(TCC) -o$@ -c pivot_.c pivot_.c : $(SRCDIR)\pivot.c +translate$E $** > $@ $(OBJDIR)\popen$O : popen_.c popen.h |
︙ | ︙ | |||
736 737 738 739 740 741 742 | $(OBJDIR)\regexp$O : regexp_.c regexp.h $(TCC) -o$@ -c regexp_.c regexp_.c : $(SRCDIR)\regexp.c +translate$E $** > $@ | < < < < < < | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | $(OBJDIR)\regexp$O : regexp_.c regexp.h $(TCC) -o$@ -c regexp_.c regexp_.c : $(SRCDIR)\regexp.c +translate$E $** > $@ $(OBJDIR)\report$O : report_.c report.h $(TCC) -o$@ -c report_.c report_.c : $(SRCDIR)\report.c +translate$E $** > $@ $(OBJDIR)\rss$O : rss_.c rss.h |
︙ | ︙ | |||
874 875 876 877 878 879 880 | $(OBJDIR)\tar$O : tar_.c tar.h $(TCC) -o$@ -c tar_.c tar_.c : $(SRCDIR)\tar.c +translate$E $** > $@ | < < < < < < | 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | $(OBJDIR)\tar$O : tar_.c tar.h $(TCC) -o$@ -c tar_.c tar_.c : $(SRCDIR)\tar.c +translate$E $** > $@ $(OBJDIR)\th_main$O : th_main_.c th_main.h $(TCC) -o$@ -c th_main_.c th_main_.c : $(SRCDIR)\th_main.c +translate$E $** > $@ $(OBJDIR)\timeline$O : timeline_.c timeline.h |
︙ | ︙ | |||
963 964 965 966 967 968 969 970 971 972 973 974 975 976 | +translate$E $** > $@ $(OBJDIR)\vfile$O : vfile_.c vfile.h $(TCC) -o$@ -c vfile_.c vfile_.c : $(SRCDIR)\vfile.c +translate$E $** > $@ $(OBJDIR)\wiki$O : wiki_.c wiki.h $(TCC) -o$@ -c wiki_.c wiki_.c : $(SRCDIR)\wiki.c +translate$E $** > $@ | > > > > > > | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 | +translate$E $** > $@ $(OBJDIR)\vfile$O : vfile_.c vfile.h $(TCC) -o$@ -c vfile_.c vfile_.c : $(SRCDIR)\vfile.c +translate$E $** > $@ $(OBJDIR)\webmail$O : webmail_.c webmail.h $(TCC) -o$@ -c webmail_.c webmail_.c : $(SRCDIR)\webmail.c +translate$E $** > $@ $(OBJDIR)\wiki$O : wiki_.c wiki.h $(TCC) -o$@ -c wiki_.c wiki_.c : $(SRCDIR)\wiki.c +translate$E $** > $@ |
︙ | ︙ | |||
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 | +translate$E $** > $@ $(OBJDIR)\winhttp$O : winhttp_.c winhttp.h $(TCC) -o$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c +translate$E $** > $@ $(OBJDIR)\xfer$O : xfer_.c xfer.h $(TCC) -o$@ -c xfer_.c xfer_.c : $(SRCDIR)\xfer.c +translate$E $** > $@ $(OBJDIR)\xfersetup$O : xfersetup_.c xfersetup.h $(TCC) -o$@ -c xfersetup_.c xfersetup_.c : $(SRCDIR)\xfersetup.c +translate$E $** > $@ $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ | > > > > > > | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 | +translate$E $** > $@ $(OBJDIR)\winhttp$O : winhttp_.c winhttp.h $(TCC) -o$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c +translate$E $** > $@ $(OBJDIR)\wysiwyg$O : wysiwyg_.c wysiwyg.h $(TCC) -o$@ -c wysiwyg_.c wysiwyg_.c : $(SRCDIR)\wysiwyg.c +translate$E $** > $@ $(OBJDIR)\xfer$O : xfer_.c xfer.h $(TCC) -o$@ -c xfer_.c xfer_.c : $(SRCDIR)\xfer.c +translate$E $** > $@ $(OBJDIR)\xfersetup$O : xfersetup_.c xfersetup.h $(TCC) -o$@ -c xfersetup_.c xfersetup_.c : $(SRCDIR)\xfersetup.c +translate$E $** > $@ $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h +makeheaders$E add_.c:add.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Changes to win/Makefile.mingw.
1 2 3 | #!/usr/bin/make # ############################################################################## | | | 1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/make # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using |
︙ | ︙ | |||
26 27 28 29 30 31 32 | # PREFIX = x86_64-w64-mingw32- #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = src | < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # PREFIX = x86_64-w64-mingw32- #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = src #### The directory into which object code files should be written. # OBJDIR = wbld #### C compiler for use in building executables that will run on # the platform that is doing the build. This is used to compile |
︙ | ︙ | |||
52 53 54 55 56 57 58 | # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 | | > > > > | 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 | # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 #### Enable JSON (http://www.json.org) support using "cson" # # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # # FOSSIL_ENABLE_SSL = 1 #### Automatically build OpenSSL when building Fossil (causes rebuild # issues when building incrementally). # # FOSSIL_BUILD_SSL = 1 #### Enable relative paths in external diff/gdiff # # FOSSIL_ENABLE_EXEC_REL_PATHS = 1 #### Enable legacy treatment of mv/rm (skip checkout files) # FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # # FOSSIL_ENABLE_TH1_DOCS = 1 #### Enable hooks for commands and web pages via TH1 # |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | #### Use POSIX memory APIs from "sys/mman.h" # # USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to | > > > > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #### Use POSIX memory APIs from "sys/mman.h" # # USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 #### Use the miniz compression library # # FOSSIL_ENABLE_MINIZ = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to |
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ZLIBCONFIG = ZLIBTARGETS = else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support | > > > > > | | > > > > > | | 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 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ifndef FOSSIL_ENABLE_MINIZ ZLIBCONFIG = LOC="-DASMV -DASMINF" OBJA="inffas86.o match.o" ZLIBTARGETS = $(ZLIBDIR)/inffas86.o $(ZLIBDIR)/match.o else ZLIBCONFIG = ZLIBTARGETS = endif else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support # for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). # SSLCONFIG += no-ssl2 no-ssl3 no-weak-ssl-ciphers no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ SSLCONFIG += --with-zlib-lib=$(PWD)/$(ZLIBDIR) --with-zlib-include=$(PWD)/$(ZLIBDIR) zlib endif #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2p OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If |
︙ | ︙ | |||
212 213 214 215 216 217 218 | #### C compiler and options for use in building executables that will # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement | < > > > > | > > | > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | #### C compiler and options for use in building executables that will # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement #### Add the necessary command line options to build with debugging # symbols, if enabled. # ifdef FOSSIL_ENABLE_SYMBOLS TCC += -g else TCC += -Os endif #### When not using the miniz compression library, zlib is required. # ifndef FOSSIL_ENABLE_MINIZ TCC += -L$(ZLIBDIR) -I$(ZINCDIR) endif #### Compile resources for use in building executables that will run # on the target platform. # RCC = $(PREFIX)windres -I$(SRCDIR) ifndef FOSSIL_ENABLE_MINIZ RCC += -I$(ZINCDIR) endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) RCC += -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win RCC += -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With miniz (i.e. instead of zlib) ifdef FOSSIL_ENABLE_MINIZ TCC += -DFOSSIL_ENABLE_MINIZ=1 RCC += -DFOSSIL_ENABLE_MINIZ=1 endif # With MinGW command line handling workaround ifdef MINGW_IS_32BIT_ONLY TCC += -DBROKEN_MINGW_CMDLINE=1 RCC += -DBROKEN_MINGW_CMDLINE=1 endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif # With relative paths in external diff/gdiff ifdef FOSSIL_ENABLE_EXEC_REL_PATHS TCC += -DFOSSIL_ENABLE_EXEC_REL_PATHS=1 RCC += -DFOSSIL_ENABLE_EXEC_REL_PATHS=1 endif # With legacy treatment of mv/rm ifdef FOSSIL_ENABLE_LEGACY_MV_RM TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 RCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 endif # With TH1 embedded docs support ifdef FOSSIL_ENABLE_TH1_DOCS TCC += -DFOSSIL_ENABLE_TH1_DOCS=1 RCC += -DFOSSIL_ENABLE_TH1_DOCS=1 endif |
︙ | ︙ | |||
353 354 355 356 357 358 359 | #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. # LIB += -lmingwex | | > > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. # LIB += -lmingwex #### When not using the miniz compression library, zlib is required. # ifndef FOSSIL_ENABLE_MINIZ LIB += -lz endif #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_ENABLE_TCL_STUBS LIB += -lkernel32 -lws2_32 |
︙ | ︙ | |||
399 400 401 402 403 404 405 | # You should not need to change anything below this line #-------------------------------------------------------- XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) SRC = \ $(SRCDIR)/add.c \ | < < < < < < < < < < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | # You should not need to change anything below this line #-------------------------------------------------------- XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) SRC = \ $(SRCDIR)/add.c \ $(SRCDIR)/alerts.c \ $(SRCDIR)/allrepo.c \ $(SRCDIR)/attach.c \ $(SRCDIR)/backoffice.c \ $(SRCDIR)/bag.c \ $(SRCDIR)/bisect.c \ $(SRCDIR)/blob.c \ $(SRCDIR)/branch.c \ $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ $(SRCDIR)/cookies.c \ $(SRCDIR)/db.c \ $(SRCDIR)/delta.c \ $(SRCDIR)/deltacmd.c \ $(SRCDIR)/descendants.c \ $(SRCDIR)/diff.c \ $(SRCDIR)/diffcmd.c \ $(SRCDIR)/dispatch.c \ $(SRCDIR)/doc.c \ $(SRCDIR)/encode.c \ $(SRCDIR)/etag.c \ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ $(SRCDIR)/file.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ $(SRCDIR)/forum.c \ $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ $(SRCDIR)/hname.c \ $(SRCDIR)/http.c \ $(SRCDIR)/http_socket.c \ $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_config.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_dir.c \ $(SRCDIR)/json_finfo.c \ |
︙ | ︙ | |||
488 489 490 491 492 493 494 | $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ $(SRCDIR)/moderate.c \ $(SRCDIR)/name.c \ | < < < | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ $(SRCDIR)/moderate.c \ $(SRCDIR)/name.c \ $(SRCDIR)/path.c \ $(SRCDIR)/piechart.c \ $(SRCDIR)/pivot.c \ $(SRCDIR)/popen.c \ $(SRCDIR)/pqueue.c \ $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ |
︙ | ︙ | |||
523 524 525 526 527 528 529 | $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ | < > > < | < > > > > > | | | | > | | | | > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ $(SRCDIR)/th_main.c \ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/unicode.c \ $(SRCDIR)/unversioned.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/webmail.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c EXTRA_FILES = \ $(SRCDIR)/../skins/aht/details.txt \ $(SRCDIR)/../skins/ardoise/css.txt \ $(SRCDIR)/../skins/ardoise/details.txt \ $(SRCDIR)/../skins/ardoise/footer.txt \ $(SRCDIR)/../skins/ardoise/header.txt \ $(SRCDIR)/../skins/black_and_white/css.txt \ $(SRCDIR)/../skins/black_and_white/details.txt \ $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ $(SRCDIR)/../skins/blitz_no_logo/css.txt \ $(SRCDIR)/../skins/blitz_no_logo/details.txt \ $(SRCDIR)/../skins/blitz_no_logo/footer.txt \ $(SRCDIR)/../skins/blitz_no_logo/header.txt \ $(SRCDIR)/../skins/blitz_no_logo/ticket.txt \ $(SRCDIR)/../skins/bootstrap/css.txt \ $(SRCDIR)/../skins/bootstrap/details.txt \ $(SRCDIR)/../skins/bootstrap/footer.txt \ $(SRCDIR)/../skins/bootstrap/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ $(SRCDIR)/../skins/default/header.txt \ $(SRCDIR)/../skins/default/js.txt \ $(SRCDIR)/../skins/eagle/css.txt \ $(SRCDIR)/../skins/eagle/details.txt \ $(SRCDIR)/../skins/eagle/footer.txt \ $(SRCDIR)/../skins/eagle/header.txt \ $(SRCDIR)/../skins/enhanced1/css.txt \ $(SRCDIR)/../skins/enhanced1/details.txt \ $(SRCDIR)/../skins/enhanced1/footer.txt \ $(SRCDIR)/../skins/enhanced1/header.txt \ $(SRCDIR)/../skins/khaki/css.txt \ $(SRCDIR)/../skins/khaki/details.txt \ $(SRCDIR)/../skins/khaki/footer.txt \ $(SRCDIR)/../skins/khaki/header.txt \ $(SRCDIR)/../skins/original/css.txt \ $(SRCDIR)/../skins/original/details.txt \ $(SRCDIR)/../skins/original/footer.txt \ $(SRCDIR)/../skins/original/header.txt \ $(SRCDIR)/../skins/plain_gray/css.txt \ $(SRCDIR)/../skins/plain_gray/details.txt \ $(SRCDIR)/../skins/plain_gray/footer.txt \ $(SRCDIR)/../skins/plain_gray/header.txt \ $(SRCDIR)/../skins/rounded1/css.txt \ $(SRCDIR)/../skins/rounded1/details.txt \ $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/graph.js \ $(SRCDIR)/href.js \ $(SRCDIR)/login.js \ $(SRCDIR)/markdown.md \ $(SRCDIR)/menu.js \ $(SRCDIR)/sbsdiff.js \ $(SRCDIR)/scroll.js \ $(SRCDIR)/skin.js \ $(SRCDIR)/sorttable.js \ $(SRCDIR)/tree.js \ $(SRCDIR)/useredit.js \ $(SRCDIR)/wiki.wiki TRANS_SRC = \ $(OBJDIR)/add_.c \ $(OBJDIR)/alerts_.c \ $(OBJDIR)/allrepo_.c \ $(OBJDIR)/attach_.c \ $(OBJDIR)/backoffice_.c \ $(OBJDIR)/bag_.c \ $(OBJDIR)/bisect_.c \ $(OBJDIR)/blob_.c \ $(OBJDIR)/branch_.c \ $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ $(OBJDIR)/cookies_.c \ $(OBJDIR)/db_.c \ $(OBJDIR)/delta_.c \ $(OBJDIR)/deltacmd_.c \ $(OBJDIR)/descendants_.c \ $(OBJDIR)/diff_.c \ $(OBJDIR)/diffcmd_.c \ $(OBJDIR)/dispatch_.c \ $(OBJDIR)/doc_.c \ $(OBJDIR)/encode_.c \ $(OBJDIR)/etag_.c \ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ $(OBJDIR)/file_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ $(OBJDIR)/forum_.c \ $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ $(OBJDIR)/hname_.c \ $(OBJDIR)/http_.c \ $(OBJDIR)/http_socket_.c \ $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_config_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_dir_.c \ $(OBJDIR)/json_finfo_.c \ |
︙ | ︙ | |||
751 752 753 754 755 756 757 | $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ $(OBJDIR)/moderate_.c \ $(OBJDIR)/name_.c \ | < < < | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ $(OBJDIR)/moderate_.c \ $(OBJDIR)/name_.c \ $(OBJDIR)/path_.c \ $(OBJDIR)/piechart_.c \ $(OBJDIR)/pivot_.c \ $(OBJDIR)/popen_.c \ $(OBJDIR)/pqueue_.c \ $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ |
︙ | ︙ | |||
786 787 788 789 790 791 792 | $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ | < > > < < < < < < < < < < | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 | $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ $(OBJDIR)/th_main_.c \ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ $(OBJDIR)/unicode_.c \ $(OBJDIR)/unversioned_.c \ $(OBJDIR)/update_.c \ $(OBJDIR)/url_.c \ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/webmail_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ $(OBJDIR)/add.o \ $(OBJDIR)/alerts.o \ $(OBJDIR)/allrepo.o \ $(OBJDIR)/attach.o \ $(OBJDIR)/backoffice.o \ $(OBJDIR)/bag.o \ $(OBJDIR)/bisect.o \ $(OBJDIR)/blob.o \ $(OBJDIR)/branch.o \ $(OBJDIR)/browse.o \ $(OBJDIR)/builtin.o \ $(OBJDIR)/bundle.o \ $(OBJDIR)/cache.o \ $(OBJDIR)/capabilities.o \ $(OBJDIR)/captcha.o \ $(OBJDIR)/cgi.o \ $(OBJDIR)/checkin.o \ $(OBJDIR)/checkout.o \ $(OBJDIR)/clearsign.o \ $(OBJDIR)/clone.o \ $(OBJDIR)/comformat.o \ $(OBJDIR)/configure.o \ $(OBJDIR)/content.o \ $(OBJDIR)/cookies.o \ $(OBJDIR)/db.o \ $(OBJDIR)/delta.o \ $(OBJDIR)/deltacmd.o \ $(OBJDIR)/descendants.o \ $(OBJDIR)/diff.o \ $(OBJDIR)/diffcmd.o \ $(OBJDIR)/dispatch.o \ $(OBJDIR)/doc.o \ $(OBJDIR)/encode.o \ $(OBJDIR)/etag.o \ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ $(OBJDIR)/file.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ $(OBJDIR)/forum.o \ $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ $(OBJDIR)/hname.o \ $(OBJDIR)/http.o \ $(OBJDIR)/http_socket.o \ $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_config.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_dir.o \ $(OBJDIR)/json_finfo.o \ |
︙ | ︙ | |||
900 901 902 903 904 905 906 | $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ $(OBJDIR)/moderate.o \ $(OBJDIR)/name.o \ | < < < | 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 | $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ $(OBJDIR)/moderate.o \ $(OBJDIR)/name.o \ $(OBJDIR)/path.o \ $(OBJDIR)/piechart.o \ $(OBJDIR)/pivot.o \ $(OBJDIR)/popen.o \ $(OBJDIR)/pqueue.o \ $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ |
︙ | ︙ | |||
935 936 937 938 939 940 941 | $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ | < > > > > | > > | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 | $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ $(OBJDIR)/th_main.o \ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ $(OBJDIR)/unicode.o \ $(OBJDIR)/unversioned.o \ $(OBJDIR)/update.o \ $(OBJDIR)/url.o \ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/webmail.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe APPTARGETS = #### If the USE_WINDOWS variable exists, it is assumed that we are building # inside of a Windows-style shell; otherwise, it is assumed that we are # building inside of a Unix-style shell. Note that the "move" command is # broken when attempting to use it from the Windows shell via MinGW make # because the SHELL variable is only used for certain commands that are # recognized internally by make. # ifdef USE_WINDOWS TRANSLATE = $(subst /,\,$(OBJDIR)/translate.exe) MAKEHEADERS = $(subst /,\,$(OBJDIR)/makeheaders.exe) MKINDEX = $(subst /,\,$(OBJDIR)/mkindex.exe) MKBUILTIN = $(subst /,\,$(OBJDIR)/mkbuiltin.exe) MKVERSION = $(subst /,\,$(OBJDIR)/mkversion.exe) MKCSS = $(subst /,\,$(OBJDIR)/mkcss.exe) CODECHECK1 = $(subst /,\,$(OBJDIR)/codecheck1.exe) CAT = type CP = copy GREP = find MV = copy RM = del /Q MKDIR = -mkdir RMDIR = rmdir /S /Q else TRANSLATE = $(OBJDIR)/translate.exe MAKEHEADERS = $(OBJDIR)/makeheaders.exe MKINDEX = $(OBJDIR)/mkindex.exe MKBUILTIN = $(OBJDIR)/mkbuiltin.exe MKVERSION = $(OBJDIR)/mkversion.exe MKCSS = $(OBJDIR)/mkcss.exe CODECHECK1 = $(OBJDIR)/codecheck1.exe CAT = cat CP = cp GREP = grep MV = mv RM = rm -f MKDIR = -mkdir -p RMDIR = rm -rf endif all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h $(OBJDIR)/default_css.h ifdef USE_WINDOWS $(CAT) $(subst /,\,$(SRCDIR)\miniz.c) | $(GREP) "define MZ_VERSION" > $(subst /,\,$(OBJDIR)\minizver.h) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CAT) $(SRCDIR)/miniz.c | $(GREP) "define MZ_VERSION" > $(OBJDIR)/minizver.h $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) |
︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 | $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) else $(MKDIR) $(OBJDIR) endif | | | | | | | | | | > > > | | | | | | | | < < < < | < | > > > > > > | | | | | | < | | | | < | | | | > > > > > > > > > > < | | | 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) else $(MKDIR) $(OBJDIR) endif $(TRANSLATE): $(SRCDIR)/translate.c $(XBCC) -o $@ $(SRCDIR)/translate.c $(MAKEHEADERS): $(SRCDIR)/makeheaders.c $(XBCC) -o $@ $(SRCDIR)/makeheaders.c $(MKINDEX): $(SRCDIR)/mkindex.c $(XBCC) -o $@ $(SRCDIR)/mkindex.c $(MKBUILTIN): $(SRCDIR)/mkbuiltin.c $(XBCC) -o $@ $(SRCDIR)/mkbuiltin.c $(MKVERSION): $(SRCDIR)/mkversion.c $(XBCC) -o $@ $(SRCDIR)/mkversion.c $(MKCSS): $(SRCDIR)/mkcss.c $(XBCC) -o $@ $(SRCDIR)/mkcss.c $(CODECHECK1): $(SRCDIR)/codecheck1.c $(XBCC) -o $@ $(SRCDIR)/codecheck1.c # WARNING. DANGER. Running the test suite modifies the repository the # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@ $(OBJDIR)/default_css.h: $(SRCDIR)/default_css.txt $(MKCSS) $(MKCSS) $(SRCDIR)/default_css.txt $@ # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ.1 = SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_MINIZ variable may be undefined, set to 0, or # set to 1. If it is set to 1, the miniz library included in the # source tree should be used; otherwise, it should not. MINIZ_OBJ.0 = MINIZ_OBJ.1 = $(OBJDIR)/miniz.o MINIZ_OBJ. = $(MINIZ_OBJ.0) # The USE_SEE variable may be undefined, 0 or 1. If undefined or # 0, ordinary SQLite is used. If 1, then sqlite3-see.c (not part of # the source tree) is used and extra flags are provided to enable # the SQLite Encryption Extension. SQLITE3_SRC.0 = sqlite3.c SQLITE3_SRC.1 = sqlite3-see.c SQLITE3_SRC. = sqlite3.c SQLITE3_SRC = $(SRCDIR)/$(SQLITE3_SRC.$(USE_SEE)) SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) EXTRAOBJ = \ $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o $(ZLIBDIR)/inffas86.o: $(TCC) -c -o $@ -DASMINF -I$(ZLIBDIR) -O3 $(ZLIBDIR)/contrib/inflate86/inffas86.c $(ZLIBDIR)/match.o: $(TCC) -c -o $@ -DASMV $(ZLIBDIR)/contrib/asm686/match.S zlib: $(ZLIBTARGETS) $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(ZLIBCONFIG) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) -f win32/Makefile.gcc clean ifdef FOSSIL_ENABLE_MINIZ BLDTARGETS = else BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean tcl: cd $(TCLSRCDIR)/win;./configure $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(TCLTARGET) clean-tcl: $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) distclean APPTARGETS += $(BLDTARGETS) ifdef FOSSIL_BUILD_SSL APPTARGETS += openssl endif $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(CODECHECK1) $(TRANS_SRC) $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: # noop |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX) $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES) $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ | | < | | | < | | | | | | | | | | | | < | | | | < | | | | | | | < | | | | | | | | | < | < | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | > | | | | > | | | < | | | < < < < < < < < | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX) $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES) $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \ $(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \ $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \ $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \ $(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \ $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \ $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \ $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \ $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \ $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ $(OBJDIR)/cookies_.c:$(OBJDIR)/cookies.h \ $(OBJDIR)/db_.c:$(OBJDIR)/db.h \ $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h \ $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h \ $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h \ $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h \ $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h \ $(OBJDIR)/dispatch_.c:$(OBJDIR)/dispatch.h \ $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h \ $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h \ $(OBJDIR)/etag_.c:$(OBJDIR)/etag.h \ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ $(OBJDIR)/forum_.c:$(OBJDIR)/forum.h \ $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \ $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \ $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \ $(OBJDIR)/import_.c:$(OBJDIR)/import.h \ $(OBJDIR)/info_.c:$(OBJDIR)/info.h \ $(OBJDIR)/json_.c:$(OBJDIR)/json.h \ $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h \ $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h \ $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h \ $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h \ $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \ $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \ $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \ $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \ $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/loadctrl_.c:$(OBJDIR)/loadctrl.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \ $(OBJDIR)/name_.c:$(OBJDIR)/name.h \ $(OBJDIR)/path_.c:$(OBJDIR)/path.h \ $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \ $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \ $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \ $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \ $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ $(OBJDIR)/sha1hard_.c:$(OBJDIR)/sha1hard.h \ $(OBJDIR)/sha3_.c:$(OBJDIR)/sha3.h \ $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \ $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ $(OBJDIR)/smtp_.c:$(OBJDIR)/smtp.h \ $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \ $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \ $(OBJDIR)/style_.c:$(OBJDIR)/style.h \ $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \ $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \ $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \ $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ $(OBJDIR)/unversioned_.c:$(OBJDIR)/unversioned.h \ $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ $(OBJDIR)/VERSION.h echo Done >$(OBJDIR)/headers $(OBJDIR)/headers: Makefile Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/add.c >$@ $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c $(OBJDIR)/add.h: $(OBJDIR)/headers $(OBJDIR)/alerts_.c: $(SRCDIR)/alerts.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/alerts.c >$@ $(OBJDIR)/alerts.o: $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/alerts.o -c $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1360 1361 1362 1363 1364 1365 1366 | $(TRANSLATE) $(SRCDIR)/attach.c >$@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers | < < < < < < < < | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | $(TRANSLATE) $(SRCDIR)/attach.c >$@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers $(OBJDIR)/backoffice_.c: $(SRCDIR)/backoffice.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/backoffice.c >$@ $(OBJDIR)/backoffice.o: $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1464 1465 1466 1467 1468 1469 1470 | $(TRANSLATE) $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers | < < < < < < < < | 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 | $(TRANSLATE) $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 | $(TRANSLATE) $(SRCDIR)/clone.c >$@ $(OBJDIR)/clone.o: $(OBJDIR)/clone_.c $(OBJDIR)/clone.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/clone.o -c $(OBJDIR)/clone_.c $(OBJDIR)/clone.h: $(OBJDIR)/headers | < < < < < < < < | 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 | $(TRANSLATE) $(SRCDIR)/clone.c >$@ $(OBJDIR)/clone.o: $(OBJDIR)/clone_.c $(OBJDIR)/clone.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/clone.o -c $(OBJDIR)/clone_.c $(OBJDIR)/clone.h: $(OBJDIR)/headers $(OBJDIR)/comformat_.c: $(SRCDIR)/comformat.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/comformat.c >$@ $(OBJDIR)/comformat.o: $(OBJDIR)/comformat_.c $(OBJDIR)/comformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/comformat.o -c $(OBJDIR)/comformat_.c $(OBJDIR)/comformat.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1568 1569 1570 1571 1572 1573 1574 | $(TRANSLATE) $(SRCDIR)/deltacmd.c >$@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers | < < < < < < < < | 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 | $(TRANSLATE) $(SRCDIR)/deltacmd.c >$@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers $(OBJDIR)/descendants_.c: $(SRCDIR)/descendants.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/descendants.c >$@ $(OBJDIR)/descendants.o: $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/descendants.o -c $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1648 1649 1650 1651 1652 1653 1654 | $(TRANSLATE) $(SRCDIR)/export.c >$@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers | < < < < < < < < < < < < < < < < | 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 | $(TRANSLATE) $(SRCDIR)/export.c >$@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers $(OBJDIR)/file_.c: $(SRCDIR)/file.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/file.c >$@ $(OBJDIR)/file.o: $(OBJDIR)/file_.c $(OBJDIR)/file.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/file.o -c $(OBJDIR)/file_.c $(OBJDIR)/file.h: $(OBJDIR)/headers $(OBJDIR)/finfo_.c: $(SRCDIR)/finfo.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/finfo.c >$@ $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 | $(TRANSLATE) $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers | < < < < < < < < | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | $(TRANSLATE) $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/glob.c >$@ $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c $(OBJDIR)/glob.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1752 1753 1754 1755 1756 1757 1758 | $(TRANSLATE) $(SRCDIR)/hname.c >$@ $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c $(OBJDIR)/hname.h: $(OBJDIR)/headers | < < < < < < < < | 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | $(TRANSLATE) $(SRCDIR)/hname.c >$@ $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c $(OBJDIR)/hname.h: $(OBJDIR)/headers $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/http.c >$@ $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/http.o -c $(OBJDIR)/http_.c $(OBJDIR)/http.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 | $(TRANSLATE) $(SRCDIR)/info.c >$@ $(OBJDIR)/info.o: $(OBJDIR)/info_.c $(OBJDIR)/info.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/info.o -c $(OBJDIR)/info_.c $(OBJDIR)/info.h: $(OBJDIR)/headers | < < < < < < < < | 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 | $(TRANSLATE) $(SRCDIR)/info.c >$@ $(OBJDIR)/info.o: $(OBJDIR)/info_.c $(OBJDIR)/info.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/info.o -c $(OBJDIR)/info_.c $(OBJDIR)/info.h: $(OBJDIR)/headers $(OBJDIR)/json_.c: $(SRCDIR)/json.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/json.c >$@ $(OBJDIR)/json.o: $(OBJDIR)/json_.c $(OBJDIR)/json.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json.o -c $(OBJDIR)/json_.c $(OBJDIR)/json.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2040 2041 2042 2043 2044 2045 2046 | $(TRANSLATE) $(SRCDIR)/name.c >$@ $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c $(OBJDIR)/name.h: $(OBJDIR)/headers | < < < < < < < < < < < < < < < < | 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 | $(TRANSLATE) $(SRCDIR)/name.c >$@ $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c $(OBJDIR)/name.h: $(OBJDIR)/headers $(OBJDIR)/path_.c: $(SRCDIR)/path.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/path.c >$@ $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c $(OBJDIR)/path.h: $(OBJDIR)/headers $(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/piechart.c >$@ $(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h: $(OBJDIR)/headers $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/pivot.c >$@ $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2136 2137 2138 2139 2140 2141 2142 | $(TRANSLATE) $(SRCDIR)/regexp.c >$@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers | < < < < < < < < | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 | $(TRANSLATE) $(SRCDIR)/regexp.c >$@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2291 2292 2293 2294 2295 2296 2297 | $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h: $(OBJDIR)/headers $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/style.c >$@ | | | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 | $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h: $(OBJDIR)/headers $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/style.c >$@ $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(OBJDIR)/default_css.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/style.o -c $(OBJDIR)/style_.c $(OBJDIR)/style.h: $(OBJDIR)/headers $(OBJDIR)/sync_.c: $(SRCDIR)/sync.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/sync.c >$@ |
︙ | ︙ | |||
2320 2321 2322 2323 2324 2325 2326 | $(TRANSLATE) $(SRCDIR)/tar.c >$@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers | < < < < < < < < | 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 | $(TRANSLATE) $(SRCDIR)/tar.c >$@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers $(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/th_main.c >$@ $(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/th_main.o -c $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 | $(OBJDIR)/vfile_.c: $(SRCDIR)/vfile.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/vfile.c >$@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wiki.o -c $(OBJDIR)/wiki_.c | > > > > > > > > | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 | $(OBJDIR)/vfile_.c: $(SRCDIR)/vfile.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/vfile.c >$@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers $(OBJDIR)/webmail_.c: $(SRCDIR)/webmail.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/webmail.c >$@ $(OBJDIR)/webmail.o: $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/webmail.o -c $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wiki.o -c $(OBJDIR)/wiki_.c |
︙ | ︙ | |||
2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 | $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/winhttp.c >$@ $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/xfer.c >$@ $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c | > > > > > > > > | 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 | $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/winhttp.c >$@ $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers $(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wysiwyg.c >$@ $(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/xfer.c >$@ $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c |
︙ | ︙ | |||
2499 2500 2501 2502 2503 2504 2505 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers MINGW_OPTIONS = -D_HAVE__MINGW_H SQLITE_OPTIONS = -DNDEBUG=1 \ | < > > > > < < < | | | | | | > | | | | > | | | | | > | | | > | < < | | | | | | | | | | | > > | | | | | | | 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers MINGW_OPTIONS = -D_HAVE__MINGW_H SQLITE_OPTIONS = -DNDEBUG=1 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_GET_TABLE \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_HAVE_ZLIB \ -DSQLITE_INTROSPECTION_PRAGMAS \ -DSQLITE_ENABLE_DBPAGE_VTAB \ -DSQLITE_WIN32_NO_ANSI \ $(MINGW_OPTIONS) \ -DSQLITE_USE_MALLOC_H \ -DSQLITE_USE_MSIZE SHELL_OPTIONS = -DNDEBUG=1 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_GET_TABLE \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_HAVE_ZLIB \ -DSQLITE_INTROSPECTION_PRAGMAS \ -DSQLITE_ENABLE_DBPAGE_VTAB \ -Dmain=sqlite3_shell \ -DSQLITE_SHELL_IS_UTF8=1 \ -DSQLITE_OMIT_LOAD_EXTENSION=1 \ -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \ -Daccess=file_access \ -Dsystem=fossil_system \ -Dgetenv=fossil_getenv \ -Dfopen=fossil_fopen MINIZ_OPTIONS = -DMINIZ_NO_STDIO \ -DMINIZ_NO_TIME \ -DMINIZ_NO_ARCHIVE_APIS $(OBJDIR)/sqlite3.o: $(SQLITE3_SRC) $(SRCDIR)/../win/Makefile.mingw $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) \ -c $(SQLITE3_SRC) -o $@ $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@ $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h $(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) -o $@ $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $@ $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ $(OBJDIR)/miniz.o: $(SRCDIR)/miniz.c $(XTCC) $(MINIZ_OPTIONS) -c $(SRCDIR)/miniz.c -o $@ |
Changes to win/Makefile.mingw.mistachkin.
1 2 3 | #!/usr/bin/make # ############################################################################## | | | 1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/make # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using |
︙ | ︙ | |||
26 27 28 29 30 31 32 | # PREFIX = x86_64-w64-mingw32- #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = src | < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # PREFIX = x86_64-w64-mingw32- #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = src #### The directory into which object code files should be written. # OBJDIR = wbld #### C compiler for use in building executables that will run on # the platform that is doing the build. This is used to compile |
︙ | ︙ | |||
52 53 54 55 56 57 58 | # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 | | > > > > | 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 | # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 #### Enable JSON (http://www.json.org) support using "cson" # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # FOSSIL_ENABLE_SSL = 1 #### Automatically build OpenSSL when building Fossil (causes rebuild # issues when building incrementally). # # FOSSIL_BUILD_SSL = 1 #### Enable relative paths in external diff/gdiff # # FOSSIL_ENABLE_EXEC_REL_PATHS = 1 #### Enable legacy treatment of mv/rm (skip checkout files) # FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # FOSSIL_ENABLE_TH1_DOCS = 1 #### Enable hooks for commands and web pages via TH1 # |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | #### Use POSIX memory APIs from "sys/mman.h" # # USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to | > > > > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #### Use POSIX memory APIs from "sys/mman.h" # # USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 #### Use the miniz compression library # # FOSSIL_ENABLE_MINIZ = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to |
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ZLIBCONFIG = ZLIBTARGETS = else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support | > > > > > | | > > > > > | | 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 | #### Determine if the optimized assembly routines provided with zlib should be # used, taking into account whether zlib is actually enabled and the target # processor architecture. # ifndef X64 SSLCONFIG = mingw ifndef FOSSIL_ENABLE_MINIZ ZLIBCONFIG = LOC="-DASMV -DASMINF" OBJA="inffas86.o match.o" ZLIBTARGETS = $(ZLIBDIR)/inffas86.o $(ZLIBDIR)/match.o else ZLIBCONFIG = ZLIBTARGETS = endif else SSLCONFIG = mingw64 ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support # for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). # SSLCONFIG += no-ssl2 no-ssl3 no-weak-ssl-ciphers no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ SSLCONFIG += --with-zlib-lib=$(PWD)/$(ZLIBDIR) --with-zlib-include=$(PWD)/$(ZLIBDIR) zlib endif #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2p OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If |
︙ | ︙ | |||
212 213 214 215 216 217 218 | #### C compiler and options for use in building executables that will # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement | < > > > > | > > | > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | #### C compiler and options for use in building executables that will # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement #### Add the necessary command line options to build with debugging # symbols, if enabled. # ifdef FOSSIL_ENABLE_SYMBOLS TCC += -g else TCC += -Os endif #### When not using the miniz compression library, zlib is required. # ifndef FOSSIL_ENABLE_MINIZ TCC += -L$(ZLIBDIR) -I$(ZINCDIR) endif #### Compile resources for use in building executables that will run # on the target platform. # RCC = $(PREFIX)windres -I$(SRCDIR) ifndef FOSSIL_ENABLE_MINIZ RCC += -I$(ZINCDIR) endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) RCC += -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win RCC += -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With miniz (i.e. instead of zlib) ifdef FOSSIL_ENABLE_MINIZ TCC += -DFOSSIL_ENABLE_MINIZ=1 RCC += -DFOSSIL_ENABLE_MINIZ=1 endif # With MinGW command line handling workaround ifdef MINGW_IS_32BIT_ONLY TCC += -DBROKEN_MINGW_CMDLINE=1 RCC += -DBROKEN_MINGW_CMDLINE=1 endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif # With relative paths in external diff/gdiff ifdef FOSSIL_ENABLE_EXEC_REL_PATHS TCC += -DFOSSIL_ENABLE_EXEC_REL_PATHS=1 RCC += -DFOSSIL_ENABLE_EXEC_REL_PATHS=1 endif # With legacy treatment of mv/rm ifdef FOSSIL_ENABLE_LEGACY_MV_RM TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 RCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 endif # With TH1 embedded docs support ifdef FOSSIL_ENABLE_TH1_DOCS TCC += -DFOSSIL_ENABLE_TH1_DOCS=1 RCC += -DFOSSIL_ENABLE_TH1_DOCS=1 endif |
︙ | ︙ | |||
353 354 355 356 357 358 359 | #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. # LIB += -lmingwex | | > > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. # LIB += -lmingwex #### When not using the miniz compression library, zlib is required. # ifndef FOSSIL_ENABLE_MINIZ LIB += -lz endif #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_ENABLE_TCL_STUBS LIB += -lkernel32 -lws2_32 |
︙ | ︙ | |||
399 400 401 402 403 404 405 | # You should not need to change anything below this line #-------------------------------------------------------- XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) SRC = \ $(SRCDIR)/add.c \ | < < < < < < < < < < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | # You should not need to change anything below this line #-------------------------------------------------------- XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) SRC = \ $(SRCDIR)/add.c \ $(SRCDIR)/alerts.c \ $(SRCDIR)/allrepo.c \ $(SRCDIR)/attach.c \ $(SRCDIR)/backoffice.c \ $(SRCDIR)/bag.c \ $(SRCDIR)/bisect.c \ $(SRCDIR)/blob.c \ $(SRCDIR)/branch.c \ $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ $(SRCDIR)/cookies.c \ $(SRCDIR)/db.c \ $(SRCDIR)/delta.c \ $(SRCDIR)/deltacmd.c \ $(SRCDIR)/descendants.c \ $(SRCDIR)/diff.c \ $(SRCDIR)/diffcmd.c \ $(SRCDIR)/dispatch.c \ $(SRCDIR)/doc.c \ $(SRCDIR)/encode.c \ $(SRCDIR)/etag.c \ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ $(SRCDIR)/file.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ $(SRCDIR)/forum.c \ $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ $(SRCDIR)/hname.c \ $(SRCDIR)/http.c \ $(SRCDIR)/http_socket.c \ $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_config.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_dir.c \ $(SRCDIR)/json_finfo.c \ |
︙ | ︙ | |||
488 489 490 491 492 493 494 | $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ $(SRCDIR)/moderate.c \ $(SRCDIR)/name.c \ | < < < | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ $(SRCDIR)/moderate.c \ $(SRCDIR)/name.c \ $(SRCDIR)/path.c \ $(SRCDIR)/piechart.c \ $(SRCDIR)/pivot.c \ $(SRCDIR)/popen.c \ $(SRCDIR)/pqueue.c \ $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ |
︙ | ︙ | |||
523 524 525 526 527 528 529 | $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ | < > > < | < > > > > > | | | | > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ $(SRCDIR)/th_main.c \ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/unicode.c \ $(SRCDIR)/unversioned.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/webmail.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c EXTRA_FILES = \ $(SRCDIR)/../skins/aht/details.txt \ $(SRCDIR)/../skins/ardoise/css.txt \ $(SRCDIR)/../skins/ardoise/details.txt \ $(SRCDIR)/../skins/ardoise/footer.txt \ $(SRCDIR)/../skins/ardoise/header.txt \ $(SRCDIR)/../skins/black_and_white/css.txt \ $(SRCDIR)/../skins/black_and_white/details.txt \ $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ $(SRCDIR)/../skins/blitz/details.txt \ $(SRCDIR)/../skins/blitz/footer.txt \ $(SRCDIR)/../skins/blitz/header.txt \ $(SRCDIR)/../skins/blitz/ticket.txt \ $(SRCDIR)/../skins/blitz_no_logo/css.txt \ $(SRCDIR)/../skins/blitz_no_logo/details.txt \ $(SRCDIR)/../skins/blitz_no_logo/footer.txt \ $(SRCDIR)/../skins/blitz_no_logo/header.txt \ $(SRCDIR)/../skins/blitz_no_logo/ticket.txt \ $(SRCDIR)/../skins/bootstrap/css.txt \ $(SRCDIR)/../skins/bootstrap/details.txt \ $(SRCDIR)/../skins/bootstrap/footer.txt \ $(SRCDIR)/../skins/bootstrap/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ $(SRCDIR)/../skins/default/header.txt \ $(SRCDIR)/../skins/default/js.txt \ $(SRCDIR)/../skins/eagle/css.txt \ $(SRCDIR)/../skins/eagle/details.txt \ $(SRCDIR)/../skins/eagle/footer.txt \ $(SRCDIR)/../skins/eagle/header.txt \ $(SRCDIR)/../skins/enhanced1/css.txt \ $(SRCDIR)/../skins/enhanced1/details.txt \ $(SRCDIR)/../skins/enhanced1/footer.txt \ $(SRCDIR)/../skins/enhanced1/header.txt \ $(SRCDIR)/../skins/khaki/css.txt \ $(SRCDIR)/../skins/khaki/details.txt \ $(SRCDIR)/../skins/khaki/footer.txt \ $(SRCDIR)/../skins/khaki/header.txt \ $(SRCDIR)/../skins/original/css.txt \ $(SRCDIR)/../skins/original/details.txt \ $(SRCDIR)/../skins/original/footer.txt \ $(SRCDIR)/../skins/original/header.txt \ $(SRCDIR)/../skins/plain_gray/css.txt \ $(SRCDIR)/../skins/plain_gray/details.txt \ $(SRCDIR)/../skins/plain_gray/footer.txt \ $(SRCDIR)/../skins/plain_gray/header.txt \ $(SRCDIR)/../skins/rounded1/css.txt \ $(SRCDIR)/../skins/rounded1/details.txt \ $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/graph.js \ $(SRCDIR)/href.js \ $(SRCDIR)/login.js \ $(SRCDIR)/markdown.md \ $(SRCDIR)/menu.js \ $(SRCDIR)/sbsdiff.js \ $(SRCDIR)/scroll.js \ $(SRCDIR)/skin.js \ $(SRCDIR)/sorttable.js \ $(SRCDIR)/tree.js \ $(SRCDIR)/useredit.js \ $(SRCDIR)/wiki.wiki TRANS_SRC = \ $(OBJDIR)/add_.c \ $(OBJDIR)/alerts_.c \ $(OBJDIR)/allrepo_.c \ $(OBJDIR)/attach_.c \ $(OBJDIR)/backoffice_.c \ $(OBJDIR)/bag_.c \ $(OBJDIR)/bisect_.c \ $(OBJDIR)/blob_.c \ $(OBJDIR)/branch_.c \ $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ $(OBJDIR)/cookies_.c \ $(OBJDIR)/db_.c \ $(OBJDIR)/delta_.c \ $(OBJDIR)/deltacmd_.c \ $(OBJDIR)/descendants_.c \ $(OBJDIR)/diff_.c \ $(OBJDIR)/diffcmd_.c \ $(OBJDIR)/dispatch_.c \ $(OBJDIR)/doc_.c \ $(OBJDIR)/encode_.c \ $(OBJDIR)/etag_.c \ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ $(OBJDIR)/file_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ $(OBJDIR)/forum_.c \ $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ $(OBJDIR)/hname_.c \ $(OBJDIR)/http_.c \ $(OBJDIR)/http_socket_.c \ $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_config_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_dir_.c \ $(OBJDIR)/json_finfo_.c \ |
︙ | ︙ | |||
747 748 749 750 751 752 753 | $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ $(OBJDIR)/moderate_.c \ $(OBJDIR)/name_.c \ | < < < | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ $(OBJDIR)/moderate_.c \ $(OBJDIR)/name_.c \ $(OBJDIR)/path_.c \ $(OBJDIR)/piechart_.c \ $(OBJDIR)/pivot_.c \ $(OBJDIR)/popen_.c \ $(OBJDIR)/pqueue_.c \ $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ |
︙ | ︙ | |||
782 783 784 785 786 787 788 | $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ | < > > < < < < < < < < < < | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 | $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ $(OBJDIR)/th_main_.c \ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ $(OBJDIR)/unicode_.c \ $(OBJDIR)/unversioned_.c \ $(OBJDIR)/update_.c \ $(OBJDIR)/url_.c \ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/webmail_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ $(OBJDIR)/add.o \ $(OBJDIR)/alerts.o \ $(OBJDIR)/allrepo.o \ $(OBJDIR)/attach.o \ $(OBJDIR)/backoffice.o \ $(OBJDIR)/bag.o \ $(OBJDIR)/bisect.o \ $(OBJDIR)/blob.o \ $(OBJDIR)/branch.o \ $(OBJDIR)/browse.o \ $(OBJDIR)/builtin.o \ $(OBJDIR)/bundle.o \ $(OBJDIR)/cache.o \ $(OBJDIR)/capabilities.o \ $(OBJDIR)/captcha.o \ $(OBJDIR)/cgi.o \ $(OBJDIR)/checkin.o \ $(OBJDIR)/checkout.o \ $(OBJDIR)/clearsign.o \ $(OBJDIR)/clone.o \ $(OBJDIR)/comformat.o \ $(OBJDIR)/configure.o \ $(OBJDIR)/content.o \ $(OBJDIR)/cookies.o \ $(OBJDIR)/db.o \ $(OBJDIR)/delta.o \ $(OBJDIR)/deltacmd.o \ $(OBJDIR)/descendants.o \ $(OBJDIR)/diff.o \ $(OBJDIR)/diffcmd.o \ $(OBJDIR)/dispatch.o \ $(OBJDIR)/doc.o \ $(OBJDIR)/encode.o \ $(OBJDIR)/etag.o \ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ $(OBJDIR)/file.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ $(OBJDIR)/forum.o \ $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ $(OBJDIR)/hname.o \ $(OBJDIR)/http.o \ $(OBJDIR)/http_socket.o \ $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_config.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_dir.o \ $(OBJDIR)/json_finfo.o \ |
︙ | ︙ | |||
896 897 898 899 900 901 902 | $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ $(OBJDIR)/moderate.o \ $(OBJDIR)/name.o \ | < < < | 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 | $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ $(OBJDIR)/moderate.o \ $(OBJDIR)/name.o \ $(OBJDIR)/path.o \ $(OBJDIR)/piechart.o \ $(OBJDIR)/pivot.o \ $(OBJDIR)/popen.o \ $(OBJDIR)/pqueue.o \ $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ |
︙ | ︙ | |||
931 932 933 934 935 936 937 | $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ | < > > > > | > > | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 | $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ $(OBJDIR)/th_main.o \ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ $(OBJDIR)/unicode.o \ $(OBJDIR)/unversioned.o \ $(OBJDIR)/update.o \ $(OBJDIR)/url.o \ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/webmail.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe APPTARGETS = #### If the USE_WINDOWS variable exists, it is assumed that we are building # inside of a Windows-style shell; otherwise, it is assumed that we are # building inside of a Unix-style shell. Note that the "move" command is # broken when attempting to use it from the Windows shell via MinGW make # because the SHELL variable is only used for certain commands that are # recognized internally by make. # ifdef USE_WINDOWS TRANSLATE = $(subst /,\,$(OBJDIR)/translate.exe) MAKEHEADERS = $(subst /,\,$(OBJDIR)/makeheaders.exe) MKINDEX = $(subst /,\,$(OBJDIR)/mkindex.exe) MKBUILTIN = $(subst /,\,$(OBJDIR)/mkbuiltin.exe) MKVERSION = $(subst /,\,$(OBJDIR)/mkversion.exe) MKCSS = $(subst /,\,$(OBJDIR)/mkcss.exe) CODECHECK1 = $(subst /,\,$(OBJDIR)/codecheck1.exe) CAT = type CP = copy GREP = find MV = copy RM = del /Q MKDIR = -mkdir RMDIR = rmdir /S /Q else TRANSLATE = $(OBJDIR)/translate.exe MAKEHEADERS = $(OBJDIR)/makeheaders.exe MKINDEX = $(OBJDIR)/mkindex.exe MKBUILTIN = $(OBJDIR)/mkbuiltin.exe MKVERSION = $(OBJDIR)/mkversion.exe MKCSS = $(OBJDIR)/mkcss.exe CODECHECK1 = $(OBJDIR)/codecheck1.exe CAT = cat CP = cp GREP = grep MV = mv RM = rm -f MKDIR = -mkdir -p RMDIR = rm -rf endif all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h $(OBJDIR)/default_css.h ifdef USE_WINDOWS $(CAT) $(subst /,\,$(SRCDIR)\miniz.c) | $(GREP) "define MZ_VERSION" > $(subst /,\,$(OBJDIR)\minizver.h) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CAT) $(SRCDIR)/miniz.c | $(GREP) "define MZ_VERSION" > $(OBJDIR)/minizver.h $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) |
︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 | $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) else $(MKDIR) $(OBJDIR) endif | | | | | | | | | | > > > | | | | | | | | < < < < | < | > > > > > > | | | | | | < | | | | < | | | | > > > > > > > > > > < | | | 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) else $(MKDIR) $(OBJDIR) endif $(TRANSLATE): $(SRCDIR)/translate.c $(XBCC) -o $@ $(SRCDIR)/translate.c $(MAKEHEADERS): $(SRCDIR)/makeheaders.c $(XBCC) -o $@ $(SRCDIR)/makeheaders.c $(MKINDEX): $(SRCDIR)/mkindex.c $(XBCC) -o $@ $(SRCDIR)/mkindex.c $(MKBUILTIN): $(SRCDIR)/mkbuiltin.c $(XBCC) -o $@ $(SRCDIR)/mkbuiltin.c $(MKVERSION): $(SRCDIR)/mkversion.c $(XBCC) -o $@ $(SRCDIR)/mkversion.c $(MKCSS): $(SRCDIR)/mkcss.c $(XBCC) -o $@ $(SRCDIR)/mkcss.c $(CODECHECK1): $(SRCDIR)/codecheck1.c $(XBCC) -o $@ $(SRCDIR)/codecheck1.c # WARNING. DANGER. Running the test suite modifies the repository the # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@ $(OBJDIR)/default_css.h: $(SRCDIR)/default_css.txt $(MKCSS) $(MKCSS) $(SRCDIR)/default_css.txt $@ # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ.1 = SQLITE3_OBJ. = $(SQLITE3_OBJ.0) # The FOSSIL_ENABLE_MINIZ variable may be undefined, set to 0, or # set to 1. If it is set to 1, the miniz library included in the # source tree should be used; otherwise, it should not. MINIZ_OBJ.0 = MINIZ_OBJ.1 = $(OBJDIR)/miniz.o MINIZ_OBJ. = $(MINIZ_OBJ.0) # The USE_SEE variable may be undefined, 0 or 1. If undefined or # 0, ordinary SQLite is used. If 1, then sqlite3-see.c (not part of # the source tree) is used and extra flags are provided to enable # the SQLite Encryption Extension. SQLITE3_SRC.0 = sqlite3.c SQLITE3_SRC.1 = sqlite3-see.c SQLITE3_SRC. = sqlite3.c SQLITE3_SRC = $(SRCDIR)/$(SQLITE3_SRC.$(USE_SEE)) SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) EXTRAOBJ = \ $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ $(MINIZ_OBJ.$(FOSSIL_ENABLE_MINIZ)) \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o $(ZLIBDIR)/inffas86.o: $(TCC) -c -o $@ -DASMINF -I$(ZLIBDIR) -O3 $(ZLIBDIR)/contrib/inflate86/inffas86.c $(ZLIBDIR)/match.o: $(TCC) -c -o $@ -DASMV $(ZLIBDIR)/contrib/asm686/match.S zlib: $(ZLIBTARGETS) $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(ZLIBCONFIG) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) -f win32/Makefile.gcc clean ifdef FOSSIL_ENABLE_MINIZ BLDTARGETS = else BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean tcl: cd $(TCLSRCDIR)/win;./configure $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(TCLTARGET) clean-tcl: $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) distclean APPTARGETS += $(BLDTARGETS) ifdef FOSSIL_BUILD_SSL APPTARGETS += openssl endif $(APPNAME): $(APPTARGETS) $(OBJDIR)/headers $(CODECHECK1) $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(CODECHECK1) $(TRANS_SRC) $(TCC) -o $@ $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: # noop |
︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX) $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES) $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ | | < | | | < | | | | | | | | | | | | < | | | | < | | | | | | | < | | | | | | | | | < | < | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | > | | | | > | | | < | | | < < < < < < < < | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX) $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES) $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/default_css.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \ $(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \ $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \ $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \ $(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \ $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \ $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \ $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \ $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \ $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ $(OBJDIR)/cookies_.c:$(OBJDIR)/cookies.h \ $(OBJDIR)/db_.c:$(OBJDIR)/db.h \ $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h \ $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h \ $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h \ $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h \ $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h \ $(OBJDIR)/dispatch_.c:$(OBJDIR)/dispatch.h \ $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h \ $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h \ $(OBJDIR)/etag_.c:$(OBJDIR)/etag.h \ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ $(OBJDIR)/forum_.c:$(OBJDIR)/forum.h \ $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \ $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \ $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \ $(OBJDIR)/import_.c:$(OBJDIR)/import.h \ $(OBJDIR)/info_.c:$(OBJDIR)/info.h \ $(OBJDIR)/json_.c:$(OBJDIR)/json.h \ $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h \ $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h \ $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h \ $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h \ $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h \ $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h \ $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h \ $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h \ $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h \ $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/loadctrl_.c:$(OBJDIR)/loadctrl.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \ $(OBJDIR)/name_.c:$(OBJDIR)/name.h \ $(OBJDIR)/path_.c:$(OBJDIR)/path.h \ $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \ $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \ $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \ $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \ $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ $(OBJDIR)/sha1hard_.c:$(OBJDIR)/sha1hard.h \ $(OBJDIR)/sha3_.c:$(OBJDIR)/sha3.h \ $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \ $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ $(OBJDIR)/smtp_.c:$(OBJDIR)/smtp.h \ $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \ $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \ $(OBJDIR)/style_.c:$(OBJDIR)/style.h \ $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \ $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \ $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \ $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ $(OBJDIR)/unversioned_.c:$(OBJDIR)/unversioned.h \ $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ $(OBJDIR)/VERSION.h echo Done >$(OBJDIR)/headers $(OBJDIR)/headers: Makefile Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/add.c >$@ $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c $(OBJDIR)/add.h: $(OBJDIR)/headers $(OBJDIR)/alerts_.c: $(SRCDIR)/alerts.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/alerts.c >$@ $(OBJDIR)/alerts.o: $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/alerts.o -c $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 | $(TRANSLATE) $(SRCDIR)/attach.c >$@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers | < < < < < < < < | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | $(TRANSLATE) $(SRCDIR)/attach.c >$@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers $(OBJDIR)/backoffice_.c: $(SRCDIR)/backoffice.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/backoffice.c >$@ $(OBJDIR)/backoffice.o: $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1460 1461 1462 1463 1464 1465 1466 | $(TRANSLATE) $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers | < < < < < < < < | 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 | $(TRANSLATE) $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1500 1501 1502 1503 1504 1505 1506 | $(TRANSLATE) $(SRCDIR)/clone.c >$@ $(OBJDIR)/clone.o: $(OBJDIR)/clone_.c $(OBJDIR)/clone.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/clone.o -c $(OBJDIR)/clone_.c $(OBJDIR)/clone.h: $(OBJDIR)/headers | < < < < < < < < | 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 | $(TRANSLATE) $(SRCDIR)/clone.c >$@ $(OBJDIR)/clone.o: $(OBJDIR)/clone_.c $(OBJDIR)/clone.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/clone.o -c $(OBJDIR)/clone_.c $(OBJDIR)/clone.h: $(OBJDIR)/headers $(OBJDIR)/comformat_.c: $(SRCDIR)/comformat.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/comformat.c >$@ $(OBJDIR)/comformat.o: $(OBJDIR)/comformat_.c $(OBJDIR)/comformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/comformat.o -c $(OBJDIR)/comformat_.c $(OBJDIR)/comformat.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1564 1565 1566 1567 1568 1569 1570 | $(TRANSLATE) $(SRCDIR)/deltacmd.c >$@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers | < < < < < < < < | 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 | $(TRANSLATE) $(SRCDIR)/deltacmd.c >$@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers $(OBJDIR)/descendants_.c: $(SRCDIR)/descendants.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/descendants.c >$@ $(OBJDIR)/descendants.o: $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/descendants.o -c $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 | $(TRANSLATE) $(SRCDIR)/export.c >$@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers | < < < < < < < < < < < < < < < < | 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 | $(TRANSLATE) $(SRCDIR)/export.c >$@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers $(OBJDIR)/file_.c: $(SRCDIR)/file.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/file.c >$@ $(OBJDIR)/file.o: $(OBJDIR)/file_.c $(OBJDIR)/file.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/file.o -c $(OBJDIR)/file_.c $(OBJDIR)/file.h: $(OBJDIR)/headers $(OBJDIR)/finfo_.c: $(SRCDIR)/finfo.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/finfo.c >$@ $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1708 1709 1710 1711 1712 1713 1714 | $(TRANSLATE) $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers | < < < < < < < < | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | $(TRANSLATE) $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/glob.c >$@ $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c $(OBJDIR)/glob.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 | $(TRANSLATE) $(SRCDIR)/hname.c >$@ $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c $(OBJDIR)/hname.h: $(OBJDIR)/headers | < < < < < < < < | 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | $(TRANSLATE) $(SRCDIR)/hname.c >$@ $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c $(OBJDIR)/hname.h: $(OBJDIR)/headers $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/http.c >$@ $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/http.o -c $(OBJDIR)/http_.c $(OBJDIR)/http.h: $(OBJDIR)/headers |
︙ | ︙ | |||
1804 1805 1806 1807 1808 1809 1810 | $(TRANSLATE) $(SRCDIR)/info.c >$@ $(OBJDIR)/info.o: $(OBJDIR)/info_.c $(OBJDIR)/info.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/info.o -c $(OBJDIR)/info_.c $(OBJDIR)/info.h: $(OBJDIR)/headers | < < < < < < < < | 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 | $(TRANSLATE) $(SRCDIR)/info.c >$@ $(OBJDIR)/info.o: $(OBJDIR)/info_.c $(OBJDIR)/info.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/info.o -c $(OBJDIR)/info_.c $(OBJDIR)/info.h: $(OBJDIR)/headers $(OBJDIR)/json_.c: $(SRCDIR)/json.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/json.c >$@ $(OBJDIR)/json.o: $(OBJDIR)/json_.c $(OBJDIR)/json.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json.o -c $(OBJDIR)/json_.c $(OBJDIR)/json.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2036 2037 2038 2039 2040 2041 2042 | $(TRANSLATE) $(SRCDIR)/name.c >$@ $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c $(OBJDIR)/name.h: $(OBJDIR)/headers | < < < < < < < < < < < < < < < < | 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 | $(TRANSLATE) $(SRCDIR)/name.c >$@ $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c $(OBJDIR)/name.h: $(OBJDIR)/headers $(OBJDIR)/path_.c: $(SRCDIR)/path.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/path.c >$@ $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c $(OBJDIR)/path.h: $(OBJDIR)/headers $(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/piechart.c >$@ $(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h: $(OBJDIR)/headers $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/pivot.c >$@ $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2132 2133 2134 2135 2136 2137 2138 | $(TRANSLATE) $(SRCDIR)/regexp.c >$@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers | < < < < < < < < | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 | $(TRANSLATE) $(SRCDIR)/regexp.c >$@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2287 2288 2289 2290 2291 2292 2293 | $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h: $(OBJDIR)/headers $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/style.c >$@ | | | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 | $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h: $(OBJDIR)/headers $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/style.c >$@ $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(OBJDIR)/default_css.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/style.o -c $(OBJDIR)/style_.c $(OBJDIR)/style.h: $(OBJDIR)/headers $(OBJDIR)/sync_.c: $(SRCDIR)/sync.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/sync.c >$@ |
︙ | ︙ | |||
2316 2317 2318 2319 2320 2321 2322 | $(TRANSLATE) $(SRCDIR)/tar.c >$@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers | < < < < < < < < | 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 | $(TRANSLATE) $(SRCDIR)/tar.c >$@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers $(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/th_main.c >$@ $(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/th_main.o -c $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h: $(OBJDIR)/headers |
︙ | ︙ | |||
2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 | $(OBJDIR)/vfile_.c: $(SRCDIR)/vfile.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/vfile.c >$@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wiki.o -c $(OBJDIR)/wiki_.c | > > > > > > > > | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 | $(OBJDIR)/vfile_.c: $(SRCDIR)/vfile.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/vfile.c >$@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers $(OBJDIR)/webmail_.c: $(SRCDIR)/webmail.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/webmail.c >$@ $(OBJDIR)/webmail.o: $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/webmail.o -c $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wiki.o -c $(OBJDIR)/wiki_.c |
︙ | ︙ | |||
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 | $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/winhttp.c >$@ $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/xfer.c >$@ $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c | > > > > > > > > | 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 | $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/winhttp.c >$@ $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers $(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wysiwyg.c >$@ $(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/xfer.c >$@ $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c |
︙ | ︙ | |||
2495 2496 2497 2498 2499 2500 2501 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers MINGW_OPTIONS = -D_HAVE__MINGW_H SQLITE_OPTIONS = -DNDEBUG=1 \ | < > > > > > < < < | | | | | | > | | | | > | | | | > | > | | | > | < < | | | | | | | | | | | > > | | | | | | | 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers MINGW_OPTIONS = -D_HAVE__MINGW_H SQLITE_OPTIONS = -DNDEBUG=1 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_GET_TABLE \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS3_PARENTHESIS \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_HAVE_ZLIB \ -DSQLITE_INTROSPECTION_PRAGMAS \ -DSQLITE_ENABLE_DBPAGE_VTAB \ -DSQLITE_WIN32_NO_ANSI \ $(MINGW_OPTIONS) \ -DSQLITE_USE_MALLOC_H \ -DSQLITE_USE_MSIZE SHELL_OPTIONS = -DNDEBUG=1 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ -DSQLITE_OMIT_DEPRECATED \ -DSQLITE_OMIT_GET_TABLE \ -DSQLITE_OMIT_PROGRESS_CALLBACK \ -DSQLITE_OMIT_SHARED_CACHE \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_MAX_EXPR_DEPTH=0 \ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS3_PARENTHESIS \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_STMTVTAB \ -DSQLITE_HAVE_ZLIB \ -DSQLITE_INTROSPECTION_PRAGMAS \ -DSQLITE_ENABLE_DBPAGE_VTAB \ -Dmain=sqlite3_shell \ -DSQLITE_SHELL_IS_UTF8=1 \ -DSQLITE_OMIT_LOAD_EXTENSION=1 \ -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \ -Daccess=file_access \ -Dsystem=fossil_system \ -Dgetenv=fossil_getenv \ -Dfopen=fossil_fopen MINIZ_OPTIONS = -DMINIZ_NO_STDIO \ -DMINIZ_NO_TIME \ -DMINIZ_NO_ARCHIVE_APIS $(OBJDIR)/sqlite3.o: $(SQLITE3_SRC) $(SRCDIR)/../win/Makefile.mingw.mistachkin $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) \ -c $(SQLITE3_SRC) -o $@ $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@ $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h $(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw.mistachkin $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) -o $@ $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $@ $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ $(OBJDIR)/miniz.o: $(SRCDIR)/miniz.c $(XTCC) $(MINIZ_OPTIONS) -c $(SRCDIR)/miniz.c -o $@ |
Changes to win/Makefile.msc.
1 2 | # ############################################################################## | | > > > > > > > | < < < | | < < < < < < < < < < < < < < < < < | | | | < < < < < < < < | 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 | # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This Makefile will only function correctly if used from a sub-directory # that is a direct child of the top-level directory for this project. # !if !exist("..\.fossil-settings") !error "Please change the current directory to the one containing this file." !endif # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # B = .. SRCDIR = $B\src OBJDIR = . OX = . O = .obj E = .exe P = .pdb # Perl is only necessary if OpenSSL support is enabled and it must # be built from source code. The PERLDIR variable should point to # the directory containing the main Perl binary (i.e. "perl.exe"). PERLDIR = C:\Perl\bin PERL = perl.exe # Enable debugging symbols? !ifndef DEBUG DEBUG = 0 !endif # Build the OpenSSL libraries? !ifndef FOSSIL_BUILD_SSL FOSSIL_BUILD_SSL = 0 !endif # Build the included zlib library? |
︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 | FOSSIL_ENABLE_EXEC_REL_PATHS = 0 !endif # Enable the JSON API? !ifndef FOSSIL_ENABLE_JSON FOSSIL_ENABLE_JSON = 0 !endif # Enable OpenSSL support? !ifndef FOSSIL_ENABLE_SSL FOSSIL_ENABLE_SSL = 0 !endif # Enable the Tcl integration subsystem? | > > > > > > > > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | FOSSIL_ENABLE_EXEC_REL_PATHS = 0 !endif # Enable the JSON API? !ifndef FOSSIL_ENABLE_JSON FOSSIL_ENABLE_JSON = 0 !endif # Enable legacy treatment of the mv/rm commands? !ifndef FOSSIL_ENABLE_LEGACY_MV_RM FOSSIL_ENABLE_LEGACY_MV_RM = 1 !endif # Enable use of miniz instead of zlib? !ifndef FOSSIL_ENABLE_MINIZ FOSSIL_ENABLE_MINIZ = 0 !endif # Enable OpenSSL support? !ifndef FOSSIL_ENABLE_SSL FOSSIL_ENABLE_SSL = 0 !endif # Enable the Tcl integration subsystem? |
︙ | ︙ | |||
107 108 109 110 111 112 113 | # Enable support for the SQLite Encryption Extension? !ifndef USE_SEE USE_SEE = 0 !endif !if $(FOSSIL_ENABLE_SSL)!=0 | | | | | > | > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | < < | | > > > > | > | > | | | < < < < < < < | | < < < < < < < < < < < < < < < < < < < | | > | > > > > > > | > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | # Enable support for the SQLite Encryption Extension? !ifndef USE_SEE USE_SEE = 0 !endif !if $(FOSSIL_ENABLE_SSL)!=0 SSLDIR = $(B)\compat\openssl-1.0.2p SSLINCDIR = $(SSLDIR)\inc32 !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLLIBDIR = $(SSLDIR)\out32dll !else SSLLIBDIR = $(SSLDIR)\out32 !endif SSLLFLAGS = /nologo /opt:ref /debug SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib crypt32.lib !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" !message Using 'x64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. # SSLCONFIG = VC-WIN64A no-asm no-ssl2 no-ssl3 no-weak-ssl-ciphers SSLCONFIG = VC-WIN64A no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared !endif SSLSETUP = ms\do_win64a.bat !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLNMAKE = ms\ntdll.mak all !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DOPENSSL_NO_WEAK_SSL_CIPHERS !endif !elseif "$(PLATFORM)"=="ia64" !message Using 'ia64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. # SSLCONFIG = VC-WIN64I no-asm no-ssl2 no-ssl3 no-weak-ssl-ciphers SSLCONFIG = VC-WIN64I no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared !endif SSLSETUP = ms\do_win64i.bat !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLNMAKE = ms\ntdll.mak all !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DOPENSSL_NO_WEAK_SSL_CIPHERS !endif !else !message Assuming 'x86' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. # SSLCONFIG = VC-WIN32 no-asm no-ssl2 no-ssl3 no-weak-ssl-ciphers SSLCONFIG = VC-WIN32 no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared !endif SSLSETUP = ms\do_ms.bat !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLNMAKE = ms\ntdll.mak all !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DOPENSSL_NO_WEAK_SSL_CIPHERS !endif !endif !endif !if $(FOSSIL_ENABLE_TCL)!=0 TCLDIR = $(B)\compat\tcl-8.6 TCLSRCDIR = $(TCLDIR) TCLINCDIR = $(TCLSRCDIR)\generic !endif # zlib options ZINCDIR = $(B)\compat\zlib ZLIBDIR = $(B)\compat\zlib !if $(FOSSIL_DYNAMIC_BUILD)!=0 ZLIB = zdll.lib !else ZLIB = zlib.lib !endif INCL = /I. /I$(SRCDIR) /I$B\win\include !if $(FOSSIL_ENABLE_MINIZ)==0 INCL = $(INCL) /I$(ZINCDIR) !endif !if $(FOSSIL_ENABLE_SSL)!=0 INCL = $(INCL) /I$(SSLINCDIR) !endif !if $(FOSSIL_ENABLE_TCL)!=0 INCL = $(INCL) /I$(TCLINCDIR) !endif CFLAGS = /nologo LDFLAGS = !if $(FOSSIL_DYNAMIC_BUILD)!=0 LDFLAGS = $(LDFLAGS) /MANIFEST !else LDFLAGS = $(LDFLAGS) /NODEFAULTLIB:msvcrt /MANIFEST:NO !endif !if $(FOSSIL_ENABLE_WINXP)!=0 XPCFLAGS = $(XPCFLAGS) /D_WIN32_WINNT=0x0501 /D_USING_V110_SDK71_=1 CFLAGS = $(CFLAGS) $(XPCFLAGS) !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" XPLDFLAGS = $(XPLDFLAGS) /SUBSYSTEM:CONSOLE,5.02 !else XPLDFLAGS = $(XPLDFLAGS) /SUBSYSTEM:CONSOLE,5.01 !endif LDFLAGS = $(LDFLAGS) $(XPLDFLAGS) !endif !if $(FOSSIL_DYNAMIC_BUILD)!=0 !if $(DEBUG)!=0 CRTFLAGS = /MDd !else CRTFLAGS = /MD !endif !else !if $(DEBUG)!=0 CRTFLAGS = /MTd !else CRTFLAGS = /MT !endif !endif !if $(DEBUG)!=0 CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) /Od LDFLAGS = $(LDFLAGS) /DEBUG !else CFLAGS = $(CFLAGS) $(CRTFLAGS) /O2 !endif BCC = $(CC) $(CFLAGS) TCC = $(CC) /c $(CFLAGS) $(MSCDEF) $(INCL) RCC = $(RC) /D_WIN32 /D_MSC_VER $(MSCDEF) $(INCL) MTC = mt LIBS = ws2_32.lib advapi32.lib dnsapi.lib LIBDIR = !if $(FOSSIL_DYNAMIC_BUILD)!=0 TCC = $(TCC) /DFOSSIL_DYNAMIC_BUILD=1 RCC = $(RCC) /DFOSSIL_DYNAMIC_BUILD=1 !endif !if $(FOSSIL_ENABLE_MINIZ)==0 LIBS = $(LIBS) $(ZLIB) LIBDIR = $(LIBDIR) /LIBPATH:$(ZLIBDIR) !endif !if $(FOSSIL_ENABLE_MINIZ)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_MINIZ=1 RCC = $(RCC) /DFOSSIL_ENABLE_MINIZ=1 !endif !if $(FOSSIL_ENABLE_JSON)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_JSON=1 RCC = $(RCC) /DFOSSIL_ENABLE_JSON=1 !endif !if $(FOSSIL_ENABLE_SSL)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) /DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) LIBDIR = $(LIBDIR) /LIBPATH:$(SSLLIBDIR) !endif !if $(FOSSIL_ENABLE_EXEC_REL_PATHS)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_EXEC_REL_PATHS=1 RCC = $(RCC) /DFOSSIL_ENABLE_EXEC_REL_PATHS=1 !endif !if $(FOSSIL_ENABLE_LEGACY_MV_RM)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 RCC = $(RCC) /DFOSSIL_ENABLE_LEGACY_MV_RM=1 !endif !if $(FOSSIL_ENABLE_TH1_DOCS)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_TH1_DOCS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TH1_DOCS=1 !endif !if $(FOSSIL_ENABLE_TH1_HOOKS)!=0 |
︙ | ︙ | |||
296 297 298 299 300 301 302 | !if $(USE_SEE)!=0 TCC = $(TCC) /DUSE_SEE=1 RCC = $(RCC) /DUSE_SEE=1 !endif SQLITE_OPTIONS = /DNDEBUG=1 \ | < > > > > < < < > > > > < < | > > | < | | | < | | | | | | | | | | | | < | | | | < | | | | | | | < | | | | | | | | | < | < | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | > | | | | > | | | < < | < | | | | | | | | | | | | | | | < < | < < < | | | | | | < < | < | | | < < < < < | | | | | | | < < < < | | | | | | < < < | | < < < < < < < < < < | < | | < | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < | | | | < | | | < | | | | | | | | | | | | < | | | | < | | | | | | | | < | | | | | | | | | < | < | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | > | | | | > | | | < | | < < | < < < < | | < | < < < < < | < < < < | | < < < | < | | < < < < < < < < < < < < < < < < < | < | | < < < < > > | > | | | | | | < | | | < | | | | | | | | | | | | < | | | | < | | | | | | | | < | | | | | | | | | < | < | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | > | | | | > | | | > > > > > | > | | | | | | | | | > > | > | | | | | | | | | | | | | | | | < | | < < | | > > | > | | | | < | | | | | | | | < | < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | < < < < | | | | | | | | | | < < < < < < < < | | < | | | | | | | | | | > > < < | | | | | | | | | | | | | | | | | | | | < < < < < < | | | | | | | | | | | | < < | < < < < | | | | | | | < < | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < | | | < < | < < < < | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | | | | | < < | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < | | | | | | | | | | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < | | | < < | < < < < | | | < < < < < | < | | | < < | < < < < | | | | | | | | | | | | | | | | | | | < < | < < < < | | | | | | | | | | | < < < < < < | | | | < < | < < < < | | | | | | | | | | | | | < < < < < | < | | | | | | | | | | | | | | | | | < | | | < | | | | | | | | | | | | < | | | | < | | | | | | | < | | | | | | | | | < | < | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | > | | | | > | | | < | | | | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 | !if $(USE_SEE)!=0 TCC = $(TCC) /DUSE_SEE=1 RCC = $(RCC) /DUSE_SEE=1 !endif SQLITE_OPTIONS = /DNDEBUG=1 \ /DSQLITE_THREADSAFE=0 \ /DSQLITE_DEFAULT_MEMSTATUS=0 \ /DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ /DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ /DSQLITE_OMIT_DECLTYPE \ /DSQLITE_OMIT_DEPRECATED \ /DSQLITE_OMIT_GET_TABLE \ /DSQLITE_OMIT_PROGRESS_CALLBACK \ /DSQLITE_OMIT_SHARED_CACHE \ /DSQLITE_OMIT_LOAD_EXTENSION \ /DSQLITE_MAX_EXPR_DEPTH=0 \ /DSQLITE_USE_ALLOCA \ /DSQLITE_ENABLE_LOCKING_STYLE=0 \ /DSQLITE_DEFAULT_FILE_FORMAT=4 \ /DSQLITE_ENABLE_EXPLAIN_COMMENTS \ /DSQLITE_ENABLE_FTS4 \ /DSQLITE_ENABLE_DBSTAT_VTAB \ /DSQLITE_ENABLE_JSON1 \ /DSQLITE_ENABLE_FTS5 \ /DSQLITE_ENABLE_STMTVTAB \ /DSQLITE_HAVE_ZLIB \ /DSQLITE_INTROSPECTION_PRAGMAS \ /DSQLITE_ENABLE_DBPAGE_VTAB \ /DSQLITE_WIN32_NO_ANSI SHELL_OPTIONS = /DNDEBUG=1 \ /DSQLITE_THREADSAFE=0 \ /DSQLITE_DEFAULT_MEMSTATUS=0 \ /DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ /DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ /DSQLITE_OMIT_DECLTYPE \ /DSQLITE_OMIT_DEPRECATED \ /DSQLITE_OMIT_GET_TABLE \ /DSQLITE_OMIT_PROGRESS_CALLBACK \ /DSQLITE_OMIT_SHARED_CACHE \ /DSQLITE_OMIT_LOAD_EXTENSION \ /DSQLITE_MAX_EXPR_DEPTH=0 \ /DSQLITE_USE_ALLOCA \ /DSQLITE_ENABLE_LOCKING_STYLE=0 \ /DSQLITE_DEFAULT_FILE_FORMAT=4 \ /DSQLITE_ENABLE_EXPLAIN_COMMENTS \ /DSQLITE_ENABLE_FTS4 \ /DSQLITE_ENABLE_DBSTAT_VTAB \ /DSQLITE_ENABLE_JSON1 \ /DSQLITE_ENABLE_FTS5 \ /DSQLITE_ENABLE_STMTVTAB \ /DSQLITE_HAVE_ZLIB \ /DSQLITE_INTROSPECTION_PRAGMAS \ /DSQLITE_ENABLE_DBPAGE_VTAB \ /Dmain=sqlite3_shell \ /DSQLITE_SHELL_IS_UTF8=1 \ /DSQLITE_OMIT_LOAD_EXTENSION=1 \ /DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ /DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ /DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \ /Daccess=file_access \ /Dsystem=fossil_system \ /Dgetenv=fossil_getenv \ /Dfopen=fossil_fopen MINIZ_OPTIONS = /DMINIZ_NO_STDIO \ /DMINIZ_NO_TIME \ /DMINIZ_NO_ARCHIVE_APIS SRC = add_.c \ alerts_.c \ allrepo_.c \ attach_.c \ backoffice_.c \ bag_.c \ bisect_.c \ blob_.c \ branch_.c \ browse_.c \ builtin_.c \ bundle_.c \ cache_.c \ capabilities_.c \ captcha_.c \ cgi_.c \ checkin_.c \ checkout_.c \ clearsign_.c \ clone_.c \ comformat_.c \ configure_.c \ content_.c \ cookies_.c \ db_.c \ delta_.c \ deltacmd_.c \ descendants_.c \ diff_.c \ diffcmd_.c \ dispatch_.c \ doc_.c \ encode_.c \ etag_.c \ event_.c \ export_.c \ file_.c \ finfo_.c \ foci_.c \ forum_.c \ fshell_.c \ fusefs_.c \ glob_.c \ graph_.c \ gzip_.c \ hname_.c \ http_.c \ http_socket_.c \ http_ssl_.c \ http_transport_.c \ import_.c \ info_.c \ json_.c \ json_artifact_.c \ json_branch_.c \ json_config_.c \ json_diff_.c \ json_dir_.c \ json_finfo_.c \ json_login_.c \ json_query_.c \ json_report_.c \ json_status_.c \ json_tag_.c \ json_timeline_.c \ json_user_.c \ json_wiki_.c \ leaf_.c \ loadctrl_.c \ login_.c \ lookslike_.c \ main_.c \ manifest_.c \ markdown_.c \ markdown_html_.c \ md5_.c \ merge_.c \ merge3_.c \ moderate_.c \ name_.c \ path_.c \ piechart_.c \ pivot_.c \ popen_.c \ pqueue_.c \ printf_.c \ publish_.c \ purge_.c \ rebuild_.c \ regexp_.c \ report_.c \ rss_.c \ schema_.c \ search_.c \ security_audit_.c \ setup_.c \ setupuser_.c \ sha1_.c \ sha1hard_.c \ sha3_.c \ shun_.c \ sitemap_.c \ skins_.c \ smtp_.c \ sqlcmd_.c \ stash_.c \ stat_.c \ statrep_.c \ style_.c \ sync_.c \ tag_.c \ tar_.c \ th_main_.c \ timeline_.c \ tkt_.c \ tktsetup_.c \ undo_.c \ unicode_.c \ unversioned_.c \ update_.c \ url_.c \ user_.c \ utf8_.c \ util_.c \ verify_.c \ vfile_.c \ webmail_.c \ wiki_.c \ wikiformat_.c \ winfile_.c \ winhttp_.c \ wysiwyg_.c \ xfer_.c \ xfersetup_.c \ zip_.c EXTRA_FILES = $(SRCDIR)\..\skins\aht\details.txt \ $(SRCDIR)\..\skins\ardoise\css.txt \ $(SRCDIR)\..\skins\ardoise\details.txt \ $(SRCDIR)\..\skins\ardoise\footer.txt \ $(SRCDIR)\..\skins\ardoise\header.txt \ $(SRCDIR)\..\skins\black_and_white\css.txt \ $(SRCDIR)\..\skins\black_and_white\details.txt \ $(SRCDIR)\..\skins\black_and_white\footer.txt \ $(SRCDIR)\..\skins\black_and_white\header.txt \ $(SRCDIR)\..\skins\blitz\css.txt \ $(SRCDIR)\..\skins\blitz\details.txt \ $(SRCDIR)\..\skins\blitz\footer.txt \ $(SRCDIR)\..\skins\blitz\header.txt \ $(SRCDIR)\..\skins\blitz\ticket.txt \ $(SRCDIR)\..\skins\blitz_no_logo\css.txt \ $(SRCDIR)\..\skins\blitz_no_logo\details.txt \ $(SRCDIR)\..\skins\blitz_no_logo\footer.txt \ $(SRCDIR)\..\skins\blitz_no_logo\header.txt \ $(SRCDIR)\..\skins\blitz_no_logo\ticket.txt \ $(SRCDIR)\..\skins\bootstrap\css.txt \ $(SRCDIR)\..\skins\bootstrap\details.txt \ $(SRCDIR)\..\skins\bootstrap\footer.txt \ $(SRCDIR)\..\skins\bootstrap\header.txt \ $(SRCDIR)\..\skins\default\css.txt \ $(SRCDIR)\..\skins\default\details.txt \ $(SRCDIR)\..\skins\default\footer.txt \ $(SRCDIR)\..\skins\default\header.txt \ $(SRCDIR)\..\skins\default\js.txt \ $(SRCDIR)\..\skins\eagle\css.txt \ $(SRCDIR)\..\skins\eagle\details.txt \ $(SRCDIR)\..\skins\eagle\footer.txt \ $(SRCDIR)\..\skins\eagle\header.txt \ $(SRCDIR)\..\skins\enhanced1\css.txt \ $(SRCDIR)\..\skins\enhanced1\details.txt \ $(SRCDIR)\..\skins\enhanced1\footer.txt \ $(SRCDIR)\..\skins\enhanced1\header.txt \ $(SRCDIR)\..\skins\khaki\css.txt \ $(SRCDIR)\..\skins\khaki\details.txt \ $(SRCDIR)\..\skins\khaki\footer.txt \ $(SRCDIR)\..\skins\khaki\header.txt \ $(SRCDIR)\..\skins\original\css.txt \ $(SRCDIR)\..\skins\original\details.txt \ $(SRCDIR)\..\skins\original\footer.txt \ $(SRCDIR)\..\skins\original\header.txt \ $(SRCDIR)\..\skins\plain_gray\css.txt \ $(SRCDIR)\..\skins\plain_gray\details.txt \ $(SRCDIR)\..\skins\plain_gray\footer.txt \ $(SRCDIR)\..\skins\plain_gray\header.txt \ $(SRCDIR)\..\skins\rounded1\css.txt \ $(SRCDIR)\..\skins\rounded1\details.txt \ $(SRCDIR)\..\skins\rounded1\footer.txt \ $(SRCDIR)\..\skins\rounded1\header.txt \ $(SRCDIR)\..\skins\xekri\css.txt \ $(SRCDIR)\..\skins\xekri\details.txt \ $(SRCDIR)\..\skins\xekri\footer.txt \ $(SRCDIR)\..\skins\xekri\header.txt \ $(SRCDIR)\ci_edit.js \ $(SRCDIR)\diff.tcl \ $(SRCDIR)\forum.js \ $(SRCDIR)\graph.js \ $(SRCDIR)\href.js \ $(SRCDIR)\login.js \ $(SRCDIR)\markdown.md \ $(SRCDIR)\menu.js \ $(SRCDIR)\sbsdiff.js \ $(SRCDIR)\scroll.js \ $(SRCDIR)\skin.js \ $(SRCDIR)\sorttable.js \ $(SRCDIR)\tree.js \ $(SRCDIR)\useredit.js \ $(SRCDIR)\wiki.wiki OBJ = $(OX)\add$O \ $(OX)\alerts$O \ $(OX)\allrepo$O \ $(OX)\attach$O \ $(OX)\backoffice$O \ $(OX)\bag$O \ $(OX)\bisect$O \ $(OX)\blob$O \ $(OX)\branch$O \ $(OX)\browse$O \ $(OX)\builtin$O \ $(OX)\bundle$O \ $(OX)\cache$O \ $(OX)\capabilities$O \ $(OX)\captcha$O \ $(OX)\cgi$O \ $(OX)\checkin$O \ $(OX)\checkout$O \ $(OX)\clearsign$O \ $(OX)\clone$O \ $(OX)\comformat$O \ $(OX)\configure$O \ $(OX)\content$O \ $(OX)\cookies$O \ $(OX)\cson_amalgamation$O \ $(OX)\db$O \ $(OX)\delta$O \ $(OX)\deltacmd$O \ $(OX)\descendants$O \ $(OX)\diff$O \ $(OX)\diffcmd$O \ $(OX)\dispatch$O \ $(OX)\doc$O \ $(OX)\encode$O \ $(OX)\etag$O \ $(OX)\event$O \ $(OX)\export$O \ $(OX)\file$O \ $(OX)\finfo$O \ $(OX)\foci$O \ $(OX)\forum$O \ $(OX)\fshell$O \ $(OX)\fusefs$O \ $(OX)\glob$O \ $(OX)\graph$O \ $(OX)\gzip$O \ $(OX)\hname$O \ $(OX)\http$O \ $(OX)\http_socket$O \ $(OX)\http_ssl$O \ $(OX)\http_transport$O \ $(OX)\import$O \ $(OX)\info$O \ $(OX)\json$O \ $(OX)\json_artifact$O \ $(OX)\json_branch$O \ $(OX)\json_config$O \ $(OX)\json_diff$O \ $(OX)\json_dir$O \ $(OX)\json_finfo$O \ $(OX)\json_login$O \ $(OX)\json_query$O \ $(OX)\json_report$O \ $(OX)\json_status$O \ $(OX)\json_tag$O \ $(OX)\json_timeline$O \ $(OX)\json_user$O \ $(OX)\json_wiki$O \ $(OX)\leaf$O \ $(OX)\loadctrl$O \ $(OX)\login$O \ $(OX)\lookslike$O \ $(OX)\main$O \ $(OX)\manifest$O \ $(OX)\markdown$O \ $(OX)\markdown_html$O \ $(OX)\md5$O \ $(OX)\merge$O \ $(OX)\merge3$O \ $(OX)\moderate$O \ $(OX)\name$O \ $(OX)\path$O \ $(OX)\piechart$O \ $(OX)\pivot$O \ $(OX)\popen$O \ $(OX)\pqueue$O \ $(OX)\printf$O \ $(OX)\publish$O \ $(OX)\purge$O \ $(OX)\rebuild$O \ $(OX)\regexp$O \ $(OX)\report$O \ $(OX)\rss$O \ $(OX)\schema$O \ $(OX)\search$O \ $(OX)\security_audit$O \ $(OX)\setup$O \ $(OX)\setupuser$O \ $(OX)\sha1$O \ $(OX)\sha1hard$O \ $(OX)\sha3$O \ $(OX)\shell$O \ $(OX)\shun$O \ $(OX)\sitemap$O \ $(OX)\skins$O \ $(OX)\smtp$O \ $(OX)\sqlcmd$O \ $(OX)\sqlite3$O \ $(OX)\stash$O \ $(OX)\stat$O \ $(OX)\statrep$O \ $(OX)\style$O \ $(OX)\sync$O \ $(OX)\tag$O \ $(OX)\tar$O \ $(OX)\th$O \ $(OX)\th_lang$O \ $(OX)\th_main$O \ $(OX)\th_tcl$O \ $(OX)\timeline$O \ $(OX)\tkt$O \ $(OX)\tktsetup$O \ $(OX)\undo$O \ $(OX)\unicode$O \ $(OX)\unversioned$O \ $(OX)\update$O \ $(OX)\url$O \ $(OX)\user$O \ $(OX)\utf8$O \ $(OX)\util$O \ $(OX)\verify$O \ $(OX)\vfile$O \ $(OX)\webmail$O \ $(OX)\wiki$O \ $(OX)\wikiformat$O \ $(OX)\winfile$O \ $(OX)\winhttp$O \ $(OX)\wysiwyg$O \ $(OX)\xfer$O \ $(OX)\xfersetup$O \ $(OX)\zip$O \ !if $(FOSSIL_ENABLE_MINIZ)!=0 $(OX)\miniz$O \ !endif $(OX)\fossil.res APPNAME = $(OX)\fossil$(E) PDBNAME = $(OX)\fossil$(P) APPTARGETS = all: $(OX) $(APPNAME) zlib: @echo Building zlib from "$(ZLIBDIR)"... !if $(FOSSIL_ENABLE_WINXP)!=0 @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc $(ZLIB) "CC=cl $(XPCFLAGS)" "LD=link $(XPLDFLAGS)" && popd !else @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc $(ZLIB) && popd !endif !if $(FOSSIL_ENABLE_SSL)!=0 openssl: @echo Building OpenSSL from "$(SSLDIR)"... !if "$(PERLDIR)" != "" @set PATH=$(PERLDIR);$(PATH) !endif @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd !if $(FOSSIL_ENABLE_WINXP)!=0 @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) "CC=cl $(SSLCFLAGS) $(XPCFLAGS)" "LFLAGS=$(SSLLFLAGS) $(XPLDFLAGS)" && popd !else @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) "CC=cl $(SSLCFLAGS)" && popd !endif !endif !if $(FOSSIL_ENABLE_MINIZ)==0 !if $(FOSSIL_BUILD_ZLIB)!=0 APPTARGETS = $(APPTARGETS) zlib !endif !endif !if $(FOSSIL_ENABLE_SSL)!=0 !if $(FOSSIL_BUILD_SSL)!=0 APPTARGETS = $(APPTARGETS) openssl !endif !endif $(APPNAME) : $(APPTARGETS) translate$E mkindex$E codecheck1$E headers $(OBJ) $(OX)\linkopts cd $(OX) codecheck1$E $(SRC) link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts if exist $@.manifest \ $(MTC) -nologo -manifest $@.manifest -outputresource:$@;1 $(OX)\linkopts: $B\win\Makefile.msc echo $(OX)\add.obj > $@ echo $(OX)\alerts.obj >> $@ echo $(OX)\allrepo.obj >> $@ echo $(OX)\attach.obj >> $@ echo $(OX)\backoffice.obj >> $@ echo $(OX)\bag.obj >> $@ echo $(OX)\bisect.obj >> $@ echo $(OX)\blob.obj >> $@ echo $(OX)\branch.obj >> $@ echo $(OX)\browse.obj >> $@ echo $(OX)\builtin.obj >> $@ echo $(OX)\bundle.obj >> $@ echo $(OX)\cache.obj >> $@ echo $(OX)\capabilities.obj >> $@ echo $(OX)\captcha.obj >> $@ echo $(OX)\cgi.obj >> $@ echo $(OX)\checkin.obj >> $@ echo $(OX)\checkout.obj >> $@ echo $(OX)\clearsign.obj >> $@ echo $(OX)\clone.obj >> $@ echo $(OX)\comformat.obj >> $@ echo $(OX)\configure.obj >> $@ echo $(OX)\content.obj >> $@ echo $(OX)\cookies.obj >> $@ echo $(OX)\cson_amalgamation.obj >> $@ echo $(OX)\db.obj >> $@ echo $(OX)\delta.obj >> $@ echo $(OX)\deltacmd.obj >> $@ echo $(OX)\descendants.obj >> $@ echo $(OX)\diff.obj >> $@ echo $(OX)\diffcmd.obj >> $@ echo $(OX)\dispatch.obj >> $@ echo $(OX)\doc.obj >> $@ echo $(OX)\encode.obj >> $@ echo $(OX)\etag.obj >> $@ echo $(OX)\event.obj >> $@ echo $(OX)\export.obj >> $@ echo $(OX)\file.obj >> $@ echo $(OX)\finfo.obj >> $@ echo $(OX)\foci.obj >> $@ echo $(OX)\forum.obj >> $@ echo $(OX)\fshell.obj >> $@ echo $(OX)\fusefs.obj >> $@ echo $(OX)\glob.obj >> $@ echo $(OX)\graph.obj >> $@ echo $(OX)\gzip.obj >> $@ echo $(OX)\hname.obj >> $@ echo $(OX)\http.obj >> $@ echo $(OX)\http_socket.obj >> $@ echo $(OX)\http_ssl.obj >> $@ echo $(OX)\http_transport.obj >> $@ echo $(OX)\import.obj >> $@ echo $(OX)\info.obj >> $@ echo $(OX)\json.obj >> $@ echo $(OX)\json_artifact.obj >> $@ echo $(OX)\json_branch.obj >> $@ echo $(OX)\json_config.obj >> $@ echo $(OX)\json_diff.obj >> $@ echo $(OX)\json_dir.obj >> $@ echo $(OX)\json_finfo.obj >> $@ echo $(OX)\json_login.obj >> $@ echo $(OX)\json_query.obj >> $@ echo $(OX)\json_report.obj >> $@ echo $(OX)\json_status.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ echo $(OX)\leaf.obj >> $@ echo $(OX)\loadctrl.obj >> $@ echo $(OX)\login.obj >> $@ echo $(OX)\lookslike.obj >> $@ echo $(OX)\main.obj >> $@ echo $(OX)\manifest.obj >> $@ echo $(OX)\markdown.obj >> $@ echo $(OX)\markdown_html.obj >> $@ echo $(OX)\md5.obj >> $@ echo $(OX)\merge.obj >> $@ echo $(OX)\merge3.obj >> $@ echo $(OX)\moderate.obj >> $@ echo $(OX)\name.obj >> $@ echo $(OX)\path.obj >> $@ echo $(OX)\piechart.obj >> $@ echo $(OX)\pivot.obj >> $@ echo $(OX)\popen.obj >> $@ echo $(OX)\pqueue.obj >> $@ echo $(OX)\printf.obj >> $@ echo $(OX)\publish.obj >> $@ echo $(OX)\purge.obj >> $@ echo $(OX)\rebuild.obj >> $@ echo $(OX)\regexp.obj >> $@ echo $(OX)\report.obj >> $@ echo $(OX)\rss.obj >> $@ echo $(OX)\schema.obj >> $@ echo $(OX)\search.obj >> $@ echo $(OX)\security_audit.obj >> $@ echo $(OX)\setup.obj >> $@ echo $(OX)\setupuser.obj >> $@ echo $(OX)\sha1.obj >> $@ echo $(OX)\sha1hard.obj >> $@ echo $(OX)\sha3.obj >> $@ echo $(OX)\shell.obj >> $@ echo $(OX)\shun.obj >> $@ echo $(OX)\sitemap.obj >> $@ echo $(OX)\skins.obj >> $@ echo $(OX)\smtp.obj >> $@ echo $(OX)\sqlcmd.obj >> $@ echo $(OX)\sqlite3.obj >> $@ echo $(OX)\stash.obj >> $@ echo $(OX)\stat.obj >> $@ echo $(OX)\statrep.obj >> $@ echo $(OX)\style.obj >> $@ echo $(OX)\sync.obj >> $@ echo $(OX)\tag.obj >> $@ echo $(OX)\tar.obj >> $@ echo $(OX)\th.obj >> $@ echo $(OX)\th_lang.obj >> $@ echo $(OX)\th_main.obj >> $@ echo $(OX)\th_tcl.obj >> $@ echo $(OX)\timeline.obj >> $@ echo $(OX)\tkt.obj >> $@ echo $(OX)\tktsetup.obj >> $@ echo $(OX)\undo.obj >> $@ echo $(OX)\unicode.obj >> $@ echo $(OX)\unversioned.obj >> $@ echo $(OX)\update.obj >> $@ echo $(OX)\url.obj >> $@ echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\webmail.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ !if $(FOSSIL_ENABLE_MINIZ)!=0 echo $(OX)\miniz.obj >> $@ !endif echo $(LIBS) >> $@ $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkbuiltin$E: $(SRCDIR)\mkbuiltin.c $(BCC) $** mkversion$E: $(SRCDIR)\mkversion.c $(BCC) $** mkcss$E: $(SRCDIR)\mkcss.c $(BCC) $** codecheck1$E: $(SRCDIR)\codecheck1.c $(BCC) $** !if $(USE_SEE)!=0 SEE_FLAGS = /DSQLITE_HAS_CODEC=1 /DSQLITE_SHELL_DBKEY_PROC=fossil_key SQLITE3_SHELL_SRC = $(SRCDIR)\shell-see.c SQLITE3_SRC = $(SRCDIR)\sqlite3-see.c !else SEE_FLAGS = SQLITE3_SHELL_SRC = $(SRCDIR)\shell.c SQLITE3_SRC = $(SRCDIR)\sqlite3.c !endif $(OX)\shell$O : $(SQLITE3_SHELL_SRC) $B\win\Makefile.msc $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) $(OX)\sqlite3$O : $(SQLITE3_SRC) $B\win\Makefile.msc $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) $(SQLITE3_SRC) $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c $(TCC) /Fo$@ -c $** $(OX)\miniz$O : $(SRCDIR)\miniz.c $(TCC) /Fo$@ -c $(MINIZ_OPTIONS) $(SRCDIR)\miniz.c VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION $** > $@ $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c $(TCC) /Fo$@ /c $** default_css.h: mkcss$E $(SRCDIR)\default_css.txt $** $@ page_index.h: mkindex$E $(SRC) $** > $@ builtin_data.h: mkbuiltin$E $(EXTRA_FILES) mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@ clean: -del $(OX)\*.obj 2>NUL -del *.obj 2>NUL -del *_.c 2>NUL -del *.h 2>NUL -del *.ilk 2>NUL -del *.map 2>NUL -del *.res 2>NUL -del headers 2>NUL -del linkopts 2>NUL -del vc*.pdb 2>NUL realclean: clean -del $(APPNAME) 2>NUL -del $(PDBNAME) 2>NUL -del translate$E 2>NUL -del translate$P 2>NUL -del mkindex$E 2>NUL -del mkindex$P 2>NUL -del makeheaders$E 2>NUL -del makeheaders$P 2>NUL -del mkversion$E 2>NUL -del mkversion$P 2>NUL -del mkcss$E 2>NUL -del mkcss$P 2>NUL -del codecheck1$E 2>NUL -del codecheck1$P 2>NUL -del mkbuiltin$E 2>NUL -del mkbuiltin$P 2>NUL $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h $(OX)\add$O : add_.c add.h $(TCC) /Fo$@ -c add_.c add_.c : $(SRCDIR)\add.c translate$E $** > $@ $(OX)\alerts$O : alerts_.c alerts.h $(TCC) /Fo$@ -c alerts_.c alerts_.c : $(SRCDIR)\alerts.c translate$E $** > $@ $(OX)\allrepo$O : allrepo_.c allrepo.h $(TCC) /Fo$@ -c allrepo_.c allrepo_.c : $(SRCDIR)\allrepo.c translate$E $** > $@ $(OX)\attach$O : attach_.c attach.h $(TCC) /Fo$@ -c attach_.c attach_.c : $(SRCDIR)\attach.c translate$E $** > $@ $(OX)\backoffice$O : backoffice_.c backoffice.h $(TCC) /Fo$@ -c backoffice_.c backoffice_.c : $(SRCDIR)\backoffice.c translate$E $** > $@ $(OX)\bag$O : bag_.c bag.h $(TCC) /Fo$@ -c bag_.c bag_.c : $(SRCDIR)\bag.c translate$E $** > $@ $(OX)\bisect$O : bisect_.c bisect.h $(TCC) /Fo$@ -c bisect_.c bisect_.c : $(SRCDIR)\bisect.c translate$E $** > $@ $(OX)\blob$O : blob_.c blob.h $(TCC) /Fo$@ -c blob_.c blob_.c : $(SRCDIR)\blob.c translate$E $** > $@ $(OX)\branch$O : branch_.c branch.h $(TCC) /Fo$@ -c branch_.c branch_.c : $(SRCDIR)\branch.c translate$E $** > $@ $(OX)\browse$O : browse_.c browse.h $(TCC) /Fo$@ -c browse_.c browse_.c : $(SRCDIR)\browse.c translate$E $** > $@ $(OX)\builtin$O : builtin_.c builtin.h $(TCC) /Fo$@ -c builtin_.c builtin_.c : $(SRCDIR)\builtin.c translate$E $** > $@ $(OX)\bundle$O : bundle_.c bundle.h $(TCC) /Fo$@ -c bundle_.c bundle_.c : $(SRCDIR)\bundle.c translate$E $** > $@ $(OX)\cache$O : cache_.c cache.h $(TCC) /Fo$@ -c cache_.c cache_.c : $(SRCDIR)\cache.c translate$E $** > $@ $(OX)\capabilities$O : capabilities_.c capabilities.h $(TCC) /Fo$@ -c capabilities_.c capabilities_.c : $(SRCDIR)\capabilities.c translate$E $** > $@ $(OX)\captcha$O : captcha_.c captcha.h $(TCC) /Fo$@ -c captcha_.c captcha_.c : $(SRCDIR)\captcha.c translate$E $** > $@ $(OX)\cgi$O : cgi_.c cgi.h $(TCC) /Fo$@ -c cgi_.c cgi_.c : $(SRCDIR)\cgi.c translate$E $** > $@ $(OX)\checkin$O : checkin_.c checkin.h $(TCC) /Fo$@ -c checkin_.c checkin_.c : $(SRCDIR)\checkin.c translate$E $** > $@ $(OX)\checkout$O : checkout_.c checkout.h $(TCC) /Fo$@ -c checkout_.c checkout_.c : $(SRCDIR)\checkout.c translate$E $** > $@ $(OX)\clearsign$O : clearsign_.c clearsign.h $(TCC) /Fo$@ -c clearsign_.c clearsign_.c : $(SRCDIR)\clearsign.c translate$E $** > $@ $(OX)\clone$O : clone_.c clone.h $(TCC) /Fo$@ -c clone_.c clone_.c : $(SRCDIR)\clone.c translate$E $** > $@ $(OX)\comformat$O : comformat_.c comformat.h $(TCC) /Fo$@ -c comformat_.c comformat_.c : $(SRCDIR)\comformat.c translate$E $** > $@ $(OX)\configure$O : configure_.c configure.h $(TCC) /Fo$@ -c configure_.c configure_.c : $(SRCDIR)\configure.c translate$E $** > $@ $(OX)\content$O : content_.c content.h $(TCC) /Fo$@ -c content_.c content_.c : $(SRCDIR)\content.c translate$E $** > $@ $(OX)\cookies$O : cookies_.c cookies.h $(TCC) /Fo$@ -c cookies_.c cookies_.c : $(SRCDIR)\cookies.c translate$E $** > $@ $(OX)\db$O : db_.c db.h $(TCC) /Fo$@ -c db_.c db_.c : $(SRCDIR)\db.c translate$E $** > $@ $(OX)\delta$O : delta_.c delta.h $(TCC) /Fo$@ -c delta_.c delta_.c : $(SRCDIR)\delta.c translate$E $** > $@ $(OX)\deltacmd$O : deltacmd_.c deltacmd.h $(TCC) /Fo$@ -c deltacmd_.c deltacmd_.c : $(SRCDIR)\deltacmd.c translate$E $** > $@ $(OX)\descendants$O : descendants_.c descendants.h $(TCC) /Fo$@ -c descendants_.c descendants_.c : $(SRCDIR)\descendants.c translate$E $** > $@ $(OX)\diff$O : diff_.c diff.h $(TCC) /Fo$@ -c diff_.c diff_.c : $(SRCDIR)\diff.c translate$E $** > $@ $(OX)\diffcmd$O : diffcmd_.c diffcmd.h $(TCC) /Fo$@ -c diffcmd_.c diffcmd_.c : $(SRCDIR)\diffcmd.c translate$E $** > $@ $(OX)\dispatch$O : dispatch_.c dispatch.h $(TCC) /Fo$@ -c dispatch_.c dispatch_.c : $(SRCDIR)\dispatch.c translate$E $** > $@ $(OX)\doc$O : doc_.c doc.h $(TCC) /Fo$@ -c doc_.c doc_.c : $(SRCDIR)\doc.c translate$E $** > $@ $(OX)\encode$O : encode_.c encode.h $(TCC) /Fo$@ -c encode_.c encode_.c : $(SRCDIR)\encode.c translate$E $** > $@ $(OX)\etag$O : etag_.c etag.h $(TCC) /Fo$@ -c etag_.c etag_.c : $(SRCDIR)\etag.c translate$E $** > $@ $(OX)\event$O : event_.c event.h $(TCC) /Fo$@ -c event_.c event_.c : $(SRCDIR)\event.c translate$E $** > $@ $(OX)\export$O : export_.c export.h $(TCC) /Fo$@ -c export_.c export_.c : $(SRCDIR)\export.c translate$E $** > $@ $(OX)\file$O : file_.c file.h $(TCC) /Fo$@ -c file_.c file_.c : $(SRCDIR)\file.c translate$E $** > $@ $(OX)\finfo$O : finfo_.c finfo.h $(TCC) /Fo$@ -c finfo_.c finfo_.c : $(SRCDIR)\finfo.c translate$E $** > $@ $(OX)\foci$O : foci_.c foci.h $(TCC) /Fo$@ -c foci_.c foci_.c : $(SRCDIR)\foci.c translate$E $** > $@ $(OX)\forum$O : forum_.c forum.h $(TCC) /Fo$@ -c forum_.c forum_.c : $(SRCDIR)\forum.c translate$E $** > $@ $(OX)\fshell$O : fshell_.c fshell.h $(TCC) /Fo$@ -c fshell_.c fshell_.c : $(SRCDIR)\fshell.c translate$E $** > $@ $(OX)\fusefs$O : fusefs_.c fusefs.h $(TCC) /Fo$@ -c fusefs_.c fusefs_.c : $(SRCDIR)\fusefs.c translate$E $** > $@ $(OX)\glob$O : glob_.c glob.h $(TCC) /Fo$@ -c glob_.c glob_.c : $(SRCDIR)\glob.c translate$E $** > $@ $(OX)\graph$O : graph_.c graph.h $(TCC) /Fo$@ -c graph_.c graph_.c : $(SRCDIR)\graph.c translate$E $** > $@ $(OX)\gzip$O : gzip_.c gzip.h $(TCC) /Fo$@ -c gzip_.c gzip_.c : $(SRCDIR)\gzip.c translate$E $** > $@ $(OX)\hname$O : hname_.c hname.h $(TCC) /Fo$@ -c hname_.c hname_.c : $(SRCDIR)\hname.c translate$E $** > $@ $(OX)\http$O : http_.c http.h $(TCC) /Fo$@ -c http_.c http_.c : $(SRCDIR)\http.c translate$E $** > $@ $(OX)\http_socket$O : http_socket_.c http_socket.h $(TCC) /Fo$@ -c http_socket_.c http_socket_.c : $(SRCDIR)\http_socket.c translate$E $** > $@ $(OX)\http_ssl$O : http_ssl_.c http_ssl.h $(TCC) /Fo$@ -c http_ssl_.c http_ssl_.c : $(SRCDIR)\http_ssl.c translate$E $** > $@ $(OX)\http_transport$O : http_transport_.c http_transport.h $(TCC) /Fo$@ -c http_transport_.c http_transport_.c : $(SRCDIR)\http_transport.c translate$E $** > $@ $(OX)\import$O : import_.c import.h $(TCC) /Fo$@ -c import_.c import_.c : $(SRCDIR)\import.c translate$E $** > $@ $(OX)\info$O : info_.c info.h $(TCC) /Fo$@ -c info_.c info_.c : $(SRCDIR)\info.c translate$E $** > $@ $(OX)\json$O : json_.c json.h $(TCC) /Fo$@ -c json_.c json_.c : $(SRCDIR)\json.c translate$E $** > $@ $(OX)\json_artifact$O : json_artifact_.c json_artifact.h $(TCC) /Fo$@ -c json_artifact_.c json_artifact_.c : $(SRCDIR)\json_artifact.c translate$E $** > $@ $(OX)\json_branch$O : json_branch_.c json_branch.h $(TCC) /Fo$@ -c json_branch_.c json_branch_.c : $(SRCDIR)\json_branch.c translate$E $** > $@ $(OX)\json_config$O : json_config_.c json_config.h $(TCC) /Fo$@ -c json_config_.c json_config_.c : $(SRCDIR)\json_config.c translate$E $** > $@ $(OX)\json_diff$O : json_diff_.c json_diff.h $(TCC) /Fo$@ -c json_diff_.c json_diff_.c : $(SRCDIR)\json_diff.c translate$E $** > $@ $(OX)\json_dir$O : json_dir_.c json_dir.h $(TCC) /Fo$@ -c json_dir_.c json_dir_.c : $(SRCDIR)\json_dir.c translate$E $** > $@ $(OX)\json_finfo$O : json_finfo_.c json_finfo.h $(TCC) /Fo$@ -c json_finfo_.c json_finfo_.c : $(SRCDIR)\json_finfo.c translate$E $** > $@ $(OX)\json_login$O : json_login_.c json_login.h $(TCC) /Fo$@ -c json_login_.c json_login_.c : $(SRCDIR)\json_login.c translate$E $** > $@ $(OX)\json_query$O : json_query_.c json_query.h $(TCC) /Fo$@ -c json_query_.c json_query_.c : $(SRCDIR)\json_query.c translate$E $** > $@ $(OX)\json_report$O : json_report_.c json_report.h $(TCC) /Fo$@ -c json_report_.c json_report_.c : $(SRCDIR)\json_report.c translate$E $** > $@ $(OX)\json_status$O : json_status_.c json_status.h $(TCC) /Fo$@ -c json_status_.c json_status_.c : $(SRCDIR)\json_status.c translate$E $** > $@ $(OX)\json_tag$O : json_tag_.c json_tag.h $(TCC) /Fo$@ -c json_tag_.c json_tag_.c : $(SRCDIR)\json_tag.c translate$E $** > $@ $(OX)\json_timeline$O : json_timeline_.c json_timeline.h $(TCC) /Fo$@ -c json_timeline_.c json_timeline_.c : $(SRCDIR)\json_timeline.c translate$E $** > $@ $(OX)\json_user$O : json_user_.c json_user.h $(TCC) /Fo$@ -c json_user_.c json_user_.c : $(SRCDIR)\json_user.c translate$E $** > $@ $(OX)\json_wiki$O : json_wiki_.c json_wiki.h $(TCC) /Fo$@ -c json_wiki_.c json_wiki_.c : $(SRCDIR)\json_wiki.c translate$E $** > $@ $(OX)\leaf$O : leaf_.c leaf.h $(TCC) /Fo$@ -c leaf_.c leaf_.c : $(SRCDIR)\leaf.c translate$E $** > $@ $(OX)\loadctrl$O : loadctrl_.c loadctrl.h $(TCC) /Fo$@ -c loadctrl_.c loadctrl_.c : $(SRCDIR)\loadctrl.c translate$E $** > $@ $(OX)\login$O : login_.c login.h $(TCC) /Fo$@ -c login_.c login_.c : $(SRCDIR)\login.c translate$E $** > $@ $(OX)\lookslike$O : lookslike_.c lookslike.h $(TCC) /Fo$@ -c lookslike_.c lookslike_.c : $(SRCDIR)\lookslike.c translate$E $** > $@ $(OX)\main$O : main_.c main.h $(TCC) /Fo$@ -c main_.c main_.c : $(SRCDIR)\main.c translate$E $** > $@ $(OX)\manifest$O : manifest_.c manifest.h $(TCC) /Fo$@ -c manifest_.c manifest_.c : $(SRCDIR)\manifest.c translate$E $** > $@ $(OX)\markdown$O : markdown_.c markdown.h $(TCC) /Fo$@ -c markdown_.c markdown_.c : $(SRCDIR)\markdown.c translate$E $** > $@ $(OX)\markdown_html$O : markdown_html_.c markdown_html.h $(TCC) /Fo$@ -c markdown_html_.c markdown_html_.c : $(SRCDIR)\markdown_html.c translate$E $** > $@ $(OX)\md5$O : md5_.c md5.h $(TCC) /Fo$@ -c md5_.c md5_.c : $(SRCDIR)\md5.c translate$E $** > $@ $(OX)\merge$O : merge_.c merge.h $(TCC) /Fo$@ -c merge_.c merge_.c : $(SRCDIR)\merge.c translate$E $** > $@ $(OX)\merge3$O : merge3_.c merge3.h $(TCC) /Fo$@ -c merge3_.c merge3_.c : $(SRCDIR)\merge3.c translate$E $** > $@ $(OX)\moderate$O : moderate_.c moderate.h $(TCC) /Fo$@ -c moderate_.c moderate_.c : $(SRCDIR)\moderate.c translate$E $** > $@ $(OX)\name$O : name_.c name.h $(TCC) /Fo$@ -c name_.c name_.c : $(SRCDIR)\name.c translate$E $** > $@ $(OX)\path$O : path_.c path.h $(TCC) /Fo$@ -c path_.c path_.c : $(SRCDIR)\path.c translate$E $** > $@ $(OX)\piechart$O : piechart_.c piechart.h $(TCC) /Fo$@ -c piechart_.c piechart_.c : $(SRCDIR)\piechart.c translate$E $** > $@ $(OX)\pivot$O : pivot_.c pivot.h $(TCC) /Fo$@ -c pivot_.c pivot_.c : $(SRCDIR)\pivot.c translate$E $** > $@ $(OX)\popen$O : popen_.c popen.h $(TCC) /Fo$@ -c popen_.c popen_.c : $(SRCDIR)\popen.c translate$E $** > $@ $(OX)\pqueue$O : pqueue_.c pqueue.h $(TCC) /Fo$@ -c pqueue_.c pqueue_.c : $(SRCDIR)\pqueue.c translate$E $** > $@ $(OX)\printf$O : printf_.c printf.h $(TCC) /Fo$@ -c printf_.c printf_.c : $(SRCDIR)\printf.c translate$E $** > $@ $(OX)\publish$O : publish_.c publish.h $(TCC) /Fo$@ -c publish_.c publish_.c : $(SRCDIR)\publish.c translate$E $** > $@ $(OX)\purge$O : purge_.c purge.h $(TCC) /Fo$@ -c purge_.c purge_.c : $(SRCDIR)\purge.c translate$E $** > $@ $(OX)\rebuild$O : rebuild_.c rebuild.h $(TCC) /Fo$@ -c rebuild_.c rebuild_.c : $(SRCDIR)\rebuild.c translate$E $** > $@ $(OX)\regexp$O : regexp_.c regexp.h $(TCC) /Fo$@ -c regexp_.c regexp_.c : $(SRCDIR)\regexp.c translate$E $** > $@ $(OX)\report$O : report_.c report.h $(TCC) /Fo$@ -c report_.c report_.c : $(SRCDIR)\report.c translate$E $** > $@ $(OX)\rss$O : rss_.c rss.h $(TCC) /Fo$@ -c rss_.c rss_.c : $(SRCDIR)\rss.c translate$E $** > $@ $(OX)\schema$O : schema_.c schema.h $(TCC) /Fo$@ -c schema_.c schema_.c : $(SRCDIR)\schema.c translate$E $** > $@ $(OX)\search$O : search_.c search.h $(TCC) /Fo$@ -c search_.c search_.c : $(SRCDIR)\search.c translate$E $** > $@ $(OX)\security_audit$O : security_audit_.c security_audit.h $(TCC) /Fo$@ -c security_audit_.c security_audit_.c : $(SRCDIR)\security_audit.c translate$E $** > $@ $(OX)\setup$O : setup_.c setup.h $(TCC) /Fo$@ -c setup_.c setup_.c : $(SRCDIR)\setup.c translate$E $** > $@ $(OX)\setupuser$O : setupuser_.c setupuser.h $(TCC) /Fo$@ -c setupuser_.c setupuser_.c : $(SRCDIR)\setupuser.c translate$E $** > $@ $(OX)\sha1$O : sha1_.c sha1.h $(TCC) /Fo$@ -c sha1_.c sha1_.c : $(SRCDIR)\sha1.c translate$E $** > $@ $(OX)\sha1hard$O : sha1hard_.c sha1hard.h $(TCC) /Fo$@ -c sha1hard_.c sha1hard_.c : $(SRCDIR)\sha1hard.c translate$E $** > $@ $(OX)\sha3$O : sha3_.c sha3.h $(TCC) /Fo$@ -c sha3_.c sha3_.c : $(SRCDIR)\sha3.c translate$E $** > $@ $(OX)\shun$O : shun_.c shun.h $(TCC) /Fo$@ -c shun_.c shun_.c : $(SRCDIR)\shun.c translate$E $** > $@ $(OX)\sitemap$O : sitemap_.c sitemap.h $(TCC) /Fo$@ -c sitemap_.c sitemap_.c : $(SRCDIR)\sitemap.c translate$E $** > $@ $(OX)\skins$O : skins_.c skins.h $(TCC) /Fo$@ -c skins_.c skins_.c : $(SRCDIR)\skins.c translate$E $** > $@ $(OX)\smtp$O : smtp_.c smtp.h $(TCC) /Fo$@ -c smtp_.c smtp_.c : $(SRCDIR)\smtp.c translate$E $** > $@ $(OX)\sqlcmd$O : sqlcmd_.c sqlcmd.h $(TCC) /Fo$@ -c sqlcmd_.c sqlcmd_.c : $(SRCDIR)\sqlcmd.c translate$E $** > $@ $(OX)\stash$O : stash_.c stash.h $(TCC) /Fo$@ -c stash_.c stash_.c : $(SRCDIR)\stash.c translate$E $** > $@ $(OX)\stat$O : stat_.c stat.h $(TCC) /Fo$@ -c stat_.c stat_.c : $(SRCDIR)\stat.c translate$E $** > $@ $(OX)\statrep$O : statrep_.c statrep.h $(TCC) /Fo$@ -c statrep_.c statrep_.c : $(SRCDIR)\statrep.c translate$E $** > $@ $(OX)\style$O : style_.c style.h $(TCC) /Fo$@ -c style_.c style_.c : $(SRCDIR)\style.c translate$E $** > $@ $(OX)\sync$O : sync_.c sync.h $(TCC) /Fo$@ -c sync_.c sync_.c : $(SRCDIR)\sync.c translate$E $** > $@ $(OX)\tag$O : tag_.c tag.h $(TCC) /Fo$@ -c tag_.c tag_.c : $(SRCDIR)\tag.c translate$E $** > $@ $(OX)\tar$O : tar_.c tar.h $(TCC) /Fo$@ -c tar_.c tar_.c : $(SRCDIR)\tar.c translate$E $** > $@ $(OX)\th_main$O : th_main_.c th_main.h $(TCC) /Fo$@ -c th_main_.c th_main_.c : $(SRCDIR)\th_main.c translate$E $** > $@ $(OX)\timeline$O : timeline_.c timeline.h $(TCC) /Fo$@ -c timeline_.c timeline_.c : $(SRCDIR)\timeline.c translate$E $** > $@ $(OX)\tkt$O : tkt_.c tkt.h $(TCC) /Fo$@ -c tkt_.c tkt_.c : $(SRCDIR)\tkt.c translate$E $** > $@ $(OX)\tktsetup$O : tktsetup_.c tktsetup.h $(TCC) /Fo$@ -c tktsetup_.c tktsetup_.c : $(SRCDIR)\tktsetup.c translate$E $** > $@ $(OX)\undo$O : undo_.c undo.h $(TCC) /Fo$@ -c undo_.c undo_.c : $(SRCDIR)\undo.c translate$E $** > $@ $(OX)\unicode$O : unicode_.c unicode.h $(TCC) /Fo$@ -c unicode_.c unicode_.c : $(SRCDIR)\unicode.c translate$E $** > $@ $(OX)\unversioned$O : unversioned_.c unversioned.h $(TCC) /Fo$@ -c unversioned_.c unversioned_.c : $(SRCDIR)\unversioned.c translate$E $** > $@ $(OX)\update$O : update_.c update.h $(TCC) /Fo$@ -c update_.c update_.c : $(SRCDIR)\update.c translate$E $** > $@ $(OX)\url$O : url_.c url.h $(TCC) /Fo$@ -c url_.c url_.c : $(SRCDIR)\url.c translate$E $** > $@ $(OX)\user$O : user_.c user.h $(TCC) /Fo$@ -c user_.c user_.c : $(SRCDIR)\user.c translate$E $** > $@ $(OX)\utf8$O : utf8_.c utf8.h $(TCC) /Fo$@ -c utf8_.c utf8_.c : $(SRCDIR)\utf8.c translate$E $** > $@ $(OX)\util$O : util_.c util.h $(TCC) /Fo$@ -c util_.c util_.c : $(SRCDIR)\util.c translate$E $** > $@ $(OX)\verify$O : verify_.c verify.h $(TCC) /Fo$@ -c verify_.c verify_.c : $(SRCDIR)\verify.c translate$E $** > $@ $(OX)\vfile$O : vfile_.c vfile.h $(TCC) /Fo$@ -c vfile_.c vfile_.c : $(SRCDIR)\vfile.c translate$E $** > $@ $(OX)\webmail$O : webmail_.c webmail.h $(TCC) /Fo$@ -c webmail_.c webmail_.c : $(SRCDIR)\webmail.c translate$E $** > $@ $(OX)\wiki$O : wiki_.c wiki.h $(TCC) /Fo$@ -c wiki_.c wiki_.c : $(SRCDIR)\wiki.c translate$E $** > $@ $(OX)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) /Fo$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c translate$E $** > $@ $(OX)\winfile$O : winfile_.c winfile.h $(TCC) /Fo$@ -c winfile_.c winfile_.c : $(SRCDIR)\winfile.c translate$E $** > $@ $(OX)\winhttp$O : winhttp_.c winhttp.h $(TCC) /Fo$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c translate$E $** > $@ $(OX)\wysiwyg$O : wysiwyg_.c wysiwyg.h $(TCC) /Fo$@ -c wysiwyg_.c wysiwyg_.c : $(SRCDIR)\wysiwyg.c translate$E $** > $@ $(OX)\xfer$O : xfer_.c xfer.h $(TCC) /Fo$@ -c xfer_.c xfer_.c : $(SRCDIR)\xfer.c translate$E $** > $@ $(OX)\xfersetup$O : xfersetup_.c xfersetup.h $(TCC) /Fo$@ -c xfersetup_.c xfersetup_.c : $(SRCDIR)\xfersetup.c translate$E $** > $@ $(OX)\zip$O : zip_.c zip.h $(TCC) /Fo$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c translate$E $** > $@ fossil.res : $B\win\fossil.rc $(RCC) /fo $@ $** headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h makeheaders$E add_.c:add.h \ alerts_.c:alerts.h \ allrepo_.c:allrepo.h \ attach_.c:attach.h \ backoffice_.c:backoffice.h \ bag_.c:bag.h \ bisect_.c:bisect.h \ blob_.c:blob.h \ branch_.c:branch.h \ browse_.c:browse.h \ builtin_.c:builtin.h \ bundle_.c:bundle.h \ cache_.c:cache.h \ capabilities_.c:capabilities.h \ captcha_.c:captcha.h \ cgi_.c:cgi.h \ checkin_.c:checkin.h \ checkout_.c:checkout.h \ clearsign_.c:clearsign.h \ clone_.c:clone.h \ comformat_.c:comformat.h \ configure_.c:configure.h \ content_.c:content.h \ cookies_.c:cookies.h \ db_.c:db.h \ delta_.c:delta.h \ deltacmd_.c:deltacmd.h \ descendants_.c:descendants.h \ diff_.c:diff.h \ diffcmd_.c:diffcmd.h \ dispatch_.c:dispatch.h \ doc_.c:doc.h \ encode_.c:encode.h \ etag_.c:etag.h \ event_.c:event.h \ export_.c:export.h \ file_.c:file.h \ finfo_.c:finfo.h \ foci_.c:foci.h \ forum_.c:forum.h \ fshell_.c:fshell.h \ fusefs_.c:fusefs.h \ glob_.c:glob.h \ graph_.c:graph.h \ gzip_.c:gzip.h \ hname_.c:hname.h \ http_.c:http.h \ http_socket_.c:http_socket.h \ http_ssl_.c:http_ssl.h \ http_transport_.c:http_transport.h \ import_.c:import.h \ info_.c:info.h \ json_.c:json.h \ json_artifact_.c:json_artifact.h \ json_branch_.c:json_branch.h \ json_config_.c:json_config.h \ json_diff_.c:json_diff.h \ json_dir_.c:json_dir.h \ json_finfo_.c:json_finfo.h \ json_login_.c:json_login.h \ json_query_.c:json_query.h \ json_report_.c:json_report.h \ json_status_.c:json_status.h \ json_tag_.c:json_tag.h \ json_timeline_.c:json_timeline.h \ json_user_.c:json_user.h \ json_wiki_.c:json_wiki.h \ leaf_.c:leaf.h \ loadctrl_.c:loadctrl.h \ login_.c:login.h \ lookslike_.c:lookslike.h \ main_.c:main.h \ manifest_.c:manifest.h \ markdown_.c:markdown.h \ markdown_html_.c:markdown_html.h \ md5_.c:md5.h \ merge_.c:merge.h \ merge3_.c:merge3.h \ moderate_.c:moderate.h \ name_.c:name.h \ path_.c:path.h \ piechart_.c:piechart.h \ pivot_.c:pivot.h \ popen_.c:popen.h \ pqueue_.c:pqueue.h \ printf_.c:printf.h \ publish_.c:publish.h \ purge_.c:purge.h \ rebuild_.c:rebuild.h \ regexp_.c:regexp.h \ report_.c:report.h \ rss_.c:rss.h \ schema_.c:schema.h \ search_.c:search.h \ security_audit_.c:security_audit.h \ setup_.c:setup.h \ setupuser_.c:setupuser.h \ sha1_.c:sha1.h \ sha1hard_.c:sha1hard.h \ sha3_.c:sha3.h \ shun_.c:shun.h \ sitemap_.c:sitemap.h \ skins_.c:skins.h \ smtp_.c:smtp.h \ sqlcmd_.c:sqlcmd.h \ stash_.c:stash.h \ stat_.c:stat.h \ statrep_.c:statrep.h \ style_.c:style.h \ sync_.c:sync.h \ tag_.c:tag.h \ tar_.c:tar.h \ th_main_.c:th_main.h \ timeline_.c:timeline.h \ tkt_.c:tkt.h \ tktsetup_.c:tktsetup.h \ undo_.c:undo.h \ unicode_.c:unicode.h \ unversioned_.c:unversioned.h \ update_.c:update.h \ url_.c:url.h \ user_.c:user.h \ utf8_.c:utf8.h \ util_.c:util.h \ verify_.c:verify.h \ vfile_.c:vfile.h \ webmail_.c:webmail.h \ wiki_.c:wiki.h \ wikiformat_.c:wikiformat.h \ winfile_.c:winfile.h \ winhttp_.c:winhttp.h \ wysiwyg_.c:wysiwyg.h \ xfer_.c:xfer.h \ xfersetup_.c:xfersetup.h \ zip_.c:zip.h \ $(SRCDIR)\sqlite3.h \ $(SRCDIR)\th.h \ VERSION.h \ $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Changes to win/buildmsvc.bat.
1 2 3 4 5 | @ECHO OFF :: :: buildmsvc.bat -- :: | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @ECHO OFF :: :: buildmsvc.bat -- :: :: This batch file attempts to build Fossil using the latest version :: Microsoft Visual Studio installed on this machine. :: :: SETLOCAL REM SET __ECHO=ECHO REM SET __ECHO2=ECHO IF NOT DEFINED _AECHO (SET _AECHO=REM) |
︙ | ︙ | |||
33 34 35 36 37 38 39 | %_VECHO% Tools = '%TOOLS%' REM REM Visual C++ ???? REM IF DEFINED VCINSTALLDIR IF EXIST "%VCINSTALLDIR%" ( | | < < < < < < < < < < < < < < < | 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 | %_VECHO% Tools = '%TOOLS%' REM REM Visual C++ ???? REM IF DEFINED VCINSTALLDIR IF EXIST "%VCINSTALLDIR%" ( %_AECHO% Build environment appears to be setup. GOTO skip_setupVisualStudio ) REM REM Visual Studio ???? REM IF DEFINED VSVARS32 IF EXIST "%VSVARS32%" ( %_AECHO% Build environment batch file manually overridden to "%VSVARS32%"... GOTO skip_detectVisualStudio ) REM REM Visual Studio 2015 REM IF NOT DEFINED VS140COMNTOOLS GOTO skip_detectVisualStudio2015 SET VSVARS32=%VS140COMNTOOLS%\vsvars32.bat IF EXIST "%VSVARS32%" ( %_AECHO% Using Visual Studio 2015... |
︙ | ︙ | |||
197 198 199 200 201 202 203 | REM :skip_setupVisualStudio %_VECHO% VcInstallDir = '%VCINSTALLDIR%' REM REM NOTE: Attempt to create the build output directory, if necessary. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < | | < | | | | < < < | | | < | < < < < | < < < < | < < | < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 | REM :skip_setupVisualStudio %_VECHO% VcInstallDir = '%VCINSTALLDIR%' REM REM NOTE: Attempt to create the build output directory, if necessary. REM IF NOT EXIST "%ROOT%\msvcbld" ( %__ECHO% MKDIR "%ROOT%\msvcbld" IF ERRORLEVEL 1 ( ECHO Could not make directory "%ROOT%\msvcbld". GOTO errors ) ) REM REM NOTE: Attempt to change to the created build output directory so that REM the generated files will be placed there. REM %__ECHO2% PUSHD "%ROOT%\msvcbld" IF ERRORLEVEL 1 ( ECHO Could not change to directory "%ROOT%\msvcbld". GOTO errors ) REM REM NOTE: If requested, setup the build environment to refer to the Windows REM SDK v7.1A, which is required if the binaries are being built with REM Visual Studio 201x and need to work on Windows XP. REM IF DEFINED USE_V110SDK71A ( %_AECHO% Forcing use of the Windows SDK v7.1A... CALL :fn_UseV110Sdk71A ) %_VECHO% Path = '%PATH%' %_VECHO% Include = '%INCLUDE%' %_VECHO% Lib = '%LIB%' %_VECHO% NmakeArgs = '%NMAKE_ARGS%' REM REM NOTE: Attempt to execute NMAKE for the Fossil MSVC makefile, passing REM anything extra from our command line along (e.g. extra options). REM %__ECHO% nmake /f "%TOOLS%\Makefile.msc" %NMAKE_ARGS% %* IF ERRORLEVEL 1 ( GOTO errors ) REM REM NOTE: Attempt to restore the previously saved directory. REM %__ECHO2% POPD IF ERRORLEVEL 1 ( ECHO Could not restore directory. GOTO errors ) GOTO no_errors :fn_UseV110Sdk71A IF "%PROCESSOR_ARCHITECTURE%" == "x86" GOTO set_v110Sdk71A_x86 SET PFILES_SDK71A=%ProgramFiles(x86)% GOTO set_v110Sdk71A_done :set_v110Sdk71A_x86 SET PFILES_SDK71A=%ProgramFiles% :set_v110Sdk71A_done SET PATH=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Bin;%PATH% SET INCLUDE=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE% IF "%PLATFORM%" == "x64" ( SET LIB=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Lib\x64;%LIB% ) ELSE ( SET LIB=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Lib;%LIB% ) CALL :fn_UnsetVariable PFILES_SDK71A SET NMAKE_ARGS=%NMAKE_ARGS% FOSSIL_ENABLE_WINXP=1 GOTO :EOF :fn_UnsetVariable SETLOCAL SET VALUE=%1 IF DEFINED VALUE ( SET VALUE= |
︙ | ︙ | |||
357 358 359 360 361 362 363 | VERIFY > NUL GOTO :EOF :fn_SetErrorLevel VERIFY MAYBE 2> NUL GOTO :EOF | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | VERIFY > NUL GOTO :EOF :fn_SetErrorLevel VERIFY MAYBE 2> NUL GOTO :EOF :usage ECHO. ECHO Usage: %~nx0 [...] ECHO. GOTO errors :errors |
︙ | ︙ |
Changes to win/fossil.exe.manifest.
1 2 3 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | | | 1 2 3 4 5 6 7 8 9 10 11 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="fossil" type="win32" /> <description> Simple, high-reliability, distributed software configuration management system. </description> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> |
︙ | ︙ | |||
32 33 34 35 36 37 38 | xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" | | | 32 33 34 35 36 37 38 39 40 41 42 43 | xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly> |
Changes to win/fossil.rc.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # define VS_FF_NONE 0x00000000L #endif /* !defined(VS_FF_NONE) */ #include "VERSION.h" #define _RC_COMPILE_ #include "config.h" #include "sqlite3.h" #include "zlib.h" #if defined(FOSSIL_ENABLE_SSL) #include "openssl/opensslv.h" #endif /* defined(FOSSIL_ENABLE_SSL) */ #if defined(FOSSIL_ENABLE_TCL) #include "tcl.h" | > > > > > > > > > > | 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 | # define VS_FF_NONE 0x00000000L #endif /* !defined(VS_FF_NONE) */ #include "VERSION.h" #define _RC_COMPILE_ #include "config.h" #include "sqlite3.h" #if defined(FOSSIL_ENABLE_MINIZ) #if defined(__MINGW32__) #include "minizver.h" #else #define MINIZ_HEADER_FILE_ONLY #include "miniz.c" #endif /* defined(__MINGW32__) */ #else #include "zlib.h" #endif /* defined(FOSSIL_ENABLE_MINIZ) */ #if defined(FOSSIL_ENABLE_SSL) #include "openssl/opensslv.h" #endif /* defined(FOSSIL_ENABLE_SSL) */ #if defined(FOSSIL_ENABLE_TCL) #include "tcl.h" |
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | VALUE "CompilerName", COMPILER_NAME "\0" VALUE "SQLiteVersion", "SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\0" #if defined(FOSSIL_DYNAMIC_BUILD) VALUE "DynamicBuild", "Yes\0" #else VALUE "DynamicBuild", "No\0" #endif VALUE "ZlibVersion", "zlib " ZLIB_VERSION "\0" #if defined(BROKEN_MINGW_CMDLINE) VALUE "CommandLineIsUnicode", "No\0" #else VALUE "CommandLineIsUnicode", "Yes\0" #endif /* defined(BROKEN_MINGW_CMDLINE) */ #if defined(FOSSIL_ENABLE_SSL) VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0" #endif /* defined(FOSSIL_ENABLE_SSL) */ VALUE "LegacyMvRm", "Yes\0" #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) VALUE "ExecRelPaths", "Yes\0" #else VALUE "ExecRelPaths", "No\0" #endif /* defined(FOSSIL_ENABLE_EXEC_REL_PATHS) */ #if defined(FOSSIL_ENABLE_TH1_DOCS) VALUE "Th1Docs", "Yes\0" | > > > > > > > > | 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 | VALUE "CompilerName", COMPILER_NAME "\0" VALUE "SQLiteVersion", "SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\0" #if defined(FOSSIL_DYNAMIC_BUILD) VALUE "DynamicBuild", "Yes\0" #else VALUE "DynamicBuild", "No\0" #endif #if defined(FOSSIL_ENABLE_MINIZ) VALUE "MinizVersion", "miniz " MZ_VERSION "\0" #else VALUE "ZlibVersion", "zlib " ZLIB_VERSION "\0" #endif /* defined(FOSSIL_ENABLE_MINIZ) */ #if defined(BROKEN_MINGW_CMDLINE) VALUE "CommandLineIsUnicode", "No\0" #else VALUE "CommandLineIsUnicode", "Yes\0" #endif /* defined(BROKEN_MINGW_CMDLINE) */ #if defined(FOSSIL_ENABLE_SSL) VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0" #endif /* defined(FOSSIL_ENABLE_SSL) */ #if defined(FOSSIL_ENABLE_LEGACY_MV_RM) VALUE "LegacyMvRm", "Yes\0" #else VALUE "LegacyMvRm", "No\0" #endif /* defined(FOSSIL_ENABLE_LEGACY_MV_RM) */ #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) VALUE "ExecRelPaths", "Yes\0" #else VALUE "ExecRelPaths", "No\0" #endif /* defined(FOSSIL_ENABLE_EXEC_REL_PATHS) */ #if defined(FOSSIL_ENABLE_TH1_DOCS) VALUE "Th1Docs", "Yes\0" |
︙ | ︙ |
Added www/CollRev1.gif.
cannot compute difference between binary files
Added www/CollRev2.gif.
cannot compute difference between binary files
Added www/CollRev3.gif.
cannot compute difference between binary files
Added www/CollRev4.gif.
cannot compute difference between binary files
Changes to www/aboutcgi.wiki.
1 | <title>How CGI Works In Fossil</title> | < | < | < < < | | < < | | | | | | | < | < | | | | | | | | | | | | < | | < | | | | | | < | | | < | | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < < < < > | 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 | <title>How CGI Works In Fossil</title> <h2>Introduction</h2><blockquote> <p>CGI or "Common Gateway Interface" is a venerable yet reliable technique for generating dynamic web content. This article gives a quick background on how CGI works and describes how Fossil can act as a CGI service. <p>This is a "how it works" guide. If you just want to set up Fossil as a CGI server, see the [./server.wiki | Fossil Server Setup] page. </blockquote> <h2>A Quick Review Of CGI</h2><blockquote> <p> An HTTP request is a block of text that is sent by a client application (usually a web browser) and arrives at the web server over a network connection. The HTTP request contains a URL that describes the information being requested. The URL in the HTTP request is typically the same URL that appears in the URL bar at the top of the web browser that is making the request. The URL might contain a "?" character followed query parameters. The HTTP will usually also contain other information such as the name of the application that made the request, whether or not the requesting application can except a compressed reply, POST parameters from forms, and so forth. <p> The job of the web server is to interpret the HTTP request and formulate an appropriate reply. The web server is free to interpret the HTTP request in any way it wants. But most web servers follow a similar pattern, described below. (Note: details may vary from one web server to another.) <p> Suppose the URL in the HTTP request looks like this: <blockquote><b>/one/two/timeline/four</b></blockquote> Most web servers will search their content area for files that match some prefix of the URL. The search starts with <b>/one</b>, then goes to <b>/one/two</b>, then <b>/one/two/timeline</b>, and finally <b>/one/two/timeline/four</b> is checked. The search stops at the first match. <p> Suppose the first match is <b>/one/two</b>. If <b>/one/two</b> is an ordinary file in the content area, then that file is returned as static content. The "<b>/timeline/four</b>" suffix is silently ignored. <p> If <b>/one/two</b> is a CGI script (or program), then the web server executes the <b>/one/two</b> script. The output generated by the script is collected and repackaged as the HTTP reply. <p> Before executing the CGI script, the web server will set up various environment variables with information useful to the CGI script: <table border=1 cellpadding=5> <tr><th>Environment<br>Variable<th>Meaning <tr><td>GATEWAY_INTERFACE<td>Always set to "CGI/1.0" <tr><td>REQUEST_URI <td>The input URL from the HTTP request. <tr><td>SCRIPT_NAME <td>The prefix of the input URL that matches the CGI script name. In this example: "/one/two". <tr><td>PATH_INFO <td>The suffix of the URL beyond the name of the CGI script. In this example: "timeline/four". <tr><td>QUERY_STRING <td>The query string that follows the "?" in the URL, if there is one. </table> <p> There are other CGI environment variables beyond those listed above. Many Fossil servers implement the [https://www.fossil-scm.org/fossil/test_env/two/three?abc=xyz|test_env] webpage that shows some of the CGI environment variables that Fossil pays attention to. <p> In addition to setting various CGI environment variables, if the HTTP request contains POST content, then the web server relays the POST content to standard input of the CGI script. <p> In summary, the task of the CGI script is to read the various CGI environment variables and the POST content on standard input (if any), figure out an appropriate reply, then write that reply on standard output. The web server will read the output from the CGI script, reformat it into an appropriate HTTP reply, and relay the result back to the requesting application. The CGI script exits as soon as it generates a single reply. The web server will (usually) persist and handle multiple HTTP requests, but a CGI script handles just one HTTP request and then exits. <p> The above is a rough outline of how CGI works. There are many details omitted from this brief discussion. See other on-line CGI tutorials for further information. </blockquote> <h2>How Fossil Acts As A CGI Program</h2> <blockquote> An appropriate CGI script for running Fossil will look something like the following: <blockquote><pre> #!/usr/bin/fossil repository: /home/www/repos/project.fossil </pre></blockquote> The first line of the script is a "[https://en.wikipedia.org/wiki/Shebang_%28Unix%29|shebang]" that tells the operating system what program to use as the interpreter for this script. On unix, when you execute a script that starts with a shebang, the operating system runs the program identified by the shebang with a single argument that is the full pathname of the script itself. In our example, the interpreter is Fossil, and the argument might be something like "/var/www/cgi-bin/one/two" (depending on how your particular web server is configured). <p> The Fossil program that is run as the script interpreter is the same Fossil that runs when you type ordinary Fossil commands like "fossil sync" or "fossil commit". But in this case, as soon as it launches, the Fossil program recognizes that the GATEWAY_INTERFACE environment variable is set to "CGI/1.0" and it therefore knows that it is being used as CGI rather than as an ordinary command-line tool, and behaves accordingly. <p> When Fossil recognizes that it is being run as CGI, it opens and reads the file identified by its sole argument (the file named by <code>argv[1]</code>). In our example, the second line of that file tells Fossil the location of the repository it will be serving. Fossil then starts looking at the CGI environment variables to figure out what web page is being requested, generates that one web page, then exits. <p> Usually, the webpage being requested is the first term of the PATH_INFO environment variable. (Exceptions to this rule are noted in the sequel.) For our example, the first term of PATH_INFO is "timeline", which means that Fossil will generate the [/help?cmd=/timeline|/timeline] webpage. <p> With Fossil, terms of PATH_INFO beyond the webpage name are converted into the "name" query parameter. Hence, the following two URLs mean exactly the same thing to Fossil: <ol type='A'> <li> [https://www.fossil-scm.org/fossil/info/c14ecc43] <li> [https://www.fossil-scm.org/fossil/info?name=c14ecc43] </ol> In both cases, the CGI script is called "/fossil". For case (A), the PATH_INFO variable will be "info/c14ecc43" and so the "[/help?cmd=/info|/info]" webpage will be generated and the suffix of PATH_INFO will be converted into the "name" query parameter, which identifies the artifact about which information is requested. In case (B), the PATH_INFO is just "info", but the same "name" query parameter is set explicitly by the URL itself. </blockquote> <h2>Serving Multiple Fossil Repositories From One CGI Script</h2> <blockquote> The previous example showed how to serve a single Fossil repository using a single CGI script. On a website that wants to serve multiple repositories, one could simply create multiple CGI scripts, one script for each repository. But it is also possible to serve multiple Fossil repositories from a single CGI script. <p> If the CGI script for Fossil contains a "directory:" line instead of a "repository:" line, then the argument to "directory:" is the name of a directory that contains multiple repository files, each ending with ".fossil". For example: <blockquote><pre> #!/usr/bin/fossil directory: /home/www/repos </pre></blockquote> Suppose the /home/www/repos directory contains files named <b>one.fossil</b>, <b>two.fossil</b>, and <b>subdir/three.fossil</b>. Further suppose that the name of the CGI script (relative to the root of the webserver document area) is "cgis/example2". Then to see the timeline for the "three.fossil" repository, the URL would be: <blockquote> <b>http://example.com/cgis/example2/subdir/three/timeline</b> </blockquote> Here is what happens: <ol> <li> The input URI on the HTTP request is <b>/cgis/example2/subdir/three/timeline</b> <li> The web server searches prefixes of the input URI until it finds the "cgis/example2" script. The web server then sets PATH_INFO to the "subdir/three/timeline" suffix and invokes the "cgis/example2" script. <li> Fossil runs and sees the "directory:" line pointing to "/home/www/repos". Fossil then starts pulling terms off the front of the PATH_INFO looking for a repository. It first looks at "/home/www/resps/subdir.fossil" but there is no such repository. So then it looks at "/home/www/repos/subdir/three.fossil" and finds a repository. The PATH_INFO is shortened by removing "subdir/three/" leaving it at just "timeline". <li> Fossil looks at the rest of PATH_INFO to see that the webpage requested is "timeline". </ol> </blockquote> <h2>Additional Observations</h2> <blockquote><ol type="I"> <li><p> Fossil does not distinguish between the various HTTP methods (GET, PUT, DELETE, etc). Fossil figures out what it needs to do purely from the webpage term of the URI. <li><p> Fossil does not distinguish between query parameters that are part of the URI, application/x-www-form-urlencoded or multipart/form-data encoded parameter that are part of the POST content, and cookies. Each information source is seen as a space of key/value pairs which are loaded into an internal property hash table. The code that runs to generate the reply can then reference various properties values. Fossil does not care where the value of each property comes from (POST content, cookies, or query parameters) only that the property exists and has a value. <li><p> The "[/help?cmd=ui|fossil ui]" and "[/help?cmd=server|fossil server]" commands are implemented using a simple built-in web server that accepts incoming HTTP requests, translates each request into a CGI invocation, then creates a separate child Fossil process to handle each request. In other words, CGI is used internally to implement "fossil ui/server". <p> SCGI is processed using the same built-in web server, just modified to parse SCGI requests instead of HTTP requests. Each SCGI request is converted into CGI, then Fossil creates a separate child Fossil process to handle each CGI request. </ol> </blockquote> |
Changes to www/aboutdownload.wiki.
1 2 3 4 5 6 7 8 | <title>How The Fossil Download Page Works</title> <h2>1.0 Overview</h2> The [/uv/download.html|Download] page for the Fossil self-hosting repository is implemented using [./unvers.wiki|unversioned files]. The "download.html" screen itself, and the various build products are all stored as unversioned content. The download.html page | > | < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <title>How The Fossil Download Page Works</title> <h1 align="center">How The Download Page Works</h1> <h2>1.0 Overview</h2> The [/uv/download.html|Download] page for the Fossil self-hosting repository is implemented using [./unvers.wiki|unversioned files]. The "download.html" screen itself, and the various build products are all stored as unversioned content. The download.html page uses AJAX to retrieve the [/help?cmd=/juvlist|/juvlist] webpage for a list of all unversioned files. Javascript in the [/uv/download.js?mimetype=text/plain|download.js] file (which is sourced by "download.html") then figures out which unversioned files are build products and paints appropriate icons on the displayed download page. When a new version is generated, the developers use the [/help?cmd=uv|fossil uv edit] command to make minor changes to the "[/uv/download.js?mimetype=text/plain|download.js]" file so that it knows about the new version number. Then the developers run the [/help?cmd=uv|fossil uv add] command for each build product. Finally, the |
︙ | ︙ | |||
40 41 42 43 44 45 46 | Notice how the hyperlinks above use the "mimetype=text/plain" query parameter in order to display the file as plain text instead of the usual HTML or Javascript. The default mimetype for "download.html" is text/html. But because the entire page is enclosed within | | | | | | 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 | Notice how the hyperlinks above use the "mimetype=text/plain" query parameter in order to display the file as plain text instead of the usual HTML or Javascript. The default mimetype for "download.html" is text/html. But because the entire page is enclosed within <b><div class='fossil-doc' data-title='Download Page'>...</div></b> Fossil knows to add its standard header and footer information to the document, making it look just like any other page. See "[./embeddeddoc.wiki|embedded documentation]" for further details on how <div class='fossil-doc'> this works. With each new release, the "releases" variable in the javascript on the [/uv/download.js?mimetype=text/plain|download.js] page is edited (using "[/help?cmd=uv|fossil uv edit download.js]") to add details of the release. When the javascript in the "download.js" file runs, it requests a listing of all unversioned content using the /juvlist URL. ([/juvlist|sample /juvlist output]). The content of the download page is constructed by matching unversioned files against regular expressions in the "releases" variable. Build products need to be constructed on different machines. The precompiled binary for Linux is compiled on Linux, the precompiled binary for Windows is compiled on Windows10, and so forth. After a new release is tagged, the release manager goes around to each of the target platforms, checks out the release and compiles it, then runs [/help?cmd=uv|fossil uv add] for the build product followed by [/help?cmd=uv|fossil uv sync] to push the new build product to the [./selfhost.wiki|various servers]. This process is repeated for each build product. |
︙ | ︙ | |||
89 90 91 92 93 94 95 | <h2>3.0 Security</h2> Only users with the [/setup_ulist_notes|"y" permission] are allowed to push unversioned content up to the servers. Having the ability to push check-ins (the [/setup_ulist_notes|"i" permission]) is not sufficient. | | | > | | | < | 86 87 88 89 90 91 92 93 94 95 96 97 98 | <h2>3.0 Security</h2> Only users with the [/setup_ulist_notes|"y" permission] are allowed to push unversioned content up to the servers. Having the ability to push check-ins (the [/setup_ulist_notes|"i" permission]) is not sufficient. On the Fossil project there are 67 people (as of 2017-03-24) who have check-in privileges. But only 3 core developers can push unversioned content and thus change the build products on the download page. Minimizing the number of people who can change the build products helps to ensure that rogue binaries do not slip onto the download page unnoticed. |
Changes to www/adding_code.wiki.
1 2 3 4 | <title>Adding Features To Fossil</title> <h2>1.0 Introduction</h2> | | | < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <title>Adding Features To Fossil</title> <h2>1.0 Introduction</h2> This article provides a brief overview of how to write new code that extends or enhances Fossil. <h2>2.0 Programming Language</h2> Fossil is written in C-89. There are specific [./style.wiki | style guidelines] that are required for any new code that will be accepted into the Fossil core. But, of course, if you are writing an extension just for yourself, you can use any programming style you want. |
︙ | ︙ | |||
43 44 45 46 47 48 49 | write code. <h2>3.0 Adding New Source Code Files</h2> New source code files are added in the "src/" subdirectory of the Fossil source tree. Suppose one wants to add a new source code file named "xyzzy.c". The first step is to add this file to the various makefiles. | | < | < | | | | < | < | | | | | < | | | < | | | | 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 | write code. <h2>3.0 Adding New Source Code Files</h2> New source code files are added in the "src/" subdirectory of the Fossil source tree. Suppose one wants to add a new source code file named "xyzzy.c". The first step is to add this file to the various makefiles. Do so by editing the file src/makemake.tcl and adding "xyzzy" (without the final ".c") to the list of source modules at the top of that script. Save the result and then run the makemake.tcl script using a TCL interpreter. The command to run the makemake.tcl script is: <b>tclsh makemake.tcl</b> The working directory must be src/ when the command above is run. Note that TCL is not normally required to build Fossil, but it is required for this step. If you do not have a TCL interpreter on your system already, they are easy to install. A popular choice is the [http://www.activestate.com/activetcl|Active Tcl] installation from ActiveState. After the makefiles have been updated, create the xyzzy.c source file from the following template: <blockquote><verbatim> /* ** Copyright boilerplate goes here. ***************************************************** ** High-level description of what this module goes ** here. */ #include "config.h" #include "xyzzy.h" #if INTERFACE /* Exported object (structure) definitions or #defines ** go here */ #endif /* INTERFACE */ /* New code goes here */ </verbatim></blockquote> Note in particular the <b>#include "xyzzy.h"</b> line near the top. The "xyzzy.h" file is automatically generated by makeheaders. Every normal Fossil source file must have a #include at the top that imports its private header file. (Some source files, such as "sqlite3.c" are exceptions to this rule. Don't worry about those exceptions. The files you write will require this #include line.) The "#if INTERFACE ... #endif" section is optional and is only needed if there are structure definitions or typedefs or macros that need to be used by other source code files. The makeheaders preprocessor uses definitions in the INTERFACE section to help it generate header files. See [../src/makeheaders.html | makeheaders.html] for additional information. After creating a template file such as shown above, and after updating the makefiles, you should be able to recompile Fossil and have it include your new source file, even before you source file contains any code. It is recommended that you try this. Be sure to [/help/add|fossil add] your new source file to the self-hosting Fossil repository and then [/help/commit|commit] your changes! <h2>4.0 Creating A New Command</h2> By "commands" we mean the keywords that follow "fossil" when invoking Fossil from the command-line. So, for example, in <b>fossil diff xyzzy.c</b> The "command" is "diff". Commands may optionally be followed by arguments and/or options. To create new commands in Fossil, add code (either to an existing source file, or to a new source file created as described above) according to the following template: <blockquote><verbatim> /* ** COMMAND: xyzzy ** ** Help text goes here. */ void xyzzy_cmd(void){ /* Implement the command here */ fossil_print("Hello, World!\n"); } </verbatim></blockquote> The example above creates a new command named "xyzzy" that prints the message "Hello, World!" on the console. This command is a normal command that will show up in the list of command from [/help/help|fossil help]. If you add an asterisk to the end of the command name, like this: <blockquote><verbatim> ** COMMAND: xyzzy* </verbatim></blockquote> Then the command will only show up if you add the "--all" option to [/help/help|fossil help]. Or, if the command name starts with "test" then the command will be considered experimental and will only show up when the --test option is used with [/help/help|fossil help]. The example above is a fully functioning Fossil command. You can add the text shown to an existing Fossil source file, recompiling then test it out by typing: <b>./fossil xyzzy<br> ./fossil help xyzzy<br> ./fossil xyzzy --help</b> The name of the C function that implements the command can be anything you like (as long as it does not collide with some other symbol in the Fossil code) but it is traditional to name the function "<i>commandname</i><b>_cmd</b>", as is done in the example. You could also use "printf()" instead of "fossil_print()" to generate the output text, if desired. But "fossil_print()" is recommended as it has extra logic to insert \r characters at the right times on Windows systems. Once you have the command running, you can then start adding code to make it do useful things. There are lots of utility functions in Fossil for parsing command-line options and for opening and accessing and manipulating the repository and the working check-out. Study implementations of existing commands to get an idea of how things are done. You can easily find the implementations of existing commands by searching for "COMMAND: <i>name</i>" in the files of the "src/" directory. <h2>5.0 Creating A New Web Page</h2> As with commands, new webpages can be added simply by inserting a function that generates the webpage together with a special header comment. A template follows: <blockquote><verbatim> /* ** WEBPAGE: helloworld */ void helloworld_page(void){ style_header("Hello World!"); @ <p>Hello, World!</p> style_footer(); } </verbatim></blockquote> Add the code above to a new or existing Fossil source code file, then recompile fossil and run [/help/ui|fossil ui] then enter "http://localhost:8080/helloworld" in your web browser and the routine above will generate a web page that says "Hello World." It really is that simple. |
︙ | ︙ | |||
221 222 223 224 225 226 227 | works. <h2>6.0 See Also</h2> * [./makefile.wiki|The Fossil Build Process] * [./tech_overview.wiki|A Technical Overview Of Fossil] * [./contribute.wiki|Contributing To The Fossil Project] | < | 209 210 211 212 213 214 215 | works. <h2>6.0 See Also</h2> * [./makefile.wiki|The Fossil Build Process] * [./tech_overview.wiki|A Technical Overview Of Fossil] * [./contribute.wiki|Contributing To The Fossil Project] |
Changes to www/alerts.md.
︙ | ︙ | |||
10 11 12 13 14 15 16 | * [Wiki](./wikitheory.wiki) page changes * New and edited [forum](./forum.wiki) posts * Announcements Subscribers can elect to receive emails as soon as these events happen, or they can receive a daily digest of the events instead. | | | | | 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 | * [Wiki](./wikitheory.wiki) page changes * New and edited [forum](./forum.wiki) posts * Announcements Subscribers can elect to receive emails as soon as these events happen, or they can receive a daily digest of the events instead. Email alerts are sent by a [Fossil server](./server.wiki), which must be [set up](#quick) by the Fossil administrator to send email. Email alerts do not currently work if you are only using Fossil from the command line. A bit of terminology: Fossil uses the terms "email alerts" and "notifications" interchangeably. We stick to the former term in this document except when referring to parts of the Fossil UI still using the latter term. ## Setup Prerequisites Much of this document describes how to set up Fossil's email alert system. To follow this guide, you will need a Fossil UI browser window open to the [Admin → Notification](/setup_notification) Fossil UI screen on the the Fossil server that will be sending these email alerts, logged in as a user with Admin capability. It is not possible to work on a clone of the server's repository and push the configuration changes up to that repo as an Admin user, [on purpose](#backup). **Important:** Do not confuse that screen with Admin → Email-Server, which sets up a different subsystem within Fossil. That feature is related to this document's topic, but it is currently incomplete, so we do not cover it at this time. |
︙ | ︙ | |||
62 63 64 65 66 67 68 | `chroot` feature to wall Fossil off from the rest of the machine, it's fairly simple to set up email alerts. (Otherwise, skip [ahead](#advanced) to the sections on advanced email service setup.) This is our "quick setup" option even though setting up an SMTP mail | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | `chroot` feature to wall Fossil off from the rest of the machine, it's fairly simple to set up email alerts. (Otherwise, skip [ahead](#advanced) to the sections on advanced email service setup.) This is our "quick setup" option even though setting up an SMTP mail server is not trival, because there are many other reasons to have such a server set up already: internal project email service, `cron` notifications, server status monitoring notifications... With that out of the way, the Fossil-specific steps are easy: 1. Go to [Admin → Notification](/setup_notification) and fill out all of the **Required** fields: |
︙ | ︙ | |||
89 90 91 92 93 94 95 | the "From" address above, or it could be a different value like `admin@example.com`. Save your changes. At the command line, say | | | | | | | 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 | the "From" address above, or it could be a different value like `admin@example.com`. Save your changes. At the command line, say $ fossil set email-send-command If that gives a blank value instead of `sendmail -ti`, say $ fossil set email-send-command "sendmail -ti" to force the setting. That works around a [known bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be squished by the time you read this. If you're running Postfix or Exim, you might think that command is wrong, since you aren't running Sendmail. These mail servers provide a `sendmail` command for compatibility with software like Fossil that has no good reason to care exactly which SMTP server implementation is running at a given site. There may be other SMTP servers that also provide a compatible `sendmail` command, in which case they may work with Fossil using the same steps as above. <a id="status"></a> If you reload the Admin → Notification page, the Status section at the top should show: Outgoing Email: Piped to command "sendmail -ti" Pending Alerts: 0 normal, 0 digest Subscribers: 0 active, 0 total Before you move on to the next section, you might like to read up on [some subtleties](#pipe) with the "pipe to a command" method that we did not cover above. <a id="usage"></a> |
︙ | ︙ | |||
153 154 155 156 157 158 159 | by the way: a user can be signed up for email alerts without having a full-fledged Fossil user account. Only when both user names are the same are the two records tied together under the hood. For more on this, see [Users vs Subscribers below](#uvs). If you are seeing the following complaint from Fossil: | > | > > | < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | by the way: a user can be signed up for email alerts without having a full-fledged Fossil user account. Only when both user names are the same are the two records tied together under the hood. For more on this, see [Users vs Subscribers below](#uvs). If you are seeing the following complaint from Fossil: <blockquote> Use a different login with greater privilege than FOO to access /subscribe </blockquote> ...then the repository's administrator forgot to [give the Alerts capability](#cap7) to that user or to a user category that the user is a member of. After a subscriber signs up for alerts for the first time, a single verification email is sent to that subscriber's given email address. The new subscriber must click a link in that email in order to activate the subscription. |
︙ | ︙ | |||
185 186 187 188 189 190 191 | Those with Fossil repository logins can adjust their email alert settings by visiting the `/alerts` page on the repository. With the default skin, you can get there by clicking the "Logout" link in the upper right corner of any Fossil UI page then clicking the "Email Alerts" link. That link is also available via the Sitemap (`/sitemap`) and via the default skin's hamburger menu (☰). | < < | | | | | | > | | < < < < | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | Those with Fossil repository logins can adjust their email alert settings by visiting the `/alerts` page on the repository. With the default skin, you can get there by clicking the "Logout" link in the upper right corner of any Fossil UI page then clicking the "Email Alerts" link. That link is also available via the Sitemap (`/sitemap`) and via the default skin's hamburger menu (☰). <a id="unsub" name="unsubscribe"></a> ### Unsubscribing To unsubscribe from alerts, visit the `/alerts` page on the repository, click the "Unsubscribe" button, then check the "Unsbuscribe" checkbox to verify your action and press the "Unsubscribe" button a second time. This interlock is intended to prevent accidental unsubscription. <a id="test"></a> ### Test Email Service The easiest way to test email sending from Fossil is via the "[Send Announcement](/announce)" link at the top of the "Email Notification Setup" page. Put your email address in the "To:" line and a test message below, then press "Send Message" to verify that outgoing email is working. Another method is from the command line: $ fossil alerts test-message you@example.com --body README.md --subject Test That should send you an email with "Test" in the subject line and the contents of your project's `README.md` file in the body. That command assumes that your project contains a "readme" file, but of course it does, because you have followed the [Programming Style Guide Checklist][cl], right? Right. [cl]: https://sendgrid.com/blog/programming-style-guide-checklist/ <a id="cap7"></a> ### User Capabilities Once email alerts are working, one must also adjust user permissions to allow users to subscribe to email alerts. In the capability list for each user on the Admin → Users page is a new capability called "Email Alerts". The corresponding capability letter is "7", which you must give to any user that needs to use the subscription setup pages, `/subscribe` and `/alerts`. To allow any passer-by on the Internet to subscribe, give the "Email Alerts" capability to the "nobody" user category. To require that a person solve a simple CAPTCHA first, give that capability to the "anonymous" user category instead. <a id="first" name="frist"></a> ### First Post I suggest taking the time to compose a suitable introductory message especially for your project's forum, one which a new user would find helpful. Wait a few seconds, and you should receive an email alert with the post's subject and body text in the email. <a id="trouble"></a> ### Troubleshooting If email alerts aren't working, there are several useful commands you can give to figure out why. (Be sure to [`cd` into a repo checkout directory](#cd) first!) $ fossil alerts status This should give much the same information as you saw [above](#status). One difference is that, since you've created a forum post, the `pending-alerts` value should only be zero if you did in fact get the requested email alert. If it's zero, check your mailer's spam folder. If it's nonzero, continue with these troubleshooting steps. $ fossil backoffice That forces Fossil to run its ["back office" process](./backoffice.md). Its only purpose at the time of this writing is to push out alert emails, but it might do other things later. Sometimes it can get stuck and needs to be kicked. For that reason, you might want to set up a crontab entry to make sure it runs occasionally. $ fossil alerts send This should also kick off the backoffice processing, if there are any pending alerts to send out. $ fossil alert pending Show any pending alerts. The number of lines output here should equal the [status output above](#status). $ fossil test-add-alerts f5900 $ fossil alert send Manually create an email alert and push it out immediately. The `f` in the first command's final parameter means you're scheduling a "forum" alert. The integer is the ID of a forum post, which you can find by visiting `/timeline?showid` on your Fossil instance. The second command above is necessary because the `test-add-alerts` command doesn't kick off a backoffice run. $ fossil ale send This only does the same thing as the final command above, rather than send you an ale, as you might be hoping. Sorry. <a id="advanced"></a> ## Advanced Email Setups Fossil offers several methods of sending email: 1. Pipe the email message text into a command. 2. Store email messages as entries in a SQLite database. 3. Store email messages as individual files in a directory. 4. Send emails to an SMTP relay. 5. Send emails directly to the recipients via SMTP. This wide range of options allows Fossil to talk to pretty much any SMTP setup. The first four options let Fossil delegate email handling to an existing [MTA][mta] so that Fossil does not need to implement the [roughly two dozen][mprotos] separate [RFCs][rfcs] required in order to properly support SMTP email in this complex world we've built. As well, this design choice means you do not need to do duplicate configuration, such as to point Fossil at your server's TLS certificate in order to support users behind mail servers that require STARTTLS encryption. [mprotos]: http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html [rfcs]: https://en.wikipedia.org/wiki/Request_for_Comments <a id="pipe"></a> ### Method 1: Pipe to a Command This is our ["quick setup" option](#quick) above, but there are some details we ignored which we'll cover now. Fossil pipes the email message in [RFC 822 format][rfc822] to the standard input of the command you gave as the "Email Send Method", defaulting to `sendmail -ti`. This constitutes a protocol between Fossil and the SMTP [message transfer agent (MTA)][mta]. Any other MTA which speaks the same protocol can be used in place of the most common options: Sendmail, Exim, and Postfix. The `-t` option tells the command to expect the list of email recipients in a `To` header in the RFC 822 message presented on its standard input. Without this option, the `sendmail` command expects to receive the recipient list on the command line, but that's not possible with the |
︙ | ︙ | |||
361 362 363 364 365 366 367 | occur such that a dot or period in an alert message is at the beginning of a line, you'll get a truncated email message without this option. Statistically, this will happen about once every 70 or so messages, so it is important to give this option if your MTA treats leading dots on a line this way. <a id="msmtp"></a> | | | > | < < | | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | occur such that a dot or period in an alert message is at the beginning of a line, you'll get a truncated email message without this option. Statistically, this will happen about once every 70 or so messages, so it is important to give this option if your MTA treats leading dots on a line this way. <a id="msmtp"></a> We believe the [`msmtp`][msmtp] SMTP client is compatible with this protocol if you give it the `-t` option. To our knowledge, this remains untested, but if it works, this would be a useful option on a server hosting a Fossil repository which doesn't otherwise require a separate SMTP server for other purposes. It is probably also possible to configure [`procmail`][pmdoc] to work with this protocol. If you know how to do it, a patch to this document or a how-to on [the Fossil forum][ff] would be appreciated. [ff]: https://fossil-scm.org/forum/ [msmtp]: https://marlam.de/msmtp/ [mta]: https://en.wikipedia.org/wiki/Message_transfer_agent [pmdoc]: http://pm-doc.sourceforge.net/doc/ [rfc822]: https://www.w3.org/Protocols/rfc822/ <a id="db"></a> ### Method 2: Store in a Database The self-hosting Fossil repository at <https://www.fossil-scm.org/> currently uses this method rather than [the pipe method](#pipe) because it is running inside of a restrictive [chroot jail][cj] which is unable to hand off messages to the local MTA directly. When you configure a Fossil server this way, it adds outgoing email messages to a SQLite database file. A separate daemon process can then extract those messages for further disposition. |
︙ | ︙ | |||
419 420 421 422 423 424 425 | corruption][rdbc] if used with a file sharing technology that doesn't use proper file locking. You can start this Tcl script as a daemon automatically on most Unix and Unix-like systems by adding the following line to the `/etc/rc.local` file of the server that hosts the repository sending email alerts: | | | | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | corruption][rdbc] if used with a file sharing technology that doesn't use proper file locking. You can start this Tcl script as a daemon automatically on most Unix and Unix-like systems by adding the following line to the `/etc/rc.local` file of the server that hosts the repository sending email alerts: /usr/bin/tclsh /home/www/fossil/email-sender.tcl & [cj]: https://en.wikipedia.org/wiki/Chroot [rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations <a id="dir"></a> ### Method 3: Store in a Directory This method is functionally very similar to [the DB method](#db), differing only in that messages are written to a directory in the filesystem. You should therefore read that section and make the minor adjustments required by the storage method. This method may work over a file sharing mechanism that doesn't do file locking properly, as long as the reading process is somehow restricted from reading a message file as it's being written. It might be useful in testing and debugging to temporarily switch to this method, since you can easily read the generated email messages without needing to involve [an MTA][mta]. <a id="relay"></a> ### Method 4: SMTP Relay In this configuration, the Fossil server contacts an open SMTP relay and sends the messages to it. This method is only appropriate when: |
︙ | ︙ | |||
476 477 478 479 480 481 482 | <a id="uvs"></a> ## Users vs Subscribers Fossil makes a distinction between "users" and "subscribers". A user is someone with a username and password: that is, someone who can log into | | | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | <a id="uvs"></a> ## Users vs Subscribers Fossil makes a distinction between "users" and "subscribers". A user is someone with a username and password: that is, someone who can log into the Fossi repository. A subscriber is someone who receives email alerts. Users can also be subscribers and subscribers can be users, but that does not have to be the case. It is possible to be a user without being a subscriber and to be a subscriber without being a user. In the repository database file, users are tracked with the `user` table and subscribers are tracked via the `subscriber` table. |
︙ | ︙ | |||
526 527 528 529 530 531 532 | on behalf of a subscriber which they could do themselves, such as to [unsubscribe](#unsub) them. <a id="backup"></a> ## Cloning, Syncing, and Backups | > > > > > > | > > > > > < | | > > > > > > > | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | on behalf of a subscriber which they could do themselves, such as to [unsubscribe](#unsub) them. <a id="backup"></a> ## Cloning, Syncing, and Backups The Admin → Notification settings are not replicated using clone or sync, and it is not possible to push such settings from one repository to another. In a network of peer repositories, you only want one repository sending email alerts. If you were to replicate the email alert settings to a separate repository, then subscribers would get multiple alerts for each event, which would be bad. However, the subscriber list can be synced for backup purposes. Use the [`fossil config pull subscriber`](/help?cmd=configuration) command to pull the latest subscriber list from a server into a backup repository. The `push`, `export`, and `import` commands all work similarly. <a id="pages" name="commands"></a> ## Controlling the Email Alert System This section collects the list of Fossil UI pages and CLI commands that control the email alert system, some of which have not been mentioned so far: Commands: * The [`alerts`](/help?cmd=alerts) command * The [`test-alert`](/help?cmd=test-alert) command * The [`test-add-alerts`](/help?cmd=test-add-alerts) command Web pages available to users and subscribers: * The [`/subscribe`](/help?cmd=/subscribe) page * The [`/alerts`](/help?cmd=/alerts) page * The [`/unsubscribe`](/help?cmd=/unsubscribe) page * The [`/contact_admin`](/help?cmd=/contact_admin) page Administrator-only web pages: * The [`/setup_notification`](/help?cmd=/setup_notification) page * The [`/subscribers`](/help?cmd=/subscribers) page <a id="design"></a> ## Design of Email Alerts This section describes the low-level design of the email alert system in Fossil. This expands on the high-level administion focused material above with minimal repetition. This section assumes expert-level systems knowledge. If the material above sufficed for your purposes, feel free to skip this section, which runs to the end of this document. <a id="datades"></a> ### Data Design There are three new tables in the repository database, starting with Fossil 2.7. These tables are not created in new repositories by default. The tables only come into existence as needed when email alerts are configured and used. * <b>SUBSCRIBER</b> → The subscriber table records the email address for people who want to receive email notifications. Each subscriber has a `subscriberCode` which is a random 32-byte blob that uniquely identifies the subscriber. There are also fields to indicate what kinds of notifications the subscriber wishes to receive, whether or not the email address of the subscriber has been verified, etc. * <b>PENDING\_ALERT</b> → The PENDING\_ALERT table contains records that define events about which alert emails might need to be sent. A pending\_alert always refers to an entry in the EVENT table. The EVENT table is part of the standard schema and records timeline entries. In other words, there is one row in the EVENT table for each possible timeline entry. The PENDING\_ALERT table refers to EVENT table entries for which we might need to send alert emails. * <b>EMAIL\_BOUNCE</b> → This table is intended to record email bounce history so that subscribers with excessive bounces can be turned off. That logic has not yet been implemented so the EMAIL\_BOUNCE table is currently unused. As pointed out above, ["subscribers" are distinct from "users"](#uvs). The SUBSCRIBER.SUNAME field is the optional linkage between users and subscribers. <a id="stdout"></a> |
︙ | ︙ | |||
666 667 668 669 670 671 672 | * If the `subscriberCode` is stolen, the worst that can happen is that the thief can change that email address's subscription settings. Contrast a password which may be shared with other services, which then compromises those other services. * No PII other than the subscriber's email address is available to an attacker with the `subscriberCode`. Nor can knowledge of the | | | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | * If the `subscriberCode` is stolen, the worst that can happen is that the thief can change that email address's subscription settings. Contrast a password which may be shared with other services, which then compromises those other services. * No PII other than the subscriber's email address is available to an attacker with the `subscriberCode`. Nor can knowledge of the `subscriberCode` lead to a email flood or other annoyance attack, as far as I can see. If the `subscriberCodes` for a Fossil repository are ever compromised, new ones can be generated as follows: UPDATE subscriber SET subscriberCode=randomblob(32); Since this then affects all new email alerts going out from Fossil, your end users may never even realize that they're getting new codes, as long as they don't click on the URLs in the footer of old alert messages. With that in mind, a Fossil server administrator could choose to randomize the `subscriberCodes` periodically, such as just before the |
︙ | ︙ | |||
697 698 699 700 701 702 703 | ### Internal Processing Flow Almost all of the email alert code is found in the [`src/alerts.c`](/file/src/alerts.c) source file. When email alerts are enabled, a trigger is created in the schema (`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table | | | | 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | ### Internal Processing Flow Almost all of the email alert code is found in the [`src/alerts.c`](/file/src/alerts.c) source file. When email alerts are enabled, a trigger is created in the schema (`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table every time a row is added to the `EVENT` table. During a `fossil rebuild`, the `EVENT` table is rebuilt from scratch; since we do not want users to get alerts for every historical check-in, the trigger is disabled during `rebuild`. Email alerts are sent out by the `alert_send_alerts()` function, which is normally called automatically due to the `email-autoexec` setting, which defaults to enabled. If that setting is disabled or if the user simply wants to force email alerts to be sent immediately, they can give |
︙ | ︙ |
Changes to www/antibot.wiki.
|
| | > | | | | | | | | | | | > | | < | | | > | < > | | > > | | | | | | | | | | | | | | | < | | | | | < < | | | < | | | | | | | | | | | | | > > > > > > > | | | | < > | | < < < | | | | | | | | | 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 | <title>Defense Against Spiders</title> The website presented by a Fossil server has many hyperlinks. Even a modest project can have millions of pages in its tree, and many of those pages (for example diffs and annotations and ZIP archive of older check-ins) can be expensive to compute. If a spider or bot tries to walk a website implemented by Fossil, it can present a crippling bandwidth and CPU load. The website presented by a Fossil server is intended to be used interactively by humans, not walked by spiders. This article describes the techniques used by Fossil to try to welcome human users while keeping out spiders. <h2>The "hyperlink" user capability</h2> Every Fossil web session has a "user". For random passers-by on the internet (and for spiders) that user is "nobody". The "anonymous" user is also available for humans who do not wish to identify themselves. The difference is that "anonymous" requires a login (using a password supplied via a CAPTCHA) whereas "nobody" does not require a login. The site administrator can also create logins with passwords for specific individuals. The "h" or "hyperlink" capability is a permission that can be granted to users that enables the display of hyperlinks. Most of the hyperlinks generated by Fossil are suppressed if this capability is missing. So one simple defense against spiders is to disable the "h" permission for the "nobody" user. This means that users must log in (perhaps as "anonymous") before they can see any of the hyperlinks. Spiders do not normally attempt to log into websites and will therefore not see most of the hyperlinks and will not try to walk the millions of historical check-ins and diffs available on a Fossil-generated website. If the "h" capability is missing from user "nobody" but is present for user "anonymous", then a message automatically appears at the top of each page inviting the user to log in as anonymous in order to activate hyperlinks. Removing the "h" capability from user "nobody" is an effective means of preventing spiders from walking a Fossil-generated website. But it can also be annoying to humans, since it requires them to log in. Hence, Fossil provides other techniques for blocking spiders which are less cumbersome to humans. <h2>Automatic hyperlinks based on UserAgent</h2> Fossil has the ability to selectively enable hyperlinks for users that lack the "h" capability based on their UserAgent string in the HTTP request header and on the browsers ability to run Javascript. The UserAgent string is a text identifier that is included in the header of most HTTP requests that identifies the specific maker and version of the browser (or spider) that generated the request. Typical UserAgent strings look like this: <ul> <li> Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20100101 Firefox/19.0 <li> Mozilla/4.0 (compatible; MSIE 8.0; Windows_NT 5.1; Trident/4.0) <li> Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) <li> Wget/1.12 (openbsd4.9) </ul> The first two UserAgent strings above identify Firefox 19 and Internet Explorer 8.0, both running on Windows NT. The third example is the spider used by Google to index the internet. The fourth example is the "wget" utility running on OpenBSD. Thus the first two UserAgent strings above identify the requestor as human whereas the second two identify the requestor as a spider. Note that the UserAgent string is completely under the control of the requestor and so a malicious spider can forge a UserAgent string that makes it look like a human. But most spiders truly seem to desire to "play nicely" on the internet and are quite open about the fact that they are a spider. And so the UserAgent string provides a good first-guess about whether or not a request originates from a human or a spider. In Fossil, under the Admin/Access menu, there is a setting entitled "<b>Enable hyperlinks for "nobody" based on User-Agent and Javascript</b>". If this setting is enabled, and if the UserAgent string looks like a human and not a spider, then Fossil will enable hyperlinks even if the "h" capability is omitted from the user permissions. This setting gives humans easy access to the hyperlinks while preventing spiders from walking the millions of pages on a typical Fossil site. But the hyperlinks are not enabled directly with the setting above. Instead, the HTML code that is generated contains anchor tags ("<a>") without "href=" attributes. Then, javascript code is added to the end of the page that goes back and fills in the "href=" attributes of the anchor tags with the hyperlink targets, thus enabling the hyperlinks. This extra step of using javascript to enable the hyperlink targets is a security measure against spiders that forge a human-looking UserAgent string. Most spiders do not bother to run javascript and so to the spider the empty anchor tag will be useless. But all modern web browsers implement javascript, so hyperlinks will show up normally for human users. <h2>Further defenses</h2> Recently (as of this writing, in the spring of 2013) the Fossil server on the SQLite website ([http://www.sqlite.org/src/]) has been hit repeatedly by Chinese spiders that use forged UserAgent strings to make them look like normal web browsers and which interpret javascript. We do not believe these attacks to be nefarious since SQLite is public domain and the attackers could obtain all information they ever wanted to know about SQLite simply by cloning the repository. Instead, we believe these "attacks" are coming from "script kiddies". But regardless of whether or not malice is involved, these attacks do present an unnecessary load on the server which reduces the responsiveness of the SQLite website for well-behaved and socially responsible users. For this reason, additional defenses against spiders have been put in place. On the Admin/Access page of Fossil, just below the "<b>Enable hyperlinks for "nobody" based on User-Agent and Javascript</b>" setting, there are now two additional subsettings that can be optionally enabled to control hyperlinks. The first subsetting waits to run the javascript that sets the "href=" attributes on anchor tags until after at least one "mouseover" event has been detected on the <body> element of the page. The thinking here is that spiders will not be simulating mouse motion and so no mouseover events will ever occur and hence the hyperlinks will never become enabled for spiders. The second new subsetting is a delay (in milliseconds) before setting the "href=" attributes on anchor tags. The default value for this delay is 10 milliseconds. The idea here is that a spider will try to render the page immediately, and will not wait for delayed scripts to be run, thus will never enable the hyperlinks. These two subsettings can be used separately or together. If used together, then the delay timer does not start until after the first mouse movement is detected. See also [./server.wiki#loadmgmt|Managing Server Load] for a description of how expensive pages can be disabled when the server is under heavy load. <h2>The ongoing struggle</h2> Fossil currently does a very good job of providing easy access to humans while keeping out troublesome robots and spiders. However, spiders and bots continue to grow more sophisticated, requiring ever more advanced defenses. This "arms race" is unlikely to ever end. The developers of Fossil will continue to try improve the spider defenses of Fossil so check back from time to time for the latest releases and updates. Readers of this page who have suggestions on how to improve the spider defenses in Fossil are invited to submit your ideas to the Fossil Users mailing list: [mailto:fossil-users@lists.fossil-scm.org | fossil-users@lists.fossil-scm.org]. |
Changes to www/backoffice.md.
1 2 3 4 5 6 | Backoffice ========== This is technical documentation about the internal workings of Fossil. Ordinary Fossil users do not need to know about anything covered by this document. The information here is intended for people who want to enhance | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Backoffice ========== This is technical documentation about the internal workings of Fossil. Ordinary Fossil users do not need to know about anything covered by this document. The information here is intended for people who want to enhance or extend the Fossil code, or who just want a deeper understanding of the internal workings of Fossil. What Is The Backoffice ---------------------- The backoffice is a mechanism used by a [Fossil server](/doc/trunk/www/server.wiki) to do low-priority background work that is not directly related to the user interface. Here are some examples of the kinds of work that backoffice performs: 1. Sending email alerts and notifications 2. Sending out daily digests of email notifications 3. Other background email handling chores 4. Automatic syncing of peer repositories |
︙ | ︙ | |||
37 38 39 40 41 42 43 | This happens for every webpage, regardless of how that webpage is launched, and regardless of the purpose of the webpage. This also happens on the server for "[fossil sync](/help?cmd=sync)" and [fossil clone](/help?cmd=clone)" commands which are implemented as web requests - albeit requests that the human user never sees. Web requests can arrive at the Fossil server via direct TCP/IP (for example when Fossil is started using commands like "[fossil server](/help?cmd=server)") | | | | | | < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | 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 | This happens for every webpage, regardless of how that webpage is launched, and regardless of the purpose of the webpage. This also happens on the server for "[fossil sync](/help?cmd=sync)" and [fossil clone](/help?cmd=clone)" commands which are implemented as web requests - albeit requests that the human user never sees. Web requests can arrive at the Fossil server via direct TCP/IP (for example when Fossil is started using commands like "[fossil server](/help?cmd=server)") or via [CGI](/doc/trunk/www/server.wiki) or [SCGI](/doc/trunk/www/scgi.wiki) or via SSH. A backoffice process might be started regardless of the origin of the request. The backoffice is not a daemon. Each backoffice process runs for a short while and then exits. This helps keep Fossil easy to manage, since there are no daemons to start and stop. To upgrade Fossil to a new version, you simply replace the older "fossil" executable with the newer one, and the backoffice processes will (within a minute or so) start using the new one. (Upgrading the executable on Windows is more complicated, since on Windows it is not possible to replace an executable file that is in active use. But Windows users probably already know this.) The backoffice is serialized and rate limited. No more than a single backoffice process will be running at once, and backoffice runs will not occur more frequently than once every 60 seconds. If a Fossil server is idle, then no backoffice processes will be running. That means there are no extra processes sitting around taking up memory and process table slots for seldom accessed repositories. The backoffice is an on-demand system. A busy repository will usually have a backoffice running at all times. But an infrequently accessed repository will only have backoffice processes running for a minute or two following the most recent access. Manually Running The Backoffice ------------------------------- The automatic backoffice runs are sufficient for most installations. However, the daily digest of email notifications is handled by the backoffice. If a Fossil server can sometimes go more than a day without being accessed, then the automatic backoffice will never run, and the daily digest might not go out until somebody does visit a webpage. If this is a problem, an adminstrator can set up a cron job to periodically run: > fossil backoffice -R _REPOSITORY_ That command will cause backoffice processing to occur immediately. Note that this is almost never necessary for an internet-facing Fossil repository, since most repositories will get multiple accesses per day from random robots, which will be sufficient to kick off the daily digest emails. And even for a private server, if there is very little traffic, then the daily digests are probably a no-op anyhow and won't be missed. How Backoffice Is Implemented ----------------------------- The backoffice is implemented by the "backoffice.c" source file. Serialization and rate limiting is handled by a single entry in the repository database CONFIG table named "backoffice". This entry is called "the lease". The value of the lease is a text string representing four integers, which are respectively: 1. The process id of the "current" backoffice process 2. The lease expiration time of the current backoffice process 3. The process id of the "next" backoffice process 4. The lease expiration time for the next backoffice process Times are expressed in seconds since 1970. A process id of zero means "no process". Sometimes the process id will be non-zero even if there is no corresponding process. Fossil knows how to figure out whether or not a process still exists. You can print out a decoded copy of the current backoffice lease using this command: > fossil test-backoffice-lease -R _REPOSITORY_ If a system has been idle for a long time, then there will be no backoffice processes. (Either the process id entries in the lease will be zero, or there will exist no process associated with the process id.) When a new web request comes in, the system sees that no backoffice process is active and so it kicks off a separate process to run backoffice. The new backoffice process becomes the "current" process. It sets a lease expiration time for itself to be 60 seconds in the future. Then it does the backoffice processing and exits. Note that usually the backoffice process will exit long before its lease expires. That is ok. The lease is there to limit the rate at which backoffice processes run. If a new backoffice process starts up and sees that the "current" lease has |
︙ | ︙ | |||
195 196 197 198 199 200 201 | The backoffice should "just work". It should not require administrator attention. However, if you suspect that something is not working right, there are some debugging aids. We have already mentioned the command that shows the backoffice lease for a repository: | | | < < < < < | < | 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 | The backoffice should "just work". It should not require administrator attention. However, if you suspect that something is not working right, there are some debugging aids. We have already mentioned the command that shows the backoffice lease for a repository: > fossil test-backoffice-lease -R _REPOSITORY_ Running that command every few seconds should show what is going on with backoffice processing in a particular repository. There are also two settings that control backoffice behavior. The "backoffice-nodelay" setting prevents the "next" process from taking a lease and sleeping. If "backoffice-nodelay" is set, that causes all backoffice processes to exit either immediately or after doing whatever backoffice works needs to be done. If something is going wrong and backoffice leases are causing delays in webpage processing, then setting "backoffice-nodelay" to true can work around the problem until the bug can be fixed. The "backoffice-logfile" setting is the name of a log file onto which is appended a short message everything a backoffice process actually starts to do the backoffice work. This log file can be used to verify that backoffice really is running, if there is any doubt. Most installations should leave "backoffice-nodelay" off and leave "backoffice-logfile" unset or set to an empty string. |
Deleted www/backup.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/blockchain.md.
|
| | | < < < < < < < | | | | < < < < < < < < < < < | < < < | | > > | | | < | > > > > | < > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | # Fossil As Blockchain Fossil is a version control system built around blockchain. Wikipedia defines "blockchain" as > "a growing list of records, called blocks, which are linked using cryptography. Each block contains a cryptographic hash of the previous block, a timestamp, and transaction data..." [(1)][] By that definition, Fossil is clearly an implementation of blockchain. The blocks are ["manifests" artifacts](./fileformat.wiki#manifest). Each manifest has a SHA1 or SHA3 hash of its parent or parents, a timestamp, and other tranactional data. The repository grows by add new manifests onto the list. Some people have come to associate blockchain with cryptocurrency, however, and since Fossil has nothing to do with cryptocurrency, the claim that Fossil is build around blockchain is met with skepticism. The key thing to note here is that cryptocurrency implementations like BitCoin are built around blockchain, but they are not synonymous with blockchain. Blockchain is a much broader concept. Blockchain is a mechanism for constructed a distributed ledger of transactions. Yes, you can use a distributed ledger to implement a cryptocurrency, but you can also use a distributed ledger to implement a version control system, and probably many other kinds of applications as well. Blockchain is a much broader idea than cryptocurrency. [(1)]: https://en.wikipedia.org/wiki/Blockchain |
Added www/branch01.gif.
cannot compute difference between binary files
Added www/branch02.gif.
cannot compute difference between binary files
Added www/branch03.gif.
cannot compute difference between binary files
Added www/branch04.gif.
cannot compute difference between binary files
Added www/branch05.gif.
cannot compute difference between binary files
Changes to www/branching.wiki.
1 2 3 4 | <title>Branching, Forking, Merging, and Tagging</title> <h2>Background</h2> In a simple and perfect world, the development of a project would proceed | | > | < | < < < < < | | | > | | | > | < | < < < < < | | | < < < | | | | | | > | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < > > | < | < < < < < | | < < | | > | < | < < < < < < < < | | | | | | | < | < | | | | < < | | | | < < | | | | | < | | | | < | < < < < < < < < < < < < < < < < < < < < < | < < > | | | | | | | | | | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < | | | | | 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 | <title>Branching, Forking, Merging, and Tagging</title> <h2>Background</h2> In a simple and perfect world, the development of a project would proceed linearly, as shown in figure 1. <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> <tr><td align="center"> <img src="branch01.gif" width=280 height=68><br> Figure 1 </td></tr></table> Each circle represents a check-in. For the sake of clarity, the check-ins are given small consecutive numbers. In a real system, of course, the check-in numbers would be long hexadecimal hashes since it is not possible to allocate collision-free sequential numbers in a distributed system. But as sequential numbers are easier to read, we will substitute them for the long hashes in this document. The arrows in figure 1 show the evolution of a project. The initial check-in is 1. Check-in 2 is derived from 1. In other words, check-in 2 was created by making edits to check-in 1 and then committing those edits. We say that 2 is a <i>child</i> of 1 and that 1 is a <i>parent</i> of 2. Check-in 3 is derived from check-in 2, making 3 a child of 2. We say that 3 is a <i>descendant</i> of both 1 and 2 and that 1 and 2 are both <i>ancestors</i> of 3. <a name="dag"></a> <h2>DAGs</h2> The graph of check-ins is a [http://en.wikipedia.org/wiki/Directed_acyclic_graph | directed acyclic graph] commonly shortened to <i>DAG</i>. Check-in 1 is the <i>root</i> of the DAG since it has no ancestors. Check-in 4 is a <i>leaf</i> of the DAG since it has no descendants. (We will give a more precise definition later of "leaf.") Alas, reality often interferes with the simple linear development of a project. Suppose two programmers make independent modifications to check-in 2. After both changes are committed, the check-in graph looks like figure 2: <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> <tr><td align="center"> <img src="branch02.gif" width=210 height=140><br> Figure 2 </td></tr></table> The graph in figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has two children, check-ins 3 and 4. We call this state a <i>fork</i>. Fossil tries to prevent forks. Suppose two programmers named Alice and Bob are each editing check-in 2 separately. Alice finishes her edits first and commits her changes, resulting in check-in 3. Later, when Bob attempts to commit his changes, fossil verifies that check-in 2 is still a leaf. Fossil sees that check-in 3 has occurred and aborts Bob's commit attempt with a message "would fork." This allows Bob to do a "fossil update" which pulls in Alice's changes, merging them into his own changes. After merging, Bob commits check-in 4 as a child of check-in 3. The result is a linear graph as shown in figure 1. This is how CVS works. This is also how fossil works in [./concepts.wiki#workflow | "autosync"] mode. But perhaps Bob is off-network when he does his commit, so he has no way of knowing that Alice has already committed her changes. Or, it could be that Bob has turned off "autosync" mode in Fossil. Or, maybe Bob just doesn't want to merge in Alice's changes before he has saved his own, so he forces the commit to occur using the "--allow-fork" option to the fossil <b>commit</b> command. For any of these reasons, two commits against check-in 2 have occurred and now the DAG has two leaves. So which version of the project is the "latest" in the sense of having the most features and the most bug fixes? When there is more than one leaf in the graph, you don't really know. So we like to have graphs with a single leaf. To resolve this situation, Alice can use the fossil <b>merge</b> command to merge in Bob's changes in her local copy of check-in 3. Then she can commit the results as check-in 5. This results in a DAG as shown in figure 3. <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> <tr><td align="center"> <img src="branch03.gif" width=282 height=152><br> Figure 3 </td></tr></table> Check-in 5 is a child of check-in 3 because it was created by editing check-in 3. But check-in 5 also inherits the changes from check-in 4 by virtue of the merge. So we say that check-in 5 is a <i>merge child</i> of check-in 4 and that it is a <i>direct child</i> of check-in 3. The graph is now back to a single leaf (check-in 5). We have already seen that if fossil is in autosync mode then Bob would have been warned about the potential fork the first time he tried to commit check-in 4. If Bob had updated his local check-out to merge in Alice's check-in 3 changes, then committed, then the fork would have never occurred. The resulting graph would have been linear, as shown in figure 1. Really the graph of figure 1 is a subset of figure 3. Hold your hand over the check-in 4 circle of figure 3 and then figure 3 looks exactly like figure 1 (except that the leaf has a different check-in number, but that is just a notational difference - the two check-ins have exactly the same content). In other words, figure 3 is really a superset of figure 1. The check-in 4 of figure 3 captures additional state which is omitted from figure 1. Check-in 4 of figure 3 holds a copy of Bob's local checkout before he merged in Alice's changes. That snapshot of Bob's changes, which is independent of Alice's changes, is omitted from figure 1. Some people say that the approach taken in figure 3 is better because it preserves this extra intermediate state. Others say that the approach taken in figure 1 is better because it is much easier to visualize a linear line of development and because the merging happens automatically instead of as a separate manual step. We will not take sides in that debate. We will simply point out that fossil enables you to do it either way. <h2>Forking Versus Branching</h2> Having more than one leaf in the check-in DAG is called a "fork." This is usually undesirable and either avoided entirely, as in figure 1, or else quickly resolved as shown in figure 3. But sometimes, one does want to have multiple leaves. For example, a project might have one leaf that is the latest version of the project under development and another leaf that is the latest version that has been tested. When multiple leaves are desirable, we call this <i>branching</i> instead of <i>forking</i>. Figure 4 shows an example of a project where there are two branches, one for development work and another for testing. <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> <tr><td align="center"> <img src="branch04.gif" width=426 height=123><br> Figure 4 </td></tr></table> The hypothetical scenario of figure 4 is this: The project starts and progresses to a point where (at check-in 2) it is ready to enter testing for its first release. In a real project, of course, there might be hundreds or thousands of check-ins before a project reaches this point, but for simplicity of presentation we will say that the project is ready after check-in 2. The project then splits into two branches that are used by separate teams. The testing team, using the blue branch, finds and fixes a few bugs. This is shown by check-ins 6 and 9. Meanwhile the development team, working on the top uncolored branch, is busy adding features for the second release. Of course, the development team would like to take advantage of the bug fixes implemented by the testing team. So periodically, the changes in the test branch are merged into the dev branch. This is shown by the dashed merge arrows between check-ins 6 and 7 and between check-ins 9 and 10. In both figures 2 and 4, check-in 2 has two children. In figure 2, we call this a "fork." In diagram 4, we call it a "branch." What is the difference? As far as the internal fossil data structures are concerned, there is no difference. The distinction is in the intent. In figure 2, the fact that check-in 2 has multiple children is an accident that stems from concurrent development. In figure 4, giving check-in 2 multiple children is a deliberate act. So, to a good approximation, we define forking to be by accident and branching to be by intent. Apart from that, they are the same. <a name="tags"></a> <h2>Tags And Properties</h2> Tags and properties are used in fossil to help express the intent, and thus to distinguish between forks and branches. Figure 5 shows the same scenario as figure 4 but with tags and properties added: <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> <tr><td align="center"> <img src="branch05.gif" width=485 height=177><br> Figure 5 </td></tr></table> A <i>tag</i> is a name that is attached to a check-in. A <i>property</i> is a name/value pair. Internally, fossil implements tags as properties with a NULL value. So, tags and properties really are much the same thing, and henceforth we will use the word "tag" to mean either a tag or a property. A tag can be a one-time tag, a propagating tag or a cancellation tag. A one-time tag only applies to the check-in to which it is attached. A propagating tag applies to the check-in to which it is attached and also to all direct descendants of that check-in. A <i>direct descendant</i> is a descendant through direct children. Tag propagation does not cross merges. Tag propagation also stops as soon as it encounters another check-in with the same tag. A cancellation tag is attached to a single check-in in order to either override a one-time tag that was previously placed on that same check-in, or to block tag propagation from an ancestor. The initial check-in of every repository has two propagating tags. In figure 5, that initial check-in is check-in 1. The <b>branch</b> tag tells (by its value) what branch the check-in is a member of. The default branch is called "trunk." All tags that begin with "<b>sym-</b>" are symbolic name tags. When a symbolic name tag is attached to a check-in, that allows you to refer to that check-in by its symbolic name rather than by its hexadecimal hash name. When a symbolic name tag propagates (as does the <b>sym-trunk</b> tag) then referring to that name is the same as referring to the most recent check-in with that name. |
︙ | ︙ | |||
481 482 483 484 485 486 487 488 | Figure 5 also shows two one-time tags on check-in 9. (The diagram does not make a graphical distinction between one-time and propagating tags.) The <b>sym-release-1.0</b> tag means that check-in 9 can be referred to using the more meaningful name "release-1.0." The <b>closed</b> tag means that check-in 9 is a "closed leaf." A closed leaf is a leaf that should never have direct children. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | Figure 5 also shows two one-time tags on check-in 9. (The diagram does not make a graphical distinction between one-time and propagating tags.) The <b>sym-release-1.0</b> tag means that check-in 9 can be referred to using the more meaningful name "release-1.0." The <b>closed</b> tag means that check-in 9 is a "closed leaf." A closed leaf is a leaf that should never have direct children. <h2>Review Of Terminology</h2> <blockquote><dl> <dt><b>Branch</b></dt> <dd><p>A branch is a set of check-ins with the same value for their "branch" property.</p></dd> <dt><b>Leaf</b></dt> <dd><p>A leaf is a check-in with no children in the same branch.</p></dd> <dt><b>Closed Leaf</b></dt> <dd><p>A closed leaf is any leaf with the <b>closed</b> tag. These leaves are intended to never be extended with descendants and hence are omitted from lists of leaves in the command-line and web interface.</p></dd> <dt><b>Open Leaf</b></dt> <dd><p>A open leaf is a leaf that is not closed.</p></dd> <dt><b>Fork</b></dt> <dd><p>A fork is when a check-in has two or more direct (non-merge) children in the same branch.</p></dd> <dt><b>Branch Point</b></dt> <dd><p>A branch point occurs when a check-in has two or more direct (non-merge) children in different branches. A branch point is similar to a fork, except that the children are in different branches.</p></dd> </dl></blockquote> Check-in 4 of figure 3 is not a leaf because it has a child (check-in 5) in the same branch. Check-in 9 of figure 5 also has a child (check-in 10) but that child is in a different branch, so check-in 9 is a leaf. Because of the <b>closed</b> tag on check-in 9, it is a closed leaf. Check-in 2 of figure 3 is considered a "fork" because it has two children in the same branch. Check-in 2 of figure 5 also has two children, but each child is in a different branch, hence in figure 5, check-in 2 is considered a "branch point." <h2>Differences With Other DVCSes</h2> Fossil keeps all check-ins on a single DAG. Branches are identified with tags. This means that check-ins can be freely moved between branches simply by altering their tags. Most other DVCSes maintain a separate DAG for each branch. |
Changes to www/bugtheory.wiki.
︙ | ︙ | |||
110 111 112 113 114 115 116 | to repopulate the table using the new column names. Note that the TICKET table schema and content is part of the local state of a repository and is not shared with other repositories during a sync, push, or pull. Each repository also defines scripts used to generate web pages for creating new tickets, viewing existing tickets, and modifying an existing ticket. These scripts consist of HTML with an embedded | | | > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | to repopulate the table using the new column names. Note that the TICKET table schema and content is part of the local state of a repository and is not shared with other repositories during a sync, push, or pull. Each repository also defines scripts used to generate web pages for creating new tickets, viewing existing tickets, and modifying an existing ticket. These scripts consist of HTML with an embedded scripts written a Tcl-like language called "TH1". Every new fossil repository is created with default scripts. Paul Ruizendaal has written documentation on the TH1 language that is available at [http://www.sqliteconcepts.org/THManual.pdf]. Administrators wishing to customize their ticket entry, viewing, and editing screens should modify the default scripts to suit their needs. These screen generator scripts are part of the local state of a repository and are not shared with other repositories during a sync, push, or pull. <i>To be continued...</i> |
Changes to www/build.wiki.
1 2 3 4 | <title>Compiling and Installing Fossil</title> <h2>0.0 Using A Pre-compiled Binary</h2> | | | < < < < | | | | | | | | | | | | | | | | < < < < | < < < < < < < < < < | < < | < < < < < < < < < < | | | < < < < < | < | < | | | | | | | < | | < < < < < < < < < < < | | < < < | | | | | < < < > | | | > | | | | | | | | | | | | | < | | < | < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | <title>Compiling and Installing Fossil</title> <h2>0.0 Using A Pre-compiled Binary</h2> <p>[/uv/download.html|Pre-compiled binaries] are available for recent releases. Just download the appropriate executable for your platform and put it on your $PATH. To uninstall, simply delete the executable. To upgrade from an older release, just overwrite the older binary with the newer one.</p> <h2>0.1 Executive Summary</h2> <p>Building and installing is very simple. Three steps:</p> <ol> <li> Download and unpack a source tarball or ZIP. <li> <b>./configure; make</b> <li> Move the resulting "fossil" or "fossil.exe" executable to someplace on your $PATH. </ol> <p><hr> <h2>1.0 Obtaining The Source Code</h2> <p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball containing a snapshot of the <em>latest</em> version directly from Fossil's own fossil repository. Additionally, source archives of <em>released</em> versions of fossil are available from the [/uv/download.html|downloads page]. To obtain a development version of fossil, follow these steps:</p> <ol> <li><p>Point your web browser to [https://www.fossil-scm.org/]</li> <li><p>Click on the [/timeline|Timeline] link at the top of the page.</p></li> <li><p>Select a version of of Fossil you want to download. The latest version on the trunk branch is usually a good choice. Click on its link.</p></li> <li><p>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your computer. </ol> <h2>Aside: Is it really safe to use an unreleased development version of the Fossil source code?</h2> Yes! Any check-in on the [/timeline?t=trunk | trunk branch] of the Fossil [http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository] will work fine. (Dodgy code is always on a branch.) In the unlikely event that you pick a version with a serious bug, it still won't clobber your files. Fossil uses several [./selfcheck.wiki | self-checks] prior to committing any repository change that prevent loss-of-work due to bugs. The Fossil [./selfhost.wiki | self-hosting repositories], especially the one at [http://www.fossil-scm.org/fossil], usually run a version of trunk that is less than a week or two old. Look at the bottom left-hand corner of this screen (to the right of "This page was generated in...") to see exactly which version of Fossil is rendering this page. It is always safe to use whatever version of the Fossil code you find running on the main Fossil website. <h2>2.0 Compiling</h2> <ol> <li value="5"> <p>Unpack the ZIP or tarball you downloaded then <b>cd</b> into the directory created.</p></li> <li><i>(Optional, Unix only)</i> Run <b>./configure</b> to construct a makefile. <ol type="a"> <li><p> If you do not have the OpenSSL library installed on your system, then add <b>--with-openssl=none</b> to omit the https functionality. <li><p> To build a statically linked binary (suitable for use inside a chroot jail) add the <b>--static</b> option. <li><p> To enable the native [./th1.md#tclEval | Tcl integration feature] feature, add the <b>--with-tcl=1</b> and <b>--with-tcl-private-stubs=1</b> options. <li><p> Other configuration options can be seen by running <b>./configure --help</b> </ol> <li><p>Run "<b>make</b>" to build the "fossil" or "fossil.exe" executable. The details depend on your platform and compiler. <ol type="a"> <li><p><i>Unix</i> → the configure-generated Makefile should work on all Unix and Unix-like systems. Simply type "<b>make</b>". <li><p><i>Unix without running "configure"</i> → if you prefer to avoid running configure, you can also use: <b>make -f Makefile.classic</b>. You may want to make minor edits to Makefile.classic to configure the build for your system. <li><p><i>MinGW 3.x (<u>not</u> 4.x) / MinGW-w64</i> → Use the MinGW makefile: "<b>make -f win/Makefile.mingw</b>". On a Windows box you will need either Cygwin or Msys as build environment. On Cygwin, Linux or Darwin you may want to make minor edits to win/Makefile.mingw to configure the cross-compile environment. To enable the native [./th1.md#tclEval | Tcl integration feature], use a command line like the following (all on one line): <b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b> Alternatively, <b>./configure</b> may now be used to create a Makefile suitable for use with MinGW; however, options passed to configure that are not applicable on Windows may cause the configuration or compilation to fail (e.g. fusefs, internal-sqlite, etc). <i>HINT</i>: Do <u>not</u> use MinGW-4.x, it may compile but the Fossil binary will not work correctly, see [https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c | ticket]. <li><p><i>MSVC</i> → Use the MSVC makefile. First change to the "win/" subdirectory ("<b>cd win</b>") then run "<b>nmake /f Makefile.msc</b>".<br><br>Alternatively, the batch file "<b>win\buildmsvc.bat</b>" may be used and it will attempt to detect and use the latest installed version of MSVC.<br><br>To enable the optional <a href="https://www.openssl.org/">OpenSSL</a> support, first <a href="https://www.openssl.org/source/">download the official source code for OpenSSL</a> and extract it to an appropriately named "<b>openssl-X.Y.ZA</b>" subdirectory within the local [/tree?ci=trunk&name=compat | compat] directory (e.g. "<b>compat/openssl-1.0.2p</b>"), then make sure that some recent <a href="http://www.perl.org/">Perl</a> binaries are installed locally, and finally run one of the following commands: <blockquote><pre> nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin </pre></blockquote> <blockquote><pre> buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin </pre></blockquote> To enable the optional native [./th1.md#tclEval | Tcl integration feature], run one of the following commands or add the "FOSSIL_ENABLE_TCL=1" argument to one of the other NMAKE command lines: <blockquote><pre> nmake /f Makefile.msc FOSSIL_ENABLE_TCL=1 </pre></blockquote> <blockquote><pre> buildmsvc.bat FOSSIL_ENABLE_TCL=1 </pre></blockquote> <li><p><i>Cygwin</i> → The same as other Unix-like systems. It is recommended to configure using: "<b>configure --disable-internal-sqlite</b>", making sure you have the "libsqlite3-devel" , "zlib-devel" and "openssl-devel" packages installed first. </ol> </ol> <h2>3.0 Installing</h2> <ol> <li value="8"> <p>The finished binary is named "fossil" (or "fossil.exe" on Windows). Put this binary in a directory that is somewhere on your PATH environment variable. It does not matter where.</p> <li> <p><b>(Optional:)</b> To uninstall, just delete the binary.</p> </ol> <h2>4.0 Additional Considerations</h2> <ul> <li><p> If the makefiles that come with Fossil do not work for you, or for some other reason you want to know how to build Fossil manually, then refer to the [./makefile.wiki | Fossil Build Process] document which describes in detail what the makefiles do behind the scenes. <li><p> The fossil executable is self-contained and stand-alone and usually requires no special libraries or other software to be installed. However, the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk be installed on the local machine. You can get Tcl/Tk from [http://www.activestate.com/activetcl|ActiveState]. <li><p> To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile generated by configure to add the following lines: <blockquote><pre> TCC += -DSQLITE_WITHOUT_ZONEMALLOC TCC += -D_BSD_SOURCE TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 </pre></blockquote> </ul> |
Deleted www/cap-theorem.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/caps/admin-v-setup.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/caps/impl.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/caps/index.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/caps/login-groups.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/caps/ref.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/cgi.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/changes.wiki.
1 2 | <title>Change Log</title> | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 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 | <title>Change Log</title> <a name='v2_7'></a> <h2>Changes for Version 2.7 (2018-09-22)</h2> * Add the [./alerts.md|email alerts] feature for commits, ticket changes, wiki changes, forum posts, and announcements. This is still a work in progress. It is functional, but it is not as easy to setup and use as it ought to be. * Add the [./forum.wiki|discussion forum] feature. * Add new user capabilities letters needed to support alerts and forum. Formerly, user capabilities were letters from [a-z], but with the enhancements, the supply of lower case letters was exhausted. User capabilities are now letters in [a-zA-Z0-9]. * The built-in skins are now responsive, providing better layout on small screens, including mobile devices. * The default skin now includes a hamburger menu that is generated by the [/sitemap] page. * All of the built-in skins now use a [https://en.wikipedia.org/wiki/Content_Security_Policy|Content Security Policy (CSP)] to help prevent cross-site injection and forgery attacks. There are no known vulnerabilities in Fossil. The added CSP does not fix anything; it merely adds another layer of defense. * The [/sitemap] and other list pages show as multiple columns if the viewing window is wide enough. * There is an optional "js" file for each skin that can be used to |
︙ | ︙ | |||
951 952 953 954 955 956 957 | * The `mv-rm-files` setting is now compiled into Fossil in the default Fossil configuration; no longer must you say <tt>./configure --with-legacy-mv-rm</tt> to make it available. The setting remains disabled by default, however, so you must still say <tt>fossil set mv-rm-files 1</tt> to enable it on each repository where you want hard <tt>mv/rm</tt> behavior. | > | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | * The `mv-rm-files` setting is now compiled into Fossil in the default Fossil configuration; no longer must you say <tt>./configure --with-legacy-mv-rm</tt> to make it available. The setting remains disabled by default, however, so you must still say <tt>fossil set mv-rm-files 1</tt> to enable it on each repository where you want hard <tt>mv/rm</tt> behavior. <a name='v2_6'></a> <h2>Changes for Version 2.6 (2018-05-04)</h2> * Fix a bug that was causing crashes while trying to clone the TCL repository. This fix is the main reason for the current release. * Added the new "Classic" timeline viewing mode. "Classic" is the same as "Verbose" in the previous release. The "Verbose" mode is now like "Compact" except the extra check-in details are shown by default. |
︙ | ︙ | |||
979 980 981 982 983 984 985 | time column. * In the tarball cache replacement algorithm, give extra weight to tarballs that have been accessed more than once. * Additional defenses against web-based attacks. There have not been any known vulnerabilities. We are just being paranoid. * Update the built-in SQLite to an alpha version of 3.24.0. | > | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | time column. * In the tarball cache replacement algorithm, give extra weight to tarballs that have been accessed more than once. * Additional defenses against web-based attacks. There have not been any known vulnerabilities. We are just being paranoid. * Update the built-in SQLite to an alpha version of 3.24.0. <a name='v2_5'></a> <h2>Changes for Version 2.5 (2018-02-07)</h2> * Numerous enhancements to the look and feel of the web interface. Especially: Added separate "Modern", "Compact", "Verbose", and "Columnar" view options on timelines. * Common display settings (such as the "view" option and the number of rows in a timeline) are held in a cookie and thus persist across multiple pages. |
︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 | * Begin factoring out in-line javascript into separately loaded script files. This is a step along the road toward supporting a strict Content Security Policy. More work is to be done. * Initial infrastructure is in place to make use of the pledge() system call in OpenBSD. More work is to be done. | > | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | * Begin factoring out in-line javascript into separately loaded script files. This is a step along the road toward supporting a strict Content Security Policy. More work is to be done. * Initial infrastructure is in place to make use of the pledge() system call in OpenBSD. More work is to be done. <a name='v2_4'></a> <h2>Changes for Version 2.4 (2017-11-03)</h2> * New feature: URL Aliases. URL Aliases allow an administrator to define their own URLs on the web interface that are rewritten to built-in URLs with specific parameters. Create and configure URL Aliases using the /Setup/URL_Aliases menu option in the web interface. * Add tech-note search capability. * Add the -r|--revision and -o|--origin options to the |
︙ | ︙ | |||
1053 1054 1055 1056 1057 1058 1059 | [/help?cmd=zip|zip], and [/help?cmd=tarball|tarball] pages and commands to honor the versioned manifest setting when outside of an open checkout directory. * The admin-log and access-log settings are now on by default for new repositories. * Update the built-in SQLite to version 3.21.0. | > | > | > | > | | > | | > | | 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 256 257 258 | [/help?cmd=zip|zip], and [/help?cmd=tarball|tarball] pages and commands to honor the versioned manifest setting when outside of an open checkout directory. * The admin-log and access-log settings are now on by default for new repositories. * Update the built-in SQLite to version 3.21.0. <a name='v2_3'></a> <h2>Changes for Version 2.3 (2017-07-21)</h2> * Update the built-in SQLite to version 3.20.0 (beta). * Update internal Unicode character tables, used in regular expression handling, from version 9.0 to 10.0. * Show the last-sync-URL on the [/help?cmd=/urllist|/urllist] page. * Added the "Event Summary" activity report. [/reports?type=ci&view=lastchng|example] * Added the "Security Audit" page, available to administrators only * Added the Last Login time to the user list page, for administrators only * Added the --numstat option to the [/help?cmd=diff|fossil diff] command * Limit the size of the heap and stack on unix systems, as a proactive defense against the [https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt|Stack Clash] attack. * Fix "database locked" warnings caused by "PRAGMA optimize". * Fix a potential XSS vulnerability on the [/help?cmd=/help|/help] webpage. * Documentation updates <a name='v2_2'></a> <h2>Changes for Version 2.2 (2017-04-11)</h2> * GIT comment tags are now handled by Fossil during import/export. * Show the content of README files on directory listings. ([/file/skins|example]) * Support for Basic Authentication if enabled (default off). * Show the hash algorithms used on the [/help?cmd=/rcvfromlist|/rcvfromlist] page. * The [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] pages now use the the r= query parameter to select which check-in to deliver. The uuid= query parameter is still accepted for backwards compatibility. * Update the built-in SQLite to version 3.18.0. * Run "[https://www.sqlite.org/pragma.html#pragma_optimize|PRAGMA optimize]" on the database connection as it is closing. <a name='v2_1'></a> <h2>Changes for Version 2.1 (2017-03-10)</h2> * Add support for [./hashpolicy.wiki|hash policies] that control which of the Hardened-SHA1 or SHA3-256 algorithms is used to name new artifacts. * Add the "gshow" and "gcat" subcommands to [/help?cmd=stash|fossil stash]. * Add the [/help?cmd=/juvlist|/juvlist] web page and use it to construct the [/uv/download.html|Download Page] of the Fossil self-hosting website using Ajax. <a name='v2_0'></a> <h2>Changes for Version 2.0 (2017-03-03)</h2> * Use the [https://github.com/cr-marcstevens/sha1collisiondetection|hardened SHA1] implemenation by Marc Stevens and Dan Shumow. * Add the ability to read and understand [./fileformat.wiki#names|artifact names] that are based on SHA3-256 rather than SHA1, but do not actually generate any such names. * Added the [/help?cmd=sha3sum|sha3sum] command. * Update the built-in SQLite to version 3.17.0. <a name='v1_37'></a> <h2>Changes for Version 1.37 (2017-01-16)</h2> * Add checkbox widgets to various web pages. See [/technote/8d18bf27e9| this technote] for more information. To get the checkboxes to look as intended, you must update the CSS in your repository and all clones. * Add the [/help/all|fossil all ui] command * Add the [/help?cmd=/file|/file] webpage * Enhance the [/help?cmd=/brlist|/brlist] webpage to make use of branch colors. * Add support for the ms=EXACT|LIKE|GLOB|REGEXP query parameter on the [/help?cmd=/timeline|/timeline] webpage, with associated form widgets. * Enhance the [/help/changes|changes] and [/help/status|status] commands with many new filter options so that specific kinds of changes can be found without having to pipe through grep or sed. * Enhanced the [/help/sqlite3|fossil sql] command so that it opens the [./tech_overview.wiki#localdb|checkout database] and the [./tech_overview.wiki#configdb|configuration database] in addition to the respository database. * TH1 enhancements: <ul><li>Add <nowiki>[unversioned content]</nowiki> command.</li> <li>Add <nowiki>[unversioned list]</nowiki> command.</li> <li>Add project_description variable.</li> </ul> * Rename crnl-glob [/help/settings|setting] to crlf-glob, but keep crnl-glob as a compatibility alias. * Added the --command option to the [/help/diff|diff] command. * Fix a C99-ism that prevents the 1.36 release from building with MSVC. * Fix [/help?cmd=ticket|ticket set] when using the "+" prefix with fields from the "ticketchng" table. * Remove the "fusefs" command from builds that do not have the underlying support enabled. * Fixes for incremental git import/export. * Minor security enhancements to [./encryptedrepos.wiki|encrypted repositories]. * Update the built-in SQLite to version 3.16.2. * Update the built-in Zlib to version 1.2.11. <a name='v1_36'></a> <h2>Changes for Version 1.36 (2016-10-24)</h2> * Add support for [./unvers.wiki|unversioned content], the [/help?cmd=unversioned|fossil unversioned] command and the [/help?cmd=/uv|/uv] and [/uvlist] web pages. * The [/uv/download.html|download page] is moved into [./unvers.wiki|unversioned content] so that the self-hosting Fossil websites no longer uses any external content. |
︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 | queries are filled in using HTTP query parameter values. * Added support for [./childprojects.wiki|child projects] that are able to pull from their parent but not push. * Added the -nocomplain option to the TH1 "query" command. * Added support for the chng=GLOBLIST query parameter on the [/help?cmd=/timeline|/timeline] webpage. | > | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | queries are filled in using HTTP query parameter values. * Added support for [./childprojects.wiki|child projects] that are able to pull from their parent but not push. * Added the -nocomplain option to the TH1 "query" command. * Added support for the chng=GLOBLIST query parameter on the [/help?cmd=/timeline|/timeline] webpage. <a name='v1_35'></a> <h2>Changes for Version 1.35 (2016-06-14)</h2> * Enable symlinks by default on all non-Windows platforms. * Enhance the [/md_rules|Markdown formatting] so that hyperlinks that begin with "/" are relative to the root of the Fossil repository. * Rework the [/help?cmd=/setup_ulist|/setup_list page] (the User List page) to display all users in a click-to-sort table. * Fix backslash-octal escape on filenames while importing from git |
︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 | * Added --include and --exclude options to [/help?cmd=tarball|fossil tarball] and [/help?cmd=zip|fossil zip] and the in= and ex= query parameters to the [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] web pages. * Add support for [./encryptedrepos.wiki|encrypted Fossil repositories]. * If the FOSSIL_PWREADER environment variable is set, then use the program it names in place of getpass() to read passwords and passphrases * Option --baseurl now works on Windows. | | > | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | * Added --include and --exclude options to [/help?cmd=tarball|fossil tarball] and [/help?cmd=zip|fossil zip] and the in= and ex= query parameters to the [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] web pages. * Add support for [./encryptedrepos.wiki|encrypted Fossil repositories]. * If the FOSSIL_PWREADER environment variable is set, then use the program it names in place of getpass() to read passwords and passphrases * Option --baseurl now works on Windows. * Numerious documentation improvements. * Update the built-in SQLite to version 3.13.0. <a name='v1_34'></a> <h2>Changes for Version 1.34 (2015-11-02)</h2> * Make the [/help?cmd=clean|fossil clean] command undoable for files less than 10MiB. * Update internal Unicode character tables, used in regular expression handling, from version 7.0 to 8.0. * Add the new [/help?cmd=amend|amend] command which is used to modify tags of a "check-in". |
︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 | * Fix --hard option to [/help?cmd=mv|fossil mv] and [/help?cmd=rm|fossil rm] to enable them to work properly with certain relative paths. * Change the mimetype for ".n" and ".man" files to text/plain. * Display improvements in the [/help?cmd=bisect|fossil bisect chart] command. * Updated the built-in SQLite to version 3.9.1 and activated JSON1 and FTS5 support (both currently unused within Fossil). | > | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | * Fix --hard option to [/help?cmd=mv|fossil mv] and [/help?cmd=rm|fossil rm] to enable them to work properly with certain relative paths. * Change the mimetype for ".n" and ".man" files to text/plain. * Display improvements in the [/help?cmd=bisect|fossil bisect chart] command. * Updated the built-in SQLite to version 3.9.1 and activated JSON1 and FTS5 support (both currently unused within Fossil). <a name='v1_33'></a> <h2>Changes for Version 1.33 (2015-05-23)</h2> * Improved fork detection on [/help?cmd=update|fossil update], [/help?cmd=status|fossil status] and related commands. * Change the default skin to what used to be called "San Francisco Modern". * Add the [/repo-tabsize] web page * Add [/help?cmd=import|fossil import --svn], for importing a subversion repository into fossil which was exported using "svnadmin dump". * Add the "--compress-only" option to [/help?cmd=rebuild|fossil rebuild]. |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | * Permit filtering weekday and file [/help?cmd=/reports|reports] by user. Also ensure the user parameter is preserved when changing types. Add a field for direct entry of the user name to each applicable report. * Create parent directories of [/help?cmd=settings|empty-dirs] if they don't already exist. * Inhibit timeline links to wiki pages that have been deleted. | > | > | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | * Permit filtering weekday and file [/help?cmd=/reports|reports] by user. Also ensure the user parameter is preserved when changing types. Add a field for direct entry of the user name to each applicable report. * Create parent directories of [/help?cmd=settings|empty-dirs] if they don't already exist. * Inhibit timeline links to wiki pages that have been deleted. <a name='v1_33'></a> <h2>Changes for Version 1.32 (2015-03-14)</h2> * When creating a new repository using [/help?cmd=init|fossil init], ensure that the new repository is fully compatible with historical versions of Fossil by having a valid manifest as RID 1. * Anti-aliased rendering of arrowheads on timeline graphs. * Added vi/less-style key bindings to the --tk diff GUI. * Documentation updates to fix spellings and changes all "checkins" to "check-ins". * Add the --repolist option to server commands such as [/help?cmd=server|fossil server] or [/help?cmd=http|fossil http]. * Added the "Xekri" skin. * Enhance the "ln=" query parameter on artifact displays to accept multiple ranges, separate by spaces (or "+" when URL-encoded). * Added [/help?cmd=forget|fossil forget] as an alias for [/help?cmd=rm|fossil rm]. <a name='v1_31'></a> <h2>Changes For Version 1.31 (2015-02-23)</h2> * Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID columns to the schema, to support better drawing of file change graphs. A [/help?cmd=rebuild|fossil rebuild] is recommended but is not required. so that the new graph drawing logic can work effectively. * Added [/search|search] over Check-in comments, Documents, Tickets and Wiki. Disabled by default. The search can be either a full-scan or it can use an index that is kept up-to-date automatically. The new |
︙ | ︙ | |||
1371 1372 1373 1374 1375 1376 1377 | * Added the [/mimetype_list] page. * Added the [/hash-collisions] page. * Allow the user of Common Table Expressions in the SQL that defaults ticket reports. * Break out the components (css, footer, and header) for the various built-in skins into separate files in the source tree. | > | | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | * Added the [/mimetype_list] page. * Added the [/hash-collisions] page. * Allow the user of Common Table Expressions in the SQL that defaults ticket reports. * Break out the components (css, footer, and header) for the various built-in skins into separate files in the source tree. <a name='v1_30'></a> <h2>Changes For Version 1.30 (2015-01-19)</h2> * Added the [/help?cmd=bundle|fossil bundle] command. * Added the [/help?cmd=purge|fossil purge] command. * Added the [/help?cmd=publish|fossil publish] command. * Added the [/help?cmd=unpublished|fossil unpublished] command. * Enhance the [/tree] webpage to show the age of each file with the option to sort by age. * Enhance the [/brlist] webpage to show additional information about each branch |
︙ | ︙ | |||
1441 1442 1443 1444 1445 1446 1447 | diff option in a separate file for easier editing. * (Internal:) Implement a system of compile-time checks to help ensure the correctness of printf-style formatting strings. * Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability. * Numerous documentation fixes and improvements. * Other obscure and minor bug fixes - see the timeline for details. | > | | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | diff option in a separate file for easier editing. * (Internal:) Implement a system of compile-time checks to help ensure the correctness of printf-style formatting strings. * Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability. * Numerous documentation fixes and improvements. * Other obscure and minor bug fixes - see the timeline for details. <a name='v1_29'></a> <h2>Changes For Version 1.29 (2014-06-12)</h2> * Add the ability to display content, diffs and annotations for UTF16 text files in the web interface. * Add the "SaveAs..." and "Invert" buttons to the graphical diff display that results from using the --tk option with the [/help/diff | fossil diff] command. * The [/reports] page now requires Read ("o") permissions. The "byweek" report now properly propagates the selected year through the event type |
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 | * Enhance the SSH transport mechanism so that it runs a single instance of the "fossil" executable on the remote side, obviating the need for a shell on the remote side. Some users may need to add the "?fossil=/path/to/fossil" query parameter to "ssh:" URIs if their fossil binary is not in a standard place. * Add the "[/help?cmd=blame | fossil blame]" command that works just like "fossil annotate" but uses a different output format that includes the | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | * Enhance the SSH transport mechanism so that it runs a single instance of the "fossil" executable on the remote side, obviating the need for a shell on the remote side. Some users may need to add the "?fossil=/path/to/fossil" query parameter to "ssh:" URIs if their fossil binary is not in a standard place. * Add the "[/help?cmd=blame | fossil blame]" command that works just like "fossil annotate" but uses a different output format that includes the user who made each changes and omits line numbers. * Add the "Tarball and ZIP-archive Prefix" configuration parameter under Admin/Configuration. * Fix CGI processing so that it works on web servers that do not supply REQUEST_URI. * Add options --dirsonly, --emptydirs, and --allckouts to the "[/help?cmd=clean | fossil clean]" command. * Ten-fold performance improvement in large "fossil blame" or |
︙ | ︙ | |||
1718 1719 1720 1721 1722 1723 1724 | * Improved detection of forks in a commit race. * Added the --analyze option to "fossil rebuild". <h2>Changes For Version 1.24 (2012-10-22)</h2> * Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off by default and can be turned on by setting a configuration option. * Allow style= attribute to occur in HTML markup on wiki pages. | | | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 | * Improved detection of forks in a commit race. * Added the --analyze option to "fossil rebuild". <h2>Changes For Version 1.24 (2012-10-22)</h2> * Added support for WYSIWYG editing of wiki pages. WYSIWYG is turned off by default and can be turned on by setting a configuration option. * Allow style= attribute to occur in HTML markup on wiki pages. * Added the --tk option to the "fossi diff" and "fossil stash diff" commands, causing color-coded diff output to be displayed in a Tcl/Tk GUI window. This option only works if Tcl/Tk is installed on the host. * On Windows, make the "gdiff" command default to use WinDiff.exe. * Update the "fossil stash" command so that it always prompts for a comment if the -m option is omitted. * Enhance the timeline webpages so that a=, b=, c=, d=, p=, and dp= |
︙ | ︙ | |||
1936 1937 1938 1939 1940 1941 1942 | * Performance improvements on SHA1 checksums * Update to the latest SQLite version 3.7.8 alpha. * Fix the tarball generator to work with very log pathnames <h2>Changes For Version 1.18 (2011-07-14)</h2> * Added this Change Log * Added sequential version numbering | | | 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 | * Performance improvements on SHA1 checksums * Update to the latest SQLite version 3.7.8 alpha. * Fix the tarball generator to work with very log pathnames <h2>Changes For Version 1.18 (2011-07-14)</h2> * Added this Change Log * Added sequential version numbering * Added a optional configure script - the Makefile still works for most systems. * Improvements to the "annotate" algorithm: only search primary ancestors and ignore branches. * Update the "scrub" command to remove traces of login-groups and subrepositories. * Added the --type option to the "fossil tag find" command. * In contexts where only a check-in makes sense, resolve branch and tag names to checkins only, never events or other artifacts. * Improved display of file renames on a diff. A rebuild is required to take full advantage of this change. * Update the built-in SQLite to version 3.7.7. |
Deleted www/chat.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/checkin.wiki.
︙ | ︙ | |||
39 40 41 42 43 44 45 | Before you go ahead and push content back to the servers, make sure that the username you are using by default matches your username within the project. Also remember to enable the localauth setting if you intend to make changes via a locally served web UI. Item 1 is the most important step. Consider using <b>gdiff</b> instead of <b>diff</b> if you have a graphical differ configured. Or | | | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | Before you go ahead and push content back to the servers, make sure that the username you are using by default matches your username within the project. Also remember to enable the localauth setting if you intend to make changes via a locally served web UI. Item 1 is the most important step. Consider using <b>gdiff</b> instead of <b>diff</b> if you have a graphical differ configured. Or use the command-line option <b>--tk</b>. Also consider the <b>-N</b> command-line option to show the complete text newly added files. The recommended command for completing checklist item 1 is: <b>fossil diff --tk -N</b> Look carefully at every changed line in item 1. Make sure that you are not about to commit unrelated changes. If there are two or more unrelated changes present, consider breaking up the commit into two or more separate commits. Always make 100% sure that all changes are compatible with the BSD license, that you have the authority to commit the code in accordance |
︙ | ︙ |
Changes to www/checkin_names.wiki.
1 2 | <title>Check-in Names</title> | | | > > > | < | | < < | | | | | | | | | | | | | < | | | | | | | | | | < | | | | | | | | | | > > | > | | | | | | < | | | | | | | | | | | | | < < < < | | | < < | < < < < < < < < | | | | | | | < | < < < | | | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < | | | < < | < < < | < < < | | < | < < | > > | < < < | | | | | | < < < < < < < < < < < < < < < < < < < | 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 | <title>Check-in Names</title> <table align="right" border="1" width="33%" cellpadding="10"> <tr><td> <h3>Executive Summary</h3> <p>A check-in can be identified using any of the following names: <ul> <li> Cryptographic hash prefix <li> Tag or branchname <li> Timestamp: <i>YYYY-MM-DD HH:MM:SS</i> <li> <i>tag-name</i> <big><b>:</b></big> <i>timestamp</i> <li> <b>root :</b> <i>branchname</i> <li> Special names: <ul> <li> <b>tip</b> <li> <b>current</b> <li> <b>next</b> <li> <b>previous</b> or <b>prev</b> <li> <b>ckout</b> for embedded docs </ul> </ul> </td></tr> </table> Many Fossil [/help|commands] and [./webui.wiki | web-interface] URLs accept check-in names as an argument. For example, the "[/help/info|info]" command accepts an optional check-in name to identify the specific checkout about which information is desired: <blockquote> <tt>fossil info</tt> <i>checkin-name</i> </blockquote> You are perhaps reading this page from the following URL: <blockquote> http://www.fossil-scm.org/fossil/doc/<b>trunk</b>/www/checkin_names.wiki </blockquote> The URL above is an example of an [./embeddeddoc.wiki | embedded documentation] page in Fossil. The bold term of the pathname is a check-in name that determines which version of the documentation to display. Fossil provides a variety of ways to specify a check-in. This document describes the various methods. <h2>Canonical Check-in Name</h2> The canonical name of a check-in is the hash of its [./fileformat.wiki#manifest | manifest] expressed as a 40-or-more character lowercase hexadecimal number. For example: <blockquote><pre> fossil info e5a734a19a9826973e1d073b49dc2a16aa2308f9 </pre></blockquote> The full 40+ character hash is unwieldy to remember and type, though, so Fossil also accepts a unique prefix of the hash, using any combination of upper and lower case letters, as long as the prefix is at least 4 characters long. Hence the following commands all accomplish the same thing as the above: <blockquote><pre> fossil info e5a734a19a9 fossil info E5a734A fossil info e5a7 </blockquote> Many web-interface screens identify check-ins by 10- or 16-character prefix of canonical name. <h2>Tags And Branch Names</h2> Using a tag or branch name where a check-in name is expected causes Fossil to choose the most recent check-in with that tag or branch name. So, for example, as of this writing the most recent check-in that is tagged with "release" is [d0753799e44]. So the command: <blockquote><pre> fossil info release </pre></blockquote> Results in the following input: <blockquote><pre> uuid: d0753799e447b795933e9f266233767d84aa1d84 2010-11-01 14:23:35 UTC parent: 4e1241f3236236187ad2a8f205323c05b98c9895 2010-10-31 21:51:11 UTC child: 4a094f46ade70bd9d1e4ffa48cbe94b4d3750aef 2010-11-01 18:52:37 UTC child: f4033ec09ee6bb2a73fa588c217527a1f311bd27 2010-11-01 23:38:34 UTC tags: trunk, release comment: Fix a typo in the file format documentation reported on the Tcl/Tk chatroom. (user: drh) </pre></blockquote> There are multiple check-ins that are tagged with "release" but (as of this writing) the [d0753799e44] check-in is the most recent so it is the one that is selected. Note that unlike other command DVCSes, a "branch" in Fossil is not anything special; it is simply a sequence of check-ins that share a common tag. So the same mechanism that resolves tag names also resolves branch names. Note also that there can (in theory) be an ambiguity between tag names and canonical names. Suppose, for example, you had a check-in with the canonical name deed28aa99a835f01fa06d5b4a41ecc2121bf419 and you also happened to have tagged a different check-in with "deed2". If you use the "deed2" name, does it choose the canonical name or the tag name? In such cases, you can prefix the tag name with "tag:". For example: <blockquote><tt> fossil info tag:deed2 </tt></blockquote> The "tag:deed2" name will refer to the most recent check-in tagged with "deed2" not to the check-in whose canonical name begins with "deed2". <h2>Whole Branches</h2> Usually when a branch name is specified, it means the latest check-in on that branch. But for some commands (ex: [/help/purge|purge]) a branch name on the argument means the earliest connected check-in on the branch. This seems confusing when being explained here, but it works out to be intuitive in practice. For example, the command "fossil purge XYZ" means to purge the check-in XYZ and all of its descendants. But when XYZ is in the form of a branch name, one generally wants to purge the entire branch, not just the last check-in on the branch. And so for this reason, commands like purge will interpret a branch name to be the first check-in of the branch rather than the last. If there are two or more branches with the same name, then these commands will select the first check-in of the branch that has the most recent check-in. What happens is that Fossil searches for the most recent check-in with the given tag, just as it always does. But if that tag is a branch name, it then walks back down the branch looking for the first check-in of that branch. Again, this behavior only occurs on a few commands where it make sense. <h2>Timestamps</h2> A timestamp in one of the formats shown below means the most recent check-in that occurs no later than the timestamp given: * <i>YYYY-MM-DD</i> * <i>YYYY-MM-DD HH:MM</i> * <i>YYYY-MM-DD HH:MM:SS</i> * <i>YYYY-MM-DD HH:MM:SS.SSS</i> The space between the day and the year can optionally be replaced by an uppercase <b>T</b> and the entire timestamp can optionally be followed by "<b>z</b>" or "<b>Z</b>". In the fourth form with fractional seconds, any number of digits may follow the decimal point, though due to precision limits only the first three digits will be significant. In its default configuration, Fossil interprets and displays all dates in Universal Coordinated Time (UTC). This tends to work the best for distributed projects where participants are scattered around the globe. But there is an option on the Admin/Timeline page of the web-interface to switch to local time. The "<b>Z</b>" suffix on a timestamp check-in name is meaningless if Fossil is in the default mode of using UTC for everything, but if Fossil has been switched to local time mode, then the "<b>Z</b>" suffix means to interpret that particular timestamp using UTC instead of local time. For an example of how timestamps are useful, consider the homepage for the Fossil website itself: <blockquote> http://www.fossil-scm.org/fossil/doc/<b>trunk</b>/www/index.wiki </blockquote> The bold component of that URL is a check-in name. To see what the Fossil website looked like on January 1, 2009, one has merely to change the URL to the following: <blockquote> http://www.fossil-scm.org/fossil/doc/<b>2009-01-01</b>/www/index.wiki </blockquote> <h2>Tag And Timestamp</h2> A check-in name can also take the form of a tag or branch name followed by a colon and then a timestamp. The combination means to take the most recent check-in with the given tag or branch which is not more recent than the timestamp. So, for example: <blockquote> fossil update trunk:2010-07-01T14:30 </blockquote> Would cause Fossil to update the working check-out to be the most recent check-in on the trunk that is not more recent that 14:30 (UTC) on July 1, 2010. <h2>Root Of A Branch</h2> A branch name that begins with the "<tt>root:</tt>" prefix refers to the last check-in in the parent branch prior to the beginning of the branch. Such a label is useful, for example, in computing all diffs for a single branch. The following example will show all changes in the hypothetical branch "xyzzy": <blockquote> fossil diff --from root:xyzzy --to xyzzy </blockquote> <h2>Special Tags</h2> The tag "tip" means the most recent check-in. The "tip" tag is roughly equivalent to the timestamp tag "5000-01-01". If the command is being run from a working check-out (not against a bare repository) then a few extra tags apply. The "current" tag means the current check-out. The "next" tag means the youngest child of the current check-out. And the "previous" or "prev" tag means the primary (non-merge) parent of the current check-out. For embedded documentation, the tag "ckout" means the version as present in the local source tree on disk, provided that the web server is started using "fossil ui" or "fossil server" from within the source tree. This tag can be used to preview local changes to documentation before committing them. It does not apply to CLI commands. <h2>Additional Examples</h2> To view the changes in the most recent check-in prior to the version currently checked out: <blockquote><pre> fossil diff --from previous --to current </pre></blockquote> Suppose you are of the habit of tagging each release with a "release" tag. Then to see everything that has changed on the trunk since the last release: <blockquote><pre> fossil diff --from release --to trunk </pre></blockquote> |
Changes to www/childprojects.wiki.
︙ | ︙ | |||
26 27 28 29 30 31 32 | at the request of the child. <h2>Creating a Child Project</h2> To create a new child project, first clone the parent. Then make manual SQL changes to the child repository as follows: | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | at the request of the child. <h2>Creating a Child Project</h2> To create a new child project, first clone the parent. Then make manual SQL changes to the child repository as follows: <blockquote><verbatim> UPDATE config SET name='parent-project-code' WHERE name='project-code'; UPDATE config SET name='parent-project-name' WHERE name='project-name'; INSERT INTO config(name,value) VALUES('project-code',lower(hex(randomblob(20)))); INSERT INTO config(name,value) VALUES('project-name','CHILD-PROJECT-NAME'); </verbatim></blockquote> Modify the CHILD-PROJECT-NAME in the last statement to be the name of the child project, of course. The repository is now a separate project, independent from its parent. Clone the new project to the developers as needed. |
︙ | ︙ |
Deleted www/chroot.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/ckout-workflows.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/co-vs-up.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/collisions.ipynb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/colordiff.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added www/concept1.gif.
cannot compute difference between binary files
Added www/concept2.gif.
cannot compute difference between binary files
Changes to www/concepts.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <title>Fossil Concepts</title> <h2>1.0 Introduction</h2> [./index.wiki | Fossil] is a [http://en.wikipedia.org/wiki/Software_configuration_management | software configuration management] system. Fossil is software that is designed to control and track the development of a software project and to record the history of the project. There are many such systems in use today. Fossil strives to distinguish itself from the others by being extremely simple to setup and operate. This document is intended as a quick introduction to the concepts behind Fossil. See also: | > | | | < < < < < < < < < < < < < < < < | 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 | <title>Fossil Concepts</title> <h1 align="center">Fossil Concepts</h1> <h2>1.0 Introduction</h2> [./index.wiki | Fossil] is a [http://en.wikipedia.org/wiki/Software_configuration_management | software configuration management] system. Fossil is software that is designed to control and track the development of a software project and to record the history of the project. There are many such systems in use today. Fossil strives to distinguish itself from the others by being extremely simple to setup and operate. This document is intended as a quick introduction to the concepts behind Fossil. See also: * [./whyusefossil.wiki#definitions|Definitions] * [./quickstart.wiki|Quick start guide] <h2>2.0 Composition Of A Project</h2> <img src="concept1.gif" align="right" hspace="10"> A software project normally consists of a "source tree". A source tree is a hierarchy of files that are used to generate the end product. The source tree changes over time as the software grows and expands and as features are added and bugs are fixed. A snapshot of the source tree at any point in time is called a "version" or "revision" or a "baseline" of the product. |
︙ | ︙ | |||
88 89 90 91 92 93 94 | remote repository into a local repository. Or one can do a "sync" which is a shortcut for doing both a push and a pull at the same time. Fossil also has the concept of "cloning". A "clone" is like a "pull", except that instead of beginning with an existing local repository, a clone begins with nothing and creates a new local repository that is a duplicate of a remote repository. | | < | | | | < | < < | > | < | | | | | | | | | | 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 | remote repository into a local repository. Or one can do a "sync" which is a shortcut for doing both a push and a pull at the same time. Fossil also has the concept of "cloning". A "clone" is like a "pull", except that instead of beginning with an existing local repository, a clone begins with nothing and creates a new local repository that is a duplicate of a remote repository. Communication between repositories is via HTTP. Remote repositories are identified by URL. You can also point a web browser at a repository and get human-readable status, history, and tracking information about the project. <h3>2.1 Identification Of Artifacts</h3> A particular version of a particular file is called an "artifact". Each artifact has a universally unique name which is the <a href="http://en.wikipedia.org/wiki/SHA1">SHA1</a> hash of the content of that file expressed as 40 characters of lower-case hexadecimal. Such a hash is referred to as the Artifact Identifier or Artifact ID for the artifact. The SHA1 algorithm is created with the purpose of providing a highly forgery-resistant identifier for a file. Given any file it is simple to find the artifact ID for that file. But given a artifact ID it is computationally intractable to generate a file that will have that Artifact ID. Artifact IDs look something like this: <blockquote><b> 6089f0b563a9db0a6d90682fe47fd7161ff867c8<br> 59712614a1b3ccfd84078a37fa5b606e28434326<br> 19dbf73078be9779edd6a0156195e610f81c94f9<br> b4104959a67175f02d6b415480be22a239f1f077<br> 997c9d6ae03ad114b2b57f04e9eeef17dcb82788 </b></blockquote> When referring to an artifact using Fossil, you can use a unique prefix of the artifact ID that is four characters or longer. This saves a lot of typing. When displaying artifact IDs, Fossil will usually only show the first 10 digits since that is normally enough to uniquely identify a file. |
︙ | ︙ | |||
156 157 158 159 160 161 162 | of the file and the name of the file as it appears on disk, and thus serves as a mapping from artifact ID to disk name. The artifact ID of the manifest is the identifier for the entire check-in. When you look at a "timeline" of changes in Fossil, the ID associated with each check-in or commit is really just the artifact ID of the manifest for that check-in. | | | | | | > | | 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 | of the file and the name of the file as it appears on disk, and thus serves as a mapping from artifact ID to disk name. The artifact ID of the manifest is the identifier for the entire check-in. When you look at a "timeline" of changes in Fossil, the ID associated with each check-in or commit is really just the artifact ID of the manifest for that check-in. <p>The manifest file is not normally a real file on disk. Instead, the manifest is computed in memory by Fossil whenever it needs it. However, the "fossil setting manifest on" command will cause the manifest file to be materialized to disk, if desired. Both Fossil itself, and SQLite cause the manifest file to be materialized to disk so that the makefiles for these project can read the manifest and embed version information in generated binaries. <p>Fossil automatically generates a manifest whenever you "commit" a new check-in. So this is not something that you, the developer, need to worry with. The format of a manifest is intentionally designed to be simple to parse, so that if you want to read and interpret a manifest, either by hand or with a script, that is easy to do. But you will probably never need to do so.</p> <p>In addition to identifying all files in the check-in, a manifest also contains a check-in comment, the date and time when the check-in was established, who created the check-in, and links to other check-ins from which the current check-in is derived. There is also a couple of checksums used to verify the integrity of the check-in. And the whole manifest might be PGP clearsigned.</p> <a name="keyconc"></a> <h3>2.3 Key concepts</h3> <ul> <li>A <b>check-in</b> is a set of files arranged in a hierarchy.</li> <li>A <b>repository</b> keeps a record of historical check-ins.</li> <li>Repositories share their changes using <b>push</b>, <b>pull</b>, <b>sync</b>, and <b>clone</b>.</li> |
︙ | ︙ | |||
203 204 205 206 207 208 209 | <h2>3.0 Fossil - The Program</h2> Fossil is software. The implementation of Fossil is in the form of a single executable named "fossil" (or "fossil.exe" on Windows). To install Fossil on your system, all you have to do is obtain a copy of this one executable file (either by downloading a | | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | <h2>3.0 Fossil - The Program</h2> Fossil is software. The implementation of Fossil is in the form of a single executable named "fossil" (or "fossil.exe" on Windows). To install Fossil on your system, all you have to do is obtain a copy of this one executable file (either by downloading a <a href="https://www.fossil-scm.org/fossil/uv/download.html">pre-compiled version</a> or [./build.wiki | compiling it yourself]) and then putting that file somewhere on your PATH. Fossil is completely self-contained. It is not necessary to install any other software in order to use Fossil. You do <u>not</u> need CVS, gzip, diff, rsync, Python, Perl, Tcl, Java, apache, PostgreSQL, MySQL, SQLite, patch, or any similar software on your system in order to use Fossil effectively. You will want to have some kind of text editor for entering check-in comments. Fossil will use whatever text editor is identified by your VISUAL environment variable. Fossil will also use GPG to clearsign your manifests if you happen to have it installed, but Fossil will skip that step if GPG missing from your system. You can optionally set up Fossil to use external "diff" programs, |
︙ | ︙ | |||
236 237 238 239 240 241 242 | an upgrade. Running "all rebuild" never hurts, so when upgrading it is a good policy to run it even if it is not strictly necessary. To use Fossil, simply type the name of the executable in your shell, followed by one of the various built-in commands and arguments appropriate for that command. For example: | > | > > | < < < < < < < < < < < < < < < < < | | | | | | | 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 256 257 258 259 260 261 262 263 | an upgrade. Running "all rebuild" never hurts, so when upgrading it is a good policy to run it even if it is not strictly necessary. To use Fossil, simply type the name of the executable in your shell, followed by one of the various built-in commands and arguments appropriate for that command. For example: <blockquote><b> fossil help </b></blockquote> In the next section, when we say things like "use the <b>help</b> command" we mean to use the command name "help" as the first token after the name of the Fossil executable, as shown above. <a name="workflow"></a> <h2>4.0 Workflow</h2> <img src="concept2.gif" align="right" hspace="10"> Fossil has two modes of operation: <i>"autosync"</i> and <i>"manual-merge"</i> Autosync mode is reminiscent of CVS or SVN in that it automatically keeps your changes in synchronization with your co-workers through the use of a central server. The manual-merge mode is the standard workflow for GIT or Mercurial in that your local repository develops independently of your coworkers and you share and merge your changes manually. An interesting feature of Fossil is that it supports both autosync and manual-merge work flows. The default setting for Fossil is to be in autosync mode. You can change the autosync setting or check the current autosync setting using commands like: <blockquote> <b>fossil setting autosync on<br> fossil setting autosync off<br> <b>fossil settings</b> </blockquote> By default, Fossil runs with autosync mode turned on. The authors finds that projects run more smoothly in autosync mode since autosync helps to prevent pointless forking and merging and helps keeps all collaborators working on exactly the same code rather than on their own personal forks of the code. In the author's view, manual-merge mode should be reserved for disconnected operation. |
︙ | ︙ | |||
430 431 432 433 434 435 436 | </ol> <h2>5.0 Setting Up A Fossil Server</h2> With other configuration management software, setting up a server is a lot of work and normally takes time, patience, and a lot of system knowledge. Fossil is designed to avoid this frustration. Setting up | | > | | | | | | | | | | | | | | | > | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | </ol> <h2>5.0 Setting Up A Fossil Server</h2> With other configuration management software, setting up a server is a lot of work and normally takes time, patience, and a lot of system knowledge. Fossil is designed to avoid this frustration. Setting up a server with Fossil is ridiculously easy. You have four options:</p> <ol> <li><p><b>Stand-alone server.</b> Simply run the [/help?cmd=server|fossil server] or [/help?cmd=ui|fossil ui] command from the command-line. <li><p><b>CGI.</b> Install a 2-line CGI script on a CGI-enabled web-server like Apache. <li><p><b>SCGI.</b> Start an SCGI server using the [/help?cmd=server| fossil server --scgi] command for handling SCGI requests from web-servers like Nginx. <li><p><b>Inetd or Stunnel.</b> Configure programs like inetd, xinetd, or stunnel to hand off HTTP requests directly to the [/help?cmd=http|fossil http] command. </ol> See the [./server.wiki | How To Configure A Fossil Server] document for details. <h2>6.0 Review Of Key Concepts</h2> <ul> <li>The <b>fossil</b> program is a self-contained stand-alone executable. Just put it somewhere on your PATH to install it.</li> |
︙ | ︙ |
Deleted www/contact.md.
|
| < < < < < < < < < < < < < < |
Deleted www/containers.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/contribute.wiki.
1 2 | <title>Contributing To Fossil</title> | | | | | | < < < | < < < < < < < < < | < < < < < < < < < | | | | | | | | | | | | > | < < < < | < | < < < < | < < < < < | < < < < < < < < < < < | | 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 | <title>Contributing To Fossil</title> Users are encouraged to contributed enhancements back to the Fossil project. This note outlines some of the procedures for making useful contributions. <h2>1.0 Contributor Agreement</h2> In order to accept your contributions, we <u>must</u> have a [./copyright-release.pdf | Contributor Agreement (PDF)] (or [./copyright-release.html | as HTML]) on file for you. We require this in order to maintain clear title to the Fossil code and prevent the introduction of code with incompatible licenses or other entanglements that might cause legal problems for Fossil users. Many larger companies and other lawyer-rich organizations require this as a precondition to using Fossil. If you do not wish to submit a Contributor Agreement, we would still welcome your suggestions and example code, but we will not use your code directly - we will be forced to re-implement your changes from scratch which might take longer. <h2>2.0 Submitting Patches</h2> Suggested changes or bug fixes can be submitted by creating a patch against the current source tree. Email patches to <a href="mailto:drh@sqlite.org">drh@sqlite.org</a>. Be sure to describe in detail what the patch does and which version of Fossil it is written against. A contributor agreement is not strictly necessary to submit a patch. However, without a contributor agreement on file, your patch will be used for reference only - it will not be applied to the code. This may delay acceptance of your patch. Your patches or changes might not be accepted even if you do have a contributor agreement on file. Please do not take this personally or as an affront to your coding ability. Sometimes patches are rejected because they seem to be taking the project in a direction that the architect does not want to go. Or, there might be an alternative implementation of the same feature being prepared separately. <h2>3.0 Check-in Privileges</h2> Check-in privileges are granted on a case-by-case basis. Your chances of getting check-in privileges are much improved if you have a history of submitting quality patches and/or making thoughtful posts on the [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/ | mailing list]. A contributor agreement is, of course, a prerequisite for check-in privileges.</p> Contributors are asked to make all non-trivial changes on a branch. The Fossil Architect (Richard Hipp) will merge changes onto the trunk.</p> Contributors are required to following the [./checkin.wiki | pre-checkin checklist] prior to every check-in to the Fossil self-hosting repository. This checklist is short and succinct and should only require a few seconds to follow. Contributors should print out a copy of the pre-checkin checklist and keep it on a notecard beside their workstations, for quick reference. Contributors should review the [./style.wiki | Coding Style Guidelines] and mimic the coding style used through the rest of the Fossil source code. Your code should blend in. A third-party reader should be unable to distinguish your code from any other code in the source corpus. <h2>4.0 Testing</h2> Fossil has the beginnings of a [../test/release-checklist.wiki | release checklist] but this is an area that needs further work. (Your contributions here are welcomed!) Contributors with check-in privileges are expected to run the release checklist on any major changes they contribute, and if appropriate expand the checklist and/or the automated test scripts to cover their additions. <h2>5.0 See Also</h2> * [./build.wiki | How To Compile And Install Fossil] * [./makefile.wiki | The Fossil Build Process] * [./tech_overview.wiki | A Technical Overview of Fossil] * [./adding_code.wiki | Adding Features To Fossil] |
Deleted www/css-tricks.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/css/diff.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/css/index.md.
|
| < < < < < < < < < < < < |
Changes to www/custom_ticket.wiki.
1 | <title>Customizing The Ticket System</title> | | | > | | < > > | | < > > | | | < | | | | | | < | | < | | | < | | < | | | | < | | < < < < | | | | | | | | | | | < | | > > | | | < < | < | | | < < | < < < < < < < | < < | < | > | | | > | | | < > | > > | 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 | <title>Customizing The Ticket System</title> <nowiki> <h2>Introduction</h2> <p> This guide will explain how to add the "assigned_to" and "submitted_by" fields to the ticket system in Fossil, as well as making the system more useful. You must have "admin" access to the repository to implement these instructions. </p> <h2>First modify the TICKET table</h2><blockquote> <p> Click on the "Admin" menu, then "Tickets", then "Table". After the other fields and before the final ")", insert: <pre> , assigned_to TEXT, opened_by TEXT </pre> And "Apply Changes". You have just added two more fields to the ticket database! NOTE: I won't tell you to "Apply Changes" after each step from here on out. Now, how do you use these fields? </p> </blockquote> <h2>Next add assignees</h2><blockquote> <p> Back to the "Tickets" admin page, and click "Common". Add something like this: <pre> set assigned_choices { unassigned tom dick harriet } </pre> Obviously, choose names corresponding to the logins on your system. The 'unassigned' entry is important, as it prevents you from having a NULL in that field (which causes problems later when editing). </p> </blockquote> <h2>Now modify the 'new ticket' page</h2><blockquote> <p> Back to the "Tickets" admin page, and click "New Ticket Page". This is a little more tricky. Edit the top part: <pre> if {[info exists submit]} { set status Open set opened_by $login set assigned_to "unassigned" submit_ticket } </pre> Note the "set opened_by" bit -- that will automatically set the "opened_by" field to the login name of the bug reporter. Now, skip to the part with "EMail" and modify it like so: <pre> <th1>enable_output [expr { "$login" eq "anonymous"}]</th1> <tr> <td align="right">EMail: <input type="text" name="private_contact" value="$<private_contact>" size="30"> </td> <td><u>Not publicly visible</u>. Used by developers to contact you with questions.</td> </tr> <th1>enable_output 1</th1> </pre> This bit of code will get rid of the "email" field entry for logged-in users. Since we know the user's information, we don't have to ask for it. NOTE: it might be good to automatically scoop up the user's email and put it here. </p> </blockquote> <h2>Modify the 'view ticket' page</h2><blockquote> <p> Look for the text "Contact:" (about halfway through). Then insert these lines after the closing tr tag and before the "enable_output" line: <pre> <tr> <td align="right">Assigned to:</td><td bgcolor="#d0d0d0"> $<assigned_to> </td> <td align="right">Opened by:</td><td bgcolor="#d0d0d0"> $<opened_by> </td> </pre> This will add a row which displays these two fields, in the event the user has "edit" capability. </p> </blockquote> <h2>Modify the 'edit ticket' page</h2><blockquote> <p> Before the "Severity:" line, add this: <pre> <tr><td align="right">Assigned to:</td><td> <th1>combobox assigned_to $assigned_choices 1</th1> </td></tr> </pre> That will give you a drop-down list of assignees. Now, similar to the previous section, look for "Contact:" and add this: <pre> <tr><td align="right">Reported by:</td><td> <input type="text" name="opened_by" size="40" value="$<opened_by>"> </td></tr> </pre> </p> </blockquote> <h2>What next?</h2><blockquote> <p> Now you can add custom reports which select based on the person to whom the ticket is assigned. For example, an "Assigned to me" report could be: <pre> SELECT CASE WHEN status IN ('Open','Verified') THEN '#f2dcdc' WHEN status='Review' THEN '#e8e8e8' WHEN status='Fixed' THEN '#cfe8bd' WHEN status='Tested' THEN '#bde5d6' WHEN status='Deferred' THEN '#cacae5' ELSE '#c8c8c8' END AS 'bgcolor', substr(tkt_uuid,1,10) AS '#', datetime(tkt_mtime) AS 'mtime', type, status, subsystem, title FROM ticket WHERE assigned_to=user() </pre> </p> </blockquote> </nowiki> |
Changes to www/customgraph.md.
1 2 3 4 5 6 7 8 9 10 11 | # Customizing the Timeline Graph Beginning with version 1.33, Fossil gives users and skin authors significantly more control over the look and feel of the timeline graph. ## <a id="basic-style"></a>Basic Style Options Fossil includes several options for changing the graph's style without having to delve into CSS. These can be found in the details.txt file of your skin or under Admin/Skins/Details in the web UI. | | | | | | 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 | # Customizing the Timeline Graph Beginning with version 1.33, Fossil gives users and skin authors significantly more control over the look and feel of the timeline graph. ## <a id="basic-style"></a>Basic Style Options Fossil includes several options for changing the graph's style without having to delve into CSS. These can be found in the details.txt file of your skin or under Admin/Skins/Details in the web UI. * ###`timeline-arrowheads` Set this to `0` to hide arrowheads on primary child lines. * ###`timeline-circle-nodes` Set this to `1` to make check-in nodes circular instead of square. * ###`timeline-color-graph-lines` Set this to `1` to colorize primary child lines. * ###`white-foreground` Set this to `1` if your skin uses white (or any light color) text. This tells Fossil to generate darker background colors for branches. ## <a id="adv-style"></a>Advanced Styling |
︙ | ︙ | |||
40 41 42 43 44 45 46 | latter, less obvious type. ## <a id="pos-elems"></a>Positioning Elements These elements aren't intended to be seen. They're only used to help position the graph and its visible elements. | | | | | | | | | | | | 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 | latter, less obvious type. ## <a id="pos-elems"></a>Positioning Elements These elements aren't intended to be seen. They're only used to help position the graph and its visible elements. * ###<a id="tl-canvas"></a>`.tl-canvas` Set the left and right margins on this class to give the desired amount of space between the graph and its adjacent columns in the timeline. #### Additional Classes * `.sel`: See [`.tl-node`](#tl-node) for more information. * ###<a id="tl-rail"></a>`.tl-rail` Think of rails as invisible vertical lines on which check-in nodes are placed. The more simultaneous branches in a graph, the more rails required to draw it. Setting the `width` property on this class determines the maximum spacing between rails. This spacing is automatically reduced as the number of rails increases. If you change the `width` of `.tl-node` elements, you'll probably need to change this value, too. * ###<a id="tl-mergeoffset"></a>`.tl-mergeoffset` A merge line often runs vertically right beside a primary child line. This class's `width` property specifies the maximum spacing between the two. Setting this value to `0` will eliminate the vertical merge lines. Instead, the merge arrow will extend directly off the primary child line. As with rail spacing, this is also adjusted automatically as needed. * ###<a id="tl-nodemark"></a>`.tl-nodemark` In the timeline table, the second cell in each check-in row contains an invisible div with this class. These divs are used to determine the vertical position of the nodes. By setting the `margin-top` property, you can adjust this position. ## <a id="vis-elems"></a>Visible Elements These are the elements you can actually see on the timeline graph: the nodes, arrows, and lines. Each of these elements may also have additional classes attached to them, depending on their context. * ###<a id="tl-node"></a>`.tl-node` A node exists for each check-in in the timeline. #### Additional Classes * `.leaf`: Specifies that the check-in is a leaf (i.e. that it has no children in the same branch). * `.merge`: Specifies that the check-in contains a merge. * `.sel`: When the user clicks a node to designate it as the beginning of a diff, this class is added to both the node itself and the [`.tl-canvas`](#tl-canvas) element. The class is removed from both elements when the node is clicked again. * ###<a id="tl-arrow"></a>`.tl-arrow` Arrows point from parent nodes to their children. Technically, this class is just for the arrowhead. The rest of the arrow is composed of [`.tl-line`](#tl-line) elements. There are six additional classes that are used to distinguish the different types of arrows. However, only these combinations are valid: * `.u`: Up arrow that points to a child from its primary parent. * `.u.sm`: Smaller up arrow, used when there is limited space between parent and child nodes. * `.merge.l` or `.merge.r`: Merge arrow pointing either to the left or right. * `.warp`: A timewarped arrow (always points to the right), used when a misconfigured clock makes a check-in appear to have occurred before its parent ([example](https://www.sqlite.org/src/timeline?c=2010-09-29&nd)). * ###<a id="tl-line"></a>`.tl-line` Along with arrows, lines connect parent and child nodes. Line thickness is determined by the `width` property, regardless of whether the line is horizontal or vertical. You can also use borders to create special line styles. Here's a CSS snippet for making dotted merge lines: .tl-line.merge { width: 0; background: transparent; border: 0 dotted #000; } .tl-line.merge.h { border-top-width: 1px; } .tl-line.merge.v { border-left-width: 1px; } #### Additional Classes * `.merge`: A merge line. * `.h` or `.v`: Horizontal or vertical. * `.warp`: A timewarped line. |
︙ | ︙ |
Changes to www/customskin.md.
|
| | > > | > > > > > > > | > > > | > | > > > > > > | > > > > > > > | > > > > > > | | | > | | < | < < < | > | < | > > > > | > | > | | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | > | > | > > > > > | > > | > | | < > > > > | > | | | | | < | | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | < | > | | | | | | | | | | < < < < < < < < | | | | | | | | < | > | | < | > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | Theming ======= Every HTML page generated by Fossil has the following basic structure: <blockquote><table border=1 cellpadding=10><tbody> <tr><td style='background-color:lightblue;text-align:center;'>Header</td></tr> <tr><td style='background-color:lightgreen;text-align:center;'> Fossil-Generated Content</td></tr> <tr><td style='background-color:lightblue;text-align:center;'>Footer</td></tr> <tr><td style='background-color:lightyellow;text-align:center;'>Javascript (optional)</td></tr> </tbody></table></blockquote> The header and footer control the "look" of Fossil pages. Those two sections can be customized separately for each repository to develop a new theme. The header will normally look something like this: <html> <head> ... </head> <body> ... top banner and menu bar ... <div class='content'> And the footer will look something like this: </div> ... bottom material ... </body> </html> The <head> element in the header will normally reference the /style.css CSS file that Fossil stores internally. (The $stylesheet_url TH1 variable, described below, is useful for accomplishing this.) The middle "content" section comprised the bulk of most pages and contains the actual Fossil-generated data that the user is interested in seeing. The text of this content section is not normally configurable. The content text can be styled using CSS, but it otherwise fixed. Hence it is the header and footer and the CSS that determine the look of a repository. We call the bundle of built-in CSS, header, and footer a "skin". Built-in Skins -------------- Fossil comes with several built-in skins. The sources to these built-ins can be found in the Fossil source tree under the skins/ folder. The skins/ folder contains a separate subfolder for each built-in skin, with each subfolders holding four files, "css.txt", "details.txt", "footer.txt", and "header.txt", that describe the CSS, rendering options, footer, and header for that skin, respectively. The skin of a repository can be changed to any of the built-in skins using the web interface by going to the /setup_skin web page (requires Admin privileges) and clicking the appropriate button. Or, the --skin command line option can be used for the [fossil ui](../../../help?cmd=ui) or [fossil server](../../../help?cmd=server) commands to force that particular instance of Fossil to use the specified built-in skin. Sharing Skins ------------- The skin of a repository is not part of the versioned state and does not "push" or "pull" like checked-in files. The skin is local to the repository. However, skins can be shared between repositories using the [fossil config](../../../help?cmd=configuration) command. The "fossil config push skin" command will send the local skin to a remote repository and the "fossil config pull skin" command will import a skin from a remote repository. The "fossil config export skin FILENAME" will export the skin for a repository into a file FILENAME. This file can then be imported into a different repository using the "fossil config import FILENAME" command. Unlike "push" and "pull", the "export" and "import" commands are able to move skins between repositories for different projects. So, for example, if you have a group of related repositories, you can develop a skin for one of them, then get a consistent look across all the repositories by exporting the skin from the first repository and importing into all the others. The file generated by "fossil config export" could be checked into one of your repositories and versioned, if desired. This will not automatically change the skin when looking backwards in time, but it will provide an historical record of what the skin used to be and allow the historical look of the repositories to be recreated if necessary. When cloning a repository, the skin of new repository is initialized to the skin of the repository from which it was cloned. Header And Footer Processing ---------------------------- The header.txt and footer.txt files of a skin are merely the HTML text of the header and footer. Except, before being prepended and appended to the content, the header and footer text are run through a [TH1 interpreter](./th1.md) that might adjust the text as follows: * All text within <th1>...</th1> is elided from the output and that text is instead run as a TH1 script. That TH1 script has the opportunity to insert new text in place of itself, or to inhibit or enable the output of subsequent text. * Text for the form "$NAME" or "$<NAME>" is replace with the value of the TH1 variable NAME. For example, the following is the first few lines of a typical header file: <html> <head> <base href="$baseurl/$current_page" /> <title>$<project_name>: $<title></title> <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="$home/timeline.rss" /> <link rel="stylesheet" href="$stylesheet_url" type="text/css" media="screen" /> </head> After variables are substituted by TH1, the final header text delivered to the web browser might look something like this: <html> <head> <base href="https://www.fossil-scm.org/skin2/timeline" /> <title>Fossil: Timeline</title> <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/skin2/timeline.rss" /> <link rel="stylesheet" href="/skin2/style.css?default" type="text/css" media="screen" /> </head> The same TH1 interpreter is used for both the header and the footer and for all scripts contained within them both. Hence, any global TH1 variables that are set by the header are available to the footer. Customizing the ≡ Hamburger Menu -------------------------------- The menu bar of the default skin has an entry to open a drop-down menu with additional navigation links, represented by the ≡ button (hence the name "hamburger menu"). The Javascript logic to open and close the hamburger menu when the button is clicked is contained in the optional Javascript part (js.txt) of the default skin. Out of the box, the drop-down menu shows the [Site Map](../../../sitemap), loaded by an AJAX request prior to the first display. The ≡ button for the hamburger menu is added to the menu bar by the following TH1 command in the default skin header.txt, right before the menu bar links: html "<a id='hbbtn' href='#'>☰</a>" The hamburger button can be repositioned between the other menu links (but the drop-down menu is always left-aligned with the menu bar), or it can be removed by deleting the above statement (the Javascript logic detects this case and remains idle, so it's not necessary to modify the default skin js.txt). The following empty element at the bottom of the default skin header.txt serves as the panel to hold the drop-down menu elements: <div id='hbdrop'></div> Out of the box, the contents of the panel is populated with the [Site Map](../../../sitemap), but only if the panel does not already contain any HTML elements (that is, not just comments, plain text or non-presentational white space). So the hamburger menu can be customized by replacing the empty `<div id='hbdrop'></div>` element with a menu structure knitted according to the following template: <div id="hbdrop" data-anim-ms="400"> <ul class="columns" style="column-width: 20em; column-count: auto"> <!-- NEW GROUP WITH HEADING LINK --> <li> <a href="$home$index_page">Link: Home</a> <ul> <li><a href="$home/timeline">Link: Timeline</a></li> <li><a href="$home/dir?ci=tip">Link: File List</a></li> </ul> </li> <!-- NEW GROUP WITH HEADING TEXT --> <li> Heading Text <ul> <li><a href="$home/doc/trunk/www/customskin.md">Link: Theming</a></li> <li><a href="$home/doc/trunk/www/th1.md">Link: TH1 Scripts</a></li> </ul> </li> <!-- NEXT GROUP GOES HERE --> </ul> </div> The custom `data-anim-ms` attribute can be added to the panel element to direct the Javascript logic to override the default menu animation duration of 400 ms. A faster animation duration of 80-200 ms may be preferred for smaller menus. The animation is disabled by setting the attribute to `"0"`. TH1 Variables ------------- Before expanding the TH1 within the header and footer, Fossil first initializes a number of TH1 variables to values that depend on respository settings and the specific page being generated. * **project_name** - The project_name variable is filled with the name of the project as configured under the Admin/Configuration menu. * **project_description** - The project_description variable is filled with the description of the project as configured under the Admin/Configuration menu. * **title** - The title variable holds the title of the page being generated. The title variable is special in that it is deleted after the header script runs and before the footer script. This is necessary to avoid a conflict with a variable by the same name used in my ticket-screen scripts. * **baseurl** - The root of the URL namespace for this server. * **secureurl** - The same as $baseurl except that if the scheme is "http:" it is changed to "https:" * **home** - The $baseurl without the scheme and hostname. For example, if the $baseurl is "http://projectX.com/cgi-bin/fossil" then the $home will be just "/cgi-bin/fossil". * **index_page** - The landing page URI as specified by the Admin/Configuration setup page. * **current_page** - The name of the page currently being processed, without the leading "/" and without query parameters. Examples: "timeline", "doc/trunk/README.txt", "wiki". * **csrf_token** - A token used to prevent cross-site request forgery. * **release_version** - The release version of Fossil. Ex: "1.31" * **manifest_version** - A prefix on the check-in hash of the specific version of fossil that is running. Ex: "\[47bb6432a1\]" * **manifest_date** - The date of the source-code check-in for the version of fossil that is running. * **compiler_name** - The name and version of the compiler used to build the fossil executable. * **login** - This variable only exists if the user has logged in. The value is the username of the user. * **stylesheet_url** - A URL for the internal style-sheet maintained by Fossil. * **log\_image\_url** - A URL for the logo image for this project, as configured on the Admin/Logo page. * **background\_image\_url** - A URL for a background image for this project, as configured on the Admin/Logo page. All of the above are variables in the sense that either the header or the footer is free to change or erase them. But they should probably be treated as constants. New predefined values are likely to be added in future releases of Fossil. Suggested Skin Customization Procedure -------------------------------------- Developers are free, of course, to develop new skins using any method they want, but the following is a technique that has worked well in the past and can serve as a starting point for future work: 1. Select a built-in skin that is closest to the desired look. Make copies of the css, footer, and header into files name "css.txt", "details.txt", "footer.txt", and "header.txt" in some temporary directory. If the Fossil source code is available, then these three files can be copied directly out of one of the subdirectories under skins. If sources are not easily at hand, then a copy/paste out of the CSS, footer, and header editing screens under the Admin menu will work just as well. The important point is that the three files be named exactly "css.txt", "footer.txt", and "header.txt" and that they all be in the same directory. 2. Run the [fossil ui](../../../help?cmd=ui) command with an extra option "--skin SKINDIR" where SKINDIR is the name of the directory in which the three txt files were stored in step 1. This will bring up the Fossil website using the tree files in SKINDIR. 3. Edit the four txt files in SKINDIR. After making each small change, press Reload on the web browser to see the effect of that change. Iterate until the desired look is achieved. 4. Copy/paste the resulting css.txt, details.txt, header.txt, and footer.txt files into the CSS, details, header, and footer configuration screens under the Admin/Skins menu. See Also -------- * [Customizing the Timeline Graph](customgraph.md) |
Deleted www/defcsp.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/delta-manifests.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added www/delta1.gif.
cannot compute difference between binary files
Added www/delta2.gif.
cannot compute difference between binary files
Added www/delta3.gif.
cannot compute difference between binary files
Added www/delta4.gif.
cannot compute difference between binary files
Added www/delta5.gif.
cannot compute difference between binary files
Added www/delta6.gif.
cannot compute difference between binary files
Changes to www/delta_encoder_algorithm.wiki.
1 | <title>Fossil Delta Encoding Algorithm</title> | | | | | | 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 | <title>Fossil Delta Encoding Algorithm</title> <nowiki> <h2>Abstract</h2> <p>A key component for the efficient storage of multiple revisions of a file in fossil repositories is the use of delta-compression, i.e. to store only the changes between revisions instead of the whole file.</p> <p>This document describes the encoding algorithm used by Fossil to generate deltas. It is targeted at developers working on either <a href="index.wiki">fossil</a> itself, or on tools compatible with it. The exact format of the generated byte-sequences, while in general not necessary to understand encoder operation, can be found in the companion specification titled "<a href="delta_format.wiki">Fossil Delta Format</a>". </p> <p>The algorithm is inspired by <a href="http://samba.anu.edu.au/rsync/">rsync</a>.</p> <a name="argresparam"></a><h2>1.0 Arguments, Results, and Parameters</h2> <p>The encoder takes two byte-sequences as input, the "original", and the "target", and returns a single byte-sequence containing the "delta" which transforms the original into the target upon its application.</p> <p>Note that the data of a "byte-sequence" includes its length, i.e. the number of bytes contained in the sequence.</p> <p>The algorithm has one parameter named "NHASH", the size of the "sliding window" for the "rolling hash", in bytes. These two terms are explained in the next section. The value of this parameter has to be a power of two for the algorithm to work. For Fossil the value of this parameter is set to "16".</p> <a name="operation"></a><h2>2.0 Operation</h2> <p>The algorithm is split into three phases which generate the <a href="delta_format.wiki#header">header</a>, <a href="delta_format.wiki#slist">segment list</a>, and <a href="delta_format.wiki#trailer">trailer</a> of the delta, per its general <a href="delta_format.wiki#structure">structure</a>.</p> <p>The two phases generating header and trailer are not covered here as their implementation trivially follows directly from the specification of the <a href="delta_format.wiki">delta format</a>.</p> <p>This leaves the segment-list. Its generation is done in two phases, a pre-processing step operating on the "original" byte-sequence, followed by the processing of the "target" byte-sequence using the information gathered by the first step.</p> <a name="preprocessing"></a><h3>2.1 Preprocessing the original</h3> <p>A major part of the processing of the "target" is to find a range in the "original" which contains the same content as found at the current location in the "target".</p> <p>A naive approach to this would be to search the whole "original" for such content. This however is very inefficient as it would search |
︙ | ︙ | |||
81 82 83 84 85 86 87 | computed. </li> <li>A hash table is filled, mapping from the hashes of the chunks to the list of chunk locations having this hash. </li> </ol> | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | computed. </li> <li>A hash table is filled, mapping from the hashes of the chunks to the list of chunk locations having this hash. </li> </ol> <a name="processing"></a><h3>2.1 Processing the target</h3> <p>This, the main phase of the encoder, processes the target in a loop from beginning to end. The state of the encoder is captured by two locations, the "base" and the "slide". "base" points to the first byte of the target for which no delta output has been generated yet, and "slide" is the location of the window used to look in the "origin" for commonalities. This window is NHASH bytes long.</p> |
︙ | ︙ | |||
105 106 107 108 109 110 111 | to <a href="delta_format.wiki#copyrange">copy a range</a>, or </li> <li>move the window forward one byte. </li> </ul> </p> | < < < < < < < < < < < < | < < < < < < < < < < < < < < | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | to <a href="delta_format.wiki#copyrange">copy a range</a>, or </li> <li>move the window forward one byte. </li> </ul> </p> <img src="encode10.gif" align="right" hspace="10"> <p>To make this decision the encoder first computes the hash value for the NHASH bytes in the window and then looks at all the locations in the "origin" which have the same signature. This part uses the hash table created by the pre-processing step to efficiently find these locations.</p> <p>For each of the possible candidates the encoder finds the maximal |
︙ | ︙ | |||
191 192 193 194 195 196 197 | </p> <p>If the processing loop left bytes unencoded, i.e. "base" not exactly at the end of the "target", as is possible for both end conditions, then one last insert instruction is emitted to put these bytes into the delta.<p> | | | | > | | | > | > | | | > | 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 | </p> <p>If the processing loop left bytes unencoded, i.e. "base" not exactly at the end of the "target", as is possible for both end conditions, then one last insert instruction is emitted to put these bytes into the delta.<p> <a name="exceptions"></a><h2>3.0 Exceptions</h2> <p>If the "original" is at most NHASH bytes long no compression of changes is possible, and the segment-list of the delta consists of a single literal which contains the entire "target".</p> <p>This is actually equivalent to the second end condition of the processing loop described in the previous section, just checked before actually entering the loop.</p> <a name="rollhash"></a><h2>4.0 The rolling hash</h2> <p>The rolling hash described below and used to compute content signatures was chosen not only for good hashing properties, but also to enable the easy (incremental) recalculation of its value for a sliding window, i.e. where the oldest byte is removed from the window and a new byte is shifted in.<p> <a name="rhdef"></a><h3>4.1 Definition</h3> <p>Assuming an array Z of NHASH bytes (indexing starting at 0) the hash V is computed via</p> <p align=center><table><tr><td> <p><img src="encode1.gif" align="center"></p> <p><img src="encode2.gif" align="center"></p> <p><img src="encode3.gif" align="center"></p> </td></tr></table></p> where A and B are unsigned 16-bit integers (hence the <u>mod</u>), and V is a 32-bit unsigned integer with B as MSB, A as LSB. <a name="rhincr"></a><h3>4.2 Incremental recalculation</h3> <p>Assuming an array Z of NHASH bytes (indexing starting at 0) with hash V (and components A and B), the dropped byte <img src="encode4.gif" align="center">, and the new byte <img src="encode5.gif" align="center"> , the new hash can be computed incrementally via: </p> <p align=center><table><tr><td> <p><img src="encode6.gif" align="center"></p> <p><img src="encode7.gif" align="center"></p> <p><img src="encode8.gif" align="center"></p> </td></tr></table></p> <p>For A, the regular sum, it can be seen easily that this the correct way recomputing that component.</p> <p>For B, the weighted sum, note first that <img src="encode4.gif" align="center"> has the weight NHASH in the sum, so that is what has to be removed. Then adding in <img src="encode9.gif" align="center"> adds one weight factor to all the other values of Z, and at last adds in <img src="encode5.gif" align="center"> with weight 1, also generating the correct new sum</p> |
Changes to www/delta_format.wiki.
1 | <title>Fossil Delta Format</title> | > | | | > | | | < < < < | < | < < < < < < | < | | < < | < < | < < | < < | > < < < | < < < | < < < < < < < < < < < < < < < < < < < | | | | | < | < < < | | | | | < | < < < | | | | | | | < | < < < < < < < < < < < < | < < < < < < < < < < | | | | | | | < < < < < < | | | | | | < < < < < < < | < | | | > | < < | < > > | < < < < < < < | | | | | | | | | | | | | | | | | | | | | | 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 | <title>Fossil Delta Format</title> <nowiki> <h2>Abstract</h2> <p>Fossil achieves efficient storage and low-bandwidth synchronization through the use of delta-compression. Instead of storing or transmitting the complete content of an artifact, fossil stores or transmits only the changes relative to a related artifact. </p> <p>This document describes the delta-encoding format used by fossil. The intended audience is developers working on either <a href="index.wiki">fossil</a> itself, or on tools compatible with fossil.</p> <p>Note that the delta-encoding is not a fundamental element of the state of a fossil repository. A state of a fossil repository is defined by the uncompressed and undeltaed content of all artifacts. The fact the artifacts are stored on disk using this delta-encoding format is merely an optimization. One could, in theory, create an entirely new and compatible implementation of fossil that used a different delta-encoding or did no delta-encoding at all. However, experience has shown that the delta-encoding described here is both efficient to compute and results in very small deltas, so its continued use is recommended.</p> <a name="structure"></a><h2>1.0 Structure</h2> <img src="delta1.gif" align="left" hspace="10"> <p>A delta consists of three parts, a "header", a "trailer", and a "segment-list" between them.</p> <p>Both header and trailer provide information about the target helping the decoder, and the segment-list describes how the target can be constructed from the original.</p> <a name="header"></a><h3>1.1 Header</h3> <img src="delta6.gif" align="left" hspace="10"> <p>The header consists of a single number followed by a newline character (ASCII 0x0a). The number is the length of the target in bytes.</p> <p>This means that, given a delta, the decoder can compute the size of the target (and allocate any necessary memory based on that) by simply reading the first line of the delta and decoding the number found there. In other words, before it has to decode everything else.</p> <a name="trailer"></a><h3>1.2 Trailer</h3> <img src="delta5.gif" align="left" hspace="10"> <p>The trailer consists of a single number followed by a semicolon (ASCII 0x3b). This number is a checksum of the target and can be used by a decoder to verify that the delta applied correctly, reconstructing the target from the original.</p> <p>The checksum is computed by treating the target as a series of 32-bit integer numbers (MSB first), and summing these up, modulo 2^32-1. A target whose length is not a multiple of 4 is padded with 0-bytes (ASCII 0x00) at the end.</p> <p>By putting this information at the end of the delta a decoder has it available immediately after the target has been reconstructed fully.</p> <a name="slist"></a><h3>1.3 Segment-List</h3> <img src="delta2.gif" align="left" hspace="10"> <p>The segment-list of a delta describes how to create the target from the original by a combination of inserting literal byte-sequences and copying ranges of bytes from the original. This is where the compression takes place, by encoding the large common parts of original and target in small copy instructions.</p> <p>The target is constructed from beginning to end, with the data generated by each instruction appended after the data of all previous instructions, with no gaps.</p> <a name="insertlit"></a><h4>1.3.1 Insert Literal</h4> <p>A literal is specified by two elements, the size of the literal in bytes, and the bytes of the literal itself.</p> <img src="delta4.gif" align="left" hspace="10"> <p>The length is written first, followed by a colon character (ASCII 0x3a), followed by the bytes of the literal.</p> <a name="copyrange"></a><h4>1.3.2 Copy Range</h4> <p>A range to copy is specified by two numbers, the offset of the first byte in the original to copy, and the size of the range, in bytes. The size zero is special, its usage indicates that the range extends to the end of the original.</p> <img src="delta3.gif" align="left" hspace="10"> <p>The length is written first, followed by an "at" character (ASCII 0x40), then the offset, followed by a comma (ASCII 0x2c).</p> <a name="intcoding"></a><h2>2.0 Encoding of integers</h2> <p> The format currently handles only 32 bit integer numbers. They are written base-64 encoded, MSB first, and without leading "0"-characters, except if they are significant (i.e. 0 => "0"). </p> <p> The base-64 coding is described in <a href="http://www.ietf.org/rfc/rfc3548.txt">RFC 3548</a>. </p> <a name="examples"></a><h2>3.0 Examples</h2> <a name="examplesint"></a><h3>3.1 Integer encoding</h3> <table border=1> <tr> <th>Value</th> <th>Encoding</th> </tr> <tr> <td>0</td> <td>0</td> </tr> <tr> <td>6246</td> <td>1Xb</td> </tr> <tr> <td>-1101438770</td> <td>2zMM3E</td> </tr> </table> <a name="examplesdelta"></a><h3>3.2 Delta encoding</h3> <p>An example of a delta using the specified encoding is:</p> <table border=1><tr><td><pre> 1Xb 4E@0,2:thFN@4C,6:scenda1B@Jd,6:scenda5x@Kt,6:pieces79@Qt,F: Example: eskil~E@Y0,2zMM3E;</pre> </td></tr></table> <p>This can be taken apart into the following parts:</p> <table border=1> <tr><th>What </th> <th>Encoding </th><th>Meaning </th><th>Details</th></tr> <tr><td>Header</td> <td>1Xb </td><td>Size </td><td> 6246 </td></tr> <tr><td>S-List</td> <td>4E@0, </td><td>Copy </td><td> 270 @ 0 </td></tr> <tr><td> </td> <td>2:th </td><td>Literal </td><td> 2 'th' </td></tr> <tr><td> </td> <td>FN@4C, </td><td>Copy </td><td> 983 @ 268 </td></tr> <tr><td> </td> <td>6:scenda </td><td>Literal </td><td> 6 'scenda' </td></tr> <tr><td> </td> <td>1B@Jd, </td><td>Copy </td><td> 75 @ 1256 </td></tr> <tr><td> </td> <td>6:scenda </td><td>Literal </td><td> 6 'scenda' </td></tr> <tr><td> </td> <td>5x@Kt, </td><td>Copy </td><td> 380 @ 1336 </td></tr> <tr><td> </td> <td>6:pieces </td><td>Literal </td><td> 6 'pieces' </td></tr> <tr><td> </td> <td>79@Qt, </td><td>Copy </td><td> 457 @ 1720 </td></tr> <tr><td> </td> <td>F: Example: eskil</td><td>Literal </td><td> 15 ' Example: eskil'</td></tr> <tr><td> </td> <td>~E@Y0, </td><td>Copy </td><td> 4046 @ 2176 </td></tr> <tr><td>Trailer</td><td>2zMM3E </td><td>Checksum</td><td> -1101438770 </td></tr> </table> <p>The unified diff behind the above delta is</p> <table border=1><tr><td><pre> bluepeak:(761) ~/Projects/Tcl/Fossil/Devel/devel > diff -u ../DELTA/old ../DELTA/new --- ../DELTA/old 2007-08-23 21:14:40.000000000 -0700 +++ ../DELTA/new 2007-08-23 21:14:33.000000000 -0700 @@ -5,7 +5,7 @@ * If the server does not have write permission on the database file, or on the directory containing the database file (and |
︙ | ︙ | |||
293 294 295 296 297 298 299 | single file. Allow diffs against any two arbitrary versions, not just diffs against the current check-out. Allow configuration options to replace tkdiff with some other - visual differ of the users choice. + visual differ of the users choice. Example: eskil. * Ticketing interface (expand this bullet) | | > | | 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 | single file. Allow diffs against any two arbitrary versions, not just diffs against the current check-out. Allow configuration options to replace tkdiff with some other - visual differ of the users choice. + visual differ of the users choice. Example: eskil. * Ticketing interface (expand this bullet) </pre></td></tr></table> <a name="notes"></a><h2>Notes</h2> <ul> <li>Pure text files generate a pure text delta. </li> <li>Binary files generate a delta that may contain some binary data. </li> <li>The delta encoding does not attempt to compress the content. It was considered to be much more sensible to do compression using a separate general-purpose compression library, like <a href="http://www.zlib.net">zlib</a>. </li> </ul> |
Changes to www/embeddeddoc.wiki.
1 2 3 4 5 6 7 8 | <title>Project Documentation</title> Fossil provides a built-in <a href="wikitheory.wiki">wiki</a> that can be used to store the documentation for a project. This is sufficient for many projects. If your project is well-served by wiki documentation, then you need read no further. | > | 1 2 3 4 5 6 7 8 9 | <title>Project Documentation</title> <h1 align="center">Project Documentation</h1> Fossil provides a built-in <a href="wikitheory.wiki">wiki</a> that can be used to store the documentation for a project. This is sufficient for many projects. If your project is well-served by wiki documentation, then you need read no further. |
︙ | ︙ | |||
21 22 23 24 25 26 27 | 3. Only people with check-in privileges can modify the documentation. (This might be either an advantage or disadvantage, depending on the nature of your project.) We will call documentation that is included as files in the source tree "embedded documentation". | | | | | > | | | < | | < | | | > | | | | < | | < < < < < < < < < < < < < < < < < | 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 | 3. Only people with check-in privileges can modify the documentation. (This might be either an advantage or disadvantage, depending on the nature of your project.) We will call documentation that is included as files in the source tree "embedded documentation". <h2>Fossil Support For Embedded Documentation</h2> The fossil web interface supports embedded documentation using the "/doc" page. To access embedded documentation, one points a web browser to a fossil URL of the following form: <blockquote> <i><baseurl></i><big><b>/doc/</b></big><i><version></i><big><b>/</b></big><i><filename></i> </blockquote> The <i><baseurl></i> is the main URL used to access the fossil web server. For example, the <i><baseurl></i> for the fossil project itself is either <b>http://www.fossil-scm.org/fossil</b> or <b>http://www.hwaci.com/cgi-bin/fossil</b>. If you launch the web server using the "<b>fossil server</b>" command line, then the <i><baseurl></i> is usually <b>http://localhost:8080/</b>. The <i><version></i> is any unique prefix of the check-in ID for the check-in containing the documentation you want to access. Or <i><version></i> can be the name of a [./branching.wiki | branch] in order to show the documentation for the latest version of that branch. Or <i><version></i> can be one of the keywords "<b>tip</b>" or "<b>ckout</b>". The "<b>tip</b>" keyword means to use the most recent check-in. This is useful if you want to see the very latest version of the documentation. The "<b>ckout</b>" keywords means to pull the documentation file from the local source tree on disk, not from the any check-in. The "<b>ckout</b>" keyword normally only works when you start your server using the "<b>fossil server</b>" or "<b>fossil ui</b>" command line and is intended to show what the documentation you are currently editing looks like before you check it in. Finally, the <i><filename></i> element of the URL is the pathname of the documentation file relative to the root of the source tree. The mimetype (and thus the rendering) of documentation files is determined by the file suffix. Fossil currently understands |
︙ | ︙ | |||
95 96 97 98 99 100 101 | [/md_rules | Markdown markup language]. Documentation files ending in ".txt" are plain text. Wiki, markdown, and plain text documentation files are rendered with the standard fossil header and footer added. Most other mimetypes are delivered directly to the requesting web browser without interpretation, additions, or changes. | < < | < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | > > | | > | 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 | [/md_rules | Markdown markup language]. Documentation files ending in ".txt" are plain text. Wiki, markdown, and plain text documentation files are rendered with the standard fossil header and footer added. Most other mimetypes are delivered directly to the requesting web browser without interpretation, additions, or changes. Files with the mimetype "text/html" (the .html or .htm suffix) are usually rendered directly to the browser without interpretation. However, if the file begins with a <div> element like this: <b><div class='fossil-doc' data-title='<i>Title Text</i>'></b> Then the standard Fossil header and footer are added to the document prior to being displayed. The "class='fossil-doc'" attribute is required for this to occur. The "data-title='...'" attribute is optional, but if it is present the text will become the title displayed in the Fossil header. An example of this can be seen in the text of the [/artifact/84b4b3d041d93a?txt=1 | Index Of Fossil Documentation] document. <h2>Examples</h2> This file that you are currently reading is an example of embedded documentation. The name of this file in the fossil source tree is "<b>www/embeddeddoc.wiki</b>". You are perhaps looking at this file using the URL: [http://www.fossil-scm.org/index.html/doc/trunk/www/embeddeddoc.wiki]. The first part of this path, the "[http://www.fossil-scm.org/index.html]", is the base URL. You might have originally typed: [http://www.fossil-scm.org/]. The web server at the www.fossil-scm.org site automatically redirects such links by appending "index.html". The "index.html" file on www.fossil-scm.org is really a CGI script (do not be mislead by the name) which runs the fossil web service in CGI mode. The "index.html" CGI script looks like this: <blockquote><pre> #!/usr/bin/fossil repository: /fossil/fossil.fossil </pre></blockquote> This is one of four ways to set up a <a href="./server.wiki">fossil web server</a>. The "<b>/trunk/</b>" part of the URL tells fossil to use the documentation files from the most recent trunk check-in. If you wanted to see an historical version of this document, you could substitute the name of a check-in for "<b>/trunk/</b>". For example, to see the version of this document associated with check-in [9be1b00392], simply replace the "<b>/trunk/</b>" with "<b>/9be1b00392/</b>". You can also substitute the symbolic name for a particular version or branch. For example, you might replace "<b>/trunk/</b>" with "<b>/experimental/</b>" to get the latest version of this document in the "experimental" branch. The symbolic name can also be a date and time string in any of the following formats:</p> <ul> <li> <i>YYYY-MM-DD</i> <li> <i>YYYY-MM-DD</i><b>T</b><i>HH:MM</i> <li> <i>YYYY-MM-DD</i><b>T</b><i>HH:MM:SS</i> </ul> When the symbolic name is a date and time, fossil shows the version of the document that was most recently checked in as of the date and time specified. So, for example, to see what the fossil website looked like at the beginning of 2010, enter: <blockquote> <a href="http://www.fossil-scm.org/index.html/doc/2010-01-01/www/index.wiki"> http://www.fossil-scm.org/index.html/doc/<b>2010-01-01</b>/www/index.wiki </a> </blockquote> The file that encodes this document is stored in the fossil source tree under the name "<b>www/embeddeddoc.wiki</b>" and so that name forms the last part of the URL for this document. As I sit writing this documentation file, I am testing my work by running the "<b>fossil ui</b>" command line and viewing <b>http://localhost:8080/doc/ckout/www/embeddeddoc.wiki</b> in Firefox. I am doing this even though I have not yet checked in the "<b>www/embeddeddoc.wiki</b>" file for the first time. Using the special "<b>ckout</b>" version identifier on the "<b>/doc</b>" page it is easy to make multiple changes to multiple files and see how they all look together before committing anything to the repository. |
Added www/encode10.gif.
cannot compute difference between binary files
Changes to www/encryptedrepos.wiki.
1 | <title>How To Use Encrypted Repositories</title> | < | < | | < | | | | | < | | < | < | | | | < | | | | < < | | < < | | < | < | | < > | 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 | <title>How To Use Encrypted Repositories</title> <h2>Introduction</h2><blockquote> Fossil can be compiled so that it works with encrypted repositories using the [https://www.sqlite.org/see/doc/trunk/www/readme.wiki|SQLite Encryption Extension]. This technical note explains the process. </blockquote> <h2>Building An Encryption-Enabled Fossil</h2><blockquote> The SQLite Encryption Extension (SEE) is proprietary software and requires [http://www.hwaci.com/cgi-bin/see-step1|purchasing a license]. <p> Assuming you have an SEE license, the first step of compiling Fossil to use SEE is to create an SEE-enabled version of the SQLite database source code. This alternative SQLite database source file should be called "sqlite3-see.c" and should be placed in the src/ subfolder of the Fossil sources, right beside the public-domain "sqlite3.c" source file. Also make a copy of the SEE-enabled "shell.c" file, renamed as "shell-see.c", and place it in the src/ subfolder beside the original "shell.c". <p> Add the --with-see command-line option to the configuration script to enable the use of SEE on unix-like systems. <blockquote><pre> ./configure --with-see; make </pre></blockquote> <p>To build for Windows using MSVC, add the "USE_SEE=1" argument to the "nmake" command line. <blockquote><pre> nmake -f makefile.msc USE_SEE=1 </pre></blockquote> </blockquote> <h2>Using Encrypted Repositories</h2><blockquote> Any Fossil repositories whose filename ends with ".efossil" is taken to be an encrypted repository. Fossil will prompt for the encryption password and attempt to open the repository database using that password. <p> Every invocation of fossil on an encrypted repository requires retyping the encryption password. To avoid excess password typing, consider using the "fossil shell" command which prompts for the password just once, then reuses it for each subsequent Fossil command entered at the prompt. <p> On Windows, the "fossil server", "fossil ui", and "fossil shell" commands do not (currently) work on an encrypted repository. </blockquote> <h2>Additional Security</h2><blockquote> Use the FOSSIL_SECURITY_LEVEL environment for additional protection. <blockquote><pre> export FOSSIL_SECURITY_LEVEL=1 </pre></blockquote> A setting of 1 or greater prevents fossil from trying to remember the previous sync password. <blockquote><pre> export FOSSIL_SECURITY_LEVEL=2 </pre></blockquote> A setting of 2 or greater causes all password prompts to be preceeded by a random translation matrix similar to the following: <blockquote><pre> abcde fghij klmno pqrst uvwyz qresw gjymu dpcoa fhkzv inlbt </pre></blockquote> When entering the password, the user must substitute the letter on the second line that corresponds to the letter on the first line. Uppercase substitutes for uppercase inputs, and lowercase substitutes for lowercase inputs. Letters that are not in the translation matrix (digits, punctuation, and "x") are not modified. For example, given the translation matrix above, if the password is "pilot-9crazy-xube", then the user must type "fmpav-9ekqtb-xirw". This simple substitution cypher helps prevent password capture by keyloggers. </blockquote> |
Changes to www/env-opts.md.
︙ | ︙ | |||
25 26 27 28 29 30 31 | can override the native preferences of the platform for case sensitive file names: insensitive on Windows, sensitive on Unix. There are probably odd interactions possible if you mix case sensitive and case insensitive file systems on any single platform. This option or the global setting should be used to force the case sensitivity to the most sensible condition. | < < | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | can override the native preferences of the platform for case sensitive file names: insensitive on Windows, sensitive on Unix. There are probably odd interactions possible if you mix case sensitive and case insensitive file systems on any single platform. This option or the global setting should be used to force the case sensitivity to the most sensible condition. `--chdir DIRECTORY`: Change to the named directory before processing any commands. `--comfmtflags NUMBER`: Specify flags that control how check-in comments and certain other text outputs are formatted for display. The flags are individual bits in `NUMBER`, which must be specified in base 10: |
︙ | ︙ | |||
55 56 57 58 59 60 61 | * _8_ — Attempts to break lines on word boundaries while honoring the logical line length. * _16_ — Looks for the original comment text within the text being printed. Upon matching, a new line will be emitted, thus preserving more of the pre-existing formatting. | < < < | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | * _8_ — Attempts to break lines on word boundaries while honoring the logical line length. * _16_ — Looks for the original comment text within the text being printed. Upon matching, a new line will be emitted, thus preserving more of the pre-existing formatting. `--errorlog ERRLOG`: Name a file to which fossil will log panics, errors, and warnings. `--help`: If `--help` is found anywhere on the command line, translate the command to `fossil help cmdname` where `cmdname` is the first |
︙ | ︙ | |||
112 113 114 115 116 117 118 | `--vfs VFSNAME`: Load the named VFS into SQLite. Environment Variables --------------------- | | | | > > | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | `--vfs VFSNAME`: Load the named VFS into SQLite. Environment Variables --------------------- `APPDATA`: (Windows) Location of the `~/.fossil` file. The first environment variable found in the environment from the list `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is used as the location of the `~/.fossil` file. `EDITOR`: Name the editor to use for check-in and stash comments. Overridden by the local or global `editor` setting or the `VISUAL` environment variable. `FOSSIL_BREAK`: If set, an opportunity will be created to attach a debugger to the Fossil process prior to any significant work being |
︙ | ︙ | |||
138 139 140 141 142 143 144 | `FOSSIL_FORCE_WIKI_MODERATION`: If set, *ALL* changes for wiki pages will be required to go through moderation (even those performed by the local interactive user via the command line). This can be useful for local (or remote) testing of the moderation subsystem and its impact on the contents and status of wiki pages. | | > > > | | | < < < < < < < < < < < < > > > > > > > > > > | > > > | | 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 | `FOSSIL_FORCE_WIKI_MODERATION`: If set, *ALL* changes for wiki pages will be required to go through moderation (even those performed by the local interactive user via the command line). This can be useful for local (or remote) testing of the moderation subsystem and its impact on the contents and status of wiki pages. `FOSSIL_HOME`: Location of the `~/.fossil` file. The first environment variable found in the environment from the list `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is used as the location of the `~/.fossil` file. `FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for SEE as text to be hashed into the actaul encryption key. This has no effect if Fossil was not compiled with SEE support enabled. `FOSSIL_USER`: Name of the default user account if the checkout, local or global `default-user` setting is not present. The first environment variable found in the environment from the list `FOSSIL_USER`, `USER`, `LOGNAME`, and `USERNAME` is the user name. If none of those are set, then the default user name is "root". See the discussion of Fossil Username below for a lot more detail. `FOSSIL_TCL_PATH`: When Tcl stubs support is configured, point to a specific file or folder containing the version of Tcl to load at run time. `FOSSIL_TEMP`: Fallback location of the temporary directories and files created and deleted when running the test suite. The first environment variable found in the environment from the list `FOSSIL_TEST_TEMP`, `FOSSIL_TEMP`, `TEMP`, and `TMP` is used. `FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT`: When set to the literal value `YES_DO_IT`, the test suite will relax the constraint that some tests may not run within an open checkout. This is subject to removal in the future. `FOSSIL_TEST_TEMP`: Primary location of the temporary directories and files created and deleted when running the test suite. The first environment variable found in the environment from the list `FOSSIL_TEST_TEMP`, `FOSSIL_TEMP`, `TEMP`, and `TMP` is used. `FOSSIL_VFS`: Name a VFS to load into SQLite. `GATEWAY_INTERFACE`: If present and the `--nocgi` option is not, assume fossil is invoked from a web server as a CGI command, and act accordingly. `HOME`: Location of the `~/.fossil` file. The first environment variable found in the environment from the list `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is used as the location of the `~/.fossil` file. `HOMEDRIVE`, `HOMEPATH`: (Windows) Location of the `~/.fossil` file. The first environment variable found in the environment from the list `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is used as the location of the `~/.fossil` file. |
︙ | ︙ | |||
230 231 232 233 234 235 236 | `REQUEST_URI`: If defined, included in error log messages. `SCRIPT_NAME`: If defined, included in error log messages. `SSH_CONNECTION`: Informs CGI processing if the remote client is SSH. | < < < > > > > > > | 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 256 257 258 259 260 | `REQUEST_URI`: If defined, included in error log messages. `SCRIPT_NAME`: If defined, included in error log messages. `SSH_CONNECTION`: Informs CGI processing if the remote client is SSH. `SQLITE_FORCE_PROXY_LOCKING`: From `sqlite3.c`, 1 means force always use proxy, 0 means never use proxy, and undefined means use proxy for non-local files only. `SQLITE_TMPDIR`: Names the temporary file location for SQLite. When set, this will be used instead of `TMPDIR`. `SYSTEMROOT`: (Windows) Used to locate `notepad.exe` as a fall back comment editor. `TEMP`: On Windows, the location of temporary files. The first environment variable found in the environment that names an existing directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current directory (aka `.`) is the temporary folder. `TERM`: If the linenoise library is used (almost certainly not on Windows), it will check `TERM` to verify that the interactive terminal is not named on a short list on terminals known to not work with linenoise. Linenoise is a library that provides command history and command line editing to interactive programs, and can be used in the `fossil sqlite3` command. |
︙ | ︙ | |||
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | `TH1_TEST_ANON_CAPS`: Override the default anonymous permissions used when processing the `--set-anon-caps` option for the `test-th-eval`, `test-th-render`, and `test-th-source` test commands. `TH1_TEST_USER_CAPS`: Override the default user permissions used when processing the `--set-user-caps` option for the `test-th-eval`, `test-th-render`, and `test-th-source` test commands. `TMPDIR`: Names the temporary file location for SQLite. `USER`: Name of the logged in user on many Unix-like platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. `USERNAME`: Name of the logged in user on Windows platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. `VISUAL`: Name the editor to use for check-in and stash comments. Overrides the `EDITOR` environment variable. Overridden by the local or global `editor` setting. | > > > > > > > > > > > > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | `TH1_TEST_ANON_CAPS`: Override the default anonymous permissions used when processing the `--set-anon-caps` option for the `test-th-eval`, `test-th-render`, and `test-th-source` test commands. `TH1_TEST_USER_CAPS`: Override the default user permissions used when processing the `--set-user-caps` option for the `test-th-eval`, `test-th-render`, and `test-th-source` test commands. `TMP`: On Windows, the location of temporary files. The first environment variable found in the environment that names an existing directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current directory (aka `.`) is the temporary folder. `TMPDIR`: Names the temporary file location for SQLite. `USER`: Name of the logged in user on many Unix-like platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. `USERNAME`: Name of the logged in user on Windows platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. `USERPROFILE`: On Windows, the location of temporary files. The first environment variable found in the environment that names an existing directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current directory (aka `.`) is the temporary folder. `VISUAL`: Name the editor to use for check-in and stash comments. Overrides the `EDITOR` environment variable. Overridden by the local or global `editor` setting. |
︙ | ︙ | |||
388 389 390 391 392 393 394 | in the clone even before any users have been created, and in that case it will be the new admin user. If `default-user` is not set, then the first found environment variable from the list `FOSSIL_USER`, `USER`, `LOGNAME`, and `USERNAME`, is the user name. As a final fallback, if none of those are set, then the default user name is "root". | | | < | | < | | < > > > | | | > < < < | | | < | < < | < < | < | < | | > | > | | | > | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | in the clone even before any users have been created, and in that case it will be the new admin user. If `default-user` is not set, then the first found environment variable from the list `FOSSIL_USER`, `USER`, `LOGNAME`, and `USERNAME`, is the user name. As a final fallback, if none of those are set, then the default user name is "root". ### Home Directory Fossil keeps some information interesting to each user in the user's home directory. This includes the global settings and the list of repositories and checkouts used by `fossil all`. The user's home directory is specified by the first environment variable found in the environment from the list `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME`. SQLite has its own notion of the user's home directory, which is only exposed if the interactive SQL shell is run with the "fossil sqlite3" command. Being a separate library, SQLite uses many of the same variables to find the home directory, but uses them in a different order, and does not use the `FOSSIL_HOME` variable at all. ### SQLite VFS to use See [the SQLite documentation](http://www.sqlite.org/vfs.html) for an explanation of what a VFS actually is and what it does. If the default VFS underneath SQLite is not suitable, an alternative can be selected with either the `--vfs VFSNAME` option or the `FOSSIL_VFS` environment variable. The `--vfs` option takes precedence. ### Temporary File Location Fossil places some temporary files in the current directory, notably supporting files related to merge conflicts are placed in the same folder as the merge result. Other temporary files need a home. On Unix-like systems, the first folder from the hard coded list `/var/tmp`, `/usr/tmp`, `/tmp`, `/temp`, and `.` that is found to exist in the file system is used by fossil. The SQLite library has its own code for finding a safe place for temporary files. It checks the environment variables `SQLITE_TMPDIR` and `TMPDIR` ahead of the hard coded list `/var/tmp`, `/usr/tmp`, `/tmp`, and `.` for the first directory that exists. On Windows, fossil calls [`GetTempPath`][gtp], and also queries the environment variables `TEMP`, and `TMP`. If none of those three places exist, then it uses `.`. Notice that `GetTempPath` itself used `TMP`, `TEMP`, `USERPROFILE`, and the Windows folder (named in the variable `SystemRoot`). Since the Windows folder always exists, but in modern versions of Windows is generally *not* writable by the logged in user, not having `TEMP`, `TMP`, or `USERPROFILE` set is almost guaranteed to cause trouble. [gtp]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx That said, it is not unusual for utilities on all platforms to assume that `TEMP` or `TMP` point somewhere safe for temporary files. |
︙ | ︙ | |||
479 480 481 482 483 484 485 | `google-chrome` that it can find on the `PATH`. On Apple platforms, it assumes that `open` is the command to open an URL in the user's configured default browser. On Windows platforms, it assumes that `start` is the command to open an URL in the user's configured default browser. | < < < | 489 490 491 492 493 494 495 | `google-chrome` that it can find on the `PATH`. On Apple platforms, it assumes that `open` is the command to open an URL in the user's configured default browser. On Windows platforms, it assumes that `start` is the command to open an URL in the user's configured default browser. |
Changes to www/event.wiki.
︙ | ︙ | |||
29 30 31 32 33 34 35 | roadmaps for future development, can be entered as technotes. * <b>Process Checkpoints</b>. For projects that have a formal process, technotes can be used to record the completion or the initiation of various process steps. For example, a technote can be used to record the successful completion of a long-running test, perhaps with performance results and details of where the test was run and who | | < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | roadmaps for future development, can be entered as technotes. * <b>Process Checkpoints</b>. For projects that have a formal process, technotes can be used to record the completion or the initiation of various process steps. For example, a technote can be used to record the successful completion of a long-running test, perhaps with performance results and details of where the test was run and who ran it recorded in the wiki content. * <b>News Articles</b>. Significant occurrences in the lifecycle of a project can be recorded as news articles using technotes. Perhaps the domain name of the canonical website for a project changes, or new server hardware is obtained. Such happenings are appropriate for reporting as news. * <b>Announcements</b>. Changes to the composition of the development team or acquisition of new project sponsors can be communicated as announcements which can be implemented as technotes. No project is required to use technotes. But technotes can help many projects stay better organized and provide a better historical record of the development progress. <h2>Viewing Technotes</h2> Because technotes are considered a special kind of wiki, users must have permission to read wiki in order read technotes. Enable the "j" permission under the /Setup/Users menu in order to give specific users or user classes the ability to view wiki and technotes. Technotes show up on the timeline. Click on the hyperlink beside the technote title to see the complete text. <h2>Creating And Editing Technotes</h2> There is a hyperlink under the /wikihelp menu that can be used to create new technotes. And there is a submenu hyperlink on technote displays for editing existing technotes. Users must have check-in privileges (permission "i") in order to create or edit technotes. In addition, users must have create-wiki privilege (permission "f") to create new technotes and edit-wiki privilege (permission "k") in order to edit existing technotes. Technote content may be formatted as [/wiki_rules | Fossil wiki], [/md_rules | Markdown], or a plain text. |
Changes to www/faq.tcl.
︙ | ︙ | |||
10 11 12 13 14 15 16 | faq { What GUIs are available for fossil? } { The fossil executable comes with a [./webui.wiki | web-based GUI] built in. Just run: | | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | faq { What GUIs are available for fossil? } { The fossil executable comes with a [./webui.wiki | web-based GUI] built in. Just run: <blockquote> <b>fossil [/help/ui|ui]</b> <i>REPOSITORY-FILENAME</i> </blockquote> And your default web browser should pop up and automatically point to the fossil interface. (Hint: You can omit the <i>REPOSITORY-FILENAME</i> if you are within an open check-out.) } faq { |
︙ | ︙ | |||
40 41 42 43 44 45 46 | When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add the option "--branch <i>BRANCH-NAME</i>" to make the new check-in be the first check-in for a new branch. If you want to create a new branch whose initial content is the same as an existing check-in, use this command: | | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add the option "--branch <i>BRANCH-NAME</i>" to make the new check-in be the first check-in for a new branch. If you want to create a new branch whose initial content is the same as an existing check-in, use this command: <blockquote> <b>fossil [/help/branch|branch] new</b> <i>BRANCH-NAME BASIS</i> </blockquote> The <i>BRANCH-NAME</i> argument is the name of the new branch and the <i>BASIS</i> argument is the name of the check-in that the branch splits off from. If you already have a fork in your check-in tree and you want to convert that fork to a branch, you can do this from the web interface. |
︙ | ︙ | |||
73 74 75 76 77 78 79 | "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag option to give a check-in multiple tags. Tags need not be unique. So, for example, it is common to give every released version a "release" tag. If you want add a tag to an existing check-in, you can use the <b>[/help/tag|tag]</b> command. For example: | | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag option to give a check-in multiple tags. Tags need not be unique. So, for example, it is common to give every released version a "release" tag. If you want add a tag to an existing check-in, you can use the <b>[/help/tag|tag]</b> command. For example: <blockquote> <b>fossil [/help/branch|tag] add</b> <i>TAGNAME</i> <i>CHECK-IN</i> </blockquote> The CHECK-IN in the previous line can be any [./checkin_names.wiki | valid check-in name format]. You can also add (and remove) tags from a check-in using the [./webui.wiki | web interface]. First locate the check-in that you what to tag on the timeline, then click on the link to go the detailed |
︙ | ︙ | |||
125 126 127 128 129 130 131 | See the article on [./shunning.wiki | "shunning"] for details. } faq { How do I make a clone of the fossil self-hosting repository? } { Any of the following commands should work: | < | | | | | < < | | < < | | | > | > | | | 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 | See the article on [./shunning.wiki | "shunning"] for details. } faq { How do I make a clone of the fossil self-hosting repository? } { Any of the following commands should work: <blockquote><pre> fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil fossil [/help/clone|clone] http://www3.fossil-scm.org/site.cgi fossil.fossil </pre></blockquote> Once you have the repository cloned, you can open a local check-out as follows: <blockquote><pre> mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil </pre></blockquote> Thereafter you should be able to keep your local check-out up to date with the latest code in the public repository by typing: <blockquote><pre> fossil [/help/update|update] </pre></blockquote> } faq { How do I import or export content from and to other version control systems? } { Please see [./inout.wiki | Import And Export] } ############################################################################# # Code to actually generate the FAQ # puts "<title>Fossil FAQ</title>" puts "<h1 align=\"center\">Frequently Asked Questions</h1>\n" puts "<p>Note: See also <a href=\"qandc.wiki\">Questions and Criticisms</a>.\n" puts {<ol>} for {set i 1} {$i<$cnt} {incr i} { puts "<li><a href=\"#q$i\">[lindex $faq($i) 0]</a></li>" } puts {</ol>} puts {<hr>} for {set i 1} {$i<$cnt} {incr i} { puts "<a name=\"q$i\"></a>" puts "<p><b>($i) [lindex $faq($i) 0]</b></p>\n" set body [lindex $faq($i) 1] regsub -all "\n *" [string trim $body] "\n" body puts "<blockquote>$body</blockquote></li>\n" } puts {</ol>} |
Changes to www/faq.wiki.
1 2 | <title>Fossil FAQ</title> | > | > | | | | | > > > > | | | > | | | | | > | | | | | > | | | > | | > | | < | | | | | < < | | < < | | > | | | 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 | <title>Fossil FAQ</title> <h1 align="center">Frequently Asked Questions</h1> <p>Note: See also <a href="qandc.wiki">Questions and Criticisms</a>. <ol> <li><a href="#q1">What GUIs are available for fossil?</a></li> <li><a href="#q2">What is the difference between a "branch" and a "fork"?</a></li> <li><a href="#q3">How do I create a new branch?</a></li> <li><a href="#q4">How do I tag a check-in?</a></li> <li><a href="#q5">How do I create a private branch that won't get pushed back to the main repository.</a></li> <li><a href="#q6">How can I delete inappropriate content from my fossil repository?</a></li> <li><a href="#q7">How do I make a clone of the fossil self-hosting repository?</a></li> <li><a href="#q8">How do I import or export content from and to other version control systems?</a></li> </ol> <hr> <a name="q1"></a> <p><b>(1) What GUIs are available for fossil?</b></p> <blockquote>The fossil executable comes with a [./webui.wiki | web-based GUI] built in. Just run: <blockquote> <b>fossil [/help/ui|ui]</b> <i>REPOSITORY-FILENAME</i> </blockquote> And your default web browser should pop up and automatically point to the fossil interface. (Hint: You can omit the <i>REPOSITORY-FILENAME</i> if you are within an open check-out.) See also: [http://fuelscm.org/] </blockquote></li> <a name="q2"></a> <p><b>(2) What is the difference between a "branch" and a "fork"?</b></p> <blockquote>This is a big question - too big to answer in a FAQ. Please read the <a href="branching.wiki">Branching, Forking, Merging, and Tagging</a> document.</blockquote></li> <a name="q3"></a> <p><b>(3) How do I create a new branch?</b></p> <blockquote>There are lots of ways: When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add the option "--branch <i>BRANCH-NAME</i>" to make the new check-in be the first check-in for a new branch. If you want to create a new branch whose initial content is the same as an existing check-in, use this command: <blockquote> <b>fossil [/help/branch|branch] new</b> <i>BRANCH-NAME BASIS</i> </blockquote> The <i>BRANCH-NAME</i> argument is the name of the new branch and the <i>BASIS</i> argument is the name of the check-in that the branch splits off from. If you already have a fork in your check-in tree and you want to convert that fork to a branch, you can do this from the web interface. First locate the check-in that you want to be the initial check-in of your branch on the timeline and click on its link so that you are on the <b>ci</b> page. Then find the "<b>edit</b>" link (near the "Commands:" label) and click on that. On the "Edit Check-in" page, check the box beside "Branching:" and fill in the name of your new branch to the right and press the "Apply Changes" button.</blockquote></li> <a name="q4"></a> <p><b>(4) How do I tag a check-in?</b></p> <blockquote>There are several ways: When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add a tag to that check-in using the "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag option to give a check-in multiple tags. Tags need not be unique. So, for example, it is common to give every released version a "release" tag. If you want add a tag to an existing check-in, you can use the <b>[/help/tag|tag]</b> command. For example: <blockquote> <b>fossil [/help/branch|tag] add</b> <i>TAGNAME</i> <i>CHECK-IN</i> </blockquote> The CHECK-IN in the previous line can be any [./checkin_names.wiki | valid check-in name format]. You can also add (and remove) tags from a check-in using the [./webui.wiki | web interface]. First locate the check-in that you what to tag on the timeline, then click on the link to go the detailed information page for that check-in. Then find the "<b>edit</b>" link (near the "Commands:" label) and click on that. There are controls on the edit page that allow new tags to be added and existing tags to be removed.</blockquote></li> <a name="q5"></a> <p><b>(5) How do I create a private branch that won't get pushed back to the main repository.</b></p> <blockquote>Use the <b>--private</b> command-line option on the <b>commit</b> command. The result will be a check-in which exists on your local repository only and is never pushed to other repositories. All descendants of a private check-in are also private. Unless you specify something different using the <b>--branch</b> and/or <b>--bgcolor</b> options, the new private check-in will be put on a branch named "private" with an orange background color. You can merge from the trunk into your private branch in order to keep your private branch in sync with the latest changes on the trunk. Once you have everything in your private branch the way you want it, you can then merge your private branch back into the trunk and push. Only the final merge operation will appear in other repositories. It will seem as if all the changes that occurred on your private branch occurred in a single check-in. Of course, you can also keep your branch private forever simply by not merging the changes in the private branch back into the trunk. [./private.wiki | Additional information]</blockquote></li> <a name="q6"></a> <p><b>(6) How can I delete inappropriate content from my fossil repository?</b></p> <blockquote>See the article on [./shunning.wiki | "shunning"] for details.</blockquote></li> <a name="q7"></a> <p><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p> <blockquote>Any of the following commands should work: <blockquote><pre> fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil fossil [/help/clone|clone] http://www3.fossil-scm.org/site.cgi fossil.fossil </pre></blockquote> Once you have the repository cloned, you can open a local check-out as follows: <blockquote><pre> mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil </pre></blockquote> Thereafter you should be able to keep your local check-out up to date with the latest code in the public repository by typing: <blockquote><pre> fossil [/help/update|update] </pre></blockquote></blockquote></li> <a name="q8"></a> <p><b>(8) How do I import or export content from and to other version control systems?</b></p> <blockquote>Please see [./inout.wiki | Import And Export]</blockquote></li> </ol> |
Deleted www/fileedit-page.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/fileformat.wiki.
1 2 3 4 5 6 7 8 | <title>Fossil File Formats</title> The global state of a fossil repository is kept simple so that it can endure in useful form for decades or centuries. A fossil repository is intended to be readable, searchable, and extensible by people not yet born. The global state of a fossil repository is an unordered | > > > | 1 2 3 4 5 6 7 8 9 10 11 | <title>Fossil File Formats</title> <h1 align="center"> Fossil File Formats </h1> The global state of a fossil repository is kept simple so that it can endure in useful form for decades or centuries. A fossil repository is intended to be readable, searchable, and extensible by people not yet born. The global state of a fossil repository is an unordered |
︙ | ︙ | |||
27 28 29 30 31 32 33 | different in separate repositories. The local state is not versioned and is not synchronized with the global state. The local state is not composed of artifacts and is not intended to be enduring. This document is concerned with global state only. Local state is only mentioned here in order to distinguish it from global state. | > | > | | < < | > | | | | 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 | different in separate repositories. The local state is not versioned and is not synchronized with the global state. The local state is not composed of artifacts and is not intended to be enduring. This document is concerned with global state only. Local state is only mentioned here in order to distinguish it from global state. <a name="names"></a> <h2>1.0 Artifact Names</h2> Each artifact in the repository is named by a hash of its content. No prefixes, suffixes, or other information is added to an artifact before the hash is computed. The artifact name is just the (lower-case hexadecimal) hash of the raw artifact. Fossil currently computes artifact names using either SHA1 or SHA3-256. It is relatively easy to add new algorithms in the future, but there are no plans to do so at this time. When referring to artifacts in using tty commands or webpage URLs, it is sufficient to specify a unique prefix for the artifact name. If the input prefix is not unique, Fossil will show an error. Within a structural artifact, however, all references to other artifacts must be the complete hash. Prior to Fossil version 2.0, all names were formed from the SHA1 hash of the artifact. The key innovation in Fossil 2.0 was adding support for alternative hash algorithms. <a name="structural"></a> <h2>2.0 Structural Artifacts</h2> A structural artifact is an artifact with a particular format that is used to define the relationships between other artifacts in the repository. Fossil recognizes the following kinds of structural artifacts: <ul> <li> [#manifest | Manifests] </li> <li> [#cluster | Clusters] </li> <li> [#ctrl | Control Artifacts] </li> <li> [#wikichng | Wiki Pages] </li> <li> [#tktchng | Ticket Changes] </li> <li> [#attachment | Attachments] </li> <li> [#event | TechNotes] </li> <li> [#forum | Forum Posts] </li> </ul> These eight structural artifact types are described in subsections below. Structural artifacts are ASCII text. The artifact may be PGP clearsigned. After removal of the PGP clearsign header and suffix (if any) a structural artifact consists of one or more "cards" separated by a single newline (ASCII: 0x0a) character. Each card begins with a single character "card type". Zero or more arguments may follow the card type. All arguments are separated from each other and from the card-type character by a single space character. There is no surplus white space between arguments and no leading or trailing whitespace except for the newline character that acts as the card separator. All cards must be in strict lexicographical order. There may not be any duplicate cards. In the current implementation (as of 2017-02-27) the artifacts that make up a fossil repository are stored as delta- and zlib-compressed blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This is an implementation detail and might change in a future release. For the purpose of this article "file format" means the format of the artifacts, not how the artifacts are stored on disk. It is the artifact format that is intended to be enduring. The specifics of how artifacts are stored on disk, though stable, is not intended to live as long as the artifact format. <a name="manifest"></a> <h3>2.1 The Manifest</h3> A manifest defines a check-in. A manifest contains a list of artifacts for each file in the project and the corresponding filenames, as well as information such as parent check-ins, the username of the programmer who created the check-in, the date and time when the check-in was created, and any check-in comments associated with the check-in. Allowed cards in the manifest are as follows: <blockquote> <b>B</b> <i>baseline-manifest</i><br> <b>C</b> <i>checkin-comment</i><br> <b>D</b> <i>time-and-date-stamp</i><br> <b>F</b> <i>filename</i> ?<i>hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br> <b>N</b> <i>mimetype</i><br> <b>P</b> <i>artifact-hash</i>+<br> <b>Q</b> (<b>+</b>|<b>-</b>)<i>artifact-hash</i> ?<i>artifact-hash</i>?<br> <b>R</b> <i>repository-checksum</i><br> <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br> <b>U</b> <i>user-login</i><br> <b>Z</b> <i>manifest-checksum</i> </blockquote> A manifest may optionally have a single <b>B</b> card. The <b>B</b> card specifies another manifest that serves as the "baseline" for this manifest. A manifest that has a <b>B</b> card is called a delta-manifest and a manifest that omits the <b>B</b> card is a baseline-manifest. The other manifest identified by the argument of the <b>B</b> card must be a baseline-manifest. A baseline-manifest records the complete contents of a check-in. |
︙ | ︙ | |||
143 144 145 146 147 148 149 | in the comment. A manifest must have exactly one <b>D</b> card. The sole argument to the <b>D</b> card is a date-time stamp in the ISO8601 format. The date and time should be in coordinated universal time (UTC). The format one of: | | > > | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | in the comment. A manifest must have exactly one <b>D</b> card. The sole argument to the <b>D</b> card is a date-time stamp in the ISO8601 format. The date and time should be in coordinated universal time (UTC). The format one of: <blockquote> <i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i><br> <i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i><b>.</b><i>SSS</i> </blockquote> A manifest has zero or more <b>F</b> cards. Each <b>F</b> card identifies a file that is part of the check-in. There are one, two, three, or four arguments. The first argument is the pathname of the file in the check-in relative to the root of the project file hierarchy. No ".." or "." directories are allowed within the filename. Space characters are escaped as in <b>C</b> card comment text. Backslash characters and |
︙ | ︙ | |||
246 247 248 249 250 251 252 | clear-signing prefix. The <b>Z</b> card is a sanity check to prove that the manifest is well-formed and consistent. A sample manifest from Fossil itself can be seen [/artifact/28987096ac | here]. | > | | | > | | | | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | clear-signing prefix. The <b>Z</b> card is a sanity check to prove that the manifest is well-formed and consistent. A sample manifest from Fossil itself can be seen [/artifact/28987096ac | here]. <a name="cluster"></a> <h3>2.2 Clusters</h3> A cluster is an artifact that declares the existence of other artifacts. Clusters are used during repository synchronization to help reduce network traffic. As such, clusters are an optimization and may be removed from a repository without loss or damage to the underlying project code. Allowed cards in the cluster are as follows: <blockquote> <b>M</b> <i>artifact-id</i><br /> <b>Z</b> <i>checksum</i> </blockquote> A cluster contains one or more <b>M</b> cards followed by a single <b>Z</b> card. Each <b>M</b> card has a single argument which is the artifact ID of another artifact in the repository. The <b>Z</b> card works exactly like the <b>Z</b> card of a manifest. The argument to the <b>Z</b> card is the lower-case hexadecimal representation of the MD5 checksum of all prior cards in the cluster. The <b>Z</b> card is required. An example cluster from Fossil can be seen [/artifact/d03dbdd73a2a8 | here]. <a name="ctrl"></a> <h3>2.3 Control Artifacts</h3> Control artifacts are used to assign properties to other artifacts within the repository. Allowed cards in a control artifact are as follows: <blockquote> <b>D</b> <i>time-and-date-stamp</i><br /> <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br /> <b>U</b> <i>user-name</i><br /> <b>Z</b> <i>checksum</i><br /> </blockquote> A control artifact must have one <b>D</b> card, one <b>U</b> card, one <b>Z</b> card and one or more <b>T</b> cards. No other cards or other text is allowed in a control artifact. Control artifacts might be PGP clearsigned. The <b>D</b> card and the <b>Z</b> card of a control artifact are the same as in a manifest. The <b>T</b> card represents a [./branching.wiki#tags | tag or property] that is applied to some other artifact. The <b>T</b> card has two or three values. The second argument is the 40 character lowercase artifact ID of the artifact to which the tag is to be applied. The first value is the tag name. The first character of the tag is either "+", "-", or "*". The "+" means the tag should be added to the artifact. The "-" means the tag should be removed. The "*" character means the tag should be added to the artifact and all direct descendants (but not descendants through a merge) down to but not including the first descendant that contains a |
︙ | ︙ | |||
321 322 323 324 325 326 327 | check-in user. The "date" tag overrides the check-in date. The "branch" tag sets the name of the branch that at check-in belongs to. Symbolic tags begin with the "sym-" prefix. The <b>U</b> card is the name of the user that created the control artifact. The <b>Z</b> card is the usual required artifact checksum. | | > | | < | < < < < < < < > | | | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | check-in user. The "date" tag overrides the check-in date. The "branch" tag sets the name of the branch that at check-in belongs to. Symbolic tags begin with the "sym-" prefix. The <b>U</b> card is the name of the user that created the control artifact. The <b>Z</b> card is the usual required artifact checksum. An example control artifacts can be seen [/info/9d302ccda8 | here]. <a name="wikichng"></a> <h3>2.4 Wiki Pages</h3> A wiki artifact defines a single version of a single wiki page. Wiki artifacts accept the following card types: <blockquote> <b>D</b> <i>time-and-date-stamp</i><br /> <b>L</b> <i>wiki-title</i><br /> <b>N</b> <i>mimetype</i><br /> <b>P</b> <i>parent-artifact-id</i>+<br /> <b>U</b> <i>user-name</i><br /> <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br /> <b>Z</b> <i>checksum</i> </blockquote> The <b>D</b> card is the date and time when the wiki page was edited. The <b>P</b> card specifies the parent wiki pages, if any. The <b>L</b> card gives the name of the wiki page. The optional <b>N</b> card specifies the mimetype of the wiki text. If the <b>N</b> card is omitted, the mimetype is assumed to be text/x-fossil-wiki. The <b>U</b> card specifies the login of the user who made this edit to the wiki page. The <b>Z</b> card is the usual checksum over the entire artifact and is required. The <b>W</b> card is used to specify the text of the wiki page. The argument to the <b>W</b> card is an integer which is the number of bytes of text in the wiki page. That text follows the newline character that terminates the <b>W</b> card. The wiki text is always followed by one extra newline. An example wiki artifact can be seen [/artifact?name=7b2f5fd0e0&txt=1 | here]. <a name="tktchng"></a> <h3>2.5 Ticket Changes</h3> A ticket-change artifact represents a change to a trouble ticket. The following cards are allowed on a ticket change artifact: <blockquote> <b>D</b> <i>time-and-date-stamp</i><br /> <b>J</b> ?<b>+</b>?<i>name</i> ?<i>value</i>?<br /> <b>K</b> <i>ticket-id</i><br /> <b>U</b> <i>user-name</i><br /> <b>Z</b> <i>checksum</i> </blockquote> The <b>D</b> card is the usual date and time stamp and represents the point in time when the change was entered. The <b>U</b> card is the login of the programmer who entered this change. The <b>Z</b> card is the required checksum over the entire artifact. Every ticket has a distinct ticket-id: |
︙ | ︙ | |||
412 413 414 415 416 417 418 | on the <b>J</b> card replaces any previous value of the field. The field name and value are both encoded using the character escapes defined for the <b>C</b> card of a manifest. An example ticket-change artifact can be seen [/artifact/91f1ec6af053 | here]. | > | | | | > | | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | on the <b>J</b> card replaces any previous value of the field. The field name and value are both encoded using the character escapes defined for the <b>C</b> card of a manifest. An example ticket-change artifact can be seen [/artifact/91f1ec6af053 | here]. <a name="attachment"></a> <h3>2.6 Attachments</h3> An attachment artifact associates some other artifact that is the attachment (the source artifact) with a ticket or wiki page or technical note to which the attachment is connected (the target artifact). The following cards are allowed on an attachment artifact: <blockquote> <b>A</b> <i>filename target</i> ?<i>source</i>?<br /> <b>C</b> <i>comment</i><br /> <b>D</b> <i>time-and-date-stamp</i><br /> <b>N</b> <i>mimetype</i><br /> <b>U</b> <i>user-name</i><br /> <b>Z</b> <i>checksum</i> </blockquote> The <b>A</b> card specifies a filename for the attachment in its first argument. The second argument to the <b>A</b> card is the name of the wiki page or ticket or technical note to which the attachment is connected. The third argument is either missing or else it is the 40-character artifact ID of the attachment itself. A missing third argument means that the attachment should be deleted. The <b>C</b> card is an optional comment describing what the attachment is about. The <b>C</b> card is optional, but there can only be one. A single <b>D</b> card is required to give the date and time when the attachment was applied. There may be zero or one <b>N</b> cards. The <b>N</b> card specifies the mimetype of the comment text provided in the <b>C</b> card. If the <b>N</b> card is omitted, the <b>C</b> card mimetype is taken to be text/plain. A single <b>U</b> card gives the name of the user who added the attachment. If an attachment is added anonymously, then the <b>U</b> card may be omitted. The <b>Z</b> card is the usual checksum over the rest of the attachment artifact. The <b>Z</b> card is required. <a name="event"></a> <h3>2.7 Technical Notes</h3> A technical note or "technote" artifact (formerly known as an "event" artifact) associates a timeline comment and a page of text (similar to a wiki page) with a point in time. Technotes can be used to record project milestones, release notes, blog entries, process checkpoints, or news articles. The following cards are allowed on an technote artifact: <blockquote> <b>C</b> <i>comment</i><br> <b>D</b> <i>time-and-date-stamp</i><br /> <b>E</b> <i>technote-time</i> <i>technote-id</i><br /> <b>N</b> <i>mimetype</i><br /> <b>P</b> <i>parent-artifact-id</i>+<br /> <b>T</b> <b>+</b><i>tag-name</i> <b>*</b> ?<i>value</i>?<br /> <b>U</b> <i>user-name</i><br /> <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br /> <b>Z</b> <i>checksum</i> </blockquote> The <b>C</b> card contains text that is displayed on the timeline for the technote. The <b>C</b> card is optional, but there can only be one. A single <b>D</b> card is required to give the date and time when the technote artifact was created. This is different from the time at which the technote appears on the timeline. |
︙ | ︙ | |||
520 521 522 523 524 525 526 | A single <b>W</b> card provides wiki text for the document associated with the technote. The format of the <b>W</b> card is exactly the same as for a [#wikichng | wiki artifact]. The <b>Z</b> card is the required checksum over the rest of the artifact. | > | | | | | | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | A single <b>W</b> card provides wiki text for the document associated with the technote. The format of the <b>W</b> card is exactly the same as for a [#wikichng | wiki artifact]. The <b>Z</b> card is the required checksum over the rest of the artifact. <a name="forum"></a> <h3>2.8 Forum Posts</h3> Forum posts are intended as a mechanism for users and developers to discuss a project. Forum posts are like messages on a mailing list. The following cards are allowed on an forum post artifact: <blockquote> <b>D</b> <i>time-and-date-stamp</i><br /> <b>G</b> <i>thread-root</i><br /> <b>H</b> <i>thread-title</i><br /> <b>I</b> <i>in-reply-to</i><br /> <b>N</b> <i>mimetype</i><br /> <b>P</b> <i>parent-artifact-id</i><br /> <b>U</b> <i>user-name</i><br /> <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br /> <b>Z</b> <i>checksum</i> </blockquote> Every forum post must have either one <b>I</b> card and one <b>G</b> card or one <b>H</b> card. Forum posts are organized into topic threads. The initial post for a thread (the root post) has an <b>H</b> card giving the title or subject for that thread. The argument to the <b>H</b> card is a string in the same format as a comment string in a <b>C</b> card. All follow-up posts have an <b>I</b> card that indicates which prior post in the same thread the current forum post is replying to, and a <b>G</b> card specifying the root post for the entire thread. The argument to G and <b>I</b> cards is the artifact hash for the prior forum post to which the card refers. In theory, it is sufficient for follow-up posts to have only an <b>I</b> card, since the <b>G</b> card value could be computed by following a chain of <b>I</b> cards. However, the <b>G</b> card is required in order to associate the artifact with a forum thread in the case where an intermediate artifact in the <b>I</b> card chain is shunned or otherwise |
︙ | ︙ | |||
594 595 596 597 598 599 600 | A single <b>W</b> card provides wiki text for the forum post. The format of the <b>W</b> card is exactly the same as for a [#wikichng | wiki artifact]. The <b>Z</b> card is the required checksum over the rest of the artifact. | > | | | > > > | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | A single <b>W</b> card provides wiki text for the forum post. The format of the <b>W</b> card is exactly the same as for a [#wikichng | wiki artifact]. The <b>Z</b> card is the required checksum over the rest of the artifact. <a name="summary"></a> <h2>3.0 Card Summary</h2> The following table summarizes the various kinds of cards that appear on Fossil artifacts. A blank entry means that combination of card and artifact is not legal. A number or range of numbers indicates the number of times a card may (or must) appear in the corresponding artifact type. e.g. a value of 1 indicates a required unique card and 1+ indicates that one or more such cards are required. <table border=1 width="100%"> <tr> <th rowspan=2 valign=bottom>Card Format</th> <th colspan=8>Used By</th> </tr> <tr> <th>Manifest</th> <th>Cluster</th> <th>Control</th> <th>Wiki</th> <th>Ticket</th> <th>Attachment</th> <th>Technote</th> |
︙ | ︙ | |||
642 643 644 645 646 647 648 | <td> </td> </tr> <tr> <td><b>C</b> <i>comment-text</i></td> <td align=center><b>1</b></td> <td> </td> <td> </td> | | | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 | <td> </td> </tr> <tr> <td><b>C</b> <i>comment-text</i></td> <td align=center><b>1</b></td> <td> </td> <td> </td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> <td align=center><b>0-1</b></td> <td> </td> </tr> <tr> <td><b>D</b> <i>date-time-stamp</i></td> |
︙ | ︙ | |||
701 702 703 704 705 706 707 | <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> | | | | 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 | <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> </tr> <tr> <td><b>I</b> <i>in-reply-to</i></td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> </tr> <tr> <td><b>J</b> <i>name</i> ?<i>value</i>?</td> <td> </td> <td> </td> <td> </td> <td> </td> |
︙ | ︙ | |||
778 779 780 781 782 783 784 | <td align=center><b>0-1</b></td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> | | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 | <td align=center><b>0-1</b></td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> <td> </td> <td> </td> <td align=center><b>0-1</b></td> <td align=center><b>0-1</b></td> </tr> <tr> <td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid</i> ?<i>uuid</i>?</td> <td align=center><b>0+</b></td> <td> </td> <td> </td> <td> </td> |
︙ | ︙ | |||
802 803 804 805 806 807 808 | <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <tr> | | | | | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <tr> <td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname</i> <i>uuid</i> ?<i>value</i>?</td> <td align=center><b>0+</b></td> <td> </td> <td align=center><b>1+</b></td> <td> </td> <td> </td> <td> </td> <td align=center><b>0+</b></td> <td> </td> </tr> <tr> <td><b>U</b> <i>username</i></td> <td align=center><b>1</b></td> <td> </td> <td align=center><b>1</b></td> |
︙ | ︙ | |||
847 848 849 850 851 852 853 | <td align=center><b>1</b></td> <td align=center><b>1</b></td> <td align=center><b>1</b></td> <td align=center><b>1</b></td> </tr> </table> | < < < | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 | <td align=center><b>1</b></td> <td align=center><b>1</b></td> <td align=center><b>1</b></td> <td align=center><b>1</b></td> </tr> </table> <a name="addenda"></a> <h2>4.0 Addenda</h2> This section contains additional information which may be useful when implementing algorithms described above. <h3>4.1 R-Card Hash Calculation</h3> Given a manifest file named <tt>MF</tt>, the following Bash shell code demonstrates how to compute the value of the <b>R</b> card in that manifest. This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are shell input and other lines are output. This demonstration assumes that the file versions represented by the input manifest are checked out under the current directory. |
︙ | ︙ |
Changes to www/fiveminutes.wiki.
1 2 3 4 5 6 7 8 | <title>Up and running in 5 minutes as a single user</title> <p align="center"><b><i> The following document was contributed by Gilles Ganault on 2013-01-08. </i></b> </p><hr> <h1>Up and running in 5 minutes as a single user</h1> | < | | < | < | | < | < | < | | < | < | | | < | < | < | < | | < | < | | | < | | | < | | < | < | < < < | | < | < < | < | | > > > > > > > | 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 | <title>Up and running in 5 minutes as a single user</title> <p align="center"><b><i> The following document was contributed by Gilles Ganault on 2013-01-08. </i></b> </p><hr> <h1>Up and running in 5 minutes as a single user</h1> <p>This short document explains the main basic Fossil commands for a single user, i.e. with no additional users, with no need to synchronize with some remote repository, and no need for branching/forking.</p> <h2>Create a new repository</h2> <p>fossil new c:\test.repo</p> <p>This will create the new SQLite binary file that holds the repository, i.e. files, tickets, wiki, etc. It can be located anywhere, although it's considered best practice to keep it outside the work directory where you will work on files after they've been checked out of the repository.</p> <h2>Open the repository</h2> <p>cd c:\temp\test.fossil</p> <p>fossil open c:\test.repo</p> <p>This will check out the last revision of all the files in the repository, if any, into the current work directory. In addition, it will create a binary file _FOSSIL_ to keep track of changes (on non-Windows systems it is called <tt>.fslckout</tt>).</p> <h2>Add new files</h2> <p>fossil add .</p> <p>To tell Fossil to add new files to the repository. The files aren't actually added until you run "commit". When using ".", it tells Fossil to add all the files in the current directory recursively, i.e. including all the files in all the subdirectories.</p> <p>Note: To tell Fossil to ignore some extensions:</p> <p>fossil settings ignore-glob "*.o,*.obj,*.exe" --global</p> <h2>Remove files that haven't been committed yet</h2> <p>fossil delete myfile.c</p> <p>This will simply remove the item from the list of files that were previously added through "fossil add".</p> <h2>Check current status</h2> <p>fossil changes</p> <p>This shows the list of changes that have been done and will be committed the next time you run "fossil commit". It's a useful command to run before running "fossil commit" just to check that things are OK before proceeding.</p> <h2>Commit changes</h2> <p>To actually apply the pending changes to the repository, e.g. new files marked for addition, checked-out files that have been edited and must be checked-in, etc.</p> <p>fossil commit -m "Added stuff"</p> If no file names are provided on the command-line then all changes will be checked in, otherwise just the listed file(s) will be checked in. <h2>Compare two revisions of a file</h2> <p>If you wish to compare the last revision of a file and its checked out version in your work directory:</p> <p>fossil gdiff myfile.c</p> <p>If you wish to compare two different revisions of a file in the repository:</p> <p>fossil finfo myfile: Note the first hash, which is the UUID of the commit when the file was committed</p> <p>fossil gdiff --from UUID#1 --to UUID#2 myfile.c</p> <h2>Cancel changes and go back to previous revision</h2> <p>fossil revert myfile.c</p> <p>Fossil does not prompt when reverting a file. It simply reminds the user about the "undo" command, just in case the revert was a mistake.</p> <h2>Close the repository</h2> <p>fossil close</p> <p>This will simply remove the _FOSSIL_ at the root of the work directory but will not delete the files in the work directory. From then on, any use of "fossil" will trigger an error since there is no longer any connection.</p> |
Changes to www/forum.wiki.
1 2 3 4 | <title>Fossil Forums</title> <h2>Introduction</h2> | | < < < < | > | < < < | < < < < | < < < < < < | < < < | < | < < < > | < < > | | | > > > > > | | | > > > > > > | > > > > > > | > > | > > > > | > > > > > > | > > > > > | > > > > > | > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | | | | | < | | | 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 | <title>Fossil Forums</title> <h2>Introduction</h2> As of Fossil 2.7, Fossil includes a built-in discussion forum feature. Any project complex enough to benefit from being managed by Fossil and which has more than one user can probably also benefit from having a discussion forum. Even if your project has a discussion forum already, there are many benefits to using Fossil's built-in forum feature, some of which you cannot get by using third-party alternatives: * <b>Easy to Administer:</b> Third-party discussion forum and mailing list software tends to be difficult to install, set up, and administer. The Fossil forum feature aims to be as close to zero-configuration as is practical. * <b>Malefactor Resistant:</b> Because Fossil accepts forum posts only via the web UI, it is inherently [./antibot.wiki | protected against bots]. * <b>Distributed and Tamper-Proof:</b> Posts are stored in the Fossil repository using the same [./fileformat.wiki | block chain technology] that Fossil uses to store your check-ins, wiki documents, etc. Posts sync to cloned repositories in a tamper-proof fashion. * <b>Space Efficient:</b> Because of Fossil's [./delta_format.wiki | delta compression technology], discussions add little to the size of a cloned repository. Ten years of the SQLite project's discussions — averaging about 2 dozen posts per day — compress down to [https://fossil-scm.org/forum/forumpost/9b6f3f36bdb | just 35 MB of space] in a Fossil forum repository. * <b>Built-in Full-Text Search:</b> Fossil forums use [https://sqlite.org/fts3.html | SQLite's powerful FTS4 engine] to handle searches. If your project currently uses a mailing list for discussions, this means you are no longer reliant upon third-party mailing list archive services to provide a useful search engine for your discussions. If you are running a private Fossil repository, you may not even have the <em>option</em> of delegating this useful service to a third-party; Fossil provides this service out of the box. * <b>One Result Per Matching Post:</b> When you search the forum archives via the Fossil web interface, you get only one result for each matching post. When you search for project information via a standard web search engine, you might get a result from the project site's own mail archive plus one from Nabble, one from Gmane, one from The Mail Archive... * <b>Search Off-Line:</b> Because Fossil is a [./concepts.wiki | distributed version control system], project members can search your forum archive while disconnected from the network where the central Fossil instance runs. Your past discussions are potentially just as valuable as a wiki document or checkin comment: there is no good reason why you should have to wait to get back on the Internet or back to the office before you can search for past posts. * <b>Contribute Off-Line:</b> Fossil forum posts work like any other insertion into the repository, so a user can create new threads and reply to existing ones while off-line, then sync their contributions to the server they cloned from when back on-line. Yes, you can post to the forum from inside a tent, miles from the nearest wifi router or cellular data tower. * <b>Interlink with Other Fossil-Managed Artifacts:</b> Because forum posts are normal Fossil artifacts, you can interlink them with other Fossil artifacts using short internal links: link to forum threads from a [./tickets.wiki | ticket], link to a wiki document from a forum post, etc. * <b>Durable Links:</b> Once you create a valid internal artifact link in Fossil, it <em>remains</em> valid, durably. With third-party forum software and mailing list search engines, your links are only valid until the third-party component changes its URL scheme or disappears from the web. * <b>Role-Based Access Control:</b> The forum uses the same [https://en.wikipedia.org/wiki/Role-based_access_control | RBAC system] that Fossil uses to control all other repository accesses. The Fossil forum feature simply adds several new fine-grained capability bits to the existing system. * <b>Enduring, Open File Format:</b> Since Fossil has an [./fileformat.wiki | open and well-documented file format], your discussion archives are truly that: <em>archives</em>. You are no longer dependent on the lifetime and business model of a third-party piece of software or service. Should you choose to stop using Fossil, you can easily extract your discussion traffic for transfer to another system. * <b>Lightweight Markup:</b> Posts can be marked up using Fossil's existing [/md_rules | Markdown] and [/wiki_rules | Wiki] markup processors. No longer must you choose between two bad options: to restrict posts to plain text only or to allow wild-west HTML-formatted MIME email. Fossil's lightweight markup language formatting features give you a middle path, providing your users enough formatting power to communicate complex ideas well without providing so much power as to risk [https://wonko.com/post/html-escaping | security problems]. * <b>Easy Email Alerts:</b> You can configure Fossil to [./alerts.md | send email alerts]. Forum post emails include the complete message content for the benefit of those that prefer to visit the forum only when they need to post something. Alerts are optional, and each user gets the choice of immediate or daily digest delivery. <h2 id="setup">Setting up a Fossil Forum</h2> <h3 id="caps">Capabilities</h3> Fossil forums use the same role-based access control mechanism as for normal Fossil repository logins. There are several dedicated forum-related capability bits you can grant a user: * <b>Read Forum</b> (<tt>2</tt>): The user may read forum posts. * <b>Write Forum</b> (<tt>3</tt>): The user may create new forum threads, reply to existing threads, and edit their own posts. New posts are held for moderation, and they are marked to prevent them from being included in clone and sync operations. * <b>WriteTrusted Forum</b> (<tt>4</tt>): Same as <b>Write Forum</b> except that forum updates bypass the [#moderation | moderation and private artifact restrictions]. * <b>Moderate Forum</b> (<tt>5</tt>): User gets buttons on posts which allow them to either reject or approve posts held for moderation. User also gets access to a page (<tt>/modreq</tt>) showing the list of pending moderation tasks. * <b>Supervise Forum</b> (<tt>6</tt>): User can grant or revoke <b>WriteTrusted</b> capability for other users. (Currently unimplemented.) * <b>Email Alerts</b> (<tt>7</tt>): User can sign themselves up for email alerts, a.k.a. notifications. By default, no Fossil user has permission to use the forums except for users with Setup and Admin capabilities, which get these as part of the large package of other capabilities they get. For public Fossil repositories that wish to accept new users without involving a human, go into Admin → Access and enable the "Allow users to register themselves" setting. You may also wish to give users in the <tt>anonymous</tt> category the Read Forum (2) and Write Forum (3) capabilities: this allows people to post without creating an account simply by solving [./antibot.wiki | a simple CAPTCHA]. For a private repository, you probably won't want to give the <tt>anonymous</tt> user any forum access, but you may wish to give the Read Forum capability (2) to users in the <tt>reader</tt> category. For either type of repository, you are likely to want to give at least the WriteTrusted capability (4) to users in the <tt>developer</tt> category. If you did not give the Read Forum capability (2) to <tt>anonymous</tt> above, you should give <tt>developer</tt> that capability here if you choose to give it capability 3 or 4. If you want to use the email alert feature, by default only those users in the Setup and Admin user categories can make use of it. Grant the Email Alerts capability (7) to give others access to this feature. Alternately, you can handle alert signups outside of Fossil, with a Setup or Admin users manually signing users up via Admin → Notification. You'll want to grant this capability to the <tt>nobody</tt> user category if you want anyone to sign up without any restrictions. Give it to <tt>anonymous</tt> instead if you want the user to solve a simple CAPTCHA before signing up. Or, give it to <tt>reader</tt> or <tt>developer</tt> if you want only users with Fossil logins to have this ability. (That's assuming you give one or both of these capabilities to every user on your Fossil repository.) By following this advice, you should not need to tediously add capabilities to individual accounts except in atypical cases, such as to grant the Moderate Forum capability (5) to an uncommonly highly-trusted user. <h3 id="skin">Skin Setup</h3> If you create a new Fossil repository with version 2.7 or newer, its default skin is already set up correctly for typical forum |
︙ | ︙ | |||
132 133 134 135 136 137 138 | The remainder of this section summarizes the differences you're expected to see when taking option #2. The first thing is that you'll need to add something like the following to the Header part of the skin to create the navbar link: <verbatim> | | | | | | | | | | | | | | | | | 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 256 257 258 259 260 261 262 | The remainder of this section summarizes the differences you're expected to see when taking option #2. The first thing is that you'll need to add something like the following to the Header part of the skin to create the navbar link: <verbatim> if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { menulink /forum Forum } </verbatim> These rules say that any logged-in user with any forum-related capability (2-6 inclusive, as of this writing) or an anonymous user with read or write capability on the forum (2, 3) will see the "Forum" navbar link, which just takes you to <tt>/forum</tt>. The exact code you need here varies depending on which skin you're using. Follow the style you see for the other navbar links. The new forum feature also brings many new CSS styles to the table. If you're using the stock skin or something sufficiently close, the changes may work with your existing skin as-is. Otherwise, you might need to adjust some things, such as the background color used for the selected forum post: <verbatim> div.forumSel { background-color: rgba(0, 0, 0, 0.05); } </verbatim> That overrides the default — a hard-coded light cyan — with a 95% transparent black overlay instead, which simply darkens your skin's normal background color underneath the selected post. That should work with almost any background color except for very dark background colors. For dark skins, an inverse of the above trick will work better: <verbatim> div.forumSel { background-color: rgba(255, 255, 255, 0.05); } </verbatim> That overlays the background with 5% white to lighten it slightly. Another new forum-related CSS style you might want to reflect into your existing skin is: <verbatim> div.forumPosts a:visited { color: #6A7F94; } </verbatim> This changes the clicked-hyperlink color for the forum post links on the main <tt>/forum</tt> page only, which allows your browser's history mechanism to show which threads a user has read and which not. The link color will change back to the normal link color — indicating "unread" — when a reply is added to an existing thread because that changes where |
︙ | ︙ | |||
230 231 232 233 234 235 236 | participating in the forum have special capability bits for project assets managed by Fossil, so you wish to segregate the two user sets. Yet, what of the users who will have logins on both repositories? Some users will be trusted with access to the project's main Fossil repository, and these users will probably also participate in the project's Fossil-hosted forum. Fossil has a feature to solve this | | > > > | | | | > > | | | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | participating in the forum have special capability bits for project assets managed by Fossil, so you wish to segregate the two user sets. Yet, what of the users who will have logins on both repositories? Some users will be trusted with access to the project's main Fossil repository, and these users will probably also participate in the project's Fossil-hosted forum. Fossil has a feature to solve this problem which is probably less well known than it should be, and which has been a feature of Fossil since April of 2011: Admin → Login-Group. This allows one Fossil repository to recognize users authorized on a different Fossil repository. <h3 id="alerts">Email Alerts (a.k.a. Notifications)</h3> Internet email service has become rather complicated since its initial simple and insecure implementation decades ago. Fossil's role in all of this is rather small at the moment, but the details of the integration are complex enough to justify [./alerts.md | a separate document]. (The other reason that document is separate is that Fossil's email alerts system also gets used by features of Fossil other than the forum.) <h2 id="access">Accessing the Forum</h2> There are many paths to a repository's Fossil forum: <ul> <li> <p>If you're using the default Fossil skin as shipped with Fossil 2.7 or one updated to include the changes since 2.6 or prior, there is a Forum button in the navbar which appears for users with any of the forum-related user capabilities: 2 through 6 inclusive for those with repository logins, or caps 2 and 3 for users without a user account but who have solved the Anonymous user CAPTCHA.</p> <p>This button will not appear in the default skin for such users if their browser window is not greater than 1200 pixels wide. The Fossil admin can adjust this limit in the skin's CSS section, down near the bottom in the definition of the `wideonly` style.</p> </li> <li>The other stock skins have this button in them as of 2.7 as well, without the screen width restriction, since the navbar in those skins wraps on narrow screens more gracefully than the default skin does.</li> |
︙ | ︙ | |||
290 291 292 293 294 295 296 | In this section, we're going to call all of the following a "forum update:" * create a new post * reply to an existing post * edit a post or reply | | | | > | | | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | In this section, we're going to call all of the following a "forum update:" * create a new post * reply to an existing post * edit a post or reply When a person with the normal <b>Write Forum</b> capability (<tt>3</tt>) updates the forum, Fossil saves the update in its block chain, but this update is impermanent because of two other table updates made at the same time: <ol> <li>Fossil saves the update artifact's ID in its <tt>private</tt> table, preventing Fossil from sending such artifacts to any of the repository's clones. (This is the same mechanism behind [./private.wiki | private branches].)</li> <li>Fossil also adds a reference to that artifact in the <tt>modreq</tt> table, which backs the moderation feature. This is what causes Fossil to leave out the Reply button when rendering that post's HTML in the forum's web interface.</li> </ol> When a moderator approves an update, Fossil deletes these table entries, making the update semi-permanent. This changes how Fossil renders the HTML for that update. It also means the artifact will now sync to clones, if the sync is done by a user with <b>Check-Out</b> capability (<tt>o</tt>). When a forum user edits a moderator-approved artifact, what actually happens under the hood is that Fossil writes another artifact to the repository which refers to the original version as its parent, causing Fossil UI to present the new version instead of the original. The original version remains in the repository, just as with historical checkins. The parent must remain in the repository for referential integrity purposes. When you "Delete" a moderator-approved post or reply through Fossil UI, it's actually an edit with blank replacement content. The only way to truly delete such artifacts is through [./shunning.wiki | shunning]. When a user with <b>WriteTrusted Forum</b> capability (<tt>4</tt>) updates the forum, it happens in the same way except that Fossil skips the <tt>private</tt> and <tt>modreq</tt> table insertions. When a moderator rejects an update, that artifact is unceremoniously removed from the tip of the block chain. This is safe because Fossil prevents replies to a reply or post awaiting moderator approval, so referential integrity cannot be harmed. Rejecting an edit is even safer, since the original post remains behind, so that replies continue to refer to that original post. <h2 id="mod-user">Using the Moderation Feature</h2> Having described all of the work that Fossil performs under the hood on behalf of its users, we can now give the short list of work left for the repository's administrators and moderators: <ol> <li>Add the <b>Moderate Forum</b> capability (<tt>5</tt>) to any of your users who should have this ability. You don't need to do this for any user with Setup (<tt>s</tt>) or Admin (<tt>a</tt>) capability; it's [http://fossil-scm.org/index.html/artifact/b16221ffb736caa2?ln=1246-1257 | already included].</li> <li>When someone updates the forum, an entry will appear in the timeline if the type filter is set to "Forum" or "Any Type". If that user has only the <b>Write Forum</b> capability (<tt>3</tt>), any other user with the <b>Moderate Forum</b> capability (<tt>5</tt>) will see a conditional link appear at the top of the main forum page: "Moderation Requests". Clicking this takes the moderator to the <tt>/modreq</tt> page. A moderator may wish to keep the main forum page open in a browser tab, reloading it occasionally to see when the "Moderation Requests" link reappears.</li> <li>A moderator viewing an update pending moderation sees two buttons at the bottom, "Approve" and "Reject" in place of the "Delete" button that the post's creator sees. Beware that both actions are durable and have no undo. Be careful!</li> </ol> |
Changes to www/foss-cklist.wiki.
1 2 3 | <title>Checklist For Successful Open-Source Projects</title> <nowiki> | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | <title>Checklist For Successful Open-Source Projects</title> <nowiki> <p>This checklist is loosely derived from Tom "Spot" Callaway's Fail Score blog post <a href="http://spot.livejournal.com/308370.html"> http://spot.livejournal.com/308370.html</a> (see also <a href="http://www.theopensourceway.org/book/The_Open_Source_Way-How_to_tell_if_a_FLOSS_project_is_doomed_to_FAIL.html">[1]</a> and <a href="https://www.theopensourceway.org/wiki/How_to_tell_if_a_FLOSS_project_is_doomed_to_FAIL">[2]</a>). Tom's original post assigned point scores to the various elements and by adding together the individual points, the reader is supposed to be able to judge the likelihood that the project will fail. The point scores, and the items on the list, clearly reflect Tom's biases and are not necessarily those of the larger open-source community. Nevertheless, the policy of the Fossil shall be to strive for a perfect score.</p> <p>This checklist is an inversion of Tom's original post in that it strives to say what the project should do in order to succeed rather than what it should not do to avoid failure. The point values are omitted.</p> <p>See also: <ul> <li><a href="http://offog.org/articles/packaging/"> http://offog.org/articles/packaging/</a> <li> <a href="http://www.gnu.org/prep/standards/standards.html#Managing-Releases"> http://www.gnu.org/prep/standards/standards.html#Managing-Releases</a> </ul> <hr> <ol> <li><p>The source code size is less than 100 MB, uncompressed. <li><p>The project uses a Version Control System (VCS). <ol type="a"> <li>The VCS has a working web interface. <li>There is documentation on how to use the VCS. <li>The VCS is general-purpose, not something hacked together for this one project. </ol> <li><p>The project comes with documentation on how to build from source and that documentation is lucid, correct, and up-to-date. <li><p>The project is configurable using an autoconf-generated configure script, or the equivalent, and does not require: <ol type="a"> <li>Manually editing flat files <li>Editing code header files </ol> <li><p>The project should be buildable using commonly available and standard tools like "make". <li><p>The project does not depend on 3rd-party proprietary build tools. <li><p>The project is able to dynamically link against standard libraries such as zlib and libjpeg. <ol type="a"> <li>The project does not ship with the sources to standard libraries. <i>(On the Fossil project, we will allow the SQLite library sources to be included in the source tree as long as a system-installed SQLite library can be used in its stead.)</i> <li>The project does not use slightly modified versions of standard libraries. Any required bug fixes in standard libraries are pushed back upstream. </ol> <li><p>"make install" works and can be configured to target any directory of the installer's choosing. <ol type="a"> <li>The project contains no unconfigurable hard-coded pathnames like "/opt" or "/usr/local". <li>After installation, the source tree can be moved or deleted and the application will continue working. </ol> <li><p>The source code uses only \n for line endings, not \r\n. <li><p>The code does not depend on any special compiler features or bugs. <li><p>The project has a mailing list and announces releases on the mailing list. <li><p>The project has a bug tracker. <li><p>The project has a website. <li><p>Release version numbers are in the traditional X.Y or X.Y.Z format. <li><p>Releases can be downloaded as tarball using gzip or bzip2 compression. <li><p>Releases unpack into a versioned top-level directory. (ex: "projectname-1.2.3/"). <li><p>A statement of license appears at the top of every source code file and the complete text of the license is included in the source code tarball. <li><p>There are no incompatible licenses in the code. <li><p>The project has not been blithely proclaimed "public domain" without having gone through the tedious and exacting legal steps to actually put it in the public domain. <li><p>There is an accurate change log in the code and on the website. <li><p>There is documentation in the code and on the website. </ol> |
Deleted www/fossil-is-not-relational.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/fossil-v-git.wiki.
1 2 3 4 | <title>Fossil Versus Git</title> <h2>1.0 Don't Stress!</h2> | < < < < < < < < < < < < | | < > | | > < | < < | > > | | < | < < < | < < < < < < < < | < < | < < < < < < | < < < < | | < < | < < < < < < < < < < | | < < < | | < < | < < < < < < < < < | | | | | < < < < < | | | | < < | < < < < < < < | < < < < | < < < < < < < < < | | | < < < < < < < | < | < < < < < < < | < < < < < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | < > > | | < < | | < < < | < | | < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < | < < < < < < | < | | | | | < | < < < < < < < < < < < < < | | < < < < < < < < | > > | < < < < < < < < < < | < < < < < < < < < | < < | < < < < < < < | < | < | < < | < | < < < < < < | < < | < < < < | < < < < < < < > > > > > | < < < < | < | | | < < < < < < < < < < < < | < < < < < < < < | < | < < < < | < < < < < < < < < < < < < < < < < < < | < < < | < < < | < < < | < | < < < < < < < < | | < < < < < < < < < > > > | < < < < < < < < < < < < < | < < | | < < < < < < < < < < | | | | < < < < < < < < | < < < | > > > < | < | | < < | < < < < < < < < < < < < < < < < < | | < | < < < | < < < < < < < | < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < | < < < > | < | < < | < < < | > | | | | < < < | | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < > < < < < < < < < < < < | | < < > < < < < < < > > > > > > | | | > < | | | | | < | < < < < | < < < < < < < < | < < < > | < | < | < | < < < > < < < < < < | | | | | | < < < < < | < > < < < < | < < < < < < < > < < < < < < < < > > | < < < < < < < > | < < | < < > < > < < < < > > > > > | < > < < | < < < < < | | < < < < | < | < < > | < < < < < | < < | | > | < < < < > < < < < < < < < < > | | | | < < < < < < < | < < < < < < | | | < < < > | < > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | <title>Fossil Versus Git</title> <h2>1.0 Don't Stress!</h2> If you start out using one DVCS and later decide you like the other better, you can easily [./inout.wiki | move your content]¹. Fossil and [http://git-scm.com | Git] are very similar in many respects, but they also have important differences. See the table below for a high-level summary and the text that follows for more details. Keep in mind that you are reading this on a Fossil website, and though we try to be fair, the information here might be biased in favor of Fossil. Ask around for second opinions from people who have used <em>both</em> Fossil and Git. ¹<small><i>Git does not support wiki, tickets, or tech-notes, so those elements will not transfer when exporting from Fossil to Git.</i></small> <h2>2.0 Differences Between Fossil And Git</h2> Differences between Fossil and Git are summarized by the following table, with further description in the text that follows. <blockquote><table border=1 cellpadding=5 align=center> <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> <tr><td>File versioning only</td> <td>Versioning, Tickets, Wiki, and Technotes</td></tr> <tr><td>Ad-hoc, pile-of-files key/value database</td> <td>Relational SQL database</td></tr> <tr><td>Bazaar-style development</td><td>Cathedral-style development</td></tr> <tr><td>Designed for Linux development</td> <td>Designed for SQLite development</td></tr> <tr><td>Lots of little tools</td><td>Stand-alone executable</td></tr> <tr><td>One check-out per repository</td> <td>Many check-outs per repository</td></tr> <tr><td>Remembers what you should have done</td> <td>Remembers what you actually did</td></tr> <tr><td>GPL</td><td>BSD</td></tr> </table></blockquote> <h3>2.1 Feature Set</h3> Git provides file versioning services only, whereas Fossil adds integrated [./wikitheory.wiki | wiki], [./bugtheory.wiki | ticketing & bug tracking], [./embeddeddoc.wiki | embedded documentation], and [./event.wiki | Technical notes]. These additional capabilities are available for Git as 3rd-party and/or user-installed add-ons, but with Fossil they are integrated into the design. One way to describe Fossil is that it is "[https://github.com/ | github]-in-a-box". If you clone Git's self-hosting repository you get just Git's source code. If you clone Fossil's self-hosting repository, you get the entire Fossil website - source code, documentation, ticket history, and so forth. For developers who choose to self-host projects (rather than using a 3rd-party service such as GitHub) Fossil is much easier to set up, since the stand-alone Fossil executable together with a 2-line CGI script suffice to instantiate a full-featured developer website. To accomplish the same using Git requires locating, installing, configuring, integrating, and managing a wide assortment of separate tools. Standing up a developer website using Fossil can be done in minutes, whereas doing the same using Git requires hours or days. <h3>2.2 Database</h3> The baseline data structures for Fossil and Git are the same (modulo formatting details). Both systems store check-ins as immutable objects referencing their immediate ancestors and named by a cryptographic hash of the check-in content. The difference is that Git stores its objects as individual files in the ".git" folder or compressed into bespoke "pack-files", whereas Fossil stores its objects in a relational ([https://www.sqlite.org/|SQLite]) database file. To put it another way, Git uses an ad-hoc pile-of-files key/value database whereas Fossil uses a proven, general-purpose SQL database. This difference is more than an implementation detail. It has important consequences. With Git, one can easily locate the ancestors of a particular check-in by following the pointers embedded in the check-in object, but it is difficult to go the other direction and locate the descendants of a check-in. It is so difficult, in fact, that neither native Git nor GitHub provide this capability. With Git, if you are looking at some historical check-in then you cannot ask "what came next" or "what are the children of this check-in". Fossil, on the other hand, parses essential information about check-ins (parents, children, committers, comments, files changed, etc.) into a relational database that can be easily queried using concise SQL statements to find both ancestors and descendents of a check-in. Leaf check-ins in Git that lack a "ref" become "detached", making them difficult to locate and subject to garbage collection. This "detached head" problem has caused untold grief for countless Git users. With Fossil, all check-ins are easily located using a variety of attributes (parents, children, committer, date, full-text search of the check-in comment) and so detached heads are simply not possible. The ease with which check-ins can be located and queried in Fossil has resulted in a huge variety of reports and status screens ([./webpage-ex.md|examples]) that show project state in ways that help developers maintain enhanced awareness and comprehension and avoid errors. <h3>2.3 Cathedral vs. Bazaar</h3> Fossil and Git promote different development styles. Git promotes a "bazaar" development style in which numerous anonymous developers make small and sometimes haphazard contributions. Fossil promotes a "cathedral" development model in which the project is closely supervised by an highly engaged architect and implemented by a clique of developers. Nota Bene: This is not to say that Git cannot be used for cathedral-style development or that Fossil cannot be used for bazaar-style development. They can be. But those modes are not their design intent nor their low-friction path. Git encourages a style in which individual developers work in relative isolation, maintaining their own branches and occasionally rebasing and pushing selected changes up to the main repository. Developers using Git often have their own private branches that nobody else ever sees. Work becomes siloed. This is exactly what one wants when doing bazaar-style development. Fossil, in contrast, strives to keep all changes from all contributors mirrored in the main repository (in separate branches) at all times. Work in progress from one developer is readily visible to all other developers and to the project leader, well before the code is ready to integrate. Fossil places a lot of emphasis on reporting the state of the project, and the changes underway by all developers, so that all developers and especially the project leader can maintain a better mental picture of what is happening, and better situational awareness. <h3>2.4 Linux vs. SQLite</h3> Git was specifically designed to support the development of Linux. Fossil was specifically designed to support the development of SQLite. Both SQLite and Linux are important pieces of software. SQLite is found on far more systems than Linux. (Almost every Linux system uses SQLite, but there are many non-Linux systems such as iPhones, PlayStations, and Windows PCs that use SQLite.) On the other hand, for those systems that do use Linux, Linux is a far more important component. Linux uses a bazaar-style development model. There are thousands and thousands of contributors, most of whom do not know each others names. Git is designed for this scenario. SQLite uses cathedral-style development. 95% of the code in SQLite comes from just three programmers, 64% from just the lead developer. And all SQLite developers know each other well and interact daily. Fossil is designed for this development model. <h3>2.5 Lots of little tools vs. Self-contained system</h3> Git consists of many small tools, each doing one small part of the job, which can be recombined (by experts) to perform powerful operations. Git has a lot of complexity and many dependencies and requires an "installer" script or program to get it running. Fossil is a single self-contained stand-alone executable with hardly any dependencies. Fossil can be (and often is) run inside a minimally configured chroot jail. To install Fossil, one merely puts the executable on $PATH. The designer of Git says that the unix philosophy is to have lots of small tools that collaborate to get the job done. The designer of Fossil says that the unix philosophy is "it just works". Both individuals have written their DVCSes to reflect their own view of the "unix philosophy". <h3>2.6 One vs. Many Check-outs per Repository</h3> A "repository" in Git is a pile-of-files in the ".git" subdirectory of a single check-out. The check-out and the repository are inseperable. With Fossil, a "repository" is a single SQLite database file that can be stored anywhere. There can be multiple active check-outs from the same repository, perhaps open on different branches or on different snapshots of the same branch. Long-running tests or builds can be running in one check-out while changes are being committed in another. <h3>2.7 What you should have done vs. What you actually did</h3> Git puts a lot of emphasis on maintaining a "clean" check-in history. Extraneous and experimental branches by individual developers often never make it into the main repository. And branches are often rebased before being pushed, to make it appear as if development had been linear. Git strives to record what the development of a project should have looked like had there been no mistakes. Fossil, in contrast, puts more emphasis on recording exactly what happened, including all of the messy errors, dead-ends, experimental branches, and so forth. One might argue that this makes the history of a Fossil project "messy". But another point of view is that this makes the history "accurate". In actual practice, the superior reporting tools available in Fossil mean that the added "mess" is not a factor. One commentator has mused that Git records history according to the victors, whereas Fossil records history as it actually happened. <h3>2.8 GPL vs. BSD</h3> Git is covered by the GPL license whereas Fossil is covered by a two-clause BSD license. Consider the difference between GPL and BSD licenses: GPL is designed to make writing easier at the expense of making reading harder. BSD is designed to make reading easier at the expense of making writing harder. To a first approximation, the GPL license grants the right to read source code to anyone who promises to give back enhancements. In other words, the act of reading GPL source code (a prerequiste for making changes) implies acceptance of the license which requires updates to be contributed back under the same license. (The details are more complex, but the foregoing captures the essence of the idea.) A big advantage of the GPL is that anybody can contribute to the code without having to sign additional legal documentation because they have implied their acceptance of the GPL license by the very act of reading the source code. This means that a GPL project can legally accept anonymous and drive-by patches. The BSD licenses, on the other hand, make reading much easier than the GPL, because the reader need not surrender proprietary interest in their own enhancements. On the flip side, BSD and similarly licensed projects must obtain legal affidavits from authors before new content can be added into the project. Anonymous and drive-by patches cannot be accepted. This makes signing up new contributors for BSD licensed projects harder. The licenses on the implementations of Git and Fossil only apply to the implementations themselves, not to the projects which the systems store. Nevertheless, one can see a more GPL-oriented world-view in Git and a more BSD-oriented world-view in Fossil. Git encourages anonymous contributions and siloed development, which are hallmarks of the GPL/bazaar approach to software, whereas Fossil encourages a more tightly collaborative, cliquish, cathedral-style approach more typical of BSD-licensed projects. <h2>3.0 Missing Features</h2> Most of the capabilities found in Git are also available in Fossil and the other way around. For example, both systems have local check-outs, remote repositories, push/pull/sync, bisect capabilities, and a "stash". Both systems store project history as a directed acyclic graph (DAG) of immutable check-in objects. But there are a few capabilities in one system that are missing from the other. <h3>3.1 Features found in Fossil but missing from Git</h3> * <b>The ability to show descendents of a check-in.</b> Both Git and Fossil can easily find the ancestors of a check-in. But only Fossil shows the descendents. (It is possible to find the descendents of a check-in in Git using the log, but that is sufficiently difficult that nobody ever actually does it.) * <b>Wiki, Embedded documentation, Trouble-tickets, and Tech-Notes</b> Git only provides versioning of source code. Fossil strives to provide other related configuration management services as well. * <b>Named branches</b> Branches in Fossil have persistent names that are propagated to collaborators via [/help?cmd=push|push] and [/help?cmd=pull|pull]. All developers see the same name on the same branch. Git, in contrast, uses only local branch names, so developers working on the same project can (and frequently do) use a different name for the same branch. * <b>The [/help?cmd=all|fossil all] command</b> Fossil keeps track of all repositories and check-outs and allows operations over all of them with a single command. For example, in Fossil is possible to request a pull of all repositories on a laptop from their respective servers, prior to taking the laptop off network. Or it is possible to do "fossil all status" to see if there are any uncommitted changes that were overlooked prior to the end of the workday. * <b>The [/help?cmd=ui|fossil ui] command</b> Fossil supports an integrated web interface. Some of the same features are available using third-party add-ons for Git, but they do not provide nearly as many features and they are not nearly as convenient to use. <h3>3.2 Features found in Git but missing from Fossil</h3> * <b>Rebase</b> Because of its emphasis on recording history exactly as it happened, rather than as we would have liked it to happen, Fossil deliberately does not provide a "rebase" command. One can rebase manually in Fossil, with sufficient perserverence, but it is not something that can be done with a single command. * <b>Push or pull a single branch</b> The [/help?cmd=push|fossil push], [/help?cmd=pull|fossil pull], and [/help?cmd=sync|fossil sync] commands do not provide the capability to push or pull individual branches. Pushing and pulling in Fossil is all or nothing. This is in keeping with Fossil's emphasis on maintaining a complete record and on sharing everything between all developers. |
Changes to www/fossil3.gif.
cannot compute difference between binary files
Changes to www/fossil_prompt.sh.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #------------------------------------------------------------------------- # get_fossil_data() # # If the current directory is part of a fossil checkout, then populate # a series of global variables based on the current state of that # checkout. Variables are populated based on the output of the [fossil info] # command. # # If the current directory is not part of a fossil checkout, set global # variable $fossil_info_project_name to an empty string and return. # function get_fossil_data() { fossil_info_project_name="" eval `get_fossil_data2` } function get_fossil_data2() { | > < | | | > > > > > > > | | > | | 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 | #------------------------------------------------------------------------- # get_fossil_data() # # If the current directory is part of a fossil checkout, then populate # a series of global variables based on the current state of that # checkout. Variables are populated based on the output of the [fossil info] # command. # # If the current directory is not part of a fossil checkout, set global # variable $fossil_info_project_name to an empty string and return. # function get_fossil_data() { fossil_info_project_name="" eval `get_fossil_data2` } function get_fossil_data2() { fossil info 2> /dev/null | sed 's/"//g'|grep "^[^ ]*:" | while read LINE ; do local field=`echo $LINE | sed 's/:.*$//' | sed 's/-/_/'` local value=`echo $LINE | sed 's/^[^ ]*: *//'` echo fossil_info_${field}=\"${value}\" done } #------------------------------------------------------------------------- # set_prompt() # # Set the PS1 variable. If the current directory is part of a fossil # checkout then the prompt contains information relating to the state # of the checkout. # # Otherwise, if the current directory is not part of a fossil checkout, it # is set to a fairly standard bash prompt containing the host name, user # name and current directory. # function set_prompt() { get_fossil_data if [ -n "$fossil_info_project_name" ] ; then project=$fossil_info_project_name checkout=`echo $fossil_info_checkout | sed 's/^\(........\).*/\1/'` date=`echo $fossil_info_checkout | sed 's/^[^ ]* *..//' | sed 's/:[^:]*$//'` tags=$fossil_info_tags local_root=`echo $fossil_info_local_root | sed 's/\/$//'` local=`pwd | sed "s*${local_root}**" | sed "s/^$/\//"` # Color the first part of the prompt blue if this is a clean checkout. # Or red if it has been edited in any way at all. Set $c1 to the escape # sequence required to change the type to the required color. And $c2 # to the sequence that changes it back. # if [ -n "`fossil chang`" ] ; then c1="\[\033[1;31m\]" # red else c1="\[\033[1;34m\]" # blue fi c2="\[\033[0m\]" PS1="$c1${project}.${tags}$c2 ${checkout} (${date}):${local}$c1\$$c2 " else PS1="\u@\h:\w\$ " fi } PROMPT_COMMAND=set_prompt |
Changes to www/fossil_prompt.wiki.
1 2 3 4 5 6 | <title>Fossilized Bash Prompt</title> Dan Kennedy has contributed a [./fossil_prompt.sh?mimetype=text/plain | bash script] that manipulates the bash prompt to show the status of the Fossil repository that the user is currently visiting. | > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <title>Fossilized Bash Prompt</title> <h1>2013-02-21</h1> Dan Kennedy has contributed a [./fossil_prompt.sh?mimetype=text/plain | bash script] that manipulates the bash prompt to show the status of the Fossil repository that the user is currently visiting. The prompt shows the branch, version, and timestamp for the current checkout, and the prompt changes colors from blue to red when there are uncommitted changes. To try out this script, simply download it from the link above, then type: <blockquote><pre> . fossil_prompt.sh </pre></blockquote> For a permanent installation, you can graft the code into your <tt>.bashrc</tt> file in your home directory. The code is very simple (only 32 non-comment lines, as of this writing) and hence easy to customized. |
Deleted www/gitusers.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/globs.md.
1 2 3 | # File Name Glob Patterns A [glob pattern][glob] is a text expression that matches one or more | > | | | < < < < < > | < < < < > | < | > | | | < < > | | < < | > > | > < < < < > < < < < | < < | > > | | | > > | | < < | > | | < < < < < | < < < | | < < < < < < < < < | < < | | < | | | > > > > > > > | | | | | | > | | < | < | | < < < | < | < | | < | | < < < < < | | 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 | # File Name Glob Patterns A [glob pattern][glob] is a text expression that matches one or more file names using wild cards familiar to most users of a command line. For example, `*` is a glob that matches any name at all and `Readme.txt` is a glob that matches exactly one file. Note that although both are notations for describing patterns in text, glob patterns are not the same thing as a [regular expression or regexp][regexp]. [glob]: https://en.wikipedia.org/wiki/Glob_(programming) (Wikipedia) [regexp]: https://en.wikipedia.org/wiki/Regular_expression A number of fossil setting values hold one or more file glob patterns that will identify files needing special treatment. Glob patterns are also accepted in options to certain commands as well as query parameters to certain pages. In many cases more than one glob may be specified in a setting, option, or query parameter by listing multiple globs separated by a comma or white space. Of course, many fossil commands also accept lists of files to act on, and those also may be specified with globs. Although those glob patterns are similar to what is described here, they are not defined by fossil, but rather by the conventions of the operating system in use. ## Syntax A list of glob patterns is simply one or more glob patterns separated by white space or commas. If a glob must contain white spaces or commas, it can be quoted with either single or double quotation marks. A list is said to match if any one (or more) globs in the list matches. A glob pattern is a collection of characters compared to a target text, usually a file name. The whole glob is said to match if it successfully consumes and matches the entire target text. Glob patterns are made up of ordinary characters and special characters. Ordinary characters consume a single character of the target and must match it exactly. Special characters (and special character sequences) consume zero or more characters from the target and describe what matches. The special characters (and sequences) are: :Pattern |:Effect --------------------------------------------------------------------- `*` | Matches any sequence of zero or more characters `?` | Matches exactly one character `[...]` | Matches one character from the enclosed list of characters `[^...]` | Matches one character not in the enclosed list Special character sequences have some additional features: * A range of characters may be specified with `-`, so `[a-d]` matches exactly the same characters as `[abcd]`. Ranges reflect Unicode code points without any locale-specific collation sequence. * Include `-` in a list by placing it last, just before the `]`. * Include `]` in a list by making the first character after the `[` or `[^`. At any other place, `]` ends the list. * Include `^` in a list by placing anywhere except first after the `[`. * Beware that ranges in lists may include more than you expect: `[A-z]` Matches `A` and `Z`, but also matches `a` and some less obvious characters such as `[`, `\`, and `]` with code point values between `Z` and `a`. * Beware that a range must be specified from low value to high value: `[z-a]` does not match any character at all, preventing the entire glob from matching. * Note that unlike typical Unix shell globs, wildcards (`*`, `?`, and character lists) are allowed to match `/` directory separators as well as the initial `.` in the name of a hidden file or directory. Some examples of character lists: :Pattern |:Effect --------------------------------------------------------------------- `[a-d]` | Matches any one of `a`, `b`, `c`, or `d` but not `ä` `[^a-d]` | Matches exactly one character other than `a`, `b`, `c`, or `d` `[0-9a-fA-F]` | Matches exactly one hexadecimal digit `[a-]` | Matches either `a` or `-` `[][]` | Matches either `]` or `[` `[^]]` | Matches exactly one character other than `]` `[]^]` | Matches either `]` or `^` `[^-]` | Matches exactly one character other than `-` White space means the specific ASCII characters TAB, LF, VT, FF, CR, and SPACE. Note that this does not include any of the many additional spacing characters available in Unicode, and specifically does not include U+00A0 NO-BREAK SPACE. Because both LF and CR are white space and leading and trailing spaces are stripped from each glob in a list, a list of globs may be broken into lines between globs when the list is stored in a file (as for a versioned setting). Similarly 'single quotes' and "double quotes" are the ASCII straight quote characters, not any of the other quotation marks provided in Unicode and specifically not the "curly" quotes preferred by typesetters and word processors. ## File Names to Match Before it is compared to a glob pattern, each file name is transformed to a canonical form. The glob must match the entire canonical file name to be considered a match. The canonical name of a file has all directory separators changed to `/`, redundant slashes are removed, all `.` path components are removed, and all `..` path components are resolved. (There are additional details we are ignoring here, but they cover rare edge cases and also follow the principle of least surprise.) The goal is to have a name that is the simplest possible for each particular file, and that will be the same on Windows, Unix, and any other platform where fossil is run. Beware, however, that all glob matching is case sensitive. This will not be a surprise on Unix where all file names are also case sensitive. However, most Windows file systems are case preserving and case insensitive. That is, on Windows, the names `ReadMe` and `README` are names of the same file; on Unix they are different files. Some example cases: :Pattern |:Effect -------------------------------------------------------------------------------- `README` | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part. `*/README` | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree. `*README` | Matches `src/README` as well as the file `README` in the root of the tree as well as `foo/bar/README` or any other file named `README` in the tree. However, it also matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other file whose name ends with `README`. `src/README` | Matches `src\README` on Windows because all directory separators are rewritten as `/` in the canonical name before the glob is matched. This makes it much easier to write globs that work on both Unix and Windows. `*.[ch]` | Matches every C source or header file in the tree at the root or at any depth. Again, this is (deliberately) different from Unix file globs and Windows wild cards. ## Where Globs are Used ### Settings that are Globs These settings are all lists of glob patterns: :Setting |:Description -------------------------------------------------------------------------------- `binary-glob` | Files that should be treated as binary files for committing and merging purposes `clean-glob` | Files that the [`clean`][] command will delete without prompting or allowing undo |
︙ | ︙ | |||
206 207 208 209 210 211 212 | The `ignore-glob` is an example of one setting that frequently grows to be an elaborate list of files that should be ignored by most commands. This is especially true when one (or more) IDEs are used in a project because each IDE has its own ideas of how and where to cache information that speeds up its browsing and building tasks but which need not be preserved in your project's history. | < < < < | < | | | | | | | | < | | | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | The `ignore-glob` is an example of one setting that frequently grows to be an elaborate list of files that should be ignored by most commands. This is especially true when one (or more) IDEs are used in a project because each IDE has its own ideas of how and where to cache information that speeds up its browsing and building tasks but which need not be preserved in your project's history. ### Commands that Refer to Globs Many of the commands that respect the settings containing globs have options to override some or all of the settings. These options are usually named to correspond to the setting they override, such as `--ignore` to override the `ignore-glob` setting. These commands are: * [`add`][] * [`addremove`][] * [`changes`][] * [`clean`][] * [`commit`][] * [`extras`][] * [`merge`][] * [`settings`][] * [`status`][] * [`unset`][] The commands [`tarball`][] and [`zip`][] produce compressed archives of a specific checkin. They may be further restricted by options that specify glob patterns that name files to include or exclude rather than archiving the entire checkin. The commands [`http`][], [`cgi`][], [`server`][], and [`ui`][] that implement or support with web servers provide a mechanism to name some files to serve with static content where a list of glob patterns specifies what content may be served. [`add`]: /help?cmd=add [`addremove`]: /help?cmd=addremove [`changes`]: /help?cmd=changes [`clean`]: /help?cmd=clean [`commit`]: /help?cmd=commit [`extras`]: /help?cmd=extras [`merge`]: /help?cmd=merge [`settings`]: /help?cmd=settings [`status`]: /help?cmd=status [`unset`]: /help?cmd=unset [`tarball`]: /help?cmd=tarball [`zip`]: /help?cmd=zip [`http`]: /help?cmd=http [`cgi`]: /help?cmd=cgi [`server`]: /help?cmd=server [`ui`]: /help?cmd=ui ### Web Pages that Refer to Globs The [`/timeline`][] page supports the query parameter `chng=GLOBLIST` that names a list of glob patterns defining which files to focus the timeline on. It also has the query parameters `t=TAG` and `r=TAG` that names a tag to focus on, which can be configured with `ms=STYLE` to use a glob pattern to match tag names instead of the default exact match or a couple of other comparison styles. The pages [`/tarball`][] and [`/zip`][] generate compressed archives of a specific checkin. They may be further restricted by query parameters that specify glob patterns that name files to include or exclude rather than taking the entire checkin. [`/timeline`]: /help?cmd=/timeline [`/tarball`]: /help?cmd=/tarball [`/zip`]: /help?cmd=/zip ## Platform Quirks Fossil glob patterns are based on the glob pattern feature of POSIX shells. Fossil glob patterns also have a quoting mechanism, discussed above. Because other parts of your operating system may interpret glob patterns and quotes separately from Fossil, it is often difficult to give glob patterns correctly to Fossil on the command line. Quotes and special characters in glob patterns are likely to be interpreted when given as part of a `fossil` command, causing unexpected behavior. These problems do not affect [versioned settings files](settings.wiki) or Admin → Settings in Fossil UI. Consequently, it is better to set long-term `*-glob` settings via these methods than to use `fossil settings` commands. That advice does not help you when you are giving one-off glob patterns in `fossil` commands. The remainder of this section gives remedies and workarounds for these problems. ## POSIX Systems If you are using Fossil on a system with a POSIX-compatible shell — Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. — the shell may expand the glob patterns before passing the result to the `fossil` executable. Sometimes this is exactly what you want. Consider this command for |
︙ | ︙ | |||
370 371 372 373 374 375 376 | $ fossil add --ignore "\"REALLY SECRET STUFF.txt\"" READ* It bears repeating that the two glob patterns here are not interpreted the same way when running this command from a *subdirectory* of the top checkout directory as when running it at the top of the checkout tree. If these files were in a subdirectory of the checkout tree called `doc` | | | | < < < < < < < < < < < < < < < < < | | < < | | < | > > | > > > > > > > > > | | | < < < | < < < < < < < | < > | | | | < < < < < < < < | < | | | < < < < < < < < < < < < < < < < < < | | | | | | | < < | | | | | | | | | | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | $ fossil add --ignore "\"REALLY SECRET STUFF.txt\"" READ* It bears repeating that the two glob patterns here are not interpreted the same way when running this command from a *subdirectory* of the top checkout directory as when running it at the top of the checkout tree. If these files were in a subdirectory of the checkout tree called `doc` and that was your current working directory, the command would have to be: $ fossil add --ignore "'doc/REALLY SECRET STUFF.txt'" READ* instead. The Fossil glob pattern still needs the `doc/` prefix because Fossil always interprets glob patterns from the base of the checkout directory, not from the current working directory as POSIX shells do. When in doubt, use `fossil status` after running commands like the above to make sure the right set of files were scheduled for insertion into the repository before checking the changes in. You never want to accidentally check something like a password, an API key, or the private half of a public cryptographic key into Fossil repository that can be read by people who should not have such secrets. ## Windows Neither standard Windows command shell — `cmd.exe` or PowerShell — expands glob patterns the way POSIX shells do. Windows command shells rely on the command itself to do the glob pattern expansion. The way this works depends on several factors: * the version of Windows you are using * which OS upgrades have been applied to it * the compiler that built your Fossil executable * whether you are running the command interactively * whether the command is built against a runtime system that does this at all * whether the Fossil command is being run from a file named `*.BAT` vs being named `*.CMD` These factors also affect how a program like `fossil.exe` interprets quotation marks on its command line. The fifth item above does not apply to `fossil.exe` when built with typical tool chains, but we will see an example below where the exception applies in a way that affects how Fossil interprets the glob pattern. The most common problem is figuring out how to get a glob pattern passed on the command line into `fossil.exe` without it being expanded by the C runtime library that your particular Fossil executable is linked to, which tries to act like the POSIX systems described above. Windows is not strongly governed by POSIX, so it has not historically hewed closely to its strictures. (This section does not cover the [Microsoft POSIX subsystem](https://en.wikipedia.org/wiki/Microsoft_POSIX_subsystem), Windows' obsolete [Services for Unix 3.*x*](https://en.wikipedia.org/wiki/Windows_Services_for_UNIX) feature, or the [Windows Subsystem for Linux](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux). (The latter is sometimes incorrectly called "Bash on Windows" or "Ubuntu on Windows.") See the POSIX Systems section above for those cases.) For example, consider how you would set `crlf-glob` to `*` in order to disable Fossil's "looks like a binary file" checks. The naïve approach will not work: C:\...> fossil setting crlf-glob * The C runtime library will expand that to the list of all files in the current directory, which will probably cause a Fossil error because Fossil expects either nothing or option flags after the setting's new value. Let's try again: C:\...> fossil setting crlf-glob '*' That may or may not work. Either `'*'` or `*` needs to be passed through to Fossil untouched for this to do what you expect, which may or may not happen, depending on the factors listed above. An approach that *will* work reliably is: C:\...> echo * | fossil setting crlf-glob --args - This works because the built-in command `echo` does not expand its arguments, and the `--args -` option makes it read further command arguments from Fossil's standard input, which is connected to the output of `echo` by the pipe. (`-` is a common Unix convention meaning "standard input.") Another (usually) correct approach is: C:\...> fossil setting crlf-glob *, This works because the trailing comma prevents the command shell from matching any files, unless you happen to have files named with a trailing comma in the current directory. If the pattern matches no files, it is passed into Fossil's `main()` function as-is by the C runtime system. Since Fossil uses commas to separate multiple glob patterns, this means "all files at the root of the Fossil checkout directory and nothing else." ## Converting `.gitignore` to `ignore-glob` Many other version control systems handle the specific case of ignoring certain files differently from fossil: they have you create individual "ignore" files in each folder, which specify things ignored in that folder and below. Usually some form of glob patterns are used in those files, but the details differ from fossil. In many simple cases, you can just store a top level "ignore" file in `.fossil-settings/ignore-glob`. But as usual, there will be lots of edge cases. [Git has a rich collection of ignore files][gitignore] which accumulate rules that affect the current command. There are global files, per-user files, per workspace unmanaged files, and fully version controlled files. Some of the files used have no set name, but are called out in configuration files. [gitignore]: https://git-scm.com/docs/gitignore In contrast, fossil has a global setting and a local setting, but the local setting overrides the global rather than extending it. Similarly, a fossil command's `--ignore` option replaces the `ignore-glob` setting rather than extending it. With that in mind, translating a `.gitignore` file into `.fossil-settings/ignore-glob` may be possible in many cases. Here are some of features of `.gitignore` and comments on how they relate to fossil: * "A blank line matches no files..." is the same in fossil. * "A line starting with # serves as a comment...." not in fossil. * "Trailing spaces are ignored unless they are quoted..." is similar in fossil. All whitespace before and after a glob is trimmed in fossil unless quoted with single or double quotes. Git uses backslash quoting instead, which fossil does not. * "An optional prefix "!" which negates the pattern..." not in fossil. * Git's globs are relative to the location of the `.gitignore` file; fossil's globs are relative to the root of the workspace. * Git's globs and fossil's globs treat directory separators differently. Git includes a notation for zero or more directories that is not needed in fossil. ### Example In a project with source and documentation: work +-- doc |
︙ | ︙ | |||
591 592 593 594 595 596 597 | ## Implementation and References | | > > > > > > > | | | | < < < | < < | < | > | > | > | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | ## Implementation and References Most of the implementation of glob pattern handling in fossil is found `glob.c`, `file.c`, and each individual command and web page that uses a glob pattern. Find commands and pages in the fossil sources by looking for comments like `COMMAND: add` or `WEBPAGE: timeline` in front of the function that implements the command or page in files `src/*.c`. (Fossil's build system creates the tables used to dispatch commands at build time by searching the sources for those comments.) A few starting points: :File |:Description -------------------------------------------------------------------------------- [`src/glob.c`][] | Implementation of glob pattern list loading, parsing, and matching. [`src/file.c`][] | Implementation of various kinds of canonical names of a file. [`src/glob.c`]: https://www.fossil-scm.org/index.html/file/src/glob.c [`src/file.c`]: https://www.fossil-scm.org/index.html/file/src/file.c The actual pattern matching is implemented in SQL, so the documentation for `GLOB` and the other string matching operators in [SQLite] (https://sqlite.org/lang_expr.html#like) is useful. Of course, the SQLite [source code] (https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768) and [test harnesses] (https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673) also make entertaining reading. |
Deleted www/glossary.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/grep.md.
1 2 3 | # Fossil grep vs POSIX grep As of Fossil 2.7, there is a `grep` command which acts roughly like | | | < < < | | > > > | | < < > > | > | < > > | | | < | < < < | < < < < < | < | | | | | | | 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 | # Fossil grep vs POSIX grep As of Fossil 2.7, there is a `grep` command which acts roughly like POSIX's `grep -E` over all historical versions of a single file name. This document explains the commonalities and divergences between [POSIX `grep`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html) and Fossil `grep`. ## Options Fossil `grep` supports only a small subset of the options specified for POSIX `grep`: | Option | Meaning |--------|------------------------------------------------------------- | `-i` | ignore case in matches | `-l` | list a checkin ID prefix for matching historical versions of the file | `-v` | print each checkin ID considered, regardless of whether it matches That leaves many divergences at the option level from POSIX `grep`: * There is no built-in way to get a count of matches, as with `grep -c`. * You cannot give more than one pattern, as with `grep -e` or `grep -f`. * There is no equivalent of `grep -F` to do literal fixed-string matches only. * `fossil grep -l` does not do precisely the same thing as POSIX `grep -l`: it lists checkin ID prefixes, not file names. * Fossil always gives the line number in its output, which is to say that it acts like `grep -n`. There is no way to disable the line number in `fossil grep` output. * There is no way to suppress all output, returning only a status code to indicate whether the pattern matched, as with `grep -q`. * There is no way to suppress error output, as with `grep -s`. * Fossil `grep` accepts only a single input file name. You cannot give it a list of file names, and you cannot give it a directory name for Fossil to expand to the set of all files under that directory. This means Fossil `grep` has no equivalent of the common POSIX `grep -R` extension. (And if it did, it would probably have a different option letter, since `-R` in Fossil has a different meaning, by convention.) * You cannot invert the match, as with `grep -v`. Patches to remove those limitations will be thoughtfully considered. ## Regular Expression Dialect Fossil contains a built-in regular expression engine implementing a subset of the [POSIX extended regular expression][ere] dialect: [ere]: https://en.wikipedia.org/wiki/Regular_expression#POSIX_extended | Atom | Meaning |---------|------------------------------------------------------------- | `X*` | zero or more occurrences of X | `X+` | one or more occurrences of X | `X?` | zero or one occurrences of X | `X{p,q}`| between p and q occurrences of X, inclusive | `(X)` | match X | <tt>X\|Y</tt>| X or Y | `^X` | X occurring at the beginning of a line | `X$` | X occurring at the end of a line | `.` | Match any single character | `\c` | Character `c` where `c` is one of <tt>{}()[]\|\*+?.</tt> | `\c` | C-language escapes for `c` in `afnrtv`. ex: `\t` or `\n` | `\uXXXX`| Where XXXX is exactly 4 hex digits, Unicode value XXXX | `\xXX` | Where XX is exactly 2 hex digits, Unicode value XX | `[abc]` | Any single character from the set `abc` | `[^abc]`| Any single character not in the set `abc` | `[a-z]` | Any single character in the range `a-z` | `[^a-z]`| Any single character not in the range `a-z` | `\b` | Word boundary | `\w` | Word character: `[A-Za-z0-9_]` | `\W` | Non-word character | `\d` | Digit | `\D` | Non-digit | `\s` | Whitespace character | `\S` | Non-whitespace character There are several restrictions in Fossil `grep` relative to a fully POSIX compatible regular expression engine. Among them are: * There is currently no support for POSIX character classes such as `[:lower:]`. |
︙ | ︙ |
Deleted www/gsoc-ideas.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/hacker-howto.wiki.
|
| | | < > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <title>Fossil Hackers How-To</title> The following links are of interest to programmers who want to modify or enhance Fossil. Ordinary users can safely ignore this information. * [./build.wiki | How To Compile And Install Fossil] * [./customskin.md | Theming Fossil] * [./makefile.wiki | The Fossil Build Process] * [./tech_overview.wiki | A Technical Overview of Fossil] * [./adding_code.wiki | Adding Features To Fossil] * [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project] * [./fileformat.wiki|Fossil Artifact File Format] * [./style.wiki | Coding Style Guidelines] * [./checkin.wiki | Pre-checkin Checklist] * [../test/release-checklist.wiki | Release Checklist] * [./backoffice.md | The "backoffice" subsystem] |
Deleted www/hashes.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/hashpolicy.wiki.
1 2 | <title>Hash Policy</title> | < < | | < | | | | < < < < < < | | | | | | | | | < < < < < < < < < < | | | | < | | | | | | | < | > > | | | | | | < > | < | | < < | < < < < | 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 | <title>Hash Policy</title> <h2> Executive Summary, Or How To Avoid Reading This Article </h2> There is much angst over the [http://www.shattered.io|Shattered attack] against SHA1. If you are concerned about this and its implications for Fossil, simply upgrade to Fossil 2.0 or later and the problem will go away. Everything will continue to work as before. All of your legacy repositories will continue to work and all of your old check-ins will still have the same name. Your workflow will be unchanged. But if you are curious and want a deeper understanding of what is going on, read on... <h2> Introduction </h2> The first snapshot-based distributed version control system was [http://www.monotone.ca|Monotone]. Many of the ideas behind the design of Fossil were copied from Monotone, including the use of a SHA1 hash to assign names to artifacts. Git and Mercurial did the same thing. The SHA1 hash algorithm is used only to create names for artifacts in Fossil (and in Git, Mercurial, and Monotone). It is not used for security. Nevertheless, when the [http://www.shattered.io|Shattered attack] found two different PDF files with the same SHA1 hash, many users learned that "SHA1 is broken". They see that Fossil (and Git, Mercurial, and Monotone) use SHA1 and they therefore conclude that "Fossil is broken". This is not true, but it is a public relations problem. So the decision was made to migrate Fossil away from SHA1. This article describes how that migration is occurring. <h2>Use Of Hardened SHA1</h2> In Fossil version 2.0 ([/timeline?c=version-2.0|2017-03-03]), the internal SHA1 implementation was changed from a generic FIPS PUB 180-4 SHA1 implementation to a "Hardened SHA1" [[https://github.com/cr-marcstevens/sha1collisiondetection|1]] [[https://marc-stevens.nl/research/papers/C13-S.pdf|2]]. The Hardened SHA1 implement automatically detects when the artifact being hashed is specifically designed to exploit the known weaknesses in the SHA1 algorithm, and when it detects such an attack it changes the hash algorithm (by increasing the number of rounds in the compression function) to make the algorithm secure again. If the attack detection gets a false possible, that means that Hardened SHA1 will get a different answer than the standard FIPS PUB 180-4 SHA1, but the creators of Hardened SHA1 (see the second paper [[https://marc-stevens.nl/research/papers/C13-S.pdf|2]]) report that the probability of a false positive is vanishingly small - less than 1 false positive out of 10<sup><font size=1>27</font></sup> hashes. Hardened SHA1 is slower (and a lot bigger) but Fossil does not do that much hashing, so performance is not really an issue. All versions of Fossil moving forward will use Hardened SHA1. So if someone says "SHA1 is broken, and Fossil uses SHA1, therefore Fossil is broken", you can rebut the argument by pointing out that Fossil uses <em>Hardened SHA1</em> not generic SHA1 and Hardened SHA1 is <em>not</em> broken. <h2>Support For SHA3-256</h2> Prior to Fossil version 2.0 ([/timeline?c=version-2.0|2017-03-03]), all artifacts in all Fossil repositories were named by only a SHA1 hash. Version 2.0 extended the [./fileformat.wiki|Fossil file format] to allow artifacts to be named by either SHA1 or SHA3-256 hashes. (SHA3-256 is the only variant of SHA3 that Fossil uses for artifact naming, so for the remainder of this article it will be called simply "SHA3". Similarly, "Hardened SHA1" will shortened to "SHA1" in the sequel.) Other than permitting the use of SHA3 in addition to SHA1, there were no file format changes in Fossil version 2.0 relative to the previous version 1.37. Both Fossil 2.0 and Fossil 1.37 read and write all the same repositories and sync with one another, as long as none of the repositories contain artifacts named using SHA3. If a repository does contain artifacts named using SHA3, Fossil 1.37 will not know how to interpret those artifacts and will generate various warnings and errors. <h2>How Fossil Decides Which Hash Algorithm To Use</h2> If newer versions of Fossil are able to use either SHA1 or SHA3 to name artifacts, which hash algorithm is actually used? That question is answered by the "hash policy". These are the supported hash policies: <table cellpadding=10> <tr> <td valign='top'>sha1</td> <td>Name all new artifacts using the (Hardened) SHA1 hash algorithm.</td> </tr> <tr> <td valign='top'>auto</td> <td>Name new artifacts using the SHA1 hash algorithm. But if any artifacts are encountered which are already named using SHA3, then automatically switch the hash policy to "sha3"</td> </tr> <tr> <td valign='top'>sha3</td> <td>Name new artifacts using the SHA3 hash algorithm if the artifact does not already have a SHA1 name. If the artifact already has a SHA1 name, then continue to use the older SHA1 name. Use SHA3 for new artifacts that have never before been encountered.</td> </tr> <tr> <td valign='top'>sha3-only</td> <td>Name new artifacts using the SHA3 hash algorithm even if the artifact already has a SHA1 name. In other words, force the use of SHA3. This can cause some artifacts to be added to the respository twice, once under their SHA1 name and again under their SHA3 name. But delta compression will prevent that from causing repository size problems.</td> </tr> <tr> <td valign='top'>shun-sha1</td> <td>Like "sha3-only" but at this level do not accept a push of SHA1-named artifacts. If another Fossil instance tries to push a SHA1-named artifact, that artifact is discarded and ignored. </tr> </table> For Fossil 2.0, and obviously also for Fossil 1.37 and before, the only hash policy supported was "sha1". All new artifacts were named using their SHA1 hash. Even though Fossil 2.0 was capable of understanding SHA3 hashes, it never actually generates any SHA3 hashes. Beginning with Fossil 2.1, the default hash policy for legacy repositories changed to "auto". That means Fossil 2.1 will continue to generate only SHA1 hashes until it encounters one artifact with a SHA3 hash. Once a single SHA3 hash is seen, Fossil automatically switches to "sha3" mode and thereafter generates only SHA3 hashes. When a new repository is created by cloning, the hash policy is copied from the parent. For new repositories created using the [/help?cmd=new|fossil new] command the default hash policy is "sha3". That means new repositories will normally hold nothing except SHA3 hashes. The hash policy for new repositories can be overridden using the "--sha1" option to the "fossil new" command. Even after upgrading to Fossil 2.1, Fossil will continue to use nothing but SHA1 hashes on legacy repositories, thus preserving complete compatibility with Fossil 1.37 and before. If you want Fossil to go ahead and start using SHA3 hashes, change the hash policy to "sha3" using a command like this: <blockquote><verbatim> fossil hash-policy sha3 </verbatim></blockquote> The next check-in will use a SHA3 hash. And when that check-in is pushed to colleagues, their copies of Fossil will see the new SHA3-named artifact and automatically convert to SHA3 as well. Of course, if some members of your team stubbornly refuse to upgrade past Fossil 1.37, you should avoid changing the hash policy and creating artifacts with SHA3 names, because once you do that your recalcitrant coworkers will no longer be able to collaborate. <h2>A Pure SHA3 Future</h2> At some point in the future, years from now, after everybody has finally upgraded to Fossil 2.0 or later, the default hash policy will probably change to "sha3", or maybe even "shun-sha1". By the time that happens, you will probably already be using SHA3 on all your projects and so you are unlikely to notice. |
Changes to www/hints.wiki.
1 2 | <title>Fossil Tips And Usage Hints</title> | < < | | | 1 2 3 4 5 6 7 8 9 10 11 | <title>Fossil Tips And Usage Hints</title> 1. Click on nodes of any timeline graph to see diffs between the two selected versions. 2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands to get a pop-up window containing a complete side-by-side diff. (NB: The pop-up window is run as a separate Tcl/Tk process, so you will need to have Tcl/Tk installed on your machine for this to work. Visit [http://www.activestate.com/activetcl] to for a quick download of |
︙ | ︙ | |||
31 32 33 34 35 36 37 | 6. You can manually add a "c=CHECKIN" query parameter to the timeline URL to get a snapshot of what was going on about the time of some check-in. The "CHECKIN" can be [./checkin_names.wiki | any valid check-in or version name], including tags, branch names, and dates. For example, to see what was going on in the Fossil repository on 2008-01-01, visit | | | | | < | | < < < < < < < < < < | 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 | 6. You can manually add a "c=CHECKIN" query parameter to the timeline URL to get a snapshot of what was going on about the time of some check-in. The "CHECKIN" can be [./checkin_names.wiki | any valid check-in or version name], including tags, branch names, and dates. For example, to see what was going on in the Fossil repository on 2008-01-01, visit [http://www.fossil-scm.org/fossil/timeline?c=2008-01-01]. 7. Further to the previous two hints, there are lots of query parameters that you can add to timeline pages. The available query parameters are tersely documented [/help?cmd=/timeline | here]. 8. You can run "[/help?cmd=test-diff | fossil test-diff --tk $file1 $file2]" to get a pop-up window with side-by-side diffs of two files, even if neither of the two files is part of any Fossil repository. Note that this command is "test-diff", not "diff". 9. On web pages showing the content of a file (for example [http://www.fossil-scm.org/fossil/artifact/c7dd1de9f]) you can manually add a query parameter of the form "ln=FROM,TO" to the URL that will cause the range of lines indicated to be highlighted. This is useful in pointing out a few lines of code using a hyperlink in an email or text message. Example: [http://www.fossil-scm.org/fossil/artifact/c7dd1de9f?ln=28,30]. Adding the "ln" query parameter without any argument simply turns on line numbers. This feature only works right with files with a mimetype of text/plain, of course. 10. When editing documentation to be checked in as managed files, you can preview what the documentation will look like by using the special "ckout" branch name in the "doc" URL while running "fossil ui". See the [./embeddeddoc.wiki | embedded documentation] for details. |
Deleted www/history.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/hooks.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/image-format-vs-repo-size.ipynb.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/image-format-vs-repo-size.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/image-format-vs-repo-size.svg.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/index.wiki.
|
| | | | | | < < > | > > | | < | | | < | | > | | | | < < < < < < < < | > | | | > > > > > | | | | > > > | > > > > | > | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | < < > | > > > > | < < < < > > > > | | 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 | <title>Home</title> <h3>What Is Fossil?</h3> <div style='width:200px;float:right;border:2px solid #446979;padding:10px;margin:0px 10px;'> <ul> <li> [/uv/download.html | Download] <li> [./quickstart.wiki | Quick Start] <li> [./build.wiki | Install] <li> [../COPYRIGHT-BSD2.txt | License] <li> [./faq.wiki | FAQ] <li> [./changes.wiki | Change Log] <li> [./hacker-howto.wiki | Hacker How-To] <li> [./fossil-v-git.wiki | Fossil vs. Git] <li> [./hints.wiki | Tip & Hints] <li> [./permutedindex.html | Documentation Index] <li> [https://fossil-scm.org/forum | Forum ] <li> [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | Mailing list archives] </ul> <img src="fossil3.gif" align="center"> </div> <p>Fossil is a simple, high-reliability, distributed software configuration management system with these advanced features: 1. <b>Integrated Bug Tracking, Wiki, Forum, and Technotes</b> - In addition to doing [./concepts.wiki | distributed version control] like Git and Mercurial, Fossil also supports [./bugtheory.wiki | bug tracking], [./wikitheory.wiki | wiki], [./forum.wiki | forum], and [./event.wiki | technotes]. 2. <b>Built-in Web Interface</b> - Fossil has a built-in, [https://fossil-scm.org/skins/index.html | themeable], and intuitive [./webui.wiki | web interface] with a rich variety of information pages ([./webpage-ex.md|examples]) promoting situational awareness. <p> This entire website is just a running instance of Fossil. The pages you see here are all [./wikitheory.wiki | wiki] or [./embeddeddoc.wiki | embedded documentation] or (in the case of the [/uv/download.html|download] page) [./unvers.wiki | unversioned files]. When you clone Fossil from one of its [./selfhost.wiki | self-hosting repositories], you get more than just source code - you get this entire website. 3. <b>Self-Contained</b> - Fossil is a single self-contained stand-alone executable. To install, simply download a [/uv/download.html | precompiled binary] for Linux, Mac, or Windows and put it on your $PATH. [./build.wiki | Easy-to-compile source code] is also available. 4. <b>Simple Networking</b> - No custom protocols or TCP ports. Fossil uses ordinary HTTP (or HTTPS or SSH) for network communications, so it works fine from behind restrictive firewalls, including [./quickstart.wiki#proxy|proxies]. The protocol is [./stats.wiki | bandwidth efficient] to the point that Fossil can be used comfortably over dial-up or over the exceedingly slow Wifi on airliners. 5. <b>CGI/SCGI Enabled</b> - No server is required, but if you want to set one up, Fossil supports four easy [./server.wiki | server configurations]. 6. <b>Autosync</b> - Fossil supports [./concepts.wiki#workflow | "autosync" mode] which helps to keep projects moving forward by reducing the amount of needless [./branching.wiki | forking and merging] often associated with distributed projects. 7. <b>Robust & Reliable</b> - Fossil stores content using an [./fileformat.wiki | enduring file format] in an SQLite database so that transactions are atomic even if interrupted by a power loss or system crash. Automatic [./selfcheck.wiki | self-checks] verify that all aspects of the repository are consistent prior to each commit. 8. <b>Free and Open-Source</b> - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license]. <hr> <h3>Links For Fossil Users:</h3> * [./permutedindex.html | Documentation index] with [/search?c=d | full text search]. * [./reviews.wiki | Testimonials] from satisfied Fossil users and [./quotes.wiki | Quotes] about Fossil and other DVCSes. * [./faq.wiki | Frequently Asked Questions] * The [./concepts.wiki | concepts] behind Fossil. [./whyusefossil.wiki#definitions | Another viewpoint]. * [./quickstart.wiki | Quick Start] guide to using Fossil. * [./qandc.wiki | Questions & Criticisms] directed at Fossil. * [./build.wiki | Compiling and Installing] * Fossil supports [./embeddeddoc.wiki | embedded documentation] that is versioned along with project source code. * Fossil uses an [./fileformat.wiki | enduring file format] that is designed to be readable, searchable, and extensible by people not yet born. * A tutorial on [./branching.wiki | branching], what it means and how to do it using Fossil. * The [./selfcheck.wiki | automatic self-check] mechanism helps insure project integrity. * Fossil contains a [./wikitheory.wiki | built-in wiki]. * An [./event.wiki | Event] is a special kind of wiki page associated with a point in time rather than a name. * [./settings.wiki | Settings] control the behaviour of Fossil. * [./ssl.wiki | Use SSL] to encrypt communication with the server. * There is a [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]) available for discussing Fossil issues. * [./stats.wiki | Performance statistics] taken from real-world projects hosted on Fossil. * How to [./shunning.wiki | delete content] from a Fossil repository. * How Fossil does [./password.wiki | password management]. * On-line [/help | help]. * Documentation on the [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language], used to customize [./custom_ticket.wiki | ticketing], and several other subsystems, including [./customskin.md | theming]. * List of [./th1.md | TH1 commands provided by Fossil itself] that expose its key functionality to TH1 scripts. * List of [./th1-hooks.md | TH1 hooks exposed by Fossil] that enable customization of commands and web pages. * A free hosting server for Fossil repositories is available at [http://chiselapp.com/]. * How to [./server.wiki | set up a server] for your repository. * Customizing the [./custom_ticket.wiki | ticket system]. * Methods to [./checkin_names.wiki | identify a specific check-in]. * [./inout.wiki | Import and export] from and to Git. * [./fossil-v-git.wiki | Fossil versus Git]. * [./fiveminutes.wiki | Up and running in 5 minutes as a single user] (contributed by Gilles Ganault on 2013-01-08). * [./antibot.wiki | How Fossil defends against abuse by spiders and bots]. <h3>Links For Fossil Developers:</h3> * [./contribute.wiki | Contributing] code or documentation to the Fossil project. * [./theory1.wiki | Thoughts On The Design Of Fossil]. * [./pop.wiki | Principles Of Operation] * [./tech_overview.wiki | A Technical Overview Of Fossil]. * The [./fileformat.wiki | file format] used by every content file stored in the repository. * The [./delta_format.wiki | format of deltas] used to efficiently store changes between file revisions. * The [./delta_encoder_algorithm.wiki | encoder algorithm] used to efficiently generate deltas. * The [./sync.wiki | synchronization protocol]. |
Changes to www/inout.wiki.
1 2 3 4 5 6 7 8 9 10 | <title>Import And Export</title> Fossil has the ability to import and export repositories from and to [http://git-scm.com/ | Git]. And since most other version control systems will also import/export from Git, that means that you can import/export a Fossil repository to most version control systems using Git as an intermediary. <h2>Git → Fossil</h2> | | | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < | | | | | | | 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 | <title>Import And Export</title> Fossil has the ability to import and export repositories from and to [http://git-scm.com/ | Git]. And since most other version control systems will also import/export from Git, that means that you can import/export a Fossil repository to most version control systems using Git as an intermediary. <h2>Git → Fossil</h2> To import a Git repository into Fossil, run commands like this: <blockquote><pre> cd git-repo git fast-export --all | fossil import --git new-repo.fossil </pre></blockquote> In other words, simply pipe the output of the "git fast-export" command into the "fossil import --git" command. The 3rd argument to the "fossil import" command is the name of a new Fossil repository that is created to hold the Git content. The --git option is not actually required. The git-fast-export file format is currently the only VCS interchange format that Fossil understands. But future versions of Fossil might be enhanced to understand other VCS interchange formats, and so for compatibility, use of the --git option is recommended. <h2>Fossil → Git</h2> To convert a Fossil repository into a Git repository, run commands like this: <blockquote><pre> git init new-repo cd new-repo fossil export --git ../repo.fossil | git fast-import </pre></blockquote> In other words, create a new Git repository, then pipe the output from the "fossil export --git" command into the "git fast-import" command. Note that the "fossil export --git" command only exports the versioned files. Tickets and wiki and events are not exported, since Git does not understand those concepts. As with the "import" command, the --git option is not required since the git-fast-export file format is currently the only VCS interchange format that Fossil will generate. However, future versions of Fossil might add the ability to generate other VCS interchange formats, and so for compatibility, the use of the --git option recommended. <h2>Bidirectional Synchronization</h2> Fossil also has the ability to synchronize with a Git repository via repeated imports and/or exports. To do this, it uses marks files to store a record of artifacts which are known by both Git and Fossil to exist at a given point in time. To illustrate, consider the example of a remote Fossil repository that a user wants to import into a local Git repository. First, the user would clone the remote repository and import it into a new Git repository: <blockquote><pre> fossil clone /path/to/remote/repo.fossil repo.fossil mkdir repo cd repo fossil open ../repo.fossil mkdir ../repo.git cd ../repo.git git init . fossil export --git --export-marks ../repo/fossil.marks \ ../repo.fossil | git fast-import \ --export-marks=../repo/git.marks </pre></blockquote> Once the import has completed, the user would need to <tt>git checkout trunk</tt>. At any point after this, new changes can be imported from the remote Fossil repository: <blockquote><pre> cd ../repo fossil pull cd ../repo.git fossil export --git --import-marks ../repo/fossil.marks \ --export-marks ../repo/fossil.marks \ ../repo.fossil | git fast-import \ --import-marks=../repo/git.marks \ --export-marks=../repo/git.marks </pre></blockquote> Changes in the Git repository can be exported to the Fossil repository and then pushed to the remote: <blockquote><pre> git fast-export --import-marks=../repo/git.marks \ --export-marks=../repo/git.marks --all | fossil import --git \ --incremental --import-marks ../repo/fossil.marks \ --export-marks ../repo/fossil.marks ../repo.fossil cd ../repo fossil push </pre></blockquote> |
Deleted www/interwiki.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/javascript.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/_template.md.
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-artifact.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-auth.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-branch.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-checkout.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-config.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-diff.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-dir.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-finfo.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-misc.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-query.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-settings.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-stat.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-tag.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-ticket.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-timeline.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-user.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-version.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/api-wiki.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/conventions.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/hacking.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/index.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/intro.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/json-api/tips.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/loadmgmt.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/makefile.wiki.
1 2 3 4 5 6 7 | <title>The Fossil Build Process</title> <h1>1.0 Introduction</h1> The build process for Fossil is tricky in that the source code needs to be processed by three different preprocessor programs before it is compiled. Most users will download a | | > | | | | | 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 | <title>The Fossil Build Process</title> <h1>1.0 Introduction</h1> The build process for Fossil is tricky in that the source code needs to be processed by three different preprocessor programs before it is compiled. Most users will download a [https://www.fossil-scm.org/fossil/uv/download.html | precompiled binary] so this is of no consequence to them, and even those who want to compile the code themselves can use one of the [./build.wiki | existing makefiles]. So must people do not need to be concerned with the build complexities of Fossil. But hard-core developers who desire a deep understanding of how Fossil is put together can benefit from reviewing this article. <a name="srctour"></a> <h1>2.0 Source Code Tour</h1> The source code for Fossil is found in the [/dir?ci=trunk&name=src | src/] subdirectory of the source tree. The src/ subdirectory contains all code, including the code for the separate preprocessor programs. Each preprocessor program is a separate C program implemented in a single file of C source code. The three preprocessor programs are: 1. [/file/src/mkindex.c | mkindex.c] 2. [/file/src/translate.c | translate.c] 3. [/file/src/makeheaders.c | makeheaders.c] Fossil uses [http://www.sqlite.org/ | SQLite] for on-disk storage. The SQLite implementation is contained in three source code files that do not participate in the preprocessing steps. These three files that implement SQLite are: 4. sqlite3.c |
︙ | ︙ | |||
60 61 62 63 64 65 66 | The proprocessing steps are omitted for all of these imported files. The VERSION.h header file is generated from other information sources using a small program called: | | | | | | | | | | | 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 | The proprocessing steps are omitted for all of these imported files. The VERSION.h header file is generated from other information sources using a small program called: 11. [/file/src/mkversion.c | mkversion.c] The builtin_data.h header file contains the definitions of C-language byte-array constants that contain various resources such as scripts and images. The builtin_data.h header file is generate from the original resource files using a small program called: 12 [/file/src/mkbuiltin.c | mkbuiltin.c] Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] script used to implement the --tk option to [/help?cmd=diff| fossil diff], the [/file/src/markdown.md | markdown documentation], and the various CSS scripts, headers, and footers used to implement built-in skins. New resources files are added to the "extra_files" variable in [/file/src/makemake.tcl | makemake.tcl]. The src/ subdirectory also contains documentation about the makeheaders preprocessor program: 13. [../src/makeheaders.html | makeheaders.html] Click on the link to read this documentation. In addition there is a [http://www.tcl-lang.org/ | Tcl] script used to build the various makefiles: 14. makemake.tcl Running this Tcl script will automatically regenerate all makefiles. In order to add a new source file to the Fossil implementation, simply edit makemake.tcl to add the new filename, then rerun the script, and all of the makefiles for all targets will be rebuild. There is an option code verification step implemented using 15. [/file/src/codecheck1.c | codecheck1.c] This file implements a small utility program ("codecheck1") that scans other Fossil source files looking for errors in printf-style format strings. The codecheck1 utility detects missing or surplus arguments on printf-like functions and dangerous uses of "%s" that might permit SQL injection or cross-site scripting attacks. This code check step is run automatically on each build of Fossil, and can also be run separately by typing "make codecheck". Note that the built-in printf format checking of GCC does not function for Fossil since Fossil implements its own printf (in the [/file/src/printf.c | printf.c] source file) that includes special |
︙ | ︙ | |||
139 140 141 142 143 144 145 | "manifest.uuid", and "VERSION" source files in the root directory of the source tree. (The "manifest" and "manifest.uuid" files are automatically generated and updated by Fossil itself. See the [/help/setting | fossil set manifest] command for additional information.) The VERSION.h header file is generated by | | | | | | | | | > | | | | | | | | | 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 | "manifest.uuid", and "VERSION" source files in the root directory of the source tree. (The "manifest" and "manifest.uuid" files are automatically generated and updated by Fossil itself. See the [/help/setting | fossil set manifest] command for additional information.) The VERSION.h header file is generated by a C program: src/mkversion.c. To run the VERSION.h generator, first compile the src/mkversion.c source file into a command-line program (named "mkversion.exe") then run: <blockquote><pre> mkversion.exe manifest.uuid manifest VERSION >VERSION.h </pre></blockquote> The pathnames in the above command might need to be adjusted to get the directories right. The point is that the manifest.uuid, manifest, and VERSION files in the root of the source tree are the three arguments and the generated VERSION.h file appears on standard output. The builtin_data.h header file is generated by a C program: src/mkbuiltin.c. The builtin_data.h file contains C-langauge byte-array definitions for the content of resource files used by Fossil. To generate the builtin_data.h file, first compile the mkbuiltin.c program, then run: <blockquote><pre> mkbuiltin.exe diff.tcl <i>OtherFiles...</i> >builtin_data.h </pre></blockquote> At the time of this writing, the "diff.tcl" script (a Tcl/Tk script used to generate implement --tk option on the diff command) is the only resource file processed using mkbuiltin.exe. However, new resources will likely be added using this facility in future versions of Fossil. <a name="preprocessing"></a> <h1>4.0 Preprocessing</h1> There are three preprocessors for the Fossil sources. The mkindex and translate preprocessors can be run in any order. The makeheaders preprocessor must be run after translate. <h2>4.1 The mkindex preprocessor</h2> The mkindex program scans the "src.c" source files looking for special comments that identify routines that implement various Fossil commands, web interface methods, and help text comments. The mkindex program generates some C code that Fossil uses in order to dispatch commands and HTTP requests and to show on-line help. Compile the mkindex program from the mkindex.c source file. Then run: <blockquote><pre> ./mkindex src.c >page_index.h </pre></blockquote> Note that "src.c" in the above is a stand-in for the (79) regular source files of Fossil - all source files except for the exceptions described in section 2.0 above. The output of the mkindex program is a header file that is #include-ed by the main.c source file during the final compilation step. <h2>4.2 The translate preprocessor</h2> The translate preprocessor looks for lines of source code that begin with "@" and converts those lines into string constants or (depending on context) into special "printf" operations for generating the output of an HTTP request. The translate preprocessor is a simple C program whose sources are in the translate.c source file. The translate preprocess is run on each of the other ordinary source files separately, like this: <blockquote><pre> ./translate src.c >src_.c </pre></blockquote> In this case, the "src.c" file represents any single source file from the set of ordinary source files as described in section 2.0 above. Note that each source file is translated separately. By convention, the names of the translated source files are the names of the input sources with a single "_" character at the end. But a new makefile can use any naming convention it wants - the "_" is not critical to the build process. After being translated, the output files (the "src_.c" files) should be used for all subsequent preprocessing and compilation steps. <h2>4.3 The makeheaders preprocessor</h2> For each C source module "src.c", there is an automatically generated header module "src.h" that contains all of the datatype and procedure declarations needed by the source module. These header files are generated automatically by the makeheaders program. The sources to makeheaders are contained in a single file "makeheaders.c". Additional documentation on makeheaders can be found in [../src/makeheaders.html | src/makeheaders.html]. The makeheaders program is run once. It scans all inputs source files and generates header files for each one. Note that the sqlite3.c and shell.c source files are not scanned by makeheaders. Makeheaders only runs over "ordinary" source files, not the exceptional source files. However, makeheaders also uses some extra header files as input. The general format is like this: <blockquote><pre> makeheaders src_.c:src.h sqlite3.h th.h VERSION.h </pre></blockquote> In the example above the "src_.c" and "src.h" names represent all of the (79) ordinary C source files, each as a separate argument. <h1>5.0 Compilation</h1> After all generated files have been created and all ordinary source files |
︙ | ︙ | |||
290 291 292 293 294 295 296 | Fossil needs to be linked against [http://www.zlib.net | zlib]. If the HTTPS option is enabled, then it will also need to link against the appropriate SSL implementation. And, of course, Fossil needs to link against the standard C library. No other libraries or external dependences are used. | < | < < | < < < < < < < < < < < < < < < < < < < < | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | Fossil needs to be linked against [http://www.zlib.net | zlib]. If the HTTPS option is enabled, then it will also need to link against the appropriate SSL implementation. And, of course, Fossil needs to link against the standard C library. No other libraries or external dependences are used. Fossil includes a copy of [https://github.com/richgel999/miniz | miniz] which can be used as an alternative to zlib. <h1>7.0 See Also</h1> * [./tech_overview.wiki | A Technical Overview Of Fossil] * [./adding_code.wiki | How To Add Features To Fossil] |
Deleted www/mdtest/test1.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/mirrorlimitations.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/mirrortogithub.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/mkindex.tcl.
1 2 3 4 5 6 7 | #!/usr/bin/env tclsh # # Run this TCL script to generate a WIKI page that contains a # permuted index of the various documentation files. # # tclsh mkindex.tcl # | < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < > < < < | | | | | | < < > > > | > < | < | < < | | | | > | | 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 | #!/usr/bin/env tclsh # # Run this TCL script to generate a WIKI page that contains a # permuted index of the various documentation files. # # tclsh mkindex.tcl # set doclist { aboutcgi.wiki {How CGI Works In Fossil} aboutdownload.wiki {How The Download Page Works} adding_code.wiki {Adding New Features To Fossil} adding_code.wiki {Hacking Fossil} alerts.md {Email Alerts And Notifications} antibot.wiki {Defense against Spiders and Bots} backoffice.md {The "Backoffice" mechanism of Fossil} blame.wiki {The Annotate/Blame Algorithm Of Fossil} blockchain.md {Fossil As Blockchain} branching.wiki {Branching, Forking, Merging, and Tagging} bugtheory.wiki {Bug Tracking In Fossil} build.wiki {Compiling and Installing Fossil} changes.wiki {Fossil Changelog} checkin_names.wiki {Check-in And Version Names} checkin.wiki {Check-in Checklist} childprojects.wiki {Child Projects} copyright-release.html {Contributor License Agreement} concepts.wiki {Fossil Core Concepts} contribute.wiki {Contributing Code or Documentation To The Fossil Project} customgraph.md {Theming: Customizing the Timeline Graph} customskin.md {Theming: Customizing The Appearance of Web Pages} custom_ticket.wiki {Customizing The Ticket System} delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm} delta_format.wiki {Fossil Delta Format} embeddeddoc.wiki {Embedded Project Documentation} encryptedrepos.wiki {How To Use Encrypted Repositories} env-opts.md {Environment Variables and Global Options} event.wiki {Events} faq.wiki {Frequently Asked Questions} fileformat.wiki {Fossil File Format} fiveminutes.wiki {Up and Running in 5 Minutes as a Single User} forum.wiki {Fossil Forums} foss-cklist.wiki {Checklist For Successful Open-Source Projects} fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE} fossil-v-git.wiki {Fossil Versus Git} globs.md {File Name Glob Patterns} hacker-howto.wiki {Hacker How-To} hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256} /help {Lists of Commands and Webpages} hints.wiki {Fossil Tips And Usage Hints} index.wiki {Home Page} inout.wiki {Import And Export To And From Git} makefile.wiki {The Fossil Build Process} /md_rules {Markdown Formatting Rules} newrepo.wiki {How To Create A New Fossil Repository} password.wiki {Password Management And Authentication} pop.wiki {Principles Of Operation} private.wiki {Creating, Syncing, and Deleting Private Branches} qandc.wiki {Questions And Criticisms} quickstart.wiki {Fossil Quick Start Guide} quotes.wiki {Quotes: What People Are Saying About Fossil, Git, and DVCSes in General} ../test/release-checklist.wiki {Pre-Release Testing Checklist} reviews.wiki {Reviews} selfcheck.wiki {Fossil Repository Integrity Self Checks} selfhost.wiki {Fossil Self Hosting Repositories} server.wiki {How To Configure A Fossil Server} settings.wiki {Fossil Settings} /sitemap {Site Map} shunning.wiki {Shunning: Deleting Content From Fossil} stats.wiki {Performance Statistics} style.wiki {Source Code Style Guidelines} ssl.wiki {Using SSL with Fossil} sync.wiki {The Fossil Sync Protocol} tech_overview.wiki {A Technical Overview Of The Design And Implementation Of Fossil} tech_overview.wiki {SQLite Databases Used By Fossil} th1.md {The TH1 Scripting Language} tickets.wiki {The Fossil Ticket System} theory1.wiki {Thoughts On The Design Of The Fossil DVCS} unvers.wiki {Unversioned Files} webpage-ex.md {Webpage Examples} webui.wiki {The Fossil Web Interface} whyusefossil.wiki {Why You Should Use Fossil} whyusefossil.wiki {Benefits Of Version Control} wikitheory.wiki {Wiki In Fossil} /wiki_rules {Wiki Formatting Rules} } set permindex {} set stopwords { a about against and are as by for fossil from in of on or should the to use used with } foreach {file title} $doclist { set n [llength $title] regsub -all {\s+} $title { } title lappend permindex [list $title $file 1] for {set i 0} {$i<$n-1} {incr i} { set prefix [lrange $title 0 $i] set suffix [lrange $title [expr {$i+1}] end] set firstword [string tolower [lindex $suffix 0]] if {[lsearch $stopwords $firstword]<0} { lappend permindex [list "$suffix — $prefix" $file 0] } } } set permindex [lsort -dict -index 0 $permindex] set out [open permutedindex.html w] fconfigure $out -encoding utf-8 -translation lf puts $out \ "<div class='fossil-doc' data-title='Index Of Fossil Documentation'>" puts $out { <center> <form action='$ROOT/docsrch' method='GET'> <input type="text" name="s" size="40" autofocus> <input type="submit" value="Search Docs"> </form> </center> <h2>Primary Documents:</h2> <ul> <li> <a href='quickstart.wiki'>Quick-start Guide</a> <li> <a href='faq.wiki'>FAQ</a> <li> <a href='build.wiki'>Compiling and installing Fossil</a> <li> <a href='../COPYRIGHT-BSD2.txt'>License</a> <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's book</a> <li> <a href='$ROOT/help'>List of commands, web-pages, and settings</a> <li> <a href='hacker-howto.wiki'>Hacker How-To</a> </ul> <a name="pindex"></a> <h2>Permuted Index:</h2> <ul>} foreach entry $permindex { foreach {title file bold} $entry break if {$bold} {set title <b>$title</b>} if {[string match /* $file]} {set file ../../..$file} puts $out "<li><a href=\"$file\">$title</a></li>" } puts $out "</ul></div>" |
Changes to www/newrepo.wiki.
1 2 | <title>How To Create A New Fossil Repository</title> | | | | | | | | | | | > | | | | | | | | | | | | | | | | > | | 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 | <title>How To Create A New Fossil Repository</title> <p> The [/doc/tip/www/quickstart.wiki|quickstart guide] explains how to get up and running with fossil. But once you're running, what can you do with it? This document will walk you through the process of creating a fossil repository, populating it with files, and then sharing it over the web.</p> The first thing we need to do is create a fossil repository file: <verbatim> stephan@ludo:~/fossil$ fossil new demo.fossil project-id: 9d8ccff5671796ee04e60af6932aa7788f0a990a server-id: 145fe7d71e3b513ac37ac283979d73e12ca04bfe admin-user: stephan (initial password is ******) </verbatim> The numbers it spits out are unimportant (they are version numbers). Now we have an empty repository file named <tt>demo.fossil</tt>. There is nothing magical about the extension <tt>.fossil</tt> - it's just a convention. You may name your files anything you like. The first thing we normally want to do is to run fossil as a local server so that you can configure the access rights to the repo: <verbatim> stephan@ludo:~/fossil$ fossil ui demo.fossil </verbatim> The <tt>ui</tt> command starts up a server (with an optional <tt>-port NUMBER</tt> argument) and launches a web browser pointing at the fossil server. From there it takes just a few moments to configure the repo. Most importantly, go to the Admin menu, then the Users link, and set your account name and password, and grant your account all access privileges. (I also like to grant Clone access to the anonymous user, but that's personal preference.) Once you are done, kill the fossil server (with Ctrl-C or equivalent) and close the browser window. <blockquote> Tip: it is not strictly required to configure a repository this way, but if you are going to share a repo over the net then it is highly recommended. If you are only going to work with the repo locally, you can skip the configuration step and do it later if you decide you want to share your repo. </blockquote> The next thing we need to do is <em>open</em> the repository. To do so we create a working directory and then <tt>cd</tt> to it: <verbatim> stephan@ludo:~/fossil$ mkdir demo stephan@ludo:~/fossil$ cd demo stephan@ludo:~/fossil/demo$ fossil open ../demo.fossil stephan@ludo:~/fossil/demo$ </verbatim> That creates a file called <tt>_FOSSIL_</tt> in the current directory, and this file contains all kinds of fossil-related information about your local repository. You can ignore it for all purposes, but be sure not to accidentally remove it or otherwise damage it - it belongs to fossil, not you. The next thing we need to do is add files to our repository. As it happens, we have a few C source files lying around, which we'll simply copy into our working directory. <verbatim> stephan@ludo:~/fossil/demo$ cp ../csnip/*.{c,h} . stephan@ludo:~/fossil/demo$ ls clob.c clob.h clobz.c _FOSSIL_ mkdep.c test-clob.c tokenize_path.c tokenize_path.h vappendf.c vappendf.h </verbatim> Fossil doesn't know about those files yet. Telling fossil about a new file is a two-step process. First we <em>add</em> the file to the repository, then we <em>commit</em> the file. This is a familiar process for anyone who's worked with SCM systems before: <verbatim> stephan@ludo:~/fossil/demo$ fossil add *.{c,h} stephan@ludo:~/fossil/demo$ fossil commit -m "egg" New_Version: d1296b4a08b9f8b943bb6c73698e51eed23f8f91 </verbatim> We now have a working repository! The file <tt>demo.fossil</tt> is the central storage, and we can share it amongst an arbitrary number of trees. As a silly example: <verbatim> stephan@ludo:~/fossil/demo$ cd ~/fossil stephan@ludo:~/fossil$ mkdir demo2 stephan@ludo:~/fossil$ cd demo2 stephan@ludo:~/fossil/demo2$ fossil open ../demo.fossil ADD clob.c ADD clob.h ADD clobz.c ADD mkdep.c ADD test-clob.c ADD tokenize_path.c ADD tokenize_path.h ADD vappendf.c </verbatim> You may modify the repository (e.g. add, remove, or commit files) from both working directories, and doing so might be useful when working on a branch or experimental code. Making your repository available over the web is trivial to do. We assume you have some web space where you can store your fossil file and run a CGI script. If not, then this option is not for you. If you do, then here's how... Copy copy the fossil repository file to your web server (it doesn't matter where, really). In your <tt>cgi-bin</tt> (or equivalent) directory, create a file which looks like this: <verbatim> #!/path/to/fossil repository: /path/to/my_repo.fossil </verbatim> Make that script executable, and you're all ready to go: <verbatim> ~/www/cgi-bin> chmod +x myrepo.cgi </verbatim> Now simply point your browser to <tt>http://my.domain/cgi-bin/myrepo.cgi</tt> and you should be able to manage the repository from there. To check out a copy of your remote repository, use the <em>clone</em> command: <verbatim> stephan@ludo:~/fossil$ fossil clone \ http://MyAccountName:MyAccountPassword@my.domain/cgi-bin/myrepo.cgi </verbatim> Note that you should pass your fossil login name and password (as set via local server mode) during the clone - that ensures that fossil won't ask you for it on each commit! A clone is a local copy of a remote repository, and can be opened just like a local one (as shown above). It is treated identically to your local repository, with one very important difference. When you commit changes to a cloned remote repository, they will be pushed back to the remote repository. If you have <tt>autosync</tt> on then this sync happens automatically, otherwise you will need to use the |
︙ | ︙ |
Changes to www/password.wiki.
1 2 3 4 5 6 7 8 | <title>Fossil Password Management</title> Fossil handles user authentication using passwords. Passwords are unique to each repository. Passwords are not part of the persistent state of a project. Passwords are not versioned and are not transmitted from one repository to another during a sync. Passwords are local configuration information that can (and usually does) vary from one repository to the next within the same project. | > | 1 2 3 4 5 6 7 8 9 | <title>Fossil Password Management</title> <h1 align="center">Password Management</h1> Fossil handles user authentication using passwords. Passwords are unique to each repository. Passwords are not part of the persistent state of a project. Passwords are not versioned and are not transmitted from one repository to another during a sync. Passwords are local configuration information that can (and usually does) vary from one repository to the next within the same project. |
︙ | ︙ | |||
19 20 21 22 23 24 25 | The SHA1 hash in the USER.PW field is a hash of a string composed of the project-code, the user login, and the user cleartext password. Suppose user "alice" with password "asdfg" had an account on the Fossil self-hosting repository. Then the value of USER.PW for alice would be the SHA1 hash of | | | > | | | | | | | | | 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 | The SHA1 hash in the USER.PW field is a hash of a string composed of the project-code, the user login, and the user cleartext password. Suppose user "alice" with password "asdfg" had an account on the Fossil self-hosting repository. Then the value of USER.PW for alice would be the SHA1 hash of <blockquote> CE59BB9F186226D80E49D1FA2DB29F935CCA0333/alice/asdfg </blockquote> That hash value is "f1b699cc9af3eeb98e5de244ca7802ae38e77bae". Note that by including the project-code and the login as part of the hash, a different USER.PW value results even if two or more users on the repository select the same "asdfg" password or if user alice reuses the same password on multiple projects. Whenever a password is changed using the web interface or using the "user" command-line method, the new password is stored using the SHA1 encoding. Thus, cleartext passwords will gradually migrate to become SHA1 passwords. All remaining cleartext passwords can be converted to SHA1 passwords using the following command: <blockquote><pre> fossil test-hash-passwords <i>REPOSITORY-NAME</i> </pre></blockquote> Remember that converting from cleartext to SHA1 passwords is an irreversible operation. The only way to insert a new cleartext password into the USER table is to do so manually using SQL commands. For example: <blockquote><pre> UPDATE user SET pw='asdfg' WHERE login='alice'; </pre></blockquote> Note that an password that is an empty string or NULL will disable all login for that user. Thus, to lock a user out of the system, one has only to set their password to an empty string, using either the web interface or direct SQL manipulation of the USER table. Note also that the password field is essentially ignored for the special users named "anonymous", "developer", |
︙ | ︙ | |||
69 70 71 72 73 74 75 | hashes the password and compares it against the value stored in USER.PW. If they match, the server sets a cookie on the client to record the login. This cookie contains a large amount of high-quality randomness and is thus intractable to guess. The value of the cookie and the IP address of the client is stored in the USER.COOKIE and USER.IPADDR fields of the USER table on the server. The USER.CEXPIRE field holds an expiration date | | > > > > > > > > > > > > > > | | 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 | hashes the password and compares it against the value stored in USER.PW. If they match, the server sets a cookie on the client to record the login. This cookie contains a large amount of high-quality randomness and is thus intractable to guess. The value of the cookie and the IP address of the client is stored in the USER.COOKIE and USER.IPADDR fields of the USER table on the server. The USER.CEXPIRE field holds an expiration date for the cookie, encoded as a julian day number. On all subsequent HTTP requests, the cookie value is matched against the USER table to enable access to the repository. A login cookie will only work if the IP address matches. This feature is designed to make it more difficult for an attacker to sniff the cookie and take over the connection. A cookie-sniffing attack will only work if the attacker is able to send and receive from the same IP address as the original login. However, we found that doing an exact IP match caused problems for some users who are behind proxy firewalls where the proxy might use a different IP address for each query. To work around this problem, newer versions of fossil only check the first 16 bits of the 32-bit IP address. This makes a cookie sniffing attack easier since now the attacker only has to send and receive from any IP address in a range of IPs that are similar to the initial login. But that is seen as an acceptable compromise in exchange for ease of use. If higher security is really needed, then HTTPS can be used instead of HTTP. Note that in order to log into a Fossil server, it is necessary to write information into the repository database. Hence, login is not possible on a Fossil repository with a read-only database file. The user password is sent over the wire as cleartext on the initial login attempt. The plan moving forward is to compute the SHA1 hash of the password on the client using javascript and then send only the hash over the wire, but that plan has not yet been set in code. <h2>Sync Protocol Authentication</h2> A different authentication mechanism is used when one repository wants to sync (or push or pull or clone) another repository. When two repositories are syncing, the one that initiates the transaction is |
︙ | ︙ | |||
114 115 116 117 118 119 120 | This means that when USER.PW holds a cleartext password, the login card will work for both older and newer clients. If the USER.PW on the server only holds the SHA1 hash of the password, then only newer clients will be able to authenticate to the server. The client normally gets the login and password from the "remote URL". | | | | | | 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 | This means that when USER.PW holds a cleartext password, the login card will work for both older and newer clients. If the USER.PW on the server only holds the SHA1 hash of the password, then only newer clients will be able to authenticate to the server. The client normally gets the login and password from the "remote URL". <blockquote><pre> http://<span style="color:blue">login:password</span>@servername.org/path </pre></blockquote> For older clients, the password is used for the shared secret as stated in the URL and with no encoding. For newer clients, the shared secret is derived from the password by transformed the password using the SHA1 hash encoding described above. However, if the first character of the password is "*" (ASCII 0x2a) then the "*" is skipped and the rest of the password is used directly as the share secret without the SHA1 encoding. <blockquote><pre> http://<span style="color:blue">login:*password</span>@servername.org/path </pre></blockquote> This *-before-the-password trick can be used by newer clients to sync against a legacy server that does not understand the new SHA1 password encoding. |
Deleted www/patchcmd.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/permutedindex.html.
1 2 | <div class='fossil-doc' data-title='Index Of Fossil Documentation'> | > | > < | < | < < | | | | > > > | < | | > > > > > > > | | > > > > | | > | | | > | | | | | > > | > | > > > | | > > > | > | | > > | | | < | | | | | | > > > > > > > > > > > > > > > > > > > > > > > | < | < | | < | | < | | | | | | | | > | > > | > > > > | | | | | > | | | | < | < | | > | > | > | | | | > | | > > > > > > > > > > > > > | > > | > > | > | | > > > > > > > > | > | | > > > | | < | | > | > | > | > > > > | > > > > > > > > | > > | > > > | > > | | | | < < | | | | > > > > > | | | | | > > > > > > | | > | | | > > > | 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 256 | <div class='fossil-doc' data-title='Index Of Fossil Documentation'> <center> <form action='$ROOT/docsrch' method='GET'> <input type="text" name="s" size="40" autofocus> <input type="submit" value="Search Docs"> </form> </center> <h2>Primary Documents:</h2> <ul> <li> <a href='quickstart.wiki'>Quick-start Guide</a> <li> <a href='faq.wiki'>FAQ</a> <li> <a href='build.wiki'>Compiling and installing Fossil</a> <li> <a href='../COPYRIGHT-BSD2.txt'>License</a> <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's book</a> <li> <a href='$ROOT/help'>List of commands, web-pages, and settings</a> <li> <a href='hacker-howto.wiki'>Hacker How-To</a> </ul> <a name="pindex"></a> <h2>Permuted Index:</h2> <ul> <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Up and Running in</a></li> <li><a href="fossil-from-msvc.wiki">2010 IDE — Integrating Fossil in the Microsoft Express</a></li> <li><a href="tech_overview.wiki"><b>A Technical Overview Of The Design And Implementation Of Fossil</b></a></li> <li><a href="adding_code.wiki"><b>Adding New Features To Fossil</b></a></li> <li><a href="copyright-release.html">Agreement — Contributor License</a></li> <li><a href="alerts.md">Alerts And Notifications — Email</a></li> <li><a href="delta_encoder_algorithm.wiki">Algorithm — Fossil Delta Encoding</a></li> <li><a href="blame.wiki">Algorithm Of Fossil — The Annotate/Blame</a></li> <li><a href="blame.wiki">Annotate/Blame Algorithm Of Fossil — The</a></li> <li><a href="customskin.md">Appearance of Web Pages — Theming: Customizing The</a></li> <li><a href="faq.wiki">Asked Questions — Frequently</a></li> <li><a href="password.wiki">Authentication — Password Management And</a></li> <li><a href="backoffice.md">Backoffice mechanism of Fossil — The</a></li> <li><a href="whyusefossil.wiki"><b>Benefits Of Version Control</b></a></li> <li><a href="hashpolicy.wiki">Between SHA1 and SHA3-256 — Hash Policy: Choosing</a></li> <li><a href="blockchain.md">Blockchain — Fossil As</a></li> <li><a href="antibot.wiki">Bots — Defense against Spiders and</a></li> <li><a href="private.wiki">Branches — Creating, Syncing, and Deleting Private</a></li> <li><a href="branching.wiki"><b>Branching, Forking, Merging, and Tagging</b></a></li> <li><a href="bugtheory.wiki"><b>Bug Tracking In Fossil</b></a></li> <li><a href="makefile.wiki">Build Process — The Fossil</a></li> <li><a href="aboutcgi.wiki">CGI Works In Fossil — How</a></li> <li><a href="changes.wiki">Changelog — Fossil</a></li> <li><a href="checkin_names.wiki"><b>Check-in And Version Names</b></a></li> <li><a href="checkin.wiki"><b>Check-in Checklist</b></a></li> <li><a href="checkin.wiki">Checklist — Check-in</a></li> <li><a href="../test/release-checklist.wiki">Checklist — Pre-Release Testing</a></li> <li><a href="foss-cklist.wiki"><b>Checklist For Successful Open-Source Projects</b></a></li> <li><a href="selfcheck.wiki">Checks — Fossil Repository Integrity Self</a></li> <li><a href="childprojects.wiki"><b>Child Projects</b></a></li> <li><a href="hashpolicy.wiki">Choosing Between SHA1 and SHA3-256 — Hash Policy:</a></li> <li><a href="contribute.wiki">Code or Documentation To The Fossil Project — Contributing</a></li> <li><a href="style.wiki">Code Style Guidelines — Source</a></li> <li><a href="../../../help">Commands and Webpages — Lists of</a></li> <li><a href="build.wiki"><b>Compiling and Installing Fossil</b></a></li> <li><a href="concepts.wiki">Concepts — Fossil Core</a></li> <li><a href="server.wiki">Configure A Fossil Server — How To</a></li> <li><a href="shunning.wiki">Content From Fossil — Shunning: Deleting</a></li> <li><a href="contribute.wiki"><b>Contributing Code or Documentation To The Fossil Project</b></a></li> <li><a href="copyright-release.html"><b>Contributor License Agreement</b></a></li> <li><a href="whyusefossil.wiki">Control — Benefits Of Version</a></li> <li><a href="concepts.wiki">Core Concepts — Fossil</a></li> <li><a href="newrepo.wiki">Create A New Fossil Repository — How To</a></li> <li><a href="private.wiki"><b>Creating, Syncing, and Deleting Private Branches</b></a></li> <li><a href="qandc.wiki">Criticisms — Questions And</a></li> <li><a href="customskin.md">Customizing The Appearance of Web Pages — Theming:</a></li> <li><a href="custom_ticket.wiki"><b>Customizing The Ticket System</b></a></li> <li><a href="customgraph.md">Customizing the Timeline Graph — Theming:</a></li> <li><a href="tech_overview.wiki">Databases Used By Fossil — SQLite</a></li> <li><a href="antibot.wiki"><b>Defense against Spiders and Bots</b></a></li> <li><a href="shunning.wiki">Deleting Content From Fossil — Shunning:</a></li> <li><a href="private.wiki">Deleting Private Branches — Creating, Syncing, and</a></li> <li><a href="delta_encoder_algorithm.wiki">Delta Encoding Algorithm — Fossil</a></li> <li><a href="delta_format.wiki">Delta Format — Fossil</a></li> <li><a href="tech_overview.wiki">Design And Implementation Of Fossil — A Technical Overview Of The</a></li> <li><a href="theory1.wiki">Design Of The Fossil DVCS — Thoughts On The</a></li> <li><a href="embeddeddoc.wiki">Documentation — Embedded Project</a></li> <li><a href="contribute.wiki">Documentation To The Fossil Project — Contributing Code or</a></li> <li><a href="aboutdownload.wiki">Download Page Works — How The</a></li> <li><a href="theory1.wiki">DVCS — Thoughts On The Design Of The Fossil</a></li> <li><a href="quotes.wiki">DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and</a></li> <li><a href="alerts.md"><b>Email Alerts And Notifications</b></a></li> <li><a href="embeddeddoc.wiki"><b>Embedded Project Documentation</b></a></li> <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm — Fossil Delta</a></li> <li><a href="encryptedrepos.wiki">Encrypted Repositories — How To Use</a></li> <li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li> <li><a href="event.wiki"><b>Events</b></a></li> <li><a href="webpage-ex.md">Examples — Webpage</a></li> <li><a href="inout.wiki">Export To And From Git — Import And</a></li> <li><a href="fossil-from-msvc.wiki">Express 2010 IDE — Integrating Fossil in the Microsoft</a></li> <li><a href="adding_code.wiki">Features To Fossil — Adding New</a></li> <li><a href="fileformat.wiki">File Format — Fossil</a></li> <li><a href="globs.md"><b>File Name Glob Patterns</b></a></li> <li><a href="unvers.wiki">Files — Unversioned</a></li> <li><a href="branching.wiki">Forking, Merging, and Tagging — Branching,</a></li> <li><a href="delta_format.wiki">Format — Fossil Delta</a></li> <li><a href="fileformat.wiki">Format — Fossil File</a></li> <li><a href="../../../md_rules">Formatting Rules — Markdown</a></li> <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> <li><a href="forum.wiki">Forums — Fossil</a></li> <li><a href="blockchain.md"><b>Fossil As Blockchain</b></a></li> <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> <li><a href="forum.wiki"><b>Fossil Forums</b></a></li> <li><a href="quickstart.wiki"><b>Fossil Quick Start Guide</b></a></li> <li><a href="selfcheck.wiki"><b>Fossil Repository Integrity Self Checks</b></a></li> <li><a href="selfhost.wiki"><b>Fossil Self Hosting Repositories</b></a></li> <li><a href="settings.wiki"><b>Fossil Settings</b></a></li> <li><a href="hints.wiki"><b>Fossil Tips And Usage Hints</b></a></li> <li><a href="fossil-v-git.wiki"><b>Fossil Versus Git</b></a></li> <li><a href="quotes.wiki">Fossil, Git, and DVCSes in General — Quotes: What People Are Saying About</a></li> <li><a href="faq.wiki"><b>Frequently Asked Questions</b></a></li> <li><a href="quotes.wiki">General — Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li> <li><a href="fossil-v-git.wiki">Git — Fossil Versus</a></li> <li><a href="inout.wiki">Git — Import And Export To And From</a></li> <li><a href="quotes.wiki">Git, and DVCSes in General — Quotes: What People Are Saying About Fossil,</a></li> <li><a href="globs.md">Glob Patterns — File Name</a></li> <li><a href="env-opts.md">Global Options — Environment Variables and</a></li> <li><a href="customgraph.md">Graph — Theming: Customizing the Timeline</a></li> <li><a href="quickstart.wiki">Guide — Fossil Quick Start</a></li> <li><a href="style.wiki">Guidelines — Source Code Style</a></li> <li><a href="hacker-howto.wiki"><b>Hacker How-To</b></a></li> <li><a href="adding_code.wiki"><b>Hacking Fossil</b></a></li> <li><a href="hashpolicy.wiki"><b>Hash Policy: Choosing Between SHA1 and SHA3-256</b></a></li> <li><a href="hints.wiki">Hints — Fossil Tips And Usage</a></li> <li><a href="index.wiki"><b>Home Page</b></a></li> <li><a href="selfhost.wiki">Hosting Repositories — Fossil Self</a></li> <li><a href="aboutcgi.wiki"><b>How CGI Works In Fossil</b></a></li> <li><a href="aboutdownload.wiki"><b>How The Download Page Works</b></a></li> <li><a href="server.wiki"><b>How To Configure A Fossil Server</b></a></li> <li><a href="newrepo.wiki"><b>How To Create A New Fossil Repository</b></a></li> <li><a href="encryptedrepos.wiki"><b>How To Use Encrypted Repositories</b></a></li> <li><a href="hacker-howto.wiki">How-To — Hacker</a></li> <li><a href="fossil-from-msvc.wiki">IDE — Integrating Fossil in the Microsoft Express 2010</a></li> <li><a href="tech_overview.wiki">Implementation Of Fossil — A Technical Overview Of The Design And</a></li> <li><a href="inout.wiki"><b>Import And Export To And From Git</b></a></li> <li><a href="build.wiki">Installing Fossil — Compiling and</a></li> <li><a href="fossil-from-msvc.wiki"><b>Integrating Fossil in the Microsoft Express 2010 IDE</b></a></li> <li><a href="selfcheck.wiki">Integrity Self Checks — Fossil Repository</a></li> <li><a href="webui.wiki">Interface — The Fossil Web</a></li> <li><a href="th1.md">Language — The TH1 Scripting</a></li> <li><a href="copyright-release.html">License Agreement — Contributor</a></li> <li><a href="../../../help"><b>Lists of Commands and Webpages</b></a></li> <li><a href="password.wiki">Management And Authentication — Password</a></li> <li><a href="../../../sitemap">Map — Site</a></li> <li><a href="../../../md_rules"><b>Markdown Formatting Rules</b></a></li> <li><a href="backoffice.md">mechanism of Fossil — The Backoffice</a></li> <li><a href="branching.wiki">Merging, and Tagging — Branching, Forking,</a></li> <li><a href="fossil-from-msvc.wiki">Microsoft Express 2010 IDE — Integrating Fossil in the</a></li> <li><a href="fiveminutes.wiki">Minutes as a Single User — Up and Running in 5</a></li> <li><a href="globs.md">Name Glob Patterns — File</a></li> <li><a href="checkin_names.wiki">Names — Check-in And Version</a></li> <li><a href="adding_code.wiki">New Features To Fossil — Adding</a></li> <li><a href="newrepo.wiki">New Fossil Repository — How To Create A</a></li> <li><a href="alerts.md">Notifications — Email Alerts And</a></li> <li><a href="foss-cklist.wiki">Open-Source Projects — Checklist For Successful</a></li> <li><a href="pop.wiki">Operation — Principles Of</a></li> <li><a href="env-opts.md">Options — Environment Variables and Global</a></li> <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil — A Technical</a></li> <li><a href="index.wiki">Page — Home</a></li> <li><a href="aboutdownload.wiki">Page Works — How The Download</a></li> <li><a href="customskin.md">Pages — Theming: Customizing The Appearance of Web</a></li> <li><a href="password.wiki"><b>Password Management And Authentication</b></a></li> <li><a href="globs.md">Patterns — File Name Glob</a></li> <li><a href="quotes.wiki">People Are Saying About Fossil, Git, and DVCSes in General — Quotes: What</a></li> <li><a href="stats.wiki"><b>Performance Statistics</b></a></li> <li><a href="hashpolicy.wiki">Policy: Choosing Between SHA1 and SHA3-256 — Hash</a></li> <li><a href="../test/release-checklist.wiki"><b>Pre-Release Testing Checklist</b></a></li> <li><a href="pop.wiki"><b>Principles Of Operation</b></a></li> <li><a href="private.wiki">Private Branches — Creating, Syncing, and Deleting</a></li> <li><a href="makefile.wiki">Process — The Fossil Build</a></li> <li><a href="contribute.wiki">Project — Contributing Code or Documentation To The Fossil</a></li> <li><a href="embeddeddoc.wiki">Project Documentation — Embedded</a></li> <li><a href="foss-cklist.wiki">Projects — Checklist For Successful Open-Source</a></li> <li><a href="childprojects.wiki">Projects — Child</a></li> <li><a href="sync.wiki">Protocol — The Fossil Sync</a></li> <li><a href="faq.wiki">Questions — Frequently Asked</a></li> <li><a href="qandc.wiki"><b>Questions And Criticisms</b></a></li> <li><a href="quickstart.wiki">Quick Start Guide — Fossil</a></li> <li><a href="quotes.wiki"><b>Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</b></a></li> <li><a href="selfhost.wiki">Repositories — Fossil Self Hosting</a></li> <li><a href="encryptedrepos.wiki">Repositories — How To Use Encrypted</a></li> <li><a href="newrepo.wiki">Repository — How To Create A New Fossil</a></li> <li><a href="selfcheck.wiki">Repository Integrity Self Checks — Fossil</a></li> <li><a href="reviews.wiki"><b>Reviews</b></a></li> <li><a href="../../../md_rules">Rules — Markdown Formatting</a></li> <li><a href="../../../wiki_rules">Rules — Wiki Formatting</a></li> <li><a href="fiveminutes.wiki">Running in 5 Minutes as a Single User — Up and</a></li> <li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General — Quotes: What People Are</a></li> <li><a href="th1.md">Scripting Language — The TH1</a></li> <li><a href="selfcheck.wiki">Self Checks — Fossil Repository Integrity</a></li> <li><a href="selfhost.wiki">Self Hosting Repositories — Fossil</a></li> <li><a href="server.wiki">Server — How To Configure A Fossil</a></li> <li><a href="settings.wiki">Settings — Fossil</a></li> <li><a href="hashpolicy.wiki">SHA1 and SHA3-256 — Hash Policy: Choosing Between</a></li> <li><a href="hashpolicy.wiki">SHA3-256 — Hash Policy: Choosing Between SHA1 and</a></li> <li><a href="shunning.wiki"><b>Shunning: Deleting Content From Fossil</b></a></li> <li><a href="fiveminutes.wiki">Single User — Up and Running in 5 Minutes as a</a></li> <li><a href="../../../sitemap"><b>Site Map</b></a></li> <li><a href="style.wiki"><b>Source Code Style Guidelines</b></a></li> <li><a href="antibot.wiki">Spiders and Bots — Defense against</a></li> <li><a href="tech_overview.wiki"><b>SQLite Databases Used By Fossil</b></a></li> <li><a href="ssl.wiki">SSL with Fossil — Using</a></li> <li><a href="quickstart.wiki">Start Guide — Fossil Quick</a></li> <li><a href="stats.wiki">Statistics — Performance</a></li> <li><a href="style.wiki">Style Guidelines — Source Code</a></li> <li><a href="foss-cklist.wiki">Successful Open-Source Projects — Checklist For</a></li> <li><a href="sync.wiki">Sync Protocol — The Fossil</a></li> <li><a href="private.wiki">Syncing, and Deleting Private Branches — Creating,</a></li> <li><a href="custom_ticket.wiki">System — Customizing The Ticket</a></li> <li><a href="tickets.wiki">System — The Fossil Ticket</a></li> <li><a href="branching.wiki">Tagging — Branching, Forking, Merging, and</a></li> <li><a href="tech_overview.wiki">Technical Overview Of The Design And Implementation Of Fossil — A</a></li> <li><a href="../test/release-checklist.wiki">Testing Checklist — Pre-Release</a></li> <li><a href="th1.md">TH1 Scripting Language — The</a></li> <li><a href="backoffice.md"><b>The "Backoffice" mechanism of Fossil</b></a></li> <li><a href="blame.wiki"><b>The Annotate/Blame Algorithm Of Fossil</b></a></li> <li><a href="makefile.wiki"><b>The Fossil Build Process</b></a></li> <li><a href="sync.wiki"><b>The Fossil Sync Protocol</b></a></li> <li><a href="tickets.wiki"><b>The Fossil Ticket System</b></a></li> <li><a href="webui.wiki"><b>The Fossil Web Interface</b></a></li> <li><a href="th1.md"><b>The TH1 Scripting Language</b></a></li> <li><a href="customskin.md"><b>Theming: Customizing The Appearance of Web Pages</b></a></li> <li><a href="customgraph.md"><b>Theming: Customizing the Timeline Graph</b></a></li> <li><a href="theory1.wiki"><b>Thoughts On The Design Of The Fossil DVCS</b></a></li> <li><a href="custom_ticket.wiki">Ticket System — Customizing The</a></li> <li><a href="tickets.wiki">Ticket System — The Fossil</a></li> <li><a href="customgraph.md">Timeline Graph — Theming: Customizing the</a></li> <li><a href="hints.wiki">Tips And Usage Hints — Fossil</a></li> <li><a href="bugtheory.wiki">Tracking In Fossil — Bug</a></li> <li><a href="unvers.wiki"><b>Unversioned Files</b></a></li> <li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li> <li><a href="hints.wiki">Usage Hints — Fossil Tips And</a></li> <li><a href="fiveminutes.wiki">User — Up and Running in 5 Minutes as a Single</a></li> <li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li> <li><a href="env-opts.md">Variables and Global Options — Environment</a></li> <li><a href="whyusefossil.wiki">Version Control — Benefits Of</a></li> <li><a href="checkin_names.wiki">Version Names — Check-in And</a></li> <li><a href="fossil-v-git.wiki">Versus Git — Fossil</a></li> <li><a href="webui.wiki">Web Interface — The Fossil</a></li> <li><a href="customskin.md">Web Pages — Theming: Customizing The Appearance of</a></li> <li><a href="webpage-ex.md"><b>Webpage Examples</b></a></li> <li><a href="../../../help">Webpages — Lists of Commands and</a></li> <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General — Quotes:</a></li> <li><a href="whyusefossil.wiki"><b>Why You Should Use Fossil</b></a></li> <li><a href="../../../wiki_rules"><b>Wiki Formatting Rules</b></a></li> <li><a href="wikitheory.wiki"><b>Wiki In Fossil</b></a></li> <li><a href="aboutdownload.wiki">Works — How The Download Page</a></li> <li><a href="aboutcgi.wiki">Works In Fossil — How CGI</a></li> <li><a href="whyusefossil.wiki">You Should Use Fossil — Why</a></li> </ul></div> |
Deleted www/pikchr.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/pop.wiki.
1 2 3 4 5 | <title>Principles Of Operation</title> This page attempts to define the foundational principals upon which Fossil is built. | > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | <title>Principles Of Operation</title> <h1 align="center">Principles Of Operation</h1> <p> This page attempts to define the foundational principals upon which Fossil is built. </p> <ul> <li><p>A project consists of source files, wiki pages, and trouble tickets, and control files (collectively "artifacts"). All historical copies of all artifacts are saved. The project maintains an audit trail.</p></li> <li><p>A project resides in one or more repositories. Each repository is administered and operates independently of the others.</p></li> <li><p>Each repository has both global and local state. The global state is common to all repositories (or at least has the potential to be shared in common when the repositories are fully synchronized). The local state for each repository is private to that repository. The global state represents the content of the project. The local state identifies the authorized users and access policies for a particular repository.</p></li> <li><p>The global state of a repository is an unordered collection of artifacts. Each artifact is named by a cryptographic hash (SHA1 or SHA3-256) encoded in lowercase hexadecimal. In many contexts, the name can be abbreviated to a unique prefix. A five- or six-character prefix usually suffices to uniquely identify a file.</p></li> <li><p>Because artifacts are named by a cryptographic hash, all artifacts are immutable. Any change to the content of an artifact also changes the hash that forms the artifacts name, thus creating a new artifact. Both the old original version of the artifact and the new change are preserved under different names.</p></li> <li><p>It is theoretically possible for two artifacts with different content to share the same hash. But finding two such artifacts is so incredibly difficult and unlikely that we consider it to be an impossibility.</p></li> <li><p>The signature of an artifact is the cryptographic hash of the artifact itself, exactly as it would appear in a disk file. No prefix or meta-information about the artifact is added before computing the hash. So you can always find the signature of a file by using the "sha1sum" or "sha3sum" or similar command-line utilities.</p></li> <li><p>The artifacts that comprise the global state of a repository are the complete global state of that repository. The SQLite database that holds the repository contains additional information about linkages between artifacts, but all of that added information can be discarded and reconstructed by rescanning the content artifacts.</p></li> <li><p>Two repositories for the same project can synchronize their global states simply by sharing artifacts. The local state of repositories is not normally synchronized or shared.</p></li> <li><p>Every check-in has a special file at the top-level named "manifest" which is an index of all other files in that check-in. The manifest is automatically created and maintained by the system.</p></li> <li><p>The <a href="fileformat.wiki">file formats</a> used by Fossil are all very simple so that with access to the original content files, one can easily reconstruct the content of a check-in without the need for any special tools or software.</p></li> |
Changes to www/private.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 | <title>Private Branches</title> By default, everything you check into a Fossil repository is shared to all clones of that repository. In Fossil, you don't push and pull individual branches; you push and pull everything all at once. But sometimes users want to keep some private work that is not shared with others. This might be a preliminary or experimental change that needs further refinement before it is shared and which might never be shared at all. To do this in Fossil, simply commit the change with the --private command-line option: | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | 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 | <title>Private Branches</title> By default, everything you check into a Fossil repository is shared to all clones of that repository. In Fossil, you don't push and pull individual branches; you push and pull everything all at once. But sometimes users want to keep some private work that is not shared with others. This might be a preliminary or experimental change that needs further refinement before it is shared and which might never be shared at all. To do this in Fossil, simply commit the change with the --private command-line option: <blockquote><pre> fossil commit --private </pre></blockquote> The --private option causes Fossil to put the check-in in a new branch named "private". That branch will not participate in subsequent clone, sync, push, or pull operations. The branch will remain on the one local repository where it was created. Note that you only use the --private option for the first check-in that creates the private branch. Additional checkins into the private branch remain private automatically. <h2>Publishing Private Changes</h2> After additional work, one might desire to publish the changes associated with a private branch. The usual way to do this is to merge those changes into a public branch. For example: <blockquote><pre> fossil update trunk fossil merge private fossil commit </pre></blockquote> The private branch remains private. (There is no way to convert a private branch into a public branch.) But all of the changes associated with the private branch are now folded into the public branch and are hence visible to other users of the project. <h2>Syncing Private Branches</h2> A private branch normally stays on the one repository where it was originally created. But sometimes you want to share private branches with another repository. For example, you might be building a cross-platform application and have separate repositories on your Windows laptop, your Linux desktop, and your iMac. You can transfer private branches between these machines by using the --private option on the "sync", "push", "pull", and "clone" commands. For example, if you are running "fossil server" on your Linux box and you want to clone that repository to your Mac, including all private branches, use: <blockquote><pre> fossil clone --private http://user@linux.localnetwork:8080/ mac-clone.fossil </pre></blockquote> You'll have to supply a username and password in order for this to work. Fossil will not clone (or sync) private branches anonymously. Furthermore, you have to enable the "Private" capability (the "x" capability) in order to enable private branch syncing. The Admin ("a") and Superuser ("s") do <u>not</u> imply Private ("x"); you'll have to set "x" in addition to "a" or "s". This is a little extra work, but there is a purpose here: the interface is designed to make it very difficult to accidentally sync a private branch to a public server. It is highly recommended that you leave the "x" capability turned off on all repositories used for collaboration (repositories to which many people push and pull) and only enable "x" for local repositories when you need to share private branches. Private branch sync only works if you use the --private command-line option. Private branches are never synced via the auto-sync mechanism. Once again, this restriction is designed to make it hard to accidentally push private branches beyond their intended audience. <h2>Purging Private Branches</h2> You can remove all private branches from a repository using this command: <blockquote><pre> fossil scrub --private </pre></blockquote> Note that the above is a permanent and irreversible change. You will be asked to confirm before continuing. Once the private branches are removed, they cannot be retrieved (unless you have synced them to another repository.) So be careful with the command. <h2>Additional Notes</h2> All of the features above apply to <u>all</u> private branches in a single repository at once. There is no mechanism in Fossil (currently) that allows you to push, pull, clone, sync, or scrub an individual private branch within a repository that contains multiple private branches. |
Changes to www/qandc.wiki.
1 2 | <title>Questions And Criticisms</title> | > > | | | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | > > | 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 | <title>Questions And Criticisms</title> <nowiki> <h1 align="center">Questions And Criticisms</h1> <p>This page is a collection of real questions and criticisms that have been raised against fossil together with responses from the program's author.</p> <p>Note: See also the <a href="faq.wiki">Frequently Asked Questions</a>.</p> <b>Fossil sounds like a lot of reinvention of the wheel. Why create your own DVCS when you could have reused mercurial?</b> <blockquote> <p>I wrote fossil because none of the other available DVCSes met my needs. If the other DVCSes do meet your needs, then you might not need fossil. But they don't meet mine, and so fossil is necessary for me.</p> <p>Features provided by fossil that one does not get with other DVCSes include:</p> <ol> <li> Integrated <a href="wikitheory.wiki">wiki</a>. </li> <li> Integrated <a href="bugtheory.wiki">bug tracking</a> </li> <li> Immutable artifacts </li> <li> Self-contained, stand-alone executable that can be run in a <a href="http://en.wikipedia.org/wiki/Chroot">chroot jail</a> </li> <li> Simple, well-defined, <a href="fileformat.wiki">enduring file format</a> </li> <li> Integrated <a href="webui.wiki">web interface</a> </li> </ol> </blockquote> <b>Why should I use this rather than Trac?</b> <blockquote> <ol> <li> Fossil is distributed. You can view and/or edit tickets, wiki, and code while off network, then sync your changes later. With Trac, you can only view and edit tickets and wiki while you are connected to the server. </li> <li> Fossil is lightweight and fully self-contained. It is very easy to setup on a low-resource machine. Fossil does not require an administrator.</li> <li> Fossil integrates code versioning into the same repository with wiki and tickets. There is nothing extra to add or install. Fossil is an all-in-one turnkey solution. </li> </ol> </blockquote> <b>Love the concept here. Anyone using this for real work yet?</b> <blockquote> Fossil is <a href="http://www.fossil-scm.org/">self-hosting</a>. In fact, this page was probably delivered to your web-browser via a working fossil instance. The same virtual machine that hosts http://www.fossil-scm.org/ (a <a href="http://www.linode.com/">Linode 720</a>) also hosts 24 other fossil repositories for various small projects. The documentation files for <a href="http://www.sqlite.org/">SQLite</a> are hosted in a fossil repository <a href="http://www.sqlite.org/docsrc/">here</a>, for example. Other projects are also adopting fossil. But fossil does not yet have the massive user base of git or mercurial. </blockquote> <b>Fossil looks like the bug tracker that would be in your Linksys Router's administration screen.</b> <blockquote> <p>I take a pragmatic approach to software: form follows function. To me, it is more important to have a reliable, fast, efficient, enduring, and simple DVCS than one that looks pretty.</p> <p>On the other hand, if you have patches that improve the appearance of Fossil without seriously compromising its reliability, performance, and/or maintainability, I will be happy to accept them. Fossil is self-hosting. Send email to request a password that will let you push to the main fossil repository.</p> </blockquote> <b>It would be useful to have a separate application that keeps the bug-tracking database in a versioned file. That file can then be pushed and pulled along with the rest repository.</b> <blockquote> <p>Fossil already <u>does</u> push and pull bugs along with the files in your repository. But fossil does <u>not</u> track bugs as files in the source tree. That approach to bug tracking was rejected for three reasons:</p> <ol> <li> Check-ins in fossil are immutable. So if tickets were part of the check-in, then there would be no way to add new tickets to a check-in as new bugs are discovered. <li> Any project of reasonable size and complexity will generate thousands and thousands of tickets, and we do not want all those ticket files cluttering the source tree. <li> We want tickets to be managed from the web interface and to have a permission system that is distinct from check-in permissions. In other words, we do not want to restrict the creation and editing of tickets to developers with check-in privileges and an installed copy of the fossil executable. Casual passers-by on the internet should be permitted to create tickets. </ol> <p>These points are reiterated in the opening paragraphs of the <a href="bugtheory.wiki">Bug-Tracking In Fossil</a> document.</p> </blockquote> <b>Fossil is already the name of a plan9 versioned append-only filesystem.</b> <blockquote> I did not know that. Perhaps they selected the name for the same reason that I did: because a repository with immutable artifacts preserves an excellent fossil record of a long-running project. </blockquote> <b>The idea of storing a repository in a binary blob like an SQLite database terrifies me.</b> <blockquote> The use of SQLite to store the database is likely more stable and secure than any other approach, due to the fact that SQLite is transactional. Fossil also implements several internal <a href="selfcheck.wiki">self-checks</a> to insure that no information is ever lost. </blockquote> <b>I am dubious of the benefits of including wikis and bug trackers directly in the VCS - either they are under-featured compared to full software like Trac, or the VCS is massively bloated compared to Subversion or Bazaar.</b> <blockquote> <p>I have no doubt that Trac has many features that fossil lacks. But that is not the point. Fossil has several key features that Trac lacks and that I need: most notably the fact that fossil supports disconnected operation.</p> <p>As for bloat: Fossil is a single self-contained executable. You do not need any other packages (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache, sqlite, and so forth) in order to run fossil. Fossil runs just fine in a chroot jail all by itself. And the self-contained fossil executable is much less than 1MB in size. (Update 2015-01-12: Fossil has grown in the years since the previous sentence was written but is still much less than 2MB according to "size" when compiled using -Os on x64 Linux.) Fossil is the very opposite of bloat.</p> </blockquote> </nowiki> |
Changes to www/quickstart.wiki.
1 2 | <title>Fossil Quick Start Guide</title> | > | | | | | | | | | | < | < < < < | | | | | | | | | | | | | < < < | | | | | > | < | < < < | | | | | | | < < | < | < < | < < < < | | > | | | < | | < | | | > > > | | | < > | | < < < < < < < < < < < < < < < < < < < < < < < > > > | > | | > < > < | | < | | < | | | | | < | > | > | | | | | | | | | | | | | < | < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | < | > | | | < < < < < < | < < < < < | < | < > > > | > | < < < < < > < < < > > < < < < < < > > > > | < < | | < > | > > | < | < < < > | < < | < > | < < < < < | | < | < | > < < < < < < > | < < < > > > | < < | < < < | < > | | < < > | < < > > | < < < | | < < < < < < | < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | < < < < < < | | | < | < | | < | | | < < | | > > > < < < < < < | | | | | | | | | | | | | | | | | > < | | | | | | | | | | | | | | < < < < < > | | > | > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | <title>Fossil Quick Start Guide</title> <h1 align="center">Fossil Quick Start</h1> <p>This is a guide to get you started using fossil quickly and painlessly.</p> <h2>Installing</h2> <p>Fossil is a single self-contained C program. You need to either download a <a href="https://www.fossil-scm.org/fossil/uv/download.html">precompiled binary</a> or <a href="build.wiki">compile it yourself</a> from sources. Install fossil by putting the fossil binary someplace on your $PATH.</p> <a name="fslclone"></a> <h2>General Work Flow</h2> <p>Fossil works with repository files (a database with the project's complete history) and with checked-out local trees (the working directory you use to do your work). (See [./whyusefossil.wiki#definitions | definitions] for more background.) The workflow looks like this:</p> <ul> <li>Create or clone a repository file. ([/help/init|fossil init] or [/help/clone | fossil clone]) <li>Check out a local tree. ([/help/open | fossil open]) <li>Perform operations on the repository (including repository configuration). </ul> <p>The following sections will give you a brief overview of these operations.</p> <h2>Starting A New Project</h2> <p>To start a new project with fossil, create a new empty repository this way: ([/help/init | more info]) </p> <blockquote> <b>fossil init </b><i> repository-filename</i> </blockquote> <h2>Cloning An Existing Repository</h2> <p>Most fossil operations interact with a repository that is on the local disk drive, not on a remote system. Hence, before accessing a remote repository it is necessary to make a local copy of that repository. Making a local copy of a remote repository is called "cloning".</p> <p>Clone a remote repository as follows: ([/help/clone | more info])</p> <blockquote> <b>fossil clone</b> <i>URL repository-filename</i> </blockquote> <p>The <i>URL</i> specifies the fossil repository you want to clone. The <i>repository-filename</i> is the new local filename into which the cloned repository will be written. For example: <blockquote> <b>fossil clone http://www.fossil-scm.org/ myclone.fossil</b> </blockquote> <p>If the remote repository requires a login, include a userid in the URL like this: <blockquote> <b>fossil clone http://</b><i>userid</i><b>@www.fossil-scm.org/ myclone.fossil</b> </blockquote> <p>You will be prompted separately for the password. Use "%HH" escapes for special characters in the userid. Examples: "%40" in place of "@" and "%2F" in place of "/". <p>If you are behind a restrictive firewall, you might need to <a href="#proxy">specify an HTTP proxy</a>.</p> <p>A Fossil repository is a single disk file. Instead of cloning, you can just make a copy of the repository file (for example, using "scp"). Note, however, that the repository file contains auxiliary information above and beyond the versioned files, including some sensitive information such as password hashes and email addresses. If you want to share Fossil repositories directly, consider running the [/help/scrub|fossil scrub] command to remove sensitive information before transmitting the file. <h2>Importing From Another Version Control System</h2> <p>Rather than start a new project, or clone an existing Fossil project, you might prefer to <a href="./inout.wiki">import an existing Git project</a> into Fossil using the [/help/import | fossil import] command. <h2>Checking Out A Local Tree</h2> <p>To work on a project in fossil, you need to check out a local copy of the source tree. Create the directory you want to be the root of your tree and cd into that directory. Then do this: ([/help/open | more info])</p> <blockquote> <b>fossil open </b><i> repository-filename</i> </blockquote> <p>This leaves you with the newest version of the tree checked out. From anywhere underneath the root of your local tree, you can type commands like the following to find out the status of your local tree:</p> <blockquote> <b>[/help/info | fossil info]</b><br> <b>[/help/status | fossil status]</b><br> <b>[/help/changes | fossil changes]</b><br> <b>[/help/diff | fossil diff]</b><br> <b>[/help/timeline | fossil timeline]</b><br> <b>[/help/ls | fossil ls]</b><br> <b>[/help/branch | fossil branch]</b><br> </blockquote> <p>Note that Fossil allows you to make multiple check-outs in separate directories from the same repository. This enables you, for example, to do builds from multiple branches or versions at the same time without having to generate extra clones.</p> <p>To switch a checkout between different versions and branches, use:</p> <blockquote> <b>[/help/update | fossil update]</b><br> <b>[/help/checkout | fossil checkout]</b><br> </blockquote> <p>[/help/update | update] honors the "autosync" option and does a "soft" switch, merging any local changes into the target version, whereas [/help/checkout | checkout] does not automatically sync and does a "hard" switch, overwriting local changes if told to do so.</p> <h2>Configuring Your Local Repository</h2> <p>When you create a new repository, either by cloning an existing project or create a new project of your own, you usually want to do some local configuration. This is easily accomplished using the web-server that is built into fossil. Start the fossil webserver like this: ([/help/ui | more info])</p> <blockquote> <b>fossil ui </b><i> repository-filename</i> </blockquote> <p>You can omit the <i>repository-filename</i> from the command above if you are inside a checked-out local tree.</p> <p>This starts a web server then automatically launches your web browser and makes it point to this web server. If your system has an unusual configuration, fossil might not be able to figure out how to start your web browser. In that case, first tell fossil where to find your web browser using a command like this:</p> <blockquote> <b>fossil setting web-browser </b><i> path-to-web-browser</i> </blockquote> <p>By default, fossil does not require a login for HTTP connections coming in from the IP loopback address 127.0.0.1. You can, and perhaps should, change this after you create a few users.</p> <p>When you are finished configuring, just press Control-C or use the <b>kill</b> command to shut down the mini-server.</p> <h2>Making Changes</h2> <p>To add new files to your project, or remove old files, use these commands:</p> <blockquote> <b>[/help/add | fossil add]</b> <i>file...</i><br> <b>[/help/rm | fossil rm]</b> <i>file...</i><br> <b>[/help/addremove | fossil addremove]</b> <i>file...</i><br> </blockquote> <p>You can also edit files freely. Once you are ready to commit your changes, type:</p> <blockquote> <b>[/help/commit | fossil commit]</b> </blockquote> <p>You will be prompted for check-in comments using whatever editor is specified by your VISUAL or EDITOR environment variable.</p> In the default configuration, the [/help/commit|commit] command will also automatically [/help/push|push] your changes, but that feature can be disabled. (More information about [./concepts.wiki#workflow|autosync] and how to disable it.) Remember that your coworkers can not see your changes until you commit and push them.</p> <h2>Sharing Changes</h2> <p>When [./concepts.wiki#workflow|autosync] is turned off, the changes you [/help/commit | commit] are only on your local repository. To share those changes with other repositories, do:</p> <blockquote> <b>[/help/push | fossil push]</b> <i>URL</i> </blockquote> <p>Where <i>URL</i> is the http: URL of the server repository you want to share your changes with. If you omit the <i>URL</i> argument, fossil will use whatever server you most recently synced with.</p> <p>The [/help/push | push] command only sends your changes to others. To Receive changes from others, use [/help/pull | pull]. Or go both ways at once using [/help/sync | sync]:</p> <blockquote> <b>[/help/pull | fossil pull]</b> <i>URL</i><br> <b>[/help/sync | fossil sync]</b> <i>URL</i> </blockquote> <p>When you pull in changes from others, they go into your repository, not into your checked-out local tree. To get the changes into your local tree, use [/help/update | update]:</p> <blockquote> <b>[/help/update | fossil update]</b> <i>VERSION</i> </blockquote> <p>The <i>VERSION</i> can be the name of a branch or tag or any abbreviation to the 40-character artifact identifier for a particular check-in, or it can be a date/time stamp. ([./checkin_names.wiki | more info]) If you omit the <i>VERSION</i>, then fossil moves you to the latest version of the branch your are currently on.</p> <p>The default behavior is for [./concepts.wiki#workflow|autosync] to be turned on. That means that a [/help/pull|pull] automatically occurs when you run [/help/update|update] and a [/help/push|push] happens automatically after you [/help/commit|commit]. So in normal practice, the push, pull, and sync commands are rarely used. But it is important to know about them, all the same.</p> <blockquote> <b>[/help/checkout | fossil checkout]</b> <i>VERSION</i> </blockquote> <p>Is similar to update except that it does not honor the autosync setting, nor does it merge in local changes - it prefers to overwrite them and fails if local changes exist unless the <tt>--force</tt> flag is used.</p> <h2>Branching And Merging</h2> <p>Use the --branch option to the [/help/commit | commit] command to start a new branch. Note that in Fossil, branches are normally created when you commit, not before you start editing. You can use the [/help/branch | branch new] command to create a new branch before you start editing, if you want, but most people just wait until they are ready to commit. To merge two branches back together, first [/help/update | update] to the branch you want to merge into. Then do a [/help/merge|merge] of the other branch that you want to incorporate the changes from. For example, to merge "featureX" changes into "trunk" do this:</p> <blockquote> <b>fossil [/help/update|update] trunk</b><br> <b>fossil [/help/merge|merge] featureX</b><br> <i># make sure the merge didn't break anything...</i><br> <b>fossil [/help/commit|commit] </blockquote> <p>The argument to the [/help/merge|merge] command can be any of the version identifier forms that work for [/help/update|update]. ([./checkin_names.wiki|more info].) The merge command has options to cherrypick individual changes, or to back out individual changes, if you don't want to do a full merge.</p> The merge command puts all changes in your working check-out. No changes are made to the repository. You must run [/help/commit|commit] separately to add the merge changes into your repository to make them persistent and so that your coworkers can see them. But before you do that, you will normally want to run a few tests to verify that the merge didn't cause logic breaks in your code. The same branch can be merged multiple times without trouble. Fossil automatically keeps up with things and avoids conflicts when doing multiple merges. So even if you have merged the featureX branch into trunk previously, you can do so again and Fossil will automatically know to pull in only those changes that have occurred since the previous merge. <p>If a merge or update doesn't work out (perhaps something breaks or there are many merge conflicts) then you back up using:</p> <blockquote> <b>[/help/undo | fossil undo]</b> </blockquote> <p>This will back out the changes that the merge or update made to the working checkout. There is also a [/help/redo|redo] command if you undo by mistake. Undo and redo only work for changes that have not yet been checked in using commit and there is only a single level of undo/redo.</p> <h2>Setting Up A Server</h2> <p>Fossil can act as a stand-alone web server using one of these commands:</p> <blockquote> <b>[/help/server | fossil server]</b> <i>repository-filename</i><br> <b>[/help/ui | fossil ui]</b> <i>repository-filename</i> </blockquote> <p>The <i>repository-filename</i> can be omitted when these commands are run from within an open check-out, which a particularly useful shortcut for the <b>fossil ui</b> command. <p>The <b>ui</b> command is intended for accessing the web interface from a local desktop. The <b>ui</b> command binds to the loopback IP address only (and thus makes the web interface visible only on the local machine) and it automatically start your web browser pointing at the server. For cross-machine collaboration, use the <b>server</b> command, which binds on all IP addresses and does not try to start a web browser.</p> <p>Servers are also easily configured as: <ul> <li>[./server.wiki#inetd|inetd/xinetd] <li>[./server.wiki#cgi|CGI] <li>[./server.wiki#scgi|SCGI] </ul> <p>The [./selfhost.wiki | self-hosting fossil repositories] use CGI. <a name="proxy"></a> <h2>HTTP Proxies</h2> <p>If you are behind a restrictive firewall that requires you to use an HTTP proxy to reach the internet, then you can configure the proxy in three different ways. You can tell fossil about your proxy using a command-line option on commands that use the network, <b>sync</b>, <b>clone</b>, <b>push</b>, and <b>pull</b>.</p> <blockquote> <b>fossil clone </b><i>URL</i> <b>--proxy</b> <i>Proxy-URL</i> </blockquote> <p>It is annoying to have to type in the proxy URL every time you sync your project, though, so you can make the proxy configuration persistent using the [/help/setting | setting] command:</p> <blockquote> <b>fossil setting proxy </b><i>Proxy-URL</i> </blockquote> <p>Or, you can set the "<b>http_proxy</b>" environment variable:</p> <blockquote> <b>export http_proxy=</b><i>Proxy-URL</i> </blockquote> <p>To stop using the proxy, do:</p> <blockquote> <b>fossil setting proxy off</b> </blockquote> <p>Or unset the environment variable. The fossil setting for the HTTP proxy takes precedence over the environment variable and the command-line option overrides both. If you have an persistent proxy setting that you want to override for a one-time sync, that is easily done on the command-line. For example, to sync with a co-workers repository on your LAN, you might type:</p> <blockquote> <b>fossil sync http://192.168.1.36:8080/ --proxy off</b> </blockquote> <h2>More Hints</h2> <p>A [/help | complete list of commands] is available, as is the [./hints.wiki|helpful hints] document. See the [./permutedindex.html#pindex|permuted index] for additional documentation. <p>Explore and have fun!</p> |
Changes to www/quotes.wiki.
1 2 3 4 5 6 | <title>What People Are Saying</title> The following are collected quotes from various forums and blogs about Fossil, Git, and DVCSes in general. This collection is put together by the creator of Fossil, so of course there is selection bias... | | | | | < | < | | | | | | > | > > > > > | | | | | | | | | | | | | > | > > > > > > | | | | | | | | | | | | | | | < | < < < < < | 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 | <title>What People Are Saying</title> The following are collected quotes from various forums and blogs about Fossil, Git, and DVCSes in general. This collection is put together by the creator of Fossil, so of course there is selection bias... <h2>On The Usability Of Git:</h2> <ol> <li>Git approaches the usability of iptables, which is to say, utterly unusable unless you have the manpage tattooed on you arm. <blockquote> <i>by mml at [http://news.ycombinator.com/item?id=1433387]</i> </blockquote> <li><nowiki>It's simplest to think of the state of your [git] repository as a point in a high-dimensional "code-space", in which branches are represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> <i>At [http://tartley.com/?p=1267]</i> </blockquote> <li>Git is not a Prius. Git is a Model T. Its plumbing and wiring sticks out all over the place. You have to be a mechanic to operate it successfully or you'll be stuck on the side of the road when it breaks down. And it <b>will</b> break down. <blockquote> <i>Nick Farina at [http://nfarina.com/post/9868516270/git-is-simpler]</i> </blockquote> <li>Initial revision of "git", The information manager from hell <blockquote> <i>Linus Torvalds - 2005-04-07 22:13:13<br> Commit comment on the very first source-code check-in for git </blockquote> <li>I've been experimenting a lot with git at work. Damn, it's complicated. It has things to trip you up with that sane people just wouldn't ever both with including the ability to allow you to commit stuff in such a way that you can't find it again afterwards (!!!) Demented workflow complexity on acid? <p>* dkf really wishes he could use fossil instead</p> <blockquote> <i>by Donal K. Fellow (dkf) on the Tcl/Tk chatroom, 2013-04-09.</i> </blockquote> <li>Klingon Code Warriors embrace Git; we enjoy arbitrary conflicts. Git is not for the weak and feeble. TODAY IS A GOOD DAY TO CODE. <blockquote> <i>teastain at [http://www.reddit.com/r/programming/comments/xpitj/10_things_i_hate_about_git/c5oj4fk] </blockquote> <li>[G]it is <i>designed</i> to forget things. <blockquote> <i>[http://www.cs.cmu.edu/~davide/howto/git_lose.html] </blockquote> <li>[I]n nearly 31 years of using a computer i have, in total, lost more data to git (while following the instructions!!!) than any other single piece of software. <blockquote> <i>Stephen Beal on the [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg17181.html|Fossil mailing list] 2014-09-01.</i> </blockquote> <li>If programmers _really_ wanted to help scientists, they'd build a version control system that was more usable than Git. <blockquote> <i>Tweet by Greg Wilson @gvwilson on 2015-02-22 17:47</i> </blockquote> <li><img src='xkcd-git.gif' align='top'> <blockquote><i>Randall Munroe. [http://xkcd.com/1597/]</i></blockquote> </ol> <h2>On The Usability Of Fossil:</h2> <ol> <li value=11> Fossil mesmerizes me with simplicity especially after I struggled to get a bug-tracking system to work with mercurial. <blockquote> <i>rawjeev at [http://stackoverflow.com/questions/156322/what-do-people-think-of-the-fossil-dvcs]</i> </blockquote> <li>Fossil is the best thing to happen to my development workflow this year, as I am pretty sure that using Git has resulted in the premature death of too many of my brain cells. I'm glad to be able to replace Git in every place that I possibly can with Fossil. <blockquote> <i>Joe Prostko at [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg16716.html] </blockquote> <li>Fossil is awesome!!! I have never seen an app like that before, such simplicity and flexibility!!! <blockquote> <i>zengr at [http://stackoverflow.com/questions/138621/best-version-control-for-lone-developer]</i> </blockquote> <li>This is my favourite VCS. I can carry it on a USB. And it's a complete system, with it's own server, ticketing system, Wiki pages, and a very, very helpful timeline visualization. And the entire program in a single file! <blockquote> <i>thunderbong commenting on hacker news: [https://news.ycombinator.com/item?id=9131619]</i> </blockquote> </ol> <h2>On Git Versus Fossil</h2> <ol> <li value=15> After prolonged exposure to fossil, i tend to get the jitters when I work with git... <blockquote> <i>sriku - at [https://news.ycombinator.com/item?id=16104427]</i> </blockquote> <li> Just want to say thanks for fossil making my life easier.... Also <nowiki>[for]</nowiki> not having a misanthropic command line interface. <blockquote> <i>Joshua Paine at [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg02736.html]</i> </blockquote> <li>We use it at a large university to manage code that small teams write. The runs everywhere, ease of installation and portability is something that seems to be a good fit with the environment we have (highly ditrobuted, sometimes very restrictive firewalls, OSX/Win/Linux). We are happy with it and teaching a Msc/Phd student (read complete novice) fossil has just been a smoother ride than Git was. <blockquote> <i>viablepanic at [http://www.reddit.com/r/programming/comments/bxcto/why_not_fossil_scm/]</i> </blockquote> <li>In the fossil community - and hence in fossil itself - development history is pretty much sacrosanct. The very name "fossil" was to chosen to reflect the unchanging nature of things in that history. <p>In git (or rather, the git community), the development history is part of the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather than what you actually did. <blockquote> <i>Mike Meyer on the Fossil mailing list, 2011-10-04</i> </blockquote> <li>github is such a pale shadow of what fossil does. <blockquote> <i>dkf on the Tcl chatroom, 2013-12-06</i> </blockquote> </ol> |
Deleted www/rebaseharm.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/relatedwork.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/reviews.wiki.
1 2 3 | <title>Reviews</title> <b>External links:</b> | | > > > | | | | | | 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 | <title>Reviews</title> <b>External links:</b> * [http://nixtu.blogspot.com/2010/03/fossil-dvcs-on-go-first-impressions.html | Fossil DVCS on the Go - First Impressions] * [http://blog.mired.org/2011/02/fossil-sweet-spot-in-vcs-space.html | Fossil - a sweet spot in the VCS space] by Mike Meyer. * [http://blog.s11n.net/?p=72|Four reasons to take a closer look at the Fossil SCM] by Stephan Beal <b>See Also:</b> * [./quotes.wiki | Short Quotes on Fossil, Git, And DVCSes] <b>Daniel writes on 2009-01-06:</b> <blockquote> The reasons I use fossil are that it's the only version control I have found that I can get working through the VERY annoying MS firewalls at work.. (albeit through an ntlm proxy) and I just love single .exe applications! </blockquote> <b>Joshua Paine on 2010-10-22:</b> <blockquote> With one of my several hats on, I'm in a small team using git. Another team member just checked some stuff into trunk that should have been on a branch. Nothing else had happened since, so in fossil I would have just edited that commit and put it on a new branch. In git that can't actually be done without danger once other people have pulled, so I had to create a new commit rolling back the changes, then branch and cherry pick the earlier changes, then figure out how to make my new branch shared instead of private. Just want to say thanks for fossil making my life easier on most of my projects, and being able to move commits to another branch after the fact and shared-by-default branches are good features. Also not having a misanthropic command line interface. </blockquote> <b>Stephan Beal writes on 2009-01-11:</b> <blockquote> Sometime in late 2007 I came across a link to fossil on <a href="http://www.sqlite.org/">sqlite.org</a>. It was a good thing I bookmarked it, because I was never able to find the link again (it might have been in a bug report or something). The reasons I first took a close look at it were (A) it stemmed from the sqlite project, which I've held in high regards for years (e.g. I wrote JavaScript bindings for it: |
︙ | ︙ | |||
54 55 56 57 58 59 60 | run standalone servers or add Apache modules.) So I tried it out. The thing which bugged me most about it was having to type "commit" or "com" instead of "ci" for checking in (as is custom in all other systems I've used), despite the fact that fossil uses "ci" as a filter in things like the timeline view. Looking back now, I have used fossil for about about 95% of my work in the past | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | run standalone servers or add Apache modules.) So I tried it out. The thing which bugged me most about it was having to type "commit" or "com" instead of "ci" for checking in (as is custom in all other systems I've used), despite the fact that fossil uses "ci" as a filter in things like the timeline view. Looking back now, I have used fossil for about about 95% of my work in the past year (http://blog.s11n.net/?p=71), in over 15 source trees, and I now get tripped up when I have to use svn or cvs. So, having got over typing "fossil com -m ...", here's why I love it so much... Point #1: CGI Again, this sounds archaic, but fossil has allowed me to share source trees which I cannot justifiably host in other projects I work on |
︙ | ︙ | |||
133 134 135 136 137 138 139 | I remember my first reaction to fossil being, "this will be an excellent solution for small projects (like the dozens we've all got sitting on our hard drives but which don't justify the hassle of version control)." A year of daily use in over 15 source trees has confirmed that, and I continue to heartily recommend fossil to other developers I know who also have their own collection of "unhosted" pet projects. | | | 136 137 138 139 140 141 142 143 | I remember my first reaction to fossil being, "this will be an excellent solution for small projects (like the dozens we've all got sitting on our hard drives but which don't justify the hassle of version control)." A year of daily use in over 15 source trees has confirmed that, and I continue to heartily recommend fossil to other developers I know who also have their own collection of "unhosted" pet projects. </blockquote> |
Changes to www/scgi.wiki.
1 2 3 4 5 6 | <title>Fossil SCGI</title> To run Fossil using SCGI, start the [/help/server|fossil server] command with the --scgi command-line option. You will probably also want to specific an alternative TCP/IP port using --port. For example: | | | | | | 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 | <title>Fossil SCGI</title> To run Fossil using SCGI, start the [/help/server|fossil server] command with the --scgi command-line option. You will probably also want to specific an alternative TCP/IP port using --port. For example: <blockquote><pre> fossil server $REPOSITORY --port 9000 --scgi </pre></blockquote> Then configure your SCGI-aware web-server to send SCGI requests to port 9000 on the machine where Fossil is running. A typical configuration for this in Nginx is: <blockquote><pre> location ~ ^/demo_project/ { include scgi_params; scgi_pass localhost:9000; scgi_param SCRIPT_NAME "/demo_project"; scgi_param HTTPS "on"; } </pre></blockquote> Note that Nginx does not normally send either the PATH_INFO or SCRIPT_NAME variables via SCGI, but Fossil needs one or the other. So the configuration above needs to add SCRIPT_NAME. If you do not do this, Fossil returns an error. |
Changes to www/selfcheck.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <title>Fossil Repository Integrity Self-Checks</title> Fossil is designed with features to give it a high level of integrity so that users can have confidence that content will never be mangled or lost by Fossil. This note describes the defensive measures that Fossil uses to help prevent information loss due to bugs. Fossil has been hosting itself and many other projects for years now. Many bugs have been encountered. But, thanks in large part to the defensive measures described here, no data has been lost. The integrity checks are doing their job well.</p> <h2>Atomic Check-ins With Rollback</h2> | > > | | | | | | | | | | | | | | | | 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 | <title>Fossil Repository Integrity Self-Checks</title> <h1 align="center">Fossil Repository Integrity Self-Checks</h1> Fossil is designed with features to give it a high level of integrity so that users can have confidence that content will never be mangled or lost by Fossil. This note describes the defensive measures that Fossil uses to help prevent information loss due to bugs. Fossil has been hosting itself and many other projects for years now. Many bugs have been encountered. But, thanks in large part to the defensive measures described here, no data has been lost. The integrity checks are doing their job well.</p> <h2>Atomic Check-ins With Rollback</h2> The fossil repository is stored in an <a href="http://www.sqlite.org/">SQLite</a> database file. ([./tech_overview.wiki | Addition information] about the repository file format.) SQLite is very mature and stable and has been in wide-spread use for many years, so we are confident it will not cause repository corruption. SQLite databases do not corrupt even if a program or system crash or power failure occurs in the middle of the update. If some kind of crash does occur in the middle of a change, then all the changes are rolled back the next time that the database is accessed. A check-in operation in fossil makes many changes to the repository database. But all these changes happen within a single transaction. If something goes wrong in the middle of the commit, even if that something is a power failure or OS crash, then the transaction is rolled back and the database is unchanged. <h2>Verification Of Delta Encodings Prior To Transaction Commit</h2> The content files that comprise the global state of a fossil repository are stored in the repository as a tree. The leaves of the tree are stored as zlib-compressed BLOBs. Interior nodes are deltas from their descendants. A lot of encoding is going on. There is zlib-compression which is relatively well-tested but still might cause corruption if used improperly. And there is the relatively new delta-encoding mechanism designed expressly for fossil. We want to make sure that bugs in these encoding mechanisms do not lead to loss of data. To increase our confidence that everything in the repository is recoverable, fossil makes sure it can extract an exact replica of every content file that it changes just prior to transaction commit. So during the course of check-in (or other repository operation) many different files in the repository might be modified. Some files are simply compressed. Other files are delta encoded and then compressed. While all this is going on, fossil makes a record of every file and the SHA1 or SHA3-256 hash of the original content of that file. Then just before transaction commit, fossil re-extracts the original content of all files that were written, recomputes the hash, and verifies that the recomputed hash still matches. If anything does not match up, an error message is printed and the transaction rolls back. So, in other words, fossil always checks to make sure it can re-extract a file before it commits a change to that file. Hence bugs in fossil are unlikely to corrupt the repository in a way that prevents us from extracting historical versions of files. <h2>Checksum Over All Files In A Check-in</h2> Manifest artifacts that define a check-in have two fields (the R-card and Z-card) that record MD5 hashes of the manifest itself and of all other files in the manifest. Prior to any check-in commit, these checksums are verified to ensure that the check-in agrees exactly with what is on disk. Similarly, the repository checksum is verified after a checkout to make sure that the entire repository was checked out correctly. Note that these added checks use a different hash algorithm (MD5) in order to avoid common-mode failures in the hash algorithm implementation. <h2>Checksums On Structural Artifacts And Deltas</h2> Every [./fileformat.wiki | structural artifact] in a fossil repository contains a "Z-card" bearing an MD5 checksum over the rest of the artifact. Any mismatch causes the structural artifact to be ignored. The [./delta_format.wiki | file delta format] includes a 32-bit checksum of the target file. Whenever a file is reconstructed from a delta, that checksum is verified to make sure the reconstruction was done correctly. <h2>Reliability Versus Performance</h2> Some version control systems make a big deal out of being "high performance" or the "fastest version control system". Fossil makes no such claims and has no such ambition. Indeed, profiling indicates that fossil bears a substantial performance cost for doing all of the checksumming and verification outlined above. Fossil takes the philosophy of the <a href="http://en.wikipedia.org/wiki/The_Tortoise_and_the_Hare">tortoise</a>: reliability is more important than raw speed. The developers of fossil see no merit in getting the wrong answer quickly. Fossil may not be the fastest versioning system, but it is "fast enough". Fossil runs quickly enough to stay out of the developers way. Most operations complete in milliseconds, faster that you can press the "Enter" key. |
Changes to www/selfhost.wiki.
1 2 3 4 5 | <title>Fossil Self-Hosting Repositories</title> Fossil has self-hosted since 2007-07-21. As of 2017-07-25 there are three publicly accessible repositories for the Fossil source code: | | > < < < | | | | | < | | | | | | < < | 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 | <title>Fossil Self-Hosting Repositories</title> Fossil has self-hosted since 2007-07-21. As of 2017-07-25 there are three publicly accessible repositories for the Fossil source code: 1. [https://www.fossil-scm.org/] 2. [https://www2.fossil-scm.org/] 3. [https://www3.fossil-scm.org/site.cgi] The canonical repository is (1). Repositories (2) and (3) automatically stay in synchronization with (1) via a <a href="http://en.wikipedia.org/wiki/Cron">cron job</a> that invokes "fossil sync" at regular intervals. Note that the two secondary repositories are more than just read-only mirrors. All three servers support full read/write capabilities. Changes (such as new tickets or wiki or check-ins) can be implemented on any of the three servers and those changes automatically propagate to the other two servers. Server (1) runs as a CGI script on a <a href="http://www.linode.com/">Linode 8192</a> located in Dallas, TX - on the same virtual machine that hosts <a href="http://www.sqlite.org/">SQLite</a> and over a dozen other smaller projects. This demonstrates that Fossil can run on a low-power host processor. Multiple fossil-based projects can easily be hosted on the same machine, even if that machine is itself one of several dozen virtual machines on single physical box. The CGI script that runs the canonical Fossil self-hosting repository is as follows: <blockquote><pre> #!/usr/bin/fossil repository: /fossil/fossil.fossil </pre></blockquote> Server (3) ran for 10 years as a CGI script on a shared hosting account at <a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA. This server demonstrated the ability of Fossil to run on an economical shared-host web account with no privileges beyond port 80 HTTP access and CGI. It is not necessary to have a dedicated computer with administrator privileges to run Fossil. As far as we are aware, Fossil is the only full-featured configuration management system that can run in such a restricted environment. The CGI script that ran on the Hurricane Electric server was the same as the CGI script shown above, except that the pathnames are modified to suit the environment: <blockquote><pre> #!/home/hwaci/bin/fossil repository: /home/hwaci/fossil/fossil.fossil </pre></blockquote> In recent years, virtual private servers have become a more flexible and less expensive hosting option compared to shared hosting accounts. So on 2017-07-25, server (3) was moved onto a $5/month "droplet" VPS from [https://www.digitalocean.com|Digital Ocean] located in San Francisco. Server (3) is synchronized with the canonical server (1) by running the following command via cron: <blockquote><pre> /home/hwaci/bin/fossil sync -R /home/hwaci/fossil/fossil.fossil </pre></blockquote> Server (2) is a <a href="http://www.linode.com/">Linode 4096</a> located in Newark, NJ and set up just like the canonical server (1) with the addition of a cron job for synchronization as in server (3). |
Added www/server.wiki.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | <title>How To Configure A Fossil Server</title> <h2>Introduction</h2><blockquote> <p>A server is not necessary to use Fossil, but a server does help in collaborating with peers. A Fossil server also works well as a complete website for a project. For example, the complete [https://www.fossil-scm.org/] website, including the page you are now reading, is just a Fossil server displaying the content of the self-hosting repository for Fossil.</p> <p>This article is a guide for setting up your own Fossil server. <p>See "[./aboutcgi.wiki|How CGI Works In Fossil]" for background information on the underlying CGI technology. See "[./sync.wiki|The Fossil Sync Protocol]" for information on the wire protocol used for client/server communication.</p> </blockquote> <h2>Overview</h2><blockquote> There are basically four ways to set up a Fossil server: <ol> <li>A stand-alone server <li>Using inetd or xinetd or stunnel <li>CGI <li>SCGI (a.k.a. SimpleCGI) </ol> Each of these can serve either a single repository, or a directory hierarchy containing many repositories with names ending in ".fossil". </blockquote> <a name="standalone"></a> <h2>Standalone server</h2><blockquote> The easiest way to set up a Fossil server is to use either the [/help/server|server] or the [/help/ui|ui] commands: <ul> <li><b>fossil server</b> <i>REPOSITORY</i> <li><b>fossil ui</b> <i>REPOSITORY</i> </ul> <p> The <i>REPOSITORY</i> argument is either the name of the repository file, or a directory containing many repositories. Both of these commands start a Fossil server, usually on TCP port 8080, though a higher numbered port might also be used if 8080 is already occupied. You can access these using URLs of the form <b>http://localhost:8080/</b>, or if <i>REPOSITORY</i> is a directory, URLs of the form <b>http://localhost:8080/</b><i>repo</i><b>/</b> where <i>repo</i> is the base name of the repository file without the ".fossil" suffix. The difference between "ui" and "server" is that "ui" will also start a web browser and point it to the URL mentioned above, and the "ui" command binds to the loopback IP address (127.0.0.1) only so that the "ui" command cannot be used to serve content to a different machine. </p> <p> If one of the commands above is run from within an open checkout, then the <i>REPOSITORY</i> argument can be omitted and the checkout is used as the repository. </p> <p> Both commands have additional command-line options that can be used to refine their behavior. See the [/help/server|online documentation] for an overview. </p> </blockquote> <a name="inetd"></a> <h2>Fossil as an inetd/xinetd or stunnel service</h2><blockquote> <p> A Fossil server can be launched on-demand by inetd or xinetd using the [/help/http|fossil http] command. To launch Fossil from inetd, modify your inetd configuration file (typically "/etc/inetd.conf") to contain a line something like this: <blockquote> <pre> 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil </pre> </blockquote> In this example, you are telling "inetd" that when an incoming connection appears on TCP port "80", that it should launch the binary "/usr/bin/fossil" program with the arguments shown. Obviously you will need to modify the pathnames for your particular setup. The final argument is either the name of the fossil repository to be served, or a directory containing multiple repositories. </p> <p> If you use a non-standard TCP port on systems where the port-specification must be a symbolic name and cannot be numeric, add the desired name and port to /etc/services. For example, if you want your Fossil server running on TCP port 12345 instead of 80, you will need to add: <blockquote> <pre> fossil 12345/tcp #fossil server </pre> </blockquote> and use the symbolic name ('fossil' in this example) instead of the numeral ('12345') in inetd.conf. For details, see the relevant section in your system's documentation, e.g. the [https://www.freebsd.org/doc/en/books/handbook/network-inetd.html|FreeBSD Handbook] in case you use FreeBSD. </p> <p> If your system is running xinetd, then the configuration is likely to be in the file "/etc/xinetd.conf" or in a subfile of "/etc/xinetd.d". An xinetd configuration file will appear like this:</p> <blockquote> <pre> service http { port = 80 socket_type = stream wait = no user = root server = /usr/bin/fossil server_args = http /home/fossil/repos/ } </pre> </blockquote> <p> The xinetd example above has Fossil configured to serve multiple repositories, contained under the "/home/fossil/repos/" directory. </p> <p> In both cases notice that Fossil was launched as root. This is not required, but if it is done, then Fossil will automatically put itself into a chroot jail for the user who owns the fossil repository before reading any information off of the wire. </p> <p> Inetd or xinetd must be enabled, and must be (re)started whenever their configuration changes - consult your system's documentation for details. </p> <p> [https://www.stunnel.org/ | Stunnel version 5] is an inetd-like process that accepts and decodes SSL-encrypted connections. Fossil can be run directly from stunnel in a manner similar to inetd and xinetd. This can be used to provide a secure link to a Fossil project. The configuration needed to get stunnel5 to invoke Fossil is very similar to the inetd and xinetd examples shown above. The relevant parts of an stunnel configuration might look something like the following: <blockquote><pre><nowiki> [https] accept = www.ubercool-project.org:443 TIMEOUTclose = 0 exec = /usr/bin/fossil execargs = /usr/bin/fossil http /home/fossil/ubercool.fossil --https </nowiki></pre></blockquote> See the stunnel5 documentation for further details about the /etc/stunnel/stunnel.conf configuration file. Note that the [/help/http|fossil http] command should include the --https option to let Fossil know to use "https" instead of "http" as the scheme on generated hyperlinks. <p> Using inetd or xinetd or stunnel is a more complex setup than the "standalone" server, but it has the advantage of only using system resources when an actual connection is attempted. If no-one ever connects to that port, a Fossil server will not (automatically) run. It has the disadvantage of requiring "root" access and therefore may not normally be available to lower-priced "shared" servers on the internet. </p> </blockquote> <a name="cgi"></a> <h2>Fossil as CGI</h2><blockquote> <p> A Fossil server can also be run from an ordinary web server as a CGI program. This feature allows Fossil to be seamlessly integrated into a larger website. CGI is how the [./selfhost.wiki | self-hosting fossil repositories] are implemented. </p> <p> To run Fossil as CGI, create a CGI script (here called "repo") in the CGI directory of your web server and having content like this: <blockquote><pre> #!/usr/bin/fossil repository: /home/fossil/repo.fossil </pre></blockquote> </p> <p> As always, adjust your paths appropriately. It may be necessary to set permissions properly, or to modify an ".htaccess" file or make other server-specific changes. Consult the documentation for your particular web server. In particular, the following permissions are <em>normally</em> required (but, again, may be different for a particular configuration): <ul> <li>The Fossil binary (/usr/bin/fossil in the example above) must be readable/executable, and ALL directories leading up to it must be readable by the process which executes the CGI.</li> <li>ALL directories leading to the CGI script must also be readable and the CGI script itself must be executable for the user under which it will run (which often differs from the one running the web server - consult your site's documentation or administrator).</li> <li>The repository file AND the directory containing it must be writable by the same account which executes the Fossil binary (again, this might differ from the WWW user). The directory needs to be writable so that sqlite can write its journal files.</li> <li>Fossil must be able to create temporary files, the default directory for which depends on the OS. When the CGI process is operating within a chroot, ensure that this directory exists and is readable/writeable by the user who executes the Fossil binary.</li> </ul> </p> <p> Once the script is set up correctly, and assuming your server is also set correctly, you should be able to access your repository with a URL like: <b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is accessible under "cgi-bin", which would be a typical deployment on Apache for instance). </p> <p> To serve multiple repositories from a directory using CGI, use the "directory:" tag in the CGI script rather than "repository:". You might also want to add a "notfound:" tag to tell where to redirect if the particular repository requested by the URL is not found: <blockquote><pre> #!/usr/bin/fossil directory: /home/fossil/repos notfound: http://url-to-go-to-if-repo-not-found/ </pre></blockquote> </p> <p> Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b> will serve up the repository "/home/fossil/repos/XYZ.fossil" (if it exists). </p> <p> Additional options available to the CGI script are documented in the source code. As of 2017-07-02, the available options are described at [/artifact/9a52a07b?ln=1777-1824|main.c lines 1777 through 1824]. </p> </blockquote> <a name="scgi"></a> <h2>Fossil as SCGI</h2><blockquote> <p> The [/help/server|fossil server] command, described above as a way of starting a stand-alone web server, can also be used for SCGI. Simply add the --scgi command-line option and the stand-alone server will interpret and respond to the SimpleCGI or SCGI protocol rather than raw HTTP. This can be used in combination with a webserver (such as [http://nginx.org|Nginx]) that does not support CGI. A typical Nginx configuration to support SCGI with Fossil would look something like this: <blockquote><pre> location /demo_project/ { include scgi_params; scgi_pass localhost:9000; scgi_param SCRIPT_NAME "/demo_project"; scgi_param HTTPS "on"; } </pre></blockquote> <p> Note that Fossil requires the SCRIPT_NAME variable in order to function properly, but Nginx does not provide this variable by default. So it is necessary to provide the SCRIPT_NAME parameter in the configuration. Failure to do this will cause Fossil to return an error. </p> <p> All of the features of the stand-alone server mode described above, such as the ability to serve a directory full of Fossil repositories rather than just a single repository, work the same way in SCGI mode. </p> <p> For security, it is probably a good idea to add the --localhost option to the [/help/server|fossil server] command to prevent Fossil from accepting off-site connections. And one might want to specify the listening TCP port number, rather than letting Fossil choose one for itself, just to avoid ambiguity. A typical command to start a Fossil SCGI server would be something like this: <blockquote><pre> fossil server $REPOSITORY --scgi --localhost --port 9000 </pre></blockquote> </blockquote> <h2>Securing a repository with SSL</h2><blockquote> <p> Using either CGI or SCGI, it is trivial to use SSL to secure the server. Simply set up the Fossil CGI scripts etc. as above, but modify the Apache (or IIS, etc.) server to require SSL (that is, a URL with "https://") in order to access the CGI script directory. This may also be accomplished (on Apache, at least) using appropriate ".htaccess" rules. </p> <p> If you are using "inetd" to serve your repository, then you simply need to add "/usr/bin/stunnel" (perhaps on a different path, depending on your setup) before the command line to launch Fossil. </p> <p> At this stage, the standalone server (e.g. "fossil server") does not support SSL. </p> <p> For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>. </p> </blockquote> <a name="loadmgmt"></a> <h2>Managing Server Load</h2><blockquote> <p> A Fossil server is very efficient and normally presents a very light load on the server. The Fossil [./selfhost.wiki | self-hosting server] is a 1/24th slice VM at [http://www.linode.com | Linode.com] hosting 65 other repositories in addition to Fossil (and including some very high-traffic sites such as [http://www.sqlite.org] and [http://system.data.sqlite.org]) and it has a typical load of 0.05 to 0.1. A single HTTP request to Fossil normally takes less than 10 milliseconds of CPU time to complete. So requests can be arriving at a continuous rate of 20 or more per second and the CPU can still be mostly idle. <p> However, there are some Fossil web pages that can consume large amounts of CPU time, especially on repositories with a large number of files or with long revision histories. High CPU usage pages include [/help?cmd=/zip | /zip], [/help?cmd=/tarball | /tarball], [/help?cmd=/annotate | /annotate] and others. On very large repositories, these commands can take 15 seconds or more of CPU time. If these kinds of requests arrive too quickly, the load average on the server can grow dramatically, making the server unresponsive. <p> Fossil provides two capabilities to help avoid server overload problems due to excessive requests to expensive pages: <ol> <li><p>An optional cache is available that remembers the 10 most recently requested /zip or /tarball pages and returns the precomputed answer if the same page is requested again. <li><p>Page requests can be configured to fail with a [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.4 | "503 Server Overload"] HTTP error if an expensive request is received while the host load average is too high. </ol> Both of these load-control mechanisms are turned off by default, but they are recommended for high-traffic sites. <p> The webpage cache is activated using the [/help?cmd=cache|fossil cache init] command-line on the server. Add a -R option to specify the specific repository for which to enable caching. If running this command as root, be sure to "chown" the cache database (which is a separate file in the same directory and with the same name as the repository but with the suffix changed to ".cache") to give it write permission for the userid of the webserver. <p> To activate the server load control feature visit the /Admin/Access setup page in the administrative web interface and in the "<b>Server Load Average Limit</b>" box enter the load average threshold above which "503 Server Overload" replies will be issued for expensive requests. On the self-host Fossil server, that value is set to 1.5. But you could easily set it higher on a multi-core server. <p> The maximum load average can also be set on the command line using commands like this: <blockquote><pre> fossil set max-loadavg 1.5 fossil all set max-loadavg 1.5 </pre></blockquote> The second form is especially useful for changing the maximum load average simultaneously on a large number of repositories. <p> Note that this load-average limiting feature is only available on operating systems that support the "getloadavg()" API. Most modern Unix systems have this interface, but Windows does not, so the feature will not work on Windows. Note also that Linux implements "getloadavg()" by accessing the "/proc/loadavg" file in the "proc" virtual filesystem. If you are running a Fossil instance inside a chroot() jail on Linux, you will need to make the "/proc" file system available inside that jail in order for this feature to work. On the [./selfhost.wiki|self-hosting Fossil repositories], this was accomplished by adding a line to the "/etc/fstab" file that looks like: <blockquote><pre> chroot_jail_proc /home/www/proc proc ro 0 0 </pre></blockquote> The /home/www/proc pathname should be adjusted so that the "/proc" component is in the root of the chroot jail, of course. <p> To see if the load-average limiter is functional, visit the [/test_env] page of the server to view the current load average. If the value for the load average is greater than zero, that means that it is possible to activate the load-average limiter on that repository. If the load average shows exactly "0.0", then that means that Fossil is unable to find the load average (either because it is in a chroot() jail without /proc access, or because it is running on a system that does not support "getloadavg()") and so the load-average limiter will not function. </blockquote> |
Deleted www/server/any/althttpd.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/cgi.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/http-over-ssh.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/index.md.
|
| < < < < < < < < < < < |
Deleted www/server/any/inetd.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/none.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/scgi.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/stunnel.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/any/xinetd.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/debian/index.md.
|
| < < < < < < |
Deleted www/server/debian/nginx.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/debian/service.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/index.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/macos/index.md.
|
| < < < < < |
Deleted www/server/macos/service.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/openbsd/fastcgi.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/openbsd/index.md.
|
| < < < < < < |
Deleted www/server/openbsd/service.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/whyuseaserver.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/windows/cgi-bin-perm.png.
cannot compute difference between binary files
Deleted www/server/windows/cgi-exec-perm.png.
cannot compute difference between binary files
Deleted www/server/windows/cgi-install-iis.png.
cannot compute difference between binary files
Deleted www/server/windows/cgi-script-map.png.
cannot compute difference between binary files
Deleted www/server/windows/cgi.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/windows/iis.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/windows/index.md.
|
| < < < < < < < < |
Deleted www/server/windows/none.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/windows/service.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/server/windows/stunnel.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted www/serverext.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/settings.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 | <title>Fossil Settings</title> <h2>Using Fossil Settings</h2> Settings control the behaviour of fossil. They are set with the <tt>fossil settings</tt> command, or through the web interface in the Settings page in the Admin section. For a list of all settings, view the Settings page, or type <tt>fossil help settings</tt> from the command line. | | | | | | | | 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 | <title>Fossil Settings</title> <h2>Using Fossil Settings</h2> Settings control the behaviour of fossil. They are set with the <tt>fossil settings</tt> command, or through the web interface in the Settings page in the Admin section. For a list of all settings, view the Settings page, or type <tt>fossil help settings</tt> from the command line. <h3>Repository settings</h3> Settings are set on a per-repository basis. When you clone a repository, a subset of settings are copied to your local repository. If you make a change to a setting on your local repository, it is not synced back to the server when you <tt>push</tt> or <tt>sync</tt>. If you make a change on the server, you need to manually make the change on all repositories which are cloned from this repository. You can also set a setting globally on your local machine. The value will be used for all repositories cloned to your machine, unless overridden explicitly in a particular repository. Global settings can be set by using the <tt>-global</tt> option on the <tt>fossil settings</tt> command. <h3>"Versionable" settings</h3> Most of the settings control the behaviour of fossil on your local machine, largely acting to reflect your preference on how you want to use Fossil, how you communicate with the server, or options for hosting a repository on the web. However, for historical reasons, some settings affect how you work with versioned files. These are <tt>allow-symlinks</tt>, <tt>binary-glob</tt>, <tt>crlf-glob</tt>, <tt>crnl-glob</tt>, <tt>empty-dirs</tt>, <tt>encoding-glob</tt>, <tt>ignore-glob</tt>, <tt>keep-glob</tt> and <tt>manifest</tt>. The most important is <tt>ignore-glob</tt> which specifies which files should be ignored when looking for unmanaged files with the <tt>extras</tt> command. Because these options can change over time, and the inconvenience of replicating changes, these settings are "versionable". As well as being able to be set using the <tt>settings</tt> command or the web interface, you can create versioned files in the <tt>.fossil-settings</tt> |
︙ | ︙ |
Changes to www/shunning.wiki.
1 | <title>Deleting Content From Fossil</title> | | < | | | | > | | | < < | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | <title>Deleting Content From Fossil</title> <h1 align="center">Deleting Content From Fossil</h1> Fossil is designed to keep all historical content forever. Users of Fossil are discouraged from "deleting" content simply because it has become obsolete. Old content is part of the historical record (part of the "fossil record") and should be maintained indefinitely. Such is the design intent of Fossil. Nevertheless, there may occasionally arise legitimate reasons for deleting content. Such reasons might include: * Spammers have inserted inappropriate content into a wiki page or ticket that needs to be removed. * A file that contains trade secrets or that is under copyright may have been accidentally committed and needs to be backed out. * A malformed control artifact may have been inserted and is disrupting the operation of Fossil. <h2>Shunning</h2> Fossil provides a mechanism called "shunning" for removing content from a repository. Every Fossil repository maintains a list of the hash names of |
︙ | ︙ |
Deleted www/ssl-server.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/ssl.wiki.
|
| | | | < < < < < < < < < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | <title>SSL and Fossil</title> <h2>Using SSL with Fossil</h2> If you are storing sensitive information in your repository, you should use SSL to encrypt all communications. This will protect the credentials used to access the server, as well preventing eavesdropping of the contents of your repository. To host a repository with SSL, you need to use an web server which supports SSL in front of the Fossil server. You can host it using the CGI option or by proxying Fossil's built in HTTP server. Your fossil client must be built with SSL support. The <tt>configure</tt> script will attempt to find OpenSSL on your system, but if necessary, you can specify the location with the <tt>--with-openssl</tt> option. Type <tt>./configure --help</tt> for details. Make sure the URL you clone from uses the <tt>https:</tt> scheme to ensure you're using SSL. If your server is configured to serve the repository from http as well as https, it's easy to accidentally use unencrypted HTTP if you forget the all important 's'. <h2>Certificates</h2> To verify the identify of a server, SSL uses certificates. Fossil needs to know which certificates you trust. If you are using a self-signed certificate, you'll be asked if you want to accept the certificate the first time you communicate with the server. Verify the certificate fingerprint is correct, then answer "always" to remember your decision. If you are using a certificate signed by a certificate authority, you need to specify the certificates you trust with the <tt>ssl-ca-location</tt> setting. Set this globally with the <tt>-global</tt> option for convenience. This should be set to the location of a file containing all the PEM encoded certificates you trust. You can obtain a certificate using a web browser, for example, Firefox, or just refer to your system's trusted CA roots which are usually stored somewhere in <tt>/etc</tt>. <h2>Client side certificates</h2> You can also use client side certificates to add an extra layer of authentication, over and above Fossil's built in user management. If you are particularly paranoid, you'll want to use this to remove the ability of anyone on the internet from making any request to Fossil. Without presenting a valid client side certificate, the web server won't invoke the fossil CGI handler. Configure your server to request a client side certificate, and set up a certificate authority to sign your client certificates. For each person who needs to access the repository, create a private key and certificate signed with that CA. The PEM encoded private key and certificate should be stored in a single file, simply by concatenating the key and certificate files. Specify the location of this file with the <tt>ssl-identity</tt> setting, or the <tt>--ssl-identity</tt> option to the <tt>clone</tt> command. If you've password protected the private key, the password will be requested every time you connect to the server. This password is not stored by fossil, as doing so would defeat the purpose of having a password. If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server. |
Changes to www/stats.wiki.
1 2 3 4 5 6 7 8 9 10 11 | <title>Fossil Performance</title> The questions will inevitably arise: How does Fossil perform? Does it use a lot of disk space or bandwidth? Is it scalable? In an attempt to answers these questions, this report looks at several projects that use fossil for configuration management and examines how well they are working. The following table is a summary of the results. (Last updated on 2018-06-04.) Explanation and analysis follows the table. | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <title>Fossil Performance</title> <h1 align="center">Performance Statistics</h1> The questions will inevitably arise: How does Fossil perform? Does it use a lot of disk space or bandwidth? Is it scalable? In an attempt to answers these questions, this report looks at several projects that use fossil for configuration management and examines how well they are working. The following table is a summary of the results. (Last updated on 2018-06-04.) Explanation and analysis follows the table. <table border=1> <tr> <th>Project</th> <th>Number Of Artifacts</th> <th>Number Of Check-ins</th> <th>Project Duration<br>(as of 2018-06-04)</th> <th>Uncompressed Size</th> <th>Repository Size</th> |
︙ | ︙ | |||
122 123 124 125 126 127 128 | "GB" means gigabytes (10<sup><small>9</small></sup> bytes) not <a href="http://en.wikipedia.org/wiki/Gibibyte">gibibytes</a> (2<sup><small>30</small></sup> bytes). Similarly, "MB" and "KB" means megabytes and kilobytes, not mebibytes and kibibytes. <h2>Analysis And Supplemental Data</h2> | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | "GB" means gigabytes (10<sup><small>9</small></sup> bytes) not <a href="http://en.wikipedia.org/wiki/Gibibyte">gibibytes</a> (2<sup><small>30</small></sup> bytes). Similarly, "MB" and "KB" means megabytes and kilobytes, not mebibytes and kibibytes. <h2>Analysis And Supplemental Data</h2> Perhaps the two most interesting datapoints in the above table are SQLite and SLT. SQLite is a long-running project with long revision chains. Some of the files in SQLite have been edited over a thousand times. Each of these edits is stored as a delta, and hence the SQLite project gets excellent 80:1 compression. SLT, on the other hand, consists of many large (megabyte-sized) SQL scripts that have one or maybe two edits each. There is very little delta compression occurring and so the overall repository compression ratio is much lower. Note also that |
︙ | ︙ |
Changes to www/sync.wiki.
1 2 | <title>The Fossil Sync Protocol</title> | | | | < | | | | | | | < < < < < < < < < < < < < < < < | | | | < | | | < | | < < | | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < < | < | < < < | < | < < < | < < < < < < < < < < < | | | | | > | > | | > | > | | | | < | > | | | | < | > | | | | | | | | | | | | | > | > | | | | | | | | | > | | | < | | | | | | | | < | | | | | | | | | | | | | | | | | | > | > | > | | | | > | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | | | | | | | | | | | | | | < < < < | | | | | | | | | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | <title>The Fossil Sync Protocol</title> <p>This document describes the wire protocol used to synchronize content between two Fossil repositories.</p> <h2>1.0 Overview</h2> <p>The global state of a fossil repository consists of an unordered collection of artifacts. Each artifact is identified by a cryptographic hash of its content, expressed as a lower-case hexadecimal string. Synchronization is the process of sharing artifacts between servers so that all servers have copies of all artifacts. Because artifacts are unordered, the order in which artifacts are received at a server is inconsequential. It is assumed that the hash names of artifacts are unique - that every artifact has a different hash. To a first approximation, synchronization proceeds by sharing lists hash values for available artifacts, then sharing the content of artifacts whose names are missing from one side or the other of the connection. In practice, a repository might contain millions of artifacts. The list of hash names for this many artifacts can be large. So optimizations are employed that usually reduce the number of hashes that need to be shared to a few hundred.</p> <p>Each repository also has local state. The local state determines the web-page formatting preferences, authorized users, ticket formats, and similar information that varies from one repository to another. The local state is not using transferred during a sync. Except, some local state is transferred during a [/help?cmd=clone|clone] in order to initialize the local state of the new repository. Also, an administrator can sync local state using the [/help?cmd=configuration|config push] and [/help?cmd=configuration|config pull] commands. <h2>2.0 Transport</h2> <p>All communication between client and server is via HTTP requests. The server is listening for incoming HTTP requests. The client issues one or more HTTP requests and receives replies for each request.</p> <p>The server might be running as an independent server using the <b>server</b> command, or it might be launched from inetd or xinetd using the <b>http</b> command. Or the server might be launched from CGI. (See "[./server.wiki|How To Configure A Fossil Server]" for details.) The specifics of how the server listens for incoming HTTP requests is immaterial to this protocol. The important point is that the server is listening for requests and the client is the issuer of the requests.</p> <p>A single push, pull, or sync might involve multiple HTTP requests. The client maintains state between all requests. But on the server side, each request is independent. The server does not preserve any information about the client from one request to the next.</p> <h4>2.0.1 Encrypted Transport</h4> <p>In the current implementation of Fossil, the server only understands HTTP requests. The client can send either clear-text HTTP requests or encrypted HTTPS requests. But when HTTPS requests are sent, they first must be decrypted by a webserver or proxy before being passed to the Fossil server. This limitation may be relaxed in a future release.</p> <h3>2.1 Server Identification</h3> <p>The server is identified by a URL argument that accompanies the push, pull, or sync command on the client. (As a convenience to users, the URL can be omitted on the client command and the same URL from the most recent push, pull, or sync will be reused. This saves typing in the common case where the client does multiple syncs to the same server.)</p> <p>The client modifies the URL by appending the method name "<b>/xfer</b>" to the end. For example, if the URL specified on the client command line is</p> <blockquote> http://fossil-scm.hwaci.com/fossil </blockquote> <p>Then the URL that is really used to do the synchronization will be:</p> <blockquote> http://fossil-scm.hwaci.com/fossil/xfer </blockquote> <h3>2.2 HTTP Request Format</h3> <p>The client always sends a POST request to the server. The general format of the POST request is as follows:</p> <blockquote><pre> POST /fossil/xfer HTTP/1.0 Host: fossil-scm.hwaci.com:80 Content-Type: application/x-fossil Content-Length: 4216 <i>content...</i> </pre></blockquote> <p>In the example above, the pathname given after the POST keyword on the first line is a copy of the URL pathname. The Host: parameter is also taken from the URL. The content type is always either "application/x-fossil" or "application/x-fossil-debug". The "x-fossil" content type is the default. The only difference is that "x-fossil" content is compressed using zlib whereas "x-fossil-debug" is sent uncompressed.</p> <p>A typical reply from the server might look something like this:</p> <blockquote><pre> HTTP/1.0 200 OK Date: Mon, 10 Sep 2007 12:21:01 GMT Connection: close Cache-control: private Content-Type: application/x-fossil; charset=US-ASCII Content-Length: 265 <i>content...</i> </pre></blockquote> <p>The content type of the reply is always the same as the content type of the request.</p> <h2>3.0 Fossil Synchronization Content</h2> <p>A synchronization request between a client and server consists of one or more HTTP requests as described in the previous section. This section details the "x-fossil" content type.</p> <h3>3.1 Line-oriented Format</h3> <p>The x-fossil content type consists of zero or more "cards". Cards are separated by the newline character ("\n"). Leading and trailing whitespace on a card is ignored. Blank cards are ignored.</p> <p>Each card is divided into zero or more space separated tokens. The first token on each card is the operator. Subsequent tokens are arguments. The set of operators understood by servers is slightly different from the operators understood by clients, though the two are very similar.</p> <h3>3.2 Login Cards</h3> <p>Every message from client to server begins with one or more login cards. Each login card has the following format:</p> <blockquote> <b>login</b> <i>userid nonce signature</i> </blockquote> <p>The userid is the name of the user that is requesting service from the server. The nonce is the SHA1 hash of the remainder of the message - all text that follows the newline character that terminates the login card. The signature is the SHA1 hash of the concatenation of the nonce and the users password.</p> <p>For each login card, the server looks up the user and verifies that the nonce matches the SHA1 hash of the remainder of the message. It then checks the signature hash to make sure the signature matches. If everything checks out, then the client is granted all privileges of the specified user.</p> <p>Privileges are cumulative. There can be multiple successful login cards. The session privileges are the bit-wise OR of the privileges of each individual login.</p> <h3>3.3 File Cards</h3> <p>Artifacts are transferred using either "file" cards, or "cfile" or "uvfile" cards. The name "file" card comes from the fact that most artifacts correspond to files that are under version control. The "cfile" name is an abbreviation for "compressed file". The "uvfile" name is an abbreviation for "unversioned file". </p> <h4>3.3.1 Ordinary File Cards</h4> <p>For sync protocols, artifacts are transferred using "file" cards. File cards come in two different formats depending on whether the artifact is sent directly or as a delta from some other artifact.</p> <blockquote> <b>file</b> <i>artifact-id size</i> <b>\n</b> <i>content</i><br> <b>file</b> <i>artifact-id delta-artifact-id size</i> <b>\n</b> <i>content</i> </blockquote> <p>File cards are followed by in-line "payload" data. The content of the artifact or the artifact delta is the first <i>size</i> bytes of the x-fossil content that immediately follow the newline that terminates the file card. </p> <p>The first argument of a file card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal representation of the name hash for the artifact. The last argument of the file card is the number of bytes of payload that immediately follow the file card. If the file card has only two arguments, that means the payload is the complete content of the artifact. If the file card has three arguments, then the payload is a delta and second argument is the ID of another artifact that is the source of the delta.</p> <p>File cards are sent in both directions: client to server and server to client. A delta might be sent before the source of the delta, so both client and server should remember deltas and be able to apply them when their source arrives.</p> <h4>3.3.2 Compressed File Cards</h4> <p>A client that sends a clone protocol version "3" or greater will receive artifacts as "cfile" cards while cloning. This card was introduced to improve the speed of the transfer of content by sending the compressed artifact directly from the server database to the client.</p> <p>Compressed File cards are similar to File cards, sharing the same in-line "payload" data characteristics and also the same treatment of direct content or delta content. Cfile cards come in two different formats depending on whether the artifact is sent directly or as a delta from some other artifact.</p> <blockquote> <b>cfile</b> <i>artifact-id usize csize</i> <b>\n</b> <i>content</i><br> <b>cfile</b> <i>artifact-id delta-artifact-id usize csize</i> <b>\n</b> <i>content</i><br> </blockquote> <p>The first argument of the cfile card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal representation of the name hash for the artifact. The second argument of the cfile card is the original size in bytes of the artifact. The last argument of the cfile card is the number of compressed bytes of payload that immediately follow the cfile card. If the cfile card has only three arguments, that means the payload is the complete content of the artifact. If the cfile card has four arguments, then the payload is a delta and the second argument is the ID of another artifact that is the source of the delta and the third argument is the original size of the delta artifact.</p> <p>Unlike file cards, cfile cards are only sent in one direction during a clone from server to client for clone protocol version "3" or greater.</p> <h4>3.3.3 Private artifacts</h4> <p>"Private" content consist of artifacts that are not normally synced. However, private content will be synced when the the [/help?cmd=sync|fossil sync] command includes the "--private" option. </p> <p>Private content is marked by a "private" card: <blockquote> <b>private</b> </blockquote> <p>The private card has no arguments and must directly precede a file card that contains the private content.</p> <h4>3.3.4 Unversioned File Cards</h4> <p>Unversioned content is sent in both directions (client to server and server to client) using "uvfile" cards in the following format: <blockquote> <b>uvfile</b> <i>name mtime hash size flags</i> <b>\n</b> <i>content</i> </blockquote> <p>The <i>name</i> field is the name of the unversioned file. The <i>mtime</i> is the last modification time of the file in seconds since 1970. The <i>hash</i> field is the hash of the content for the unversioned file, or "<b>-</b>" for deleted content. The <i>size</i> field is the (uncompressed) size of the content in bytes. The <i>flags</i> field is an integer which is interpreted as an array of bits. The 0x0004 bit of <i>flags</i> indicates that the <i>content</i> is to be omitted. The content might be omitted if it is too large to transmit, or if the sender merely wants to update the modification time of the file without changing the files content. The <i>content</i> is the (uncompressed) content of the file. <p>The receiver should only accept the uvfile card if the hash and size match the content and if the mtime is newer than any existing instance of the same file held by the receiver. The sender will not normally transmit a uvfile card unless all these constraints are true, but the receiver should double-check. <p>A server should only accept uvfile cards if the login user has the "y" write-unversioned permission. <p>Servers send uvfile cards in response to uvgimme cards received from the client. Clients send uvfile cards when they determine that the server needs the content based on uvigot cards previously received from the server. <h3>3.4 Push and Pull Cards</h3> <p>Among the first cards in a client-to-server message are the push and pull cards. The push card tells the server that the client is pushing content. The pull card tells the server that the client wants to pull content. In the event of a sync, both cards are sent. The format is as follows:</p> <blockquote> <b>push</b> <i>servercode projectcode</i><br> <b>pull</b> <i>servercode projectcode</i> </blockquote> <p>The <i>servercode</i> argument is the repository ID for the client. The <i>projectcode</i> is the identifier of the software project that the client repository contains. The projectcode for the client and server must match in order for the transaction to proceed.</p> <p>The server will also send a push card back to the client during a clone. This is how the client determines what project code to put in the new repository it is constructing.</p> <p>The <i>servercode</i> argument is currently unused. <h3>3.5 Clone Cards</h3> <p>A clone card works like a pull card in that it is sent from client to server in order to tell the server that the client wants to pull content. The clone card comes in two formats. Older clients use the no-argument format and newer clients use the two-argument format.</p> <blockquote> <b>clone</b><br> <b>clone</b> <i>protocol-version sequence-number</i> </blockquote> <h4>3.5.1 Protocol 3</h4> <p>The latest clients send a two-argument clone message with a protocol version of "3". (Future versions of Fossil might use larger protocol version numbers.) Version "3" of the protocol enhanced version "2" by introducing the "cfile" card which is intended to speed up clone operations. Instead of sending "file" cards, the server will send "cfile" cards</p> <h4>3.5.2 Protocol 2</h4> <p>The sequence-number sent is the number of artifacts received so far. For the first clone message, the sequence number is 0. The server will respond by sending file cards for some number of artifacts up to the maximum message size. <p>The server will also send a single "clone_seqno" card to the client so that the client can know where the server left off. <blockquote> <b>clone_seqno</b> <i>sequence-number</i> </blockquote> <p>The clone message in subsequent HTTP requests for the same clone operation will use the sequence-number from the clone_seqno of the previous reply.</p> <p>In response to an initial clone message, the server also sends the client a push message so that the client can discover the projectcode for this project.</p> <h4>3.5.3 Legacy Protocol</h4> <p>Older clients send a clone card with no argument. The server responds to a blank clone card by sending an "igot" card for every artifact in the repository. The client will then issue "gimme" cards to pull down all the content it needs. <p>The legacy protocol works well for smaller repositories (50MB with 50,000 artifacts) but is too slow and unwieldy for larger repositories. The version 2 protocol is an effort to improve performance. Further performance improvements with higher-numbered clone protocols are possible in future versions of Fossil. <h3>3.6 Igot Cards</h3> <p>An igot card can be sent from either client to server or from server to client in order to indicate that the sender holds a copy of a particular artifact. The format is:</p> <blockquote> <b>igot</b> <i>artifact-id</i> ?<i>flag</i>? </blockquote> <p>The first argument of the igot card is the ID of the artifact that the sender possesses. The receiver of an igot card will typically check to see if it also holds the same artifact and if not it will request the artifact using a gimme card in either the reply or in the next message.</p> <p>If the second argument exists and is "1", then the artifact identified by the first argument is private on the sender and should be ignored unless a "--private" [/help?cmd=sync|sync] is occurring. <h4>3.6.1 Unversioned Igot Cards</h4> <p>Zero or more "uvigot" cards are sent from server to client when synchronizing unversioned content. The format of a uvigot card is as follows: <blockquote> <b>uvigot</b> <i>name mtime hash size</i> </blockquote> <p>The <i>name</i> argument is the name of an unversioned file. The <i>mtime</i> is the last modification time of the unversioned file in seconds since 1970. The <i>hash</i> is the SHA1 or SHA3-256 hash of the unversioned file content, or "<b>-</b>" if the file has been deleted. The <i>size</i> is the uncompressed size of the file in bytes. <p>When the server sees a "pragma uv-hash" card for which the hash does not match, it sends uvigot cards for every unversioned file that it holds. The client will use this information to figure out which unversioned files need to be synchronized. The server might also send a uvigot card when it receives a uvgimme card but its reply message size is already oversized and hence unable to hold the usual uvfile reply. <p>When a client receives a "uvigot" card, it checks to see if the file needs to be transfered from client to server or from server to client. If a client-to-server transmission is needed, the client schedules that transfer to occur on a subsequent HTTP request. If a server-to-client transfer is needed, then the client sends a "uvgimme" card back to the server to request the file content. <h3>3.7 Gimme Cards</h3> <p>A gimme card is sent from either client to server or from server to client. The gimme card asks the receiver to send a particular artifact back to the sender. The format of a gimme card is this:</p> <blockquote> <b>gimme</b> <i>artifact-id</i> </blockquote> <p>The argument to the gimme card is the ID of the artifact that the sender wants. The receiver will typically respond to a gimme card by sending a file card in its reply or in the next message.</p> <h4>3.7.1 Unversioned Gimme Cards</h4> <p>Sync synchronizing unversioned content, the client may send "uvgimme" cards to the server. A uvgimme card requests that the server send unversioned content to the client. The format of a uvgimme card is as follows: <blockquote> <b>uvgimme</b> <i>name</i> </blockquote> <p>The <i>name</i> is the name of the unversioned file found on the server that the client would like to have. When a server sees a uvgimme card, it normally responses with a uvfile card, though it might also send another uvigot card if the HTTP reply is already oversized. <h3>3.8 Cookie Cards</h3> <p>A cookie card can be used by a server to record a small amount of state information on a client. The server sends a cookie to the client. The client sends the same cookie back to the server on its next request. The cookie card has a single argument which is its payload.</p> <blockquote> <b>cookie</b> <i>payload</i> </blockquote> <p>The client is not required to return the cookie to the server on its next request. Or the client might send a cookie from a different server on the next request. So the server must not depend on the cookie and the server must structure the cookie payload in such a way that it can tell if the cookie it sees is its own cookie or a cookie from another server. (Typically the server will embed its servercode as part of the cookie.)</p> <h3>3.9 Request-Configuration Cards</h3> <p>A request-configuration or "reqconfig" card is sent from client to server in order to request that the server send back "configuration" data. "Configuration" data is information about users or website appearance or other administrative details which are not part of the persistent and versioned state of the project. For example, the "name" of the project, the default Cascading Style Sheet (CSS) for the web-interface, and the project logo displayed on the web-interface are all configuration data elements. <p>The reqconfig card is normally sent in response to the "fossil configuration pull" command. The format is as follows: <blockquote> <b>reqconfig</b> <i>configuration-name</i> </blockquote> <p>As of 2018-06-04, the configuration-name must be one of the following values: <table border=0 align="center"> <tr><td valign="top"> <ul> <li> css <li> header |
︙ | ︙ | |||
609 610 611 612 613 614 615 | <li> ignore-glob <li> keep-glob <li> crlf-glob <ul></td><td valign="top"><ul> <li> crnl-glob <li> encoding-glob <li> empty-dirs | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | <li> ignore-glob <li> keep-glob <li> crlf-glob <ul></td><td valign="top"><ul> <li> crnl-glob <li> encoding-glob <li> empty-dirs <li> allow-symlinks <li> dotfiles <li> parent-project-code <li> parent-projet-name <li> hash-policy <li> mv-rm-files <li> ticket-table <li> ticket-common |
︙ | ︙ | |||
638 639 640 641 642 643 644 | <li> @reportfmt <li> @user <li> @concealed <li> @shun </ul></td></tr> </table> | | | | | | | | | | | | | | | | | | > | > | | > | | | > | | | > | | | < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | <li> @reportfmt <li> @user <li> @concealed <li> @shun </ul></td></tr> </table> <p>New configuration-names are likely to be added in future releases of Fossil. If the server receives a configuration-name that it does not understand, the entire reqconfig card is silently ignored. The reqconfig card might also be ignored if the user lacks sufficient privilege to access the requested information. <p>The configuration-names that begin with an alphabetic character refer to values in the "config" table of the server database. For example, the "logo-image" configuration item refers to the project logo image that is configured on the Admin page of the [./webui.wiki | web-interface]. The value of the configuration item is returned to the client using a "config" card. <p>If the configuration-name begins with "@", that refers to a class of values instead of a single value. The content of these configuration items is returned in a "config" card that contains pure SQL text that is intended to be evaluated by the client. <p>The @user and @concealed configuration items contain sensitive information and are ignored for clients without sufficient privilege. <h3>3.10 Configuration Cards</h3> <p>A "config" card is used to send configuration information from client to server (in response to a "fossil configuration push" command) or from server to client (in response to a "fossil configuration pull" or "fossil clone" command). The format is as follows: <blockquote> <b>config</b> <i>configuration-name size</i> <b>\n</b> <i>content</i> </blockquote> <p>The server will only accept a config card if the user has "Admin" privilege. A client will only accept a config card if it had sent a corresponding reqconfig card in its request. <p>The content of the configuration item is used to overwrite the corresponding configuration data in the receiver. <h3>3.11 Pragma Cards</h3> <p>The client may try to influence the behavior of the server by issuing a pragma card: <blockquote> <b>pragma</i> <i>name value...</i> </blockquote> <p>The "pragma" card has at least one argument which is the pragma name. The pragma name defines what the pragma does. A pragma might have zero or more "value" arguments depending on the pragma name. <p>New pragma names may be added to the protocol from time to time in order to enhance the capabilities of Fossil. Unknown pragmas are silently ignored, for backwards compatibility. <p>The following are the known pragma names as of 2016-08-03: <ol> <li><p><b>send-private</b> <p>The send-private pragma instructs the server to send all of its private artifacts to the client. The server will only obey this request if the user has the "x" or "Private" privilege. <li><p><b>send-catalog</b> <p>The send-catalog pragma instructs the server to transmit igot cards for every known artifact. This can help the client and server to get back in synchronization after a prior protocol error. The "--verily" option to the [/help?cmd=sync|fossil sync] command causes the send-catalog pragma to be transmitted.</p> <li><p><b>uv-hash</b> <i>HASH</i> <p>The uv-hash pragma is sent from client to server to provoke a synchronization of unversioned content. The <i>HASH</i> is a SHA1 hash of the names, modification times, and individual hashes of all unversioned files on the client. If the unversioned content hash from the client does not match the unversioned content hash on the server, then the server will reply with either a "pragma uv-push-ok" or "pragma uv-pull-only" card followed by one "uvigot" card for each unversioned file currently held on the server. The collection of "uvigot" cards sent in response to a "uv-hash" pragma is called the "unversioned catalog". The client will used the unversioned catalog to figure out which files (if any) need to be synchronized between client and server and send appropriate "uvfile" or "uvgimme" cards on the next HTTP request.</p> <p>If a client sends a uv-hash pragma and does not receive back either a uv-pull-only or uv-push-ok pragma, that means that the content on the server exactly matches the content on the client and no further synchronization is required. <li><p><b>uv-pull-only</b></i> <p>A server sends the uv-pull-only pragma to the client in response to a uv-hash pragma with a mismatched content hash argument. This pragma indicates that there are differences in unversioned content between the client and server but that content can only be transfered from server to client. The server is unwilling to accept content from the client because the client login lacks the "write-unversioned" permission.</p> <li><p><b>uv-push-ok</b></i> <p>A server sends the uv-push-ok pragma to the client in response to a uv-hash pragma with a mismatched content hash argument. This pragma indicates that there are differences in unversioned content between the client and server and that content can only be transfered in either direction. The server is willing to accept content from the client because the client login has the "write-unversioned" permission.</p> </ol> <h3>3.12 Comment Cards</h3> <p>Any card that begins with "#" (ASCII 0x23) is a comment card and is silently ignored.</p> <h3>3.13 Message and Error Cards</h3> <p>If the server discovers anything wrong with a request, it generates an error card in its reply. When the client sees the error card, it displays an error message to the user and aborts the sync operation. An error card looks like this:</p> <blockquote> <b>error</b> <i>error-message</i> </blockquote> <p>The error message is English text that is encoded in order to be a single token. A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash (ASCII 0x5C) is represented as two backslashes "\\". Apart from space and newline, no other whitespace characters nor any unprintable characters are allowed in the error message.</p> <p>The server can also send a message card that also prints a message on the client console, but which is not an error: <blockquote> <b>message</b> <i>message-text</i> </blockquote> <p>The message-text uses the same format as an error message. <h3>3.14 Unknown Cards</h3> <p>If either the client or the server sees a card that is not described above, then it generates an error and aborts.</p> <h2>4.0 Phantoms And Clusters</h2> <p>When a repository knows that an artifact exists and knows the ID of that artifact, but it does not know the artifact content, then it stores that artifact as a "phantom". A repository will typically create a phantom when it receives an igot card for an artifact that it does not hold or when it receives a file card that references a delta source that it does not hold. When a server is generating its reply or when a client is generating a new request, it will usually send gimme cards for every phantom that it holds.</p> <p>A cluster is a special artifact that tells of the existence of other artifacts. Any artifact in the repository that follows the syntactic rules of a cluster is considered a cluster.</p> <p>A cluster is line oriented. Each line of a cluster is a card. The cards are separated by the newline ("\n") character. Each card consists of a single character card type, a space, and a single argument. No extra whitespace and no trailing or leading whitespace is allowed. All cards in the cluster must occur in strict lexicographical order.</p> <p>A cluster consists of one or more "M" cards followed by a single "Z" card. Each M card holds an argument which is an artifact ID for an artifact in the repository. The Z card has a single argument which is the lower-case hexadecimal representation of the MD5 checksum of all preceding M cards up to and included the newline character that occurred just before the Z that starts the Z card.</p> <p>Any artifact that does not match the specifications of a cluster exactly is not a cluster. There must be no extra whitespace in the artifact. There must be one or more M cards. There must be a single Z card with a correct MD5 checksum. And all cards must be in strict lexicographical order.</p> <h3>4.1 The Unclustered Table</h3> <p>Every repository maintains a table named "<b>unclustered</b>" which records the identity of every artifact and phantom it holds that is not mentioned in a cluster. The entries in the unclustered table can be thought of as leaves on a tree of artifacts. Some of the unclustered artifacts will be other clusters. Those clusters may contain other clusters, which might contain still more clusters, and so forth. Beginning with the artifacts in the unclustered table, one can follow the chain of clusters to find every artifact in the repository.</p> <h2>5.0 Synchronization Strategies</h2> <h3>5.1 Pull</h3> <p>A typical pull operation proceeds as shown below. Details of the actual implementation may very slightly but the gist of a pull is captured in the following steps:</p> <ol> <li>The client sends login and pull cards. <li>The client sends a cookie card if it has previously received a cookie. <li>The client sends gimme cards for every phantom that it holds. <hr> <li>The server checks the login password and rejects the session if |
︙ | ︙ | |||
884 885 886 887 888 889 890 | <li>The client adds the content of file cards to its repository. <li>The client creates a phantom for every igot card in the server reply that mentions an artifact that the client does not possess. <li>The client creates a phantom for the delta source of file cards when the delta source is an artifact that the client does not possess. </ol> | | | | | | | | | | | | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | <li>The client adds the content of file cards to its repository. <li>The client creates a phantom for every igot card in the server reply that mentions an artifact that the client does not possess. <li>The client creates a phantom for the delta source of file cards when the delta source is an artifact that the client does not possess. </ol> <p>These ten steps represent a single HTTP round-trip request. The first three steps are the processing that occurs on the client to generate the request. The middle four steps are processing that occurs on the server to interpret the request and generate a reply. And the last three steps are the processing that the client does to interpret the reply.</p> <p>During a pull, the client will keep sending HTTP requests until it holds all artifacts that exist on the server.</p> <p>Note that the server tries to limit the size of its reply message to something reasonable (usually about 1MB) so that it might stop sending file cards as described in step (6) if the reply becomes too large.</p> <p>Step (5) is the only way in which new clusters can be created. By only creating clusters on the server, we hope to minimize the amount of overlap between clusters in the common configuration where there is a single server and many clients. The same synchronization protocol will continue to work even if there are multiple servers or if servers and clients sometimes change roles. The only negative effects of these unusual arrangements is that more than the minimum number of clusters might be generated.</p> <h3>5.2 Push</h3> <p>A typical push operation proceeds roughly as shown below. As with a pull, the actual implementation may vary slightly.</p> <ol> <li>The client sends login and push cards. <li>The client sends file cards for any artifacts that it holds that have never before been pushed - artifacts that come from local check-ins. <li>If this is the second or later cycle in a push, then the client sends file cards for any gimme cards that the server sent |
︙ | ︙ | |||
936 937 938 939 940 941 942 | it does not possess. <li>The server issues gimme cards for all phantoms. <hr> <li>The client remembers the gimme cards from the server so that it can generate file cards in reply on the next cycle. </ol> | | | | | | | | | | | | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | it does not possess. <li>The server issues gimme cards for all phantoms. <hr> <li>The client remembers the gimme cards from the server so that it can generate file cards in reply on the next cycle. </ol> <p>As with a pull, the steps of a push operation repeat until the server knows all artifacts that exist on the client. Also, as with pull, the client attempts to keep the size of the request from growing too large by suppressing file cards once the size of the request reaches 1MB.</p> <h3>5.3 Sync</h3> <p>A sync is just a pull and a push that happen at the same time. The first three steps of a pull are combined with the first five steps of a push. Steps (4) through (7) of a pull are combined with steps (5) through (8) of a push. And steps (8) through (10) of a pull are combined with step (9) of a push.</p> <h3>5.4 Unversioned File Sync</h3> <p>"Unversioned files" are files held in the repository where only the most recent version of the file is kept rather than the entire change history. Unversioned files are intended to be used to store ephemeral content, such as compiled binaries of the most recent release. <p>Unversioned files are identified by name and timestamp (mtime). Only the most recent version of each file (the version with the largest mtime value) is retained. <p>Unversioned files are synchronized using the [/help?cmd=unversioned|fossil unversioned sync] command. <p>A schematic of an unversioned file synchronization is as follows: <ol> <li>The client sends a "pragma uv-hash" card to the server. The argument to the uv-hash pragma is a hash of all filesnames, mtimes, and content hashes for the unversioned files held by the client. <hr> <li>If the unversioned content hash from the client matches the unversioned |
︙ | ︙ | |||
988 989 990 991 992 993 994 | then sends appropriate "uvgimme" or "uvfile" cards back to the server. <hr> <li>The server updates its unversioned file store with received "uvfile" cards and answers "uvgimme" cards with "uvfile" cards in its reply. </ol> | | | | | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | then sends appropriate "uvgimme" or "uvfile" cards back to the server. <hr> <li>The server updates its unversioned file store with received "uvfile" cards and answers "uvgimme" cards with "uvfile" cards in its reply. </ol> <p>The last two steps might be repeated multiple times if there is more unversioned content to be transferred than will fit comfortably in a single HTTP request. <h2>6.0 Summary</h2> <p>Here are the key points of the synchronization protocol:</p> <ol> <li>The client sends one or more PUSH HTTP requests to the server. The request and reply content type is "application/x-fossil". <li>HTTP request content is compressed using zlib. <li>The content of request and reply consists of cards with one card per line. |
︙ | ︙ | |||
1035 1036 1037 1038 1039 1040 1041 | <li>Clusters are artifacts that contain IDs of other artifacts. <li>Clusters are created automatically on the server during a pull. <li>Repositories keep track of all artifacts that are not named in any cluster and send igot messages for those artifacts. <li>Repositories keep track of all the phantoms they hold and send gimme messages for those artifacts. </ol> | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 944 945 946 947 948 949 950 | <li>Clusters are artifacts that contain IDs of other artifacts. <li>Clusters are created automatically on the server during a pull. <li>Repositories keep track of all artifacts that are not named in any cluster and send igot messages for those artifacts. <li>Repositories keep track of all the phantoms they hold and send gimme messages for those artifacts. </ol> |
Changes to www/tech_overview.wiki.
|
| | > > > | 1 2 3 4 5 6 7 8 9 10 11 | <title>Technical Overview</title> <h2 align="center"> A Technical Overview<br>Of The Design And Implementation<br>Of Fossil </h2> <h2>1.0 Introduction</h2> At its lowest level, a Fossil repository consists of an unordered set of immutable "artifacts". You might think of these artifacts as "files", since in many cases the artifacts are exactly that. But other "structural artifacts" are also included in the mix. |
︙ | ︙ | |||
48 49 50 51 52 53 54 | file that people are normally referring to when they say "a Fossil repository". The checkout database is found in the working checkout for a project and contains state information that is unique to that working checkout. Fossil does not always use all three database files. The web interface, for example, typically only uses the repository database. And the | | | | < < < < | > | | > > > | | > > > | | > > | < < | < | < < < < < < < < < < < | < | < < < < | < < < < < < < < | < < < < < | < < < < < < < < | | < | | | | | < | | | 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 | file that people are normally referring to when they say "a Fossil repository". The checkout database is found in the working checkout for a project and contains state information that is unique to that working checkout. Fossil does not always use all three database files. The web interface, for example, typically only uses the repository database. And the [/help/all | fossil settings] command only opens the configuration database when the --global option is used. But other commands use all three databases at once. For example, the [/help/status | fossil status] command will first locate the checkout database, then use the checkout database to find the repository database, then open the configuration database. Whenever multiple databases are used at the same time, they are all opened on the same SQLite database connection using SQLite's [http://www.sqlite.org/lang_attach.html | ATTACH] command. The chart below provides a quick summary of how each of these database files are used by Fossil, with detailed discussion following. <table border="1" width="80%" cellpadding="0" align="center"> <tr> <td width="33%" valign="top"> <h3 align="center">Configuration Database<br>"~/.fossil"</h3> <ul> <li>Global [/help/settings |settings] <li>List of active repositories used by the [/help/all | all] command </ul> </td> <td width="34%" valign="top"> <h3 align="center">Repository Database<br>"<i>project</i>.fossil"</h3> <ul> <li>[./fileformat.wiki | Global state of the project] encoded using delta-compression <li>Local [/help/settings|settings] <li>Web interface display preferences <li>User credentials and permissions <li>Metadata about the global state to facilitate rapid queries </ul> </td> <td width="33%" valign="top"> <h3 align="center">Checkout Database<br>"_FOSSIL_"</h3> <ul> <li>The repository database used by this checkout <li>The version currently checked out <li>Other versions [/help/merge | merged] in but not yet [/help/commit | committed] <li>Changes from the [/help/add | add], [/help/delete | delete], and [/help/rename | rename] commands that have not yet been committed <li>"mtime" values and other information used to efficiently detect local edits <li>The "[/help/stash | stash]" <li>Information needed to "[/help/undo|undo]" or "[/help/redo|redo]" </ul> </td> </tr> </table> <a name='configdb'></a> <h3>2.1 The Configuration Database</h3> The configuration database holds cross-repository preferences and a list of all repositories for a single user. The [/help/settings | fossil settings] command can be used to specify various operating parameters and preferences for Fossil repositories. Settings can apply to a single repository, or they can apply globally to all repositories for a user. If both a global and a repository value exists for a setting, then the repository-specific value takes precedence. All of the settings have reasonable defaults, and so many users will never need to change them. But if changes to settings are desired, the configuration database provides a way to change settings for all repositories with a single command, rather than having to change the setting individually on each repository. The configuration database also maintains a list of repositories. This list is used by the [/help/all | fossil all] command in order to run various operations such as "sync" or "rebuild" on all repositories managed by a user. On Unix systems, the configuration database is named ".fossil" and is located in the user's home directory. On Windows, the configuration database is named "_fossil" (using an underscore as the first character instead of a dot) and is located in the directory specified by the LOCALAPPDATA, APPDATA, or HOMEPATH environment variables, in that order. You can override this default location by defining the environment variable FOSSIL_HOME pointing to an appropriate (writable) directory. <h3>2.2 Repository Databases</h3> The repository database is the file that is commonly referred to as "the repository". This is because the repository database contains, among other things, the complete revision, ticket, and wiki history for a project. It is customary to name the repository database after then name of the project, with a ".fossil" suffix. For example, the repository database for the self-hosting Fossil repository is called "fossil.fossil" and the repository database for SQLite is called "sqlite.fossil". <h4>2.2.1 Global Project State</h4> The bulk of the repository database (typically 75 to 85%) consists of the artifacts that comprise the [./fileformat.wiki | enduring, global, shared state] of the project. The artifacts are stored as BLOBs, compressed using [http://www.zlib.net/ | zlib compression] and, where applicable, using [./delta_encoder_algorithm.wiki | delta compression]. The combination of zlib and delta compression results in a considerable space savings. For the SQLite project, at the time of this writing, the total size of all artifacts is over 2.0 GB but thanks to the combined zlib and delta compression, that content only takes up 32 MB of space in the repository database, for a compression ratio of about 64:1. The average size of a content BLOB in the database is around 500 bytes. Note that the zlib and delta compression is not an inherent part of the Fossil file format; it is just an optimization. The enduring file format for Fossil is the unordered set of artifacts. The compression techniques are just a detail of how the current implementation of Fossil happens to store these artifacts efficiently on disk. All of the original uncompressed and undeltaed artifacts can be extracted from a Fossil repository database using the [/help/deconstruct | fossil deconstruct] command. Individual artifacts can be extracted using the [/help/artifact | fossil artifact] command. When accessing the repository database using raw SQL and the [/help/sqlite3 | fossil sql] command, the extension function "<tt>content()</tt>" with a single argument which is the SHA1 or SHA3-256 hash of an artifact will return the complete undeleted and uncompressed content of that artifact. Going the other way, the [/help/reconstruct | fossil reconstruct] command will scan a directory hierarchy and add all files found to a new repository database. The [/help/import | fossil import] command works by reading the input git-fast-export stream and using it to construct corresponding artifacts which are then written into the repository database. |
︙ | ︙ | |||
318 319 320 321 322 323 324 | The "shun" table in the repository database records the hash values for all shunned artifacts. The shun table can be pushed or pulled using the [/help/config | fossil config] command with the "shun" AREA argument. The shun table is also copied during a [/help/clone | clone]. | > | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | The "shun" table in the repository database records the hash values for all shunned artifacts. The shun table can be pushed or pulled using the [/help/config | fossil config] command with the "shun" AREA argument. The shun table is also copied during a [/help/clone | clone]. <a name='localdb'></a> <h3>2.3 Checkout Databases</h3> Fossil allows a single repository to have multiple working checkouts. Each working checkout has a single database in its root directory that records the state of that checkout. The checkout database is named "_FOSSIL_" or ".fslckout". The checkout database records information such as the following: |
︙ | ︙ | |||
345 346 347 348 349 350 351 | * State information for the [/help/bisect | bisect] command. For Fossil commands that run from within a working checkout, the first thing that happens is that Fossil locates the checkout database. Fossil first looks in the current directory. If not found there, it looks in the parent directory. If not found there, the parent of the parent. And so forth until either the checkout database is found | | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | * State information for the [/help/bisect | bisect] command. For Fossil commands that run from within a working checkout, the first thing that happens is that Fossil locates the checkout database. Fossil first looks in the current directory. If not found there, it looks in the parent directory. If not found there, the parent of the parent. And so forth until either the checkout database is found or the search reaches the root of the filesystem. (In the latter case, Fossil returns an error, of course.) Once the checkout database is located, it is used to locate the repository database. Notice that the checkout database contains a pointer to the repository database but that the repository database has no record of the checkout databases. That means that a working checkout directory tree can be freely renamed or copied or deleted without consequence. But the |
︙ | ︙ |
Changes to www/th1-hooks.md.
︙ | ︙ | |||
34 35 36 37 38 39 40 | TH1 Hook Related Variables for Web Pages ---------------------------------------- * web\_name -- _Name of web page being rendered._ * web\_args -- _Current web page arguments._ * web\_flags -- _Bitmask of CMDFLAG values for the web page being rendered._ | | | | | | | | | 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 | TH1 Hook Related Variables for Web Pages ---------------------------------------- * web\_name -- _Name of web page being rendered._ * web\_args -- _Current web page arguments._ * web\_flags -- _Bitmask of CMDFLAG values for the web page being rendered._ <a name="cmdReturnCodes"></a>TH1 Hook Related Return Codes for Commands ----------------------------------------------------------------------- * TH\_OK -- _Command will be executed, notification will be executed._ * TH\_ERROR -- _Command will be skipped, notification will be skipped, error message will be emitted._ * TH\_BREAK -- _Command will be skipped, notification will be skipped._ * TH\_RETURN -- _Command will be executed, notification will be skipped._ * TH\_CONTINUE -- _Command will be skipped, notification will be executed._ For commands that are not included in the Fossil binary, allowing their execution will cause the standard "unknown command" error message to be generated, which will typically exit the process. Therefore, adding a new command generally requires using the TH_CONTINUE return code. <a name="webReturnCodes"></a>TH1 Hook Related Return Codes for Web Pages ------------------------------------------------------------------------ * TH\_OK -- _Web page will be rendered, notification will be executed._ * TH\_ERROR -- _Web page will be skipped, notification will be skipped, error message will be emitted._ * TH\_BREAK -- _Web page will be skipped, notification will be skipped._ * TH\_RETURN -- _Web page will be rendered, notification will be skipped._ * TH\_CONTINUE -- _Web page will be skipped, notification will be executed._ For web pages that are not included in the Fossil binary, allowing their rendering will cause the standard "Not Found" error message to be generated, which will cause an HTTP 404 status code to be sent. Therefore, adding a new web page generally requires using the TH_CONTINUE return code. <a name="triggerReturnCodes"></a>Triggering TH1 Return Codes from a Script -------------------------------------------------------------------------- * TH\_OK -- _This is the default return code, nothing special needed._ * TH\_ERROR -- _Use the **error** command._ * TH\_BREAK -- _Use the **break** command._ * TH\_RETURN -- _Use the **return -code 5** command._ * TH\_CONTINUE -- _Use the **continue** command._ <a name="command_hook"></a>TH1 command_hook Procedure ----------------------------------------------------- * command\_hook This user-defined procedure, if present, is called just before the execution of a command. The name of the command being executed will be stored in the "cmd\_name" global variable. The arguments to the command being executed will be stored in the "cmd\_args" global variable. The associated CMDFLAG value will be stored in the "cmd\_flags" global variable. Before exiting, the procedure should trigger the return <a href="#cmdReturnCodes">code</a> that corresponds to the desired action to take next. <a name="command_notify"></a>TH1 command_notify Procedure --------------------------------------------------------- * command\_notify This user-defined procedure, if present, is called just after the execution of a command. The name of the command being executed will be stored in the "cmd\_name" global variable. The arguments to the command being executed will be stored in the "cmd\_args" global variable. The associated CMDFLAG value will be stored in the "cmd\_flags" global variable. Before exiting, the procedure should trigger the return <a href="#cmdReturnCodes">code</a> that corresponds to the desired action to take next. <a name="webpage_hook"></a>TH1 webpage_hook Procedure ----------------------------------------------------- * webpage\_hook This user-defined procedure, if present, is called just before the rendering of a web page. The name of the web page being rendered will be stored in the "web\_name" global variable. The arguments to the web page being rendered will be stored in the "web\_args" global variable. The associated CMDFLAG value will be stored in the "web\_flags" global variable. Before exiting, the procedure should trigger the return <a href="#webReturnCodes">code</a> that corresponds to the desired action to take next. <a name="webpage_notify"></a>TH1 webpage_notify Procedure --------------------------------------------------------- * webpage\_notify This user-defined procedure, if present, is called just after the rendering of a web page. The name of the web page being rendered will be stored in the "web\_name" global variable. The arguments to the web page being rendered will be stored in the "web\_args" global variable. The associated CMDFLAG value will be stored in the "web\_flags" global variable. Before exiting, the procedure should trigger the return <a href="#webReturnCodes">code</a> that corresponds to the desired action to take next. |
Changes to www/th1.md.
︙ | ︙ | |||
10 11 12 13 14 15 16 | TH1 began as a minimalist re-implementation of the Tcl scripting language. There was a need to test the SQLite library on Symbian phones, but at that time all of the test cases for SQLite were written in Tcl and Tcl could not be easily compiled on the SymbianOS. So TH1 was developed as a cut-down version of Tcl that would facilitate running the SQLite test scripts on SymbianOS. | > | < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | TH1 began as a minimalist re-implementation of the Tcl scripting language. There was a need to test the SQLite library on Symbian phones, but at that time all of the test cases for SQLite were written in Tcl and Tcl could not be easily compiled on the SymbianOS. So TH1 was developed as a cut-down version of Tcl that would facilitate running the SQLite test scripts on SymbianOS. The testing of SQLite on SymbianOS was eventually accomplished by other means. But Fossil was first being designed at about the same time. Early prototypes of Fossil were written in pure Tcl. But as the development shifted toward the use of C-code, the need arose to have a Tcl-like scripting language to help with code generation. TH1 was small and light-weight and used minimal resources and seemed ideally suited for the task. The name "TH1" stands "Test Harness 1", since that was its original purpose. |
︙ | ︙ | |||
38 39 40 41 42 43 44 | Each command is terminated by the first *unescaped* newline or ";" character. The text of the command (excluding the newline or semicolon terminator) is broken into space-separated tokens. The first token is the command name and subsequent tokens are the arguments. In this sense, TH1 syntax is similar to the familiar command-line shell syntax. A token is any sequence of characters other than whitespace and semicolons. | | | | < | | | | | | | | | | | | | | | | < < < | 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 | Each command is terminated by the first *unescaped* newline or ";" character. The text of the command (excluding the newline or semicolon terminator) is broken into space-separated tokens. The first token is the command name and subsequent tokens are the arguments. In this sense, TH1 syntax is similar to the familiar command-line shell syntax. A token is any sequence of characters other than whitespace and semicolons. Or, all text without double-quotes is a single token even if it includes whitespace and semicolons. Or, all text without nested {...} pairs is a single token. The nested {...} form of tokens is important because it allows TH1 commands to have an appearance similar to C/C++. It is important to remember, though, that a TH1 script is really just a list of text commands, not a context-free language with a grammar like C/C++. This can be confusing to long-time C/C++ programmers because TH1 does look a lot like C/C++, but the semantics of TH1 are closer to FORTH or Lisp than they are to C. Consider the `if` command in TH1. if {$current eq "dev"} { puts "hello" } else { puts "world" } The example above is a single command. The first token, and the name of the command, is `if`. The second token is `$current eq "dev"` - an expression. (The outer {...} are removed from each token by the command parser.) The third token is the `puts "hello"`, with its whitespace and newlines. The fourth token is `else"` And the fifth and last token is `puts "world"`. The `if` command evaluates its first argument (the second token) as an expression, and if that expression is true, evaluates its second argument (the third token) as a TH1 script. If the expression is false and the third argument is `else`, then the fourth argument is evaluated as a TH1 expression. So, you see, even though the example above spans five lines, it is really just a single command. All of this also explains the emphasis on *unescaped* characters above: the curly braces `{ }` are string quoting characters in Tcl/TH1, not block delimiters as in C. This is how we can have a command that extends over multiple lines. It is also why the `else` keyword must be cuddled up with the closing brace for the `if` clause's scriptlet. The following is invalid Tcl/TH1: if {$current eq "dev"} { puts "hello" } else { puts "world" } If you try to run this under either Tcl or TH1, the interpreter will tell you that there is no `else` command, because with the newline on the third line, you terminated the `if` command. Occasionally in Tcl/TH1 scripts, you may need to use a backslash at the end of a line to allow a command to extend over multiple lines without being considered two separate commands. Here's an example from one of Fossil's test scripts: return [lindex [regexp -line -inline -nocase -- \ {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ $repository "" info trunk]]] end] Those backslashes allow the command to wrap nicely within a standard terminal width while telling the interpreter to consider those three lines as a single command. Summary of Core TH1 Commands ---------------------------- The original Tcl language after when TH1 is modeled has a very rich repertoire of commands. TH1, as it is designed to be minimalist and embedded has a greatly reduced command set. The following bullets summarize the commands available in TH1: * array exists VARNAME * array names VARNAME * break * catch SCRIPT ?VARIABLE? * continue * error ?STRING? * expr EXPR * for INIT-SCRIPT TEST-EXPR NEXT-SCRIPT BODY-SCRIPT * if EXPR SCRIPT (elseif EXPR SCRIPT)* ?else SCRIPT? * info commands * info exists VARNAME * info vars * lindex LIST INDEX * list ARG ... * llength LIST * lsearch LIST STRING * proc NAME ARG-LIST BODY-SCRIPT * rename OLD NEW * return ?-code CODE? ?VALUE? * set VARNAME VALUE * string compare STR1 STR2 * string first NEEDLE HAYSTACK ?START-INDEX? * string index STRING INDEX * string is CLASS STRING * string last NEEDLE HAYSTACK ?START-INDEX? * string length STRING * string range STRING FIRST LAST * string repeat STRING COUNT * unset VARNAME * uplevel ?LEVEL? SCRIPT * upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR? |
︙ | ︙ | |||
166 167 168 169 170 171 172 | TH1 Extended Commands --------------------- There are many new commands added to TH1 and used to access the special features of Fossil. The following is a summary of the extended commands: | | | | < < < < | | < | | < | < | | | | | | | | | | | | | | > > < < < | | | | | | | | | | | | | < | | | | | | | | | | | < | | < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < | < < < < < < < < < < < < < < < < < < | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | TH1 Extended Commands --------------------- There are many new commands added to TH1 and used to access the special features of Fossil. The following is a summary of the extended commands: * anoncap * anycap * artifact * checkout * combobox * date * decorate * dir * enable\_output * encode64 * getParameter * glob\_match * globalState * hascap * hasfeature * html * htmlize * http * httpize * insertCsrf * linecount * markdown * puts * query * randhex * redirect * regexp * reinitialize * render * repository * searchable * setParameter * setting * stime * styleHeader * styleFooter * styleScript * tclEval * tclExpr * tclInvoke * tclIsSafe * tclMakeSafe * tclReady * trace * unversioned content * unversioned list * utime * verifyCsrf * wiki Each of the commands above is documented by a block comment above their implementation in the th\_main.c or th\_tcl.c source files. All commands starting with "tcl", with the exception of "tclReady", require the Tcl integration subsystem be included at compile-time. Additionally, the "tcl" repository setting must be enabled at runtime in order to successfully make use of these commands. <a name="anoncap"></a>TH1 anoncap Command ----------------------------------------- * anoncap STRING... Returns true if the anonymous user has all of the capabilities listed in STRING. <a name="anycap"></a>TH1 anycap Command --------------------------------------- * anycap STRING Returns true if the current user user has any one of the capabilities listed in STRING. <a name="artifact"></a>TH1 artifact Command ------------------------------------------- * artifact ID ?FILENAME? Attempts to locate the specified artifact and return its contents. An error is generated if the repository is not open or the artifact cannot be found. <a name="checkout"></a>TH1 checkout Command ------------------------------------------- * checkout ?BOOLEAN? Return the fully qualified directory name of the current checkout or an empty string if it is not available. Optionally, it will attempt to find the current checkout, opening the configuration ("user") database and the repository as necessary, if the boolean argument is non-zero. <a name="combobox"></a>TH1 combobox Command ------------------------------------------- * combobox NAME TEXT-LIST NUMLINES Generates and emits an HTML combobox. NAME is both the name of the CGI parameter and the name of a variable that contains the currently selected value. TEXT-LIST is a list of possible values for the combobox. NUMLINES is 1 for a true combobox. If NUMLINES is greater than one then the display is a listbox with the number of lines given. <a name="date"></a>TH1 date Command ----------------------------------- * date ?-local? Return a strings which is the current time and date. If the -local option is used, the date appears using localtime instead of UTC. <a name="decorate"></a>TH1 decorate Command ------------------------------------------- * decorate STRING Renders STRING as wiki content; however, only links are handled. No other markup is processed. <a name="dir"></a>TH1 dir Command --------------------------------- * dir CHECKIN ?GLOB? ?DETAILS? Returns a list containing all files in CHECKIN. If GLOB is given only the files matching the pattern GLOB within CHECKIN will be returned. If DETAILS is non-zero, the result will be a list-of-lists, with each element containing at least three elements: the file name, the file size (in bytes), and the file last modification time (relative to the time zone configured for the repository). <a name="enable_output"></a>TH1 enable\_output Command ------------------------------------------------------ * enable\_output BOOLEAN Enable or disable sending output when the combobox, puts, or wiki commands are used. <a name="encode64"></a>TH1 encode64 Command ------------------------------------------- * encode64 STRING Encode the specified string using Base64 and return the result. <a name="getParameter"></a>TH1 getParameter Command --------------------------------------------------- * getParameter NAME ?DEFAULT? Returns the value of the specified query parameter or the specified default value when there is no matching query parameter. <a name="glob_match"></a>TH1 glob\_match Command ------------------------------------------------ * glob\_match ?-one? ?--? patternList string Checks the string against the specified glob pattern -OR- list of glob patterns and returns non-zero if there is a match. <a name="globalState"></a>TH1 globalState Command ------------------------------------------------- * globalState NAME ?DEFAULT? Returns a string containing the value of the specified global state variable -OR- the specified default value. The supported items are: |
︙ | ︙ | |||
482 483 484 485 486 487 488 | 1. **user** -- _Active user name, if any._ 1. **vfs** -- _SQLite VFS in use, if overridden._ Attempts to query for unsupported global state variables will result in a script error. Additional global state variables may be exposed in the future. | | < < | | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | 1. **user** -- _Active user name, if any._ 1. **vfs** -- _SQLite VFS in use, if overridden._ Attempts to query for unsupported global state variables will result in a script error. Additional global state variables may be exposed in the future. <a name="hascap"></a>TH1 hascap Command --------------------------------------- * hascap STRING... Returns true if the current user has all of the capabilities listed in STRING. <a name="hasfeature"></a>TH1 hasfeature Command ----------------------------------------------- * hasfeature STRING Returns true if the binary has the given compile-time feature enabled. The possible features are: |
︙ | ︙ | |||
519 520 521 522 523 524 525 | 1. **dynamicBuild** -- _Dynamically linked to libraries._ 1. **mman** -- _Uses POSIX memory APIs from "sys/mman.h"._ 1. **see** -- _Uses the SQLite Encryption Extension._ Specifying an unknown feature will return a value of false, it will not raise a script error. | | | | | | | | < < < < < < < | | < | | | | | | | | | | | | | | | | < < < < < < < | | | | | | | | | | | < < < < < < < < | | | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | 1. **dynamicBuild** -- _Dynamically linked to libraries._ 1. **mman** -- _Uses POSIX memory APIs from "sys/mman.h"._ 1. **see** -- _Uses the SQLite Encryption Extension._ Specifying an unknown feature will return a value of false, it will not raise a script error. <a name="html"></a>TH1 html Command ----------------------------------- * html STRING Outputs the STRING escaped for HTML. <a name="htmlize"></a>TH1 htmlize Command ----------------------------------------- * htmlize STRING Escape all characters of STRING which have special meaning in HTML. Returns the escaped string. <a name="http"></a>TH1 http Command ----------------------------------- * http ?-asynchronous? ?--? url ?payload? Performs an HTTP or HTTPS request for the specified URL. If a payload is present, it will be interpreted as text/plain and the POST method will be used; otherwise, the GET method will be used. Upon success, if the -asynchronous option is used, an empty string is returned as the result; otherwise, the response from the server is returned as the result. Synchronous requests are not currently implemented. <a name="httpize"></a>TH1 httpize Command ----------------------------------------- * httpize STRING Escape all characters of STRING which have special meaning in URI components. Returns the escaped string. <a name="insertCsrf"></a>TH1 insertCsrf Command ----------------------------------------------- * insertCsrf While rendering a form, call this command to add the Anti-CSRF token as a hidden element of the form. <a name="linecount"></a>TH1 linecount Command --------------------------------------------- * linecount STRING MAX MIN Returns one more than the number of \n characters in STRING. But never returns less than MIN or more than MAX. <a name="markdown"></a>TH1 markdown Command ------------------------------------------- * markdown STRING Renders the input string as markdown. The result is a two-element list. The first element contains the body, rendered as HTML. The second element is the text-only title string. <a name="puts"></a>TH1 puts Command ----------------------------------- * puts STRING Outputs the STRING unchanged. <a name="query"></a>TH1 query Command ------------------------------------- * query ?-nocomplain? SQL CODE Runs the SQL query given by the SQL argument. For each row in the result set, run CODE. In SQL, parameters such as $var are filled in using the value of variable "var". Result values are stored in variables with the column name prior to each invocation of CODE. <a name="randhex"></a>TH1 randhex Command ----------------------------------------- * randhex N Returns a string of N*2 random hexadecimal digits with N<50. If N is omitted, use a value of 10. <a name="redirect"></a>TH1 redirect Command ------------------------------------------- * redirect URL ?withMethod? Issues an HTTP redirect to the specified URL and then exits the process. By default, an HTTP status code of 302 is used. If the optional withMethod argument is present and non-zero, an HTTP status code of 307 is used, which should force the user agent to preserve the original method for the request (e.g. GET, POST) instead of (possibly) forcing the user agent to change the method to GET. <a name="regexp"></a>TH1 regexp Command --------------------------------------- * regexp ?-nocase? ?--? exp string Checks the string against the specified regular expression and returns non-zero if it matches. If the regular expression is invalid or cannot be compiled, an error will be generated. <a name="reinitialize"></a>TH1 reinitialize Command --------------------------------------------------- * reinitialize ?FLAGS? Reinitializes the TH1 interpreter using the specified flags. <a name="render"></a>TH1 render Command --------------------------------------- * render STRING Renders the TH1 template and writes the results. <a name="repository"></a>TH1 repository Command ----------------------------------------------- * repository ?BOOLEAN? Returns the fully qualified file name of the open repository or an empty string if one is not currently open. Optionally, it will attempt to open the repository if the boolean argument is non-zero. <a name="searchable"></a>TH1 searchable Command ----------------------------------------------- * searchable STRING... Return true if searching in any of the document classes identified by STRING is enabled for the repository and user has the necessary capabilities to perform the search. The possible document classes are: 1. **c** -- _Check-in comments_ 1. **d** -- _Embedded documentation_ 1. **t** -- _Tickets_ 1. **w** -- _Wiki_ To be clear, only one of the document classes identified by each STRING needs to be searchable in order for that argument to be true. But all arguments must be true for this routine to return true. Hence, to see if ALL document classes are searchable: if {[searchable c d t w]} {...} But to see if ANY document class is searchable: if {[searchable cdtw]} {...} This command is useful for enabling or disabling a "Search" entry on the menu bar. <a name="setParameter"></a>TH1 setParameter Command --------------------------------------------------- * setParameter NAME VALUE Sets the value of the specified query parameter. <a name="setting"></a>TH1 setting Command ----------------------------------------- * setting name Gets and returns the value of the specified setting. <a name="stime"></a>TH1 stime Command ------------------------------------- * stime Returns the number of microseconds of CPU time consumed by the current process in system space. <a name="styleHeader"></a>TH1 styleHeader Command ------------------------------------------------- * styleHeader TITLE Render the configured style header for the selected skin. <a name="styleFooter"></a>TH1 styleFooter Command ------------------------------------------------- * styleFooter Render the configured style footer for the selected skin. <a name="styleScript"></a>TH1 styleScript Command ------------------------------------------------- * styleScript Render the configured JavaScript for the selected skin. <a name="tclEval"></a>TH1 tclEval Command ----------------------------------------- **This command requires the Tcl integration feature.** * tclEval arg ?arg ...? Evaluates the Tcl script and returns its result verbatim. If a Tcl script error is generated, it will be transformed into a TH1 script error. The Tcl interpreter will be created automatically if it has not been already. <a name="tclExpr"></a>TH1 tclExpr Command ----------------------------------------- **This command requires the Tcl integration feature.** * tclExpr arg ?arg ...? Evaluates the Tcl expression and returns its result verbatim. If a Tcl script error is generated, it will be transformed into a TH1 script error. The Tcl interpreter will be created automatically if it has not been already. <a name="tclInvoke"></a>TH1 tclInvoke Command --------------------------------------------- **This command requires the Tcl integration feature.** * tclInvoke command ?arg ...? Invokes the Tcl command using the supplied arguments. No additional substitutions are performed on the arguments. The Tcl interpreter will be created automatically if it has not been already. <a name="tclIsSafe"></a>TH1 tclIsSafe Command --------------------------------------------- **This command requires the Tcl integration feature.** * tclIsSafe Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter will be created automatically if it has not been already. <a name="tclMakeSafe"></a>TH1 tclMakeSafe Command ------------------------------------------------- **This command requires the Tcl integration feature.** * tclMakeSafe Forces the Tcl interpreter into "safe" mode by removing all "unsafe" commands and variables. This operation cannot be undone. The Tcl interpreter will remain "safe" until the process terminates. The Tcl interpreter will be created automatically if it has not been already. <a name="tclReady"></a>TH1 tclReady Command ------------------------------------------- * tclReady Returns true if the binary has the Tcl integration feature enabled and it is currently available for use by TH1 scripts. <a name="trace"></a>TH1 trace Command ------------------------------------- * trace STRING Generates a TH1 trace message if TH1 tracing is enabled. <a name="unversioned_content"></a>TH1 unversioned content Command ----------------------------------------------------------------- * unversioned content FILENAME Attempts to locate the specified unversioned file and return its contents. An error is generated if the repository is not open or the unversioned file cannot be found. <a name="unversioned_list"></a>TH1 unversioned list Command ----------------------------------------------------------- * unversioned list Returns a list of the names of all unversioned files held in the local repository. An error is generated if the repository is not open. <a name="utime"></a>TH1 utime Command ------------------------------------- * utime Returns the number of microseconds of CPU time consumed by the current process in user space. <a name="verifyCsrf"></a>TH1 verifyCsrf Command ----------------------------------------------- * verifyCsrf Before using the results of a form, first call this command to verify that this Anti-CSRF token is present and is valid. If the Anti-CSRF token is missing or is incorrect, that indicates a cross-site scripting attack. If the event of an attack is detected, an error message is generated and all further processing is aborted. <a name="wiki"></a>TH1 wiki Command ----------------------------------- * wiki STRING Renders STRING as wiki content. Tcl Integration Commands ------------------------ When the Tcl integration subsystem is enabled, several commands are added to the Tcl interpreter. They are used to allow Tcl scripts access to the Fossil functionality provided via TH1. The following is a summary of the Tcl commands: * th1Eval * th1Expr <a name="th1Eval"></a>Tcl th1Eval Command ----------------------------------------- **This command requires the Tcl integration feature.** * th1Eval arg Evaluates the TH1 script and returns its result verbatim. If a TH1 script error is generated, it will be transformed into a Tcl script error. <a name="th1Expr"></a>Tcl th1Expr Command ----------------------------------------- **This command requires the Tcl integration feature.** * th1Expr arg Evaluates the TH1 expression and returns its result verbatim. If a TH1 script error is generated, it will be transformed into a Tcl script error. |
Changes to www/theory1.wiki.
1 2 3 4 5 6 7 8 | <title>Thoughts On The Design Of The Fossil DVCS</title> Two questions (or criticisms) that arise frequently regarding Fossil can be summarized as follows: 1. Why is Fossil based on SQLite instead of a distributed NoSQL database? 2. Why is Fossil written in C instead of a modern high-level language? | > | 1 2 3 4 5 6 7 8 9 | <title>Thoughts On The Design Of The Fossil DVCS</title> <h1 align="center">Thoughts On The Design Of The Fossil DVCS</h1> Two questions (or criticisms) that arise frequently regarding Fossil can be summarized as follows: 1. Why is Fossil based on SQLite instead of a distributed NoSQL database? 2. Why is Fossil written in C instead of a modern high-level language? |
︙ | ︙ |
Changes to www/tickets.wiki.
︙ | ︙ | |||
8 9 10 11 12 13 14 | to a ticket. The act of creating a ticket is considered a change. Each ticket change artifact contains the following information: <ul> <li>The ID of the ticket that was changed | | | | | | 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 | to a ticket. The act of creating a ticket is considered a change. Each ticket change artifact contains the following information: <ul> <li>The ID of the ticket that was changed <li>The timestamp for when the change occurred <li>The user who made the change <li>A list of key/value pairs that show what changed in the ticket </ul> To determine the current state of a particular ticket, Fossil orders the change artifacts for that ticket from oldest to most recent, then applies each change in timestamp order. On each change artifact, there are one or more key/value pairs that implement the change. The key corresponds to a field of the ticket that is modified. The value may either replace the earlier value for that key, or the value may be appended to the prior value. <h2>2.0 Ticket Tables</h2> The low-level artifact format for ticket content is tedious and cumbersome to access in realtime. To facility reporting and display of tickets, the low-level artifact information is collected and summarized in a pair of SQL tables in each local repository. Display and reporting of tickets is accomplished by querying these two tables. Note that only the low-level ticket change artifacts are synced. The content of the two ticket tables can always be reconstructed from the ticket change artifacts. And, indeed, the reconstruction of the ticket tables from low-level artifacts happens automatically whenever new ticket change artifacts are received by the system. The important point to remember is that display of tickets is accomplished using SQL tables but that recording and syncing of ticket information is accomplished using ticket change artifacts. <h3>2.1 Ticket Table Schema</h3> The two ticket tables are called TICKET and TICKETCHNG. The default schema (as of this writing) for these two tables is shown below: <blockquote><verbatim> CREATE TABLE ticket( -- Do not change any column that begins with tkt_ tkt_id INTEGER PRIMARY KEY, tkt_uuid TEXT UNIQUE, tkt_mtime DATE, tkt_ctime DATE, -- Add as many fields as required below this line |
︙ | ︙ | |||
76 77 78 79 80 81 82 | -- Add as many fields as required below this line login TEXT, username TEXT, mimetype TEXT, icomment TEXT ); CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime); | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | -- Add as many fields as required below this line login TEXT, username TEXT, mimetype TEXT, icomment TEXT ); CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime); </verbatim></blockquote> Generally speaking, there is one row in the TICKETCHNG table for each change to each ticket. In other words, there is one row in the TICKETCHNG table for each low-level ticket change artifact. The TICKET table, on the other hand, contains a summary of the current status of each ticket. |
︙ | ︙ | |||
130 131 132 133 134 135 136 | <h3>2.2 Translating Artifacts To Tables</h3> Each row in the TICKETCHNG table corresponds to a single ticket change artifact. The tkt_id field is the integer primary key of the TICKET table entry for the corresponding ticket. The tkt_rid field is the integer primary key for the BLOB table entry that contains the low-level | | | | | 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 | <h3>2.2 Translating Artifacts To Tables</h3> Each row in the TICKETCHNG table corresponds to a single ticket change artifact. The tkt_id field is the integer primary key of the TICKET table entry for the corresponding ticket. The tkt_rid field is the integer primary key for the BLOB table entry that contains the low-level artifact text. The tkt_mtime field is the timestamp on the ticket change artifact, expressed as a julian day number. If the ticket change artifact contains a key/value pair where the key is "login", then the corresponding value is stored in the login field of the TICKETCHNG table. The same it true for "username", "mimetype", and "icomment" fields. Any time there is a key/value pair in the ticket change artifact and the key corresponds to the name of a field in the TICKETCHNG table, then the value of that key/value pair is stored in the TICKETCHNG table. If the TICKETCHNG table has a field for which there is no corresponding key/value pair in the artifact, then that field of the TICKETCHNG table is NULL. If there are key/value pairs in the artifact that have no corresponding field in the TICKETCHNG table, those key/value pairs are silently ignored. Each row in the TICKET table records the overall status of a ticket. The tkt_id field is a unique integer primary key for the ticket. the tkt_uuid field is the global ticket identifier - a larger random hexadecimal constant. The tkt_mtime and tkt_ctime fields hold the times of the most recent and the oldest ticket change artifacts for this ticket, respectively. To reconstruct the TICKET table, the ticket change artifacts are visited in timestamp order. As each ticket change artifact is visited, its key/value pairs are examined. For any key/value pair in which the key is the same as a field in the TICKET table, the value of that pair either replaces or is appended to the previous value of the corresponding field in the TICKET table. Whether a value is replaced or appended is determined by markings in the ticket change artifact itself. Most fields are usually replaced. (For example, to change the status from "Open" to "Fixed" would involve a key value pair |
︙ | ︙ | |||
192 193 194 195 196 197 198 | support the "new-style" tickets. The TICKETCHNG table was added to support new-style tickets. In the new style, comment text is stored with the "icomment" (for "Incremental Comment") key and appears separately, and with its on mimetype, in multiple rows of the TICKETCHNG table. It then falls to the TH1 script code on the View Ticket Page to query the TICKETCHNG table and extract and format | | | 192 193 194 195 196 197 198 199 | support the "new-style" tickets. The TICKETCHNG table was added to support new-style tickets. In the new style, comment text is stored with the "icomment" (for "Incremental Comment") key and appears separately, and with its on mimetype, in multiple rows of the TICKETCHNG table. It then falls to the TH1 script code on the View Ticket Page to query the TICKETCHNG table and extract and format the various comments in timestamp order. |
Deleted www/tls-nginx.md.
|
| < < < |
Changes to www/uitest.html.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ////////////////////////////////////////////////////////////////////////// { url: "timeline", desc: "Simple timeline of most recent check-ins. Verify that all submenus work." }, { | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ////////////////////////////////////////////////////////////////////////// { url: "timeline", desc: "Simple timeline of most recent check-ins. Verify that all submenus work." }, { url: "timeline?n=125", desc: "Timeline with 125 entries. Verify that submenus preserve the entry count." }, { url: "wiki", desc: "The wiki homepage" |
︙ | ︙ |
Changes to www/unvers.wiki.
1 2 3 | <title>Unversioned Content</title> "Unversioned content" or "unversioned files" are | > | | | | | < | | | | | | | > | | | | | > < < < < < < < < < | | | < | | | | | | < > | < < < < | < < | | | | 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 | <title>Unversioned Content</title> <h1 align="center">Unversioned Content</h1> "Unversioned content" or "unversioned files" are files stored in a Fossil repository without history. Only the newest version of each unversioned file is retained. Though history is omitted, unversioned content is synced between respositories. In the event of a conflict during a sync, the most recent version of each unversioned file is retained and older versions are discarded. Unversioned files are useful for storing ephemeral content such as builds or frequently changing web pages. The [https://www.fossil-scm.org/fossil/uv/download.html|download] page of the self-hosting Fossil repository is stored as unversioned content, for example. <h2>Accessing Unversioned Files</h2> Unversioned files are <u>not</u> a part of a check-out. Unversioned files are intended to be accessible as web pages using URLs of the form: "http://domain/cgi-script/<b>uv</b>/<i>FILENAME</i>". In other words, the URI method "<b>uv</b>" (short for "unversioned") followed by the name of the unversioned file will retrieve the content of the file. The mimetype is inferred from the filename suffix. The content of unversioned files can also be retrieved using the [/help?cmd=unversioned|fossil unvers cat <i>FILENAME</i>] command. A list of all unversioned files on a server can be seen using the [/help?cmd=/uvlist|/uvlist] URL. ([/uvlist|example]). <h2>Syncing Unversioned Files</h2> Unversioned content is synced between respositories, though not by default. Special commands or command-line options are required. Unversioned content can be synced using the following commands: <blockquote><pre> fossil sync <b>-u</b> fossil clone <b>-u</b> <i>URL local-repo-name</i> fossil unversioned sync </pre></blockquote> The [/help?cmd=sync|fossil sync] and [/help?cmd=clone|fossil clone] commands will synchronize unversioned content if and only if the "-u" (or "--unversioned") command-line option is supplied. The [/help?cmd=unversioned|fossil unversioned sync] command will synchronize the unversioned content without synchronizing anything else. Notice that the "-u" option does not work on [/help?cmd=push|fossil push] or [/help?cmd=pull|fossil pull]. The "-u" option is only available on "sync" and "clone". A rough equivalent of an unversioned pull would be the [/help?cmd=unversioned|fossil unversioned revert] command. The "unversioned revert" command causes the unversioned content on the local repository to overwritten by the unversioned content found on the remote repository. <h2>Implementation Details</h2> <i>(This section outlines the current implementation of unversioned files. This is not an interface spec and hence subject to change.)</i> Unversioned content is stored in the repository in the "unversioned" table: <blockquote><pre> CREATE TABLE unversioned( uvid INTEGER PRIMARY KEY AUTOINCREMENT, -- unique ID for this file name TEXT UNIQUE, -- Name of the file rcvid INTEGER, -- From whence this file was received mtime DATETIME, -- Last change (seconds since 1970) hash TEXT, -- SHA1 hash of uncompressed content sz INTEGER, -- Size of uncompressed content encoding INT, -- 0: plaintext 1: zlib compressed content BLOB -- File content ); </pre></blockquote> If there are no unversioned files in the repository, then the "unversioned" table does not necessarily exist. A simple way to purge all unversioned content from a repository is to run: <blockquote><pre> fossil sql "DROP TABLE unversioned; VACUUM;" </pre></blockquote> No delta compression is performed on unversioned files, since there is no history to delta against. Unversioned content is exchanged between servers as whole, uncompressed files (though the content does get compressed when the overall HTTP message payload is compressed). SHA1 hash exchanges are used to avoid sending content over the wire unnecessarily. See the [./sync.wiki|synchronization protocol documentation] for further information. |
Deleted www/userlinks.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/webpage-ex.md.
1 2 3 4 5 6 | Web-Page Examples ================= Here are just a few examples of the many web pages supported by Fossil. Follow hyperlinks on the examples below to see many other examples. | > > > > > > > | > > | | | | < < < < | | | | | | | | | | | | | | | | | | | | | | | 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 | Web-Page Examples ================= Here are just a few examples of the many web pages supported by Fossil. Follow hyperlinks on the examples below to see many other examples. <style> .exbtn { border: 1px solid #000; margin: 1ex; border-radius: 1ex; padding: 0 1ex; background-color: #eee; } </style> * <a target='_blank' class='exbtn' href='$ROOT/timeline?y=ci&n=100'>Example</a> 100 most recent check-ins. * <a target='_blank' class='exbtn' href='$ROOT/finfo?name=src/file.c'>Example</a> All changes to the <b>src/file.c</b> source file. * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=200&uf=0c3c2d086a'>Example</a> All check-ins using a particular version of the <b>src/file.c</b> source file. * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=11&y=ci&c=2014-01-01'>Example</a> Check-ins proximate to an historical point in time (2014-01-01). * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=11&y=ci&c=2014-01-01&v=1'>Example</a> The previous example augmented with file changes. * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=25&y=ci&a=1970-01-01'>Example</a> First 25 check-ins after 1970-01-01. (The first 25 check-ins of the project.) * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=200&r=svn-import'>Example</a> All check-ins of the "svn-import" branch together with check-ins that merge with that branch. * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=200&t=svn-import'>Example</a> All check-ins of the "svn-import" branch only. * <a target='_blank' class='exbtn' href='$ROOT/timeline?n=100&y=ci&ubg'>Example</a> 100 most recent check-ins color coded by committer rather than by branch. * <a target='_blank' class='exbtn' href='$ROOT/timeline?from=version-1.27&to=version-1.28'>Example</a> All check-ins on the most direct path from version-1.27 to version-1.28 * <a target='_blank' class='exbtn' href='$ROOT/timeline?namechng'>Example</a> Show check-ins that contain file name changes * <a target='_blank' class='exbtn' href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>Example</a> Show check-ins circa 2014-01-08 by user "drh". * <a target='_blank' class='exbtn' href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>Example</a> Show all check-ins between version-1.34 and version-1.35 that make changes to either of the files src/timeline.c or src/doc.c. <big><b>→</b></big> (Hint: In the pages above, click the graph nodes for any two check-ins or files to see a diff.) <big><b>←</b></big> * <a target='_blank' class='exbtn' href='$ROOT/search?s=interesting+pages'>Example</a> Full-text search for "interesting pages". * <a target='_blank' class='exbtn' href='$ROOT/tree?ci=daff9d20621&type=tree'>Example</a> All files for a particular check-in (daff9d20621480) * <a target='_blank' class='exbtn' href='$ROOT/tree?ci=trunk&type=tree&mtime=1'>Example</a> All files for the latest check-in on a branch (trunk) sorted by last modification time. * <a target='_blank' class='exbtn' href='$ROOT/fileage?name=svn-import'>Example</a> Age of all files in the latest checking for branch "svn-import". * <a target='_blank' class='exbtn' href='$ROOT/brlist'>Example</a> Table of branches. (Click on column headers to sort.) * <a target='_blank' class='exbtn' href='$ROOT/stat'>Example</a> Overall repository status. * <a target='_blank' class='exbtn' href='$ROOT/reports?type=ci&view=byuser'>Example</a> Number of check-ins per committer. * <a target='_blank' class='exbtn' href='$ROOT/reports?view=byfile'>Example</a> Number of check-ins for each source file. (Click on column headers to sort.) * <a target='_blank' class='exbtn' href='$ROOT/blame?checkin=5260fbf63287&filename=src/rss.c&limit=-1'> Example</a> Most recent change to each line of a particular source file in a particular check-in. * <a target='_blank' class='exbtn' href='$ROOT/taglist'>Example</a> List of tags on check-ins. * <a target='_blank' class='exbtn' href='$ROOT/bigbloblist'>Example</a> The largest objects in the repository. * <a target='_blank' class='exbtn' href='$ROOT/hash-collisions'>Example</a> Hash prefix collisions * <a target='_blank' class='exbtn' href='$ROOT/sitemap'>Example</a> The "sitemap" containing links to many other pages |
Changes to www/webui.wiki.
1 2 3 4 5 6 7 8 9 10 | <title>The Fossil Web Interface</title> One of the innovative features of Fossil is its built-in web interface. This web interface provides everything you need to run a software development project: * [./bugtheory.wiki | Ticketing and bug tracking] * [./wikitheory.wiki | Wiki] * [./embeddeddoc.wiki | On-line documentation] * [./event.wiki | Technical notes] | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <title>The Fossil Web Interface</title> One of the innovative features of Fossil is its built-in web interface. This web interface provides everything you need to run a software development project: * [./bugtheory.wiki | Ticketing and bug tracking] * [./wikitheory.wiki | Wiki] * [./embeddeddoc.wiki | On-line documentation] * [./event.wiki | Technical notes] * Timelines * Full text search over all of the above * Status information * Graphs of revision and branching history * File and version lists and differences * Download historical versions as ZIP archives * Historical change data |
︙ | ︙ | |||
30 31 32 33 34 35 36 | As an example of how useful this web interface can be, the entire [./index.wiki | Fossil website], including the document you are now reading, is rendered using the Fossil web interface, with no enhancements, and little customization. | | | | | | | | 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 | As an example of how useful this web interface can be, the entire [./index.wiki | Fossil website], including the document you are now reading, is rendered using the Fossil web interface, with no enhancements, and little customization. <blockquote> <b>Key point:</b> <i>The Fossil website is just a running instance of Fossil! </blockquote> Note also that because Fossil is a distributed system, you can run the web interface on your local machine while off network (for example, while on an airplane) including making changes to wiki pages and/or trouble ticket, then synchronize with your co-workers after you reconnect. When you clone a Fossil repository, you don't just get the project source code, you get the entire project management website. <h2>Drop-Dead Simple Startup</h2> To start using the built-in Fossil web interface on an existing Fossil repository, simply type this: <b>fossil ui existing-repository.fossil</b> Substitute the name of your repository, of course. The "ui" command will start a webserver running (it figures out an available TCP port to use on its own) and then automatically launches your web browser to point at that server. If you run the "ui" command from within an open check-out, you can omit the repository name: <b>fossil ui</b> The latter case is a very useful short-cut when you are working on a Fossil project and you want to quickly do some work with the web interface. Notice that Fossil automatically finds an unused TCP port to run the server on and automatically points your web browser to the correct URL. So there is never any fumbling around trying to find an open port or to type arcane strings into your browser URL entry box. |
︙ | ︙ | |||
97 98 99 100 101 102 103 | to let anonymous users on the internet write their own ticket formats if you like. In addition to viewing and/or creating report formats, you can also create new tickets or look at summaries or complete histories of existing tickets. Any changes you make will automatically merge with changes from your co-workers the next time your repository is synchronized. You can view and edit <b>wiki</b> by following the "Wiki" link on the | | | | | | 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 | to let anonymous users on the internet write their own ticket formats if you like. In addition to viewing and/or creating report formats, you can also create new tickets or look at summaries or complete histories of existing tickets. Any changes you make will automatically merge with changes from your co-workers the next time your repository is synchronized. You can view and edit <b>wiki</b> by following the "Wiki" link on the menu bar. Fossil uses simple and easy-to-remember [/wiki_rules | wiki formatting rules] so you won't have to spend a lot of time learning a new markup language. And, as with tickets, all of your edits will automatically merge with those of your co-workers when your repository synchronizes. You can view summary reports of <b>branches</b> in the check-in graph by visiting the "Branches" link on the menu bar. From those pages you can follow hyperlinks to get additional details. These screens allow you to easily keep track of what is going on with separate subteams within your project team. The "Files" link on the menu allows you to browse through the <b>file hierarchy</b> of the project and to view complete changes histories on individual files, with hyperlinks to the check-ins that made those changes, and with diffs and annotated diffs between versions. The web interface supports [./embeddeddoc.wiki | embedded documentation]. |
︙ | ︙ | |||
129 130 131 132 133 134 135 | Users with appropriate permissions can customize the look and feel of the web interface using the "Admin" link on the main menu of the web interface. Templates for the header and footer of each page can be edited, as can the CSS for the entire page. You can even change around the main menu. Timeline display preferences can be edited. The page that is brought up as the "Home" page can be changed. It is often useful to set the | | < < < < < < < < < > | | > > | | > | 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 | Users with appropriate permissions can customize the look and feel of the web interface using the "Admin" link on the main menu of the web interface. Templates for the header and footer of each page can be edited, as can the CSS for the entire page. You can even change around the main menu. Timeline display preferences can be edited. The page that is brought up as the "Home" page can be changed. It is often useful to set the "Home" page to be a wiki page or an embedded document. <h2>Installing On A Network Server</h2> When you create a new Fossil project and after you have configured it like you want it using the web interface, you can make the project available to a distributed team by simply copying the single repository file up to a web server that supports CGI or SCGI. To run Fossil as CGI, just put the <b>sample-project.fossil</b> file in a directory where CGI scripts have both read and write permission on the file and the directory that contains the file, then add a CGI script that looks something like this: <verbatim> #!/usr/local/bin/fossil repository: /home/www/sample-project.fossil </verbatim> Adjust the script above so that the paths are correct for your system, of course, and also make sure the Fossil binary is installed on the server. But that is <u>all</u> you have to do. You now have everything you need to host a distributed software development project in less than five minutes using a two-line CGI script. Instructions for setting up an SCGI server are [./scgi.wiki | available separately]. You don't have a CGI- or SCGI-capable web server running on your server machine? Not a problem. The Fossil interface can also be launched via inetd or xinetd. An inetd configuration line sufficient to launch the Fossil web interface looks like this: <verbatim> 80 stream tcp nowait.1000 root /usr/local/bin/fossil \ /usr/local/bin/fossil http /home/www/sample-project.fossil </verbatim> As always, you'll want to adjust the pathnames to whatever is appropriate for your system. The xinetd setup uses a different syntax but follows the same idea. |
Deleted www/whyallinone.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/whyusefossil.wiki.
|
| | | | | > > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <title>Why Use Fossil</title> <h1 align='center'>Why You Should Use Fossil</h1> <p align='center'><b>Or, if not Fossil, at least some kind of modern version control<br>such as Git, Mercurial, or Subversion.</b></p> <p align='center'>(Presented in outline form, for people in a hurry)</p> <ol> <li><p><b>Benefits of Version Control</b> <ol type='A'> <li><p><b>Immutable file and version identification</b> <ol type='i'> <li>Simplified and unambiguous communication between developers <li>Detect accidental or surreptitious changes <li>Locate the origin of discovered files </ol> |
︙ | ︙ | |||
34 35 36 37 38 39 40 | <ol type='i'> <li>Everyone always has the latest code <li>Failed disk-drives cause no loss of work <li>Avoid wasting time doing manual file copying <li>Avoid human errors during manual backups </ol> </ol> | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | < < < | | | | | | | | < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | <ol type='i'> <li>Everyone always has the latest code <li>Failed disk-drives cause no loss of work <li>Avoid wasting time doing manual file copying <li>Avoid human errors during manual backups </ol> </ol> <a name='definitions'></a> <li><p><b>Definitions</b></p> <ul> <li><p><b>Project</b> → a collection of computer files that serve some common purpose. Often the project is a software application and the individual files are source code together with makefiles, scripts, and "README.txt" files. Other examples of projects include books or manuals in which each chapter or section is held in a separate file. <ul> <li><p>Projects change and evolve. The whole purpose of version control is to track and manage that evolution. <li><p>Most projects contain many files, but it is possible to have a project consisting of just a single file. <li><p>Fossil requires that all the files for a project must be collected into a single directory hierarchy - a single folder possibly with layers of subfolders. Fossil is not a good choice for managing a project that has files scattered hither and yon all over the disk. In other words, Fossil only works for projects where the files are laid out such that they can be archived into a ZIP file or tarball. </ul> <li><p><b>Repository</b> → (also called "repo") a single file that contains all historical versions of all files in a project. A repo is similar to a ZIP archive in that it is a single file that stores compressed versions of many other files. Files can be extracted from the repo and new files can be added to the repo, just as with a ZIP archive. But a repo has other capabilities above and beyond what a ZIP archive can do. <ul> <li><p>Fossil does not care what you name your repository files, though names ending with ".fossil" are recommended. <li><p>A single project typically has multiple, redundant repositories on separate machines. <li><p>All repositories stay synchronized with one another by exchanging information via HTTP or SSH. <li><p>All repos for a single project redundantly store all information about that project. So if any one repo is lost due to a disk crash, all content is preserved in the surviving repos. <li><p>The usual arrangement is one repository per user. And since most users these days have their own computer, that means one repository per computer. But this is not a requirement. It is ok to have multiple copies of the same repository on the same computer. <li><p>Fossil works fine with just a single copy of the repository. But in that case there is no redundancy. If that one repository file is lost due to a hardware malfunction, then there is no way to recover the project. <li><p>Best practice is to keep all repositories for a user in a single folder. Folders such as "~/Fossils" or "%USERPROFILE%\Fossils" are recommended. Fossil itself does not care where the repositories are stored. Nor does Fossil require repositories to be kept in the same folder. But it is easier to organize your work if all repositories are kept in the same place. </ul> <li><p><b>Check-out</b> → a set of files that have been extracted from a repository and that represent a particular version or snapshot of the project. <ul> <li><p>Check-outs must be on the same computer as the repository from which they are extracted. This is just like with a ZIP archive: one must have the ZIP archive file on the local machine before extracting files from ZIP archive. <li><p>There can be multiple check-outs (in different folders) from the same repository. <li><p>The repository must be on the same computer as the check-out, but the relative locations of the repo and the check-out are arbitrary. The repository may be located inside the folder holding the check-out, but it certainly does not have to be and usually is not. <li><p>A special file exists in every check-out that tells Fossil from which repository the check-out was extracted, and which version of the project the check-out represents. This is the ".fslckout" file on unix systems or the "_FOSSIL_" file on Windows. </ul> <li><p><b>Check-in</b> → another name for a particular version of the project. A check-in is a collection of files inside of a repository that represent a snapshot of the project for an instant in time. Check-ins exist only inside of the repository. This contrasts with a check-out which is a collection of files outside of the repository. <ul> <li><p>Every check-out knows the check-in from which it was derived. But check-outs might have been edited and so might not exactly match their associated check-in. <li><p>Check-ins are immutable. They can never be changed. But check-outs are collections of ordinary files on disk. The files of a check-out can be edited just like any other file. <li><p>A check-in can be thought of as an historical snapshot of a check-out. <li><p>"Check-in", "version", "snapshot", and "revision" are synonyms. <li><p> When used as a noun, the word "commit" is another synonym for "check-in". When used as a verb, the word "commit" means to create a new check-in. </ul> </ul> <li><p><b>Basic Fossil commands</b> <ul> <li><p><b>clone</b> → Make a copy of a repository. The original repository is usually (but not always) on a remote machine and the copy is on the local machine. The copy remembers the network location from which it was copied and (by default) tries to keep itself synchronized with the original. <li><p><b>open</b> → Create a new check-out from a repository on the local machine. <li><p><b>update</b> → Modify an existing check-out so that it is derived from a different version of the same project. <li><p><b>commit</b> → Create a new version (a new check-in) of the project that is a snapshot of the current check-out. <li><p><b>revert</b> → Undo all local edits on a check-out. Make the check-out be an exact copy of its associated check-in. <li><p><b>push</b> → Copy content found in a local repository over to a remote repository. (Fossil usually does this automatically in response to a "commit" and so this command is seldom used, but it is important to understand it.) <li><p><b>pull</b> → Copy new content found in a remote repository into a local repository. A "pull" by itself does not modify any check-out. The "pull" command only moves content between repositories. However, the "update" command will (often) automatically do a "pull" before attempting to update the local check-out. <li><p><b>sync</b> → Do both a "push" and a "pull" at the same time. <li><p><b>add</b> → Add a new file to the local check-out. The file must already be on disk. This command tells Fossil to start tracking and managing the file. This command affects only the local check-out and does not modify any repository. The new file is inserted into the repository at the next "commit" command. <li><p><b>rm/mv</b> → Short for 'remove' and 'move', these commands are like "add" in that they specify pending changes to the structure of the check-out. As with "add", no changes are made to the repository until the next "commit". </ul> <li><p><b>The history of a project is a Directed Acyclic Graph (DAG)</b> <ul> <li><p>Fossil (and other distributed VCSes like Git and Mercurial, but not Subversion) represent the history of a project as a directed acyclic graph (DAG). <ul> <li><p>Each check-in is a node in the graph <li><p>If check-in X is derived from check-in Y then there is an arc in the graph from node X to node Y. <li><p>The older check-in (X) is call the "parent" and the newer check-in (Y) is the "child". The child is derived from the parent. </ul> <li><p>Two users (or the same user working in different check-outs) might commit different changes against the same check-in. This results in one parent node having two or more children. <li><p>Command: <b>merge</b> → combines the work of multiple check-ins into a single check-out. That check-out can then be committed to create a new that has two (or more) parents. <ul> <li><p>Most check-ins have just one parent, and either zero or one child. <li><p>When a check-in has two or more parents, one of those parents is the "primary parent". All the other parent nodes are "secondary". Conceptually, the primary parent shows the main line of development. Content from the secondary parents is added into the main line. <li><p>The "direct children" of a check-in X are all children that have X as their primary parent. <li><p>A check-in node with no direct children is sometimes called a "leaf". <li><p>The "merge" command changes only the check-out. The "commit" command must be run subsequently to make the merge a permanent part of project. </ul> <li><p>Definition: <b>branch</b> → a sequence of check-ins that are all linked together in the DAG through the primary parent. <ul> <li><p>Branches are often given names which propagate to direct children. <li><p>It is possible to have multiple branches with the same name. Fossil has no problem with this, but it can be confusing to humans, so best practice is to give each branch a unique name. <li><p>The name of a branch can be changed by adding special tags to the first check-in of a branch. The name assigned by this special tag automatically propagates to all direct children. </ul> </ul> <li><p><b>Why version control is important (reprise)</b> <ol type="A"> <li><p>Every check-in and every individual file has a unique name - its SHA1 or SHA3-256 hash. Team members can unambiguously identify any specific version of the overall project or any specific version of an individual file. <li><p>Any historical version of the whole project or of any individual file can be easily recreated at any time and by any team member. <li><p>Accidental changes to files can be detected by recomputing their cryptographic hash. <li><p>Files of unknown origin can be identified using their hash. <li><p>Developers are able to work in parallel, review each others work, and easily merge their changes together. External revisions to the baseline can be easily incorporated into the latest changes. <li><p>Developers can follow experimental lines of development, then revert back to an earlier stable version if the experiment does not work out. Creativity is enhanced by allowing crazy ideas to be investigated without destabilizing the project. <li><p>Developers can work on several independent subprojects, flipping back and forth from one subproject to another at will, and merge patches together or back into the main line of development as they mature. <li><p>Older changes can be easily backed out of recent revisions, for example if bugs are found long after the code was committed. <li><p>Enhancements in a branch can be easily copied into other branches, or into the trunk. <li><p>The complete history of all changes is plainly visible to all team members. Project leaders can easily keep track of what all team members are doing. Check-in comments help everyone to understand and/or remember the reason for each change. <li><p>New team members can be brought up-to-date with all of the historical code, quickly and easily. <li><p>New developers, interns, or inexperienced staff members who still do not understand all the details of the project or who are otherwise prone to making mistakes can be assigned significant subprojects to be carried out in branches without risking main line stability. <li><p>Code is automatically synchronized across all machines. No human effort is wasted copying files from machine to machine. The risk of human errors during file transfer and backup is eliminated. <li><p>A hardware failure results in minimal lost work because all previously committed changes will have been automatically replicated on other machines. <li><p>The complete work history of the project is conveniently archived in a single file, simplifying long-term record keeping. <li><p>A precise historical record is maintained which can be used to support copyright and patent claims or regulatory compliance. </ol> </ol> |
Changes to www/wikitheory.wiki.
1 2 3 4 5 6 7 8 | <title>Wiki In Fossil</title> <h2>Introduction</h2> Fossil uses [/wiki_rules | Fossil wiki markup] and/or [/md_rules | Markdown markup] for many things: * Stand-alone wiki pages. * Description and comments in [./bugtheory.wiki | bug reports]. | | < < < | | 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 | <title>Wiki In Fossil</title> <h2>Introduction</h2> Fossil uses [/wiki_rules | Fossil wiki markup] and/or [/md_rules | Markdown markup] for many things: * Stand-alone wiki pages. * Description and comments in [./bugtheory.wiki | bug reports]. * Check-in comments. * [./embeddeddoc.wiki | Embedded documentation] files whose name ends in ".wiki" or ".md" or ".markdown". * [./event.wiki | Technical notes]. The [/wiki_rules | formatting rules for fossil wiki] are designed to be simple and intuitive. The idea is that wiki provides paragraph breaks, numbered and bulleted lists, and hyperlinking for simple documents together with a safe subset of HTML for more complex formatting tasks. The [/md_rules | Markdown formatting rules] are more complex, but are also more widely known, and are thus provided as an alternative. <h2>Stand-alone Wiki Pages</h2> Each wiki page has its own revision history which is independent of the sequence of check-ins (check-ins). Wiki pages can branch and merge just like check-ins, though as of this writing (2008-07-29) there is no mechanism in the user interface to support branching and merging. The current implementation of the wiki shows the version of the wiki page that has the most recent timestamp. In other words, if two users make unrelated changes to the same wiki page on separate repositories and those repositories are synced, the wiki page will fork. The web interface will display whichever edit was checked in last. The other edit can be found in the history. The file format will support merging the branches back together, but there is no mechanism in the user interface (yet) to perform the merge. |
︙ | ︙ | |||
57 58 59 60 61 62 63 | so that only developers with check-in privileges can change it. Embedded documentation serves this latter purpose. Both forms of documentation use the exact same markup. Some projects may choose to use both forms of documentation at the same time. Because the same format is used, it is trivial to move a file from wiki to embedded documentation or back again as the project evolves. | | | | < | | < < < < < < < < < < < < < < < < < < < < | 54 55 56 57 58 59 60 61 62 63 64 65 66 | so that only developers with check-in privileges can change it. Embedded documentation serves this latter purpose. Both forms of documentation use the exact same markup. Some projects may choose to use both forms of documentation at the same time. Because the same format is used, it is trivial to move a file from wiki to embedded documentation or back again as the project evolves. <h2>Bug-reports and check-in comments</h2> The comments on check-ins and the text in the descriptions of bug reports both use wiki formatting. Exactly the same set of formatting rules apply. There is never a need to learn one formatting language for documentation and a different markup for bugs or for check-in comments. |
Deleted www/wsl_caveats.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |