From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- tools/co-rsync.tcl | 72 + tools/codecheck1.c | 700 ++++ tools/copland/dist/copland-skin.config | 827 +++++ tools/copland/package-lock.json | 549 +++ tools/copland/package.json | 15 + tools/copland/playwright.config.mjs | 20 + tools/copland/scripts/build-config.mjs | 30 + tools/copland/scripts/create-demo.sh | 113 + tools/copland/scripts/fossil-env.sh | 42 + tools/copland/scripts/install-repolist.sh | 34 + tools/copland/scripts/install.sh | 24 + tools/copland/scripts/preview.sh | 31 + tools/copland/src/copland.scss | 443 +++ tools/copland/tests/fixtures/org/all.html | 50 + tools/copland/tests/fixtures/org/all.org | 52 + tools/copland/tests/fixtures/org/all.txt | 66 + tools/copland/tests/fixtures/org/security.html | 9 + tools/copland/tests/fixtures/org/security.org | 13 + tools/copland/tests/org-renderer.sh | 30 + tools/copland/tests/serve-fixture.sh | 18 + tools/copland/tests/smoke.sh | 188 ++ tools/copland/tests/visual.spec.mjs | 94 + .../visual.spec.mjs-snapshots/home-dark-linux.png | Bin 0 -> 21720 bytes .../visual.spec.mjs-snapshots/home-light-linux.png | Bin 0 -> 21117 bytes .../visual.spec.mjs-snapshots/login-dark-linux.png | Bin 0 -> 33606 bytes .../login-light-linux.png | Bin 0 -> 32850 bytes .../org-document-dark-linux.png | Bin 0 -> 68961 bytes .../org-document-light-linux.png | Bin 0 -> 67587 bytes .../org-document-mobile-linux.png | Bin 0 -> 53550 bytes .../org-wiki-dark-linux.png | Bin 0 -> 42595 bytes .../org-wiki-light-linux.png | Bin 0 -> 41174 bytes .../org-wiki-mobile-linux.png | Bin 0 -> 31636 bytes .../repository-list-dark-linux.png | Bin 0 -> 16492 bytes .../repository-list-light-linux.png | Bin 0 -> 15656 bytes .../timeline-dark-linux.png | Bin 0 -> 46898 bytes .../timeline-light-linux.png | Bin 0 -> 45662 bytes .../timeline-mobile-linux.png | Bin 0 -> 35066 bytes .../visual.spec.mjs-snapshots/tree-dark-linux.png | Bin 0 -> 50142 bytes .../visual.spec.mjs-snapshots/tree-light-linux.png | Bin 0 -> 48683 bytes tools/cvs2fossil/changeset | 119 + tools/cvs2fossil/cvs2fossil | 32 + tools/cvs2fossil/doc/LICENSE | 19 + tools/cvs2fossil/doc/README | 7 + tools/cvs2fossil/filerevtree | 178 + tools/cvs2fossil/getmemoryseries.tcl | 69 + tools/cvs2fossil/lib/c2f_blobstore.tcl | 155 + tools/cvs2fossil/lib/c2f_cyclebreaker.tcl | 579 ++++ tools/cvs2fossil/lib/c2f_file.tcl | 1452 ++++++++ tools/cvs2fossil/lib/c2f_fossil.tcl | 273 ++ tools/cvs2fossil/lib/c2f_frev.tcl | 552 +++ tools/cvs2fossil/lib/c2f_fsym.tcl | 325 ++ tools/cvs2fossil/lib/c2f_ftrunk.tcl | 57 + tools/cvs2fossil/lib/c2f_gtcore.tcl | 239 ++ tools/cvs2fossil/lib/c2f_integrity.tcl | 964 ++++++ tools/cvs2fossil/lib/c2f_option.tcl | 284 ++ tools/cvs2fossil/lib/c2f_pass.tcl | 243 ++ tools/cvs2fossil/lib/c2f_patopsort.tcl | 210 ++ tools/cvs2fossil/lib/c2f_pbreakacycle.tcl | 433 +++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl | 126 + tools/cvs2fossil/lib/c2f_pbreakscycle.tcl | 126 + tools/cvs2fossil/lib/c2f_pcollar.tcl | 337 ++ tools/cvs2fossil/lib/c2f_pcollrev.tcl | 680 ++++ tools/cvs2fossil/lib/c2f_pcollsym.tcl | 318 ++ tools/cvs2fossil/lib/c2f_pcsetdeps.tcl | 135 + tools/cvs2fossil/lib/c2f_pfiltersym.tcl | 598 ++++ tools/cvs2fossil/lib/c2f_pimportcsets.tcl | 133 + tools/cvs2fossil/lib/c2f_pimportfiles.tcl | 151 + tools/cvs2fossil/lib/c2f_pimportfinal.tcl | 122 + tools/cvs2fossil/lib/c2f_pinitcsets.tcl | 379 +++ tools/cvs2fossil/lib/c2f_prev.tcl | 1846 ++++++++++ tools/cvs2fossil/lib/c2f_prevlink.tcl | 240 ++ tools/cvs2fossil/lib/c2f_project.tcl | 233 ++ tools/cvs2fossil/lib/c2f_prtopsort.tcl | 159 + tools/cvs2fossil/lib/c2f_psym.tcl | 422 +++ tools/cvs2fossil/lib/c2f_ptrunk.tcl | 89 + tools/cvs2fossil/lib/c2f_repository.tcl | 502 +++ tools/cvs2fossil/lib/c2f_ristate.tcl | 113 + tools/cvs2fossil/lib/c2f_state.tcl | 231 ++ tools/cvs2fossil/lib/c2f_wsstate.tcl | 136 + tools/cvs2fossil/lib/cvs2fossil.tcl | 89 + tools/cvs2fossil/lib/dot.tcl | 108 + tools/cvs2fossil/lib/id.tcl | 64 + tools/cvs2fossil/lib/log.tcl | 184 + tools/cvs2fossil/lib/mem.tcl | 139 + tools/cvs2fossil/lib/misc.tcl | 144 + tools/cvs2fossil/lib/pkgIndex.tcl | 47 + tools/cvs2fossil/lib/rcsparser.tcl | 485 +++ tools/cvs2fossil/lib/trouble.tcl | 124 + tools/cvs2fossil/lodtree | 88 + tools/cvs2fossil/showg | 6 + tools/cvs2fossil/symboltree | 88 + tools/decode-email.c | 163 + tools/email-monitor.tcl | 51 + tools/email-sender.tcl | 65 + tools/emcc.sh.in | 66 + tools/encode_math.sh | 12 + tools/fake-smtpd.tcl | 84 + tools/find-fossil-cgis.tcl | 141 + tools/fossil-autocomplete.bash | 15 + tools/fossil-autocomplete.zsh | 3529 ++++++++++++++++++++ tools/fossil-diff-log | 72 + tools/fossil-stress.tcl | 144 + tools/fossilwiki | 132 + tools/fslsrv | 59 + tools/makeheaders.c | 3441 +++++++++++++++++++ tools/makeheaders.html | 1150 +++++++ tools/makemake.tcl | 2159 ++++++++++++ tools/man_page_command_list.tcl | 68 + tools/mkbuiltin.c | 415 +++ tools/mkindex.c | 607 ++++ tools/mkversion.c | 218 ++ tools/randomize-js-names.tcl | 36 + tools/skintxt2config.c | 219 ++ tools/sqlcompattest.c | 89 + tools/translate.c | 270 ++ 115 files changed, 31457 insertions(+) create mode 100755 tools/co-rsync.tcl create mode 100644 tools/codecheck1.c create mode 100644 tools/copland/dist/copland-skin.config create mode 100644 tools/copland/package-lock.json create mode 100644 tools/copland/package.json create mode 100644 tools/copland/playwright.config.mjs create mode 100644 tools/copland/scripts/build-config.mjs create mode 100755 tools/copland/scripts/create-demo.sh create mode 100755 tools/copland/scripts/fossil-env.sh create mode 100755 tools/copland/scripts/install-repolist.sh create mode 100755 tools/copland/scripts/install.sh create mode 100755 tools/copland/scripts/preview.sh create mode 100644 tools/copland/src/copland.scss create mode 100644 tools/copland/tests/fixtures/org/all.html create mode 100644 tools/copland/tests/fixtures/org/all.org create mode 100644 tools/copland/tests/fixtures/org/all.txt create mode 100644 tools/copland/tests/fixtures/org/security.html create mode 100644 tools/copland/tests/fixtures/org/security.org create mode 100755 tools/copland/tests/org-renderer.sh create mode 100755 tools/copland/tests/serve-fixture.sh create mode 100755 tools/copland/tests/smoke.sh create mode 100644 tools/copland/tests/visual.spec.mjs create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/home-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/home-light-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/login-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/login-light-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/org-document-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/org-document-light-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/org-document-mobile-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/org-wiki-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/org-wiki-light-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/org-wiki-mobile-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/repository-list-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/repository-list-light-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/timeline-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/timeline-light-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/timeline-mobile-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/tree-dark-linux.png create mode 100644 tools/copland/tests/visual.spec.mjs-snapshots/tree-light-linux.png create mode 100644 tools/cvs2fossil/changeset create mode 100644 tools/cvs2fossil/cvs2fossil create mode 100644 tools/cvs2fossil/doc/LICENSE create mode 100644 tools/cvs2fossil/doc/README create mode 100644 tools/cvs2fossil/filerevtree create mode 100644 tools/cvs2fossil/getmemoryseries.tcl create mode 100644 tools/cvs2fossil/lib/c2f_blobstore.tcl create mode 100644 tools/cvs2fossil/lib/c2f_cyclebreaker.tcl create mode 100644 tools/cvs2fossil/lib/c2f_file.tcl create mode 100644 tools/cvs2fossil/lib/c2f_fossil.tcl create mode 100644 tools/cvs2fossil/lib/c2f_frev.tcl create mode 100644 tools/cvs2fossil/lib/c2f_fsym.tcl create mode 100644 tools/cvs2fossil/lib/c2f_ftrunk.tcl create mode 100644 tools/cvs2fossil/lib/c2f_gtcore.tcl create mode 100644 tools/cvs2fossil/lib/c2f_integrity.tcl create mode 100644 tools/cvs2fossil/lib/c2f_option.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pass.tcl create mode 100644 tools/cvs2fossil/lib/c2f_patopsort.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pbreakacycle.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pbreakscycle.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pcollar.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pcollrev.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pcollsym.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pcsetdeps.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pfiltersym.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pimportcsets.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pimportfiles.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pimportfinal.tcl create mode 100644 tools/cvs2fossil/lib/c2f_pinitcsets.tcl create mode 100644 tools/cvs2fossil/lib/c2f_prev.tcl create mode 100644 tools/cvs2fossil/lib/c2f_prevlink.tcl create mode 100644 tools/cvs2fossil/lib/c2f_project.tcl create mode 100644 tools/cvs2fossil/lib/c2f_prtopsort.tcl create mode 100644 tools/cvs2fossil/lib/c2f_psym.tcl create mode 100644 tools/cvs2fossil/lib/c2f_ptrunk.tcl create mode 100644 tools/cvs2fossil/lib/c2f_repository.tcl create mode 100644 tools/cvs2fossil/lib/c2f_ristate.tcl create mode 100644 tools/cvs2fossil/lib/c2f_state.tcl create mode 100644 tools/cvs2fossil/lib/c2f_wsstate.tcl create mode 100644 tools/cvs2fossil/lib/cvs2fossil.tcl create mode 100644 tools/cvs2fossil/lib/dot.tcl create mode 100644 tools/cvs2fossil/lib/id.tcl create mode 100644 tools/cvs2fossil/lib/log.tcl create mode 100644 tools/cvs2fossil/lib/mem.tcl create mode 100644 tools/cvs2fossil/lib/misc.tcl create mode 100644 tools/cvs2fossil/lib/pkgIndex.tcl create mode 100644 tools/cvs2fossil/lib/rcsparser.tcl create mode 100644 tools/cvs2fossil/lib/trouble.tcl create mode 100644 tools/cvs2fossil/lodtree create mode 100644 tools/cvs2fossil/showg create mode 100644 tools/cvs2fossil/symboltree create mode 100644 tools/decode-email.c create mode 100755 tools/email-monitor.tcl create mode 100755 tools/email-sender.tcl create mode 100644 tools/emcc.sh.in create mode 100755 tools/encode_math.sh create mode 100644 tools/fake-smtpd.tcl create mode 100755 tools/find-fossil-cgis.tcl create mode 100755 tools/fossil-autocomplete.bash create mode 100755 tools/fossil-autocomplete.zsh create mode 100755 tools/fossil-diff-log create mode 100755 tools/fossil-stress.tcl create mode 100755 tools/fossilwiki create mode 100755 tools/fslsrv create mode 100644 tools/makeheaders.c create mode 100644 tools/makeheaders.html create mode 100755 tools/makemake.tcl create mode 100755 tools/man_page_command_list.tcl create mode 100644 tools/mkbuiltin.c create mode 100644 tools/mkindex.c create mode 100644 tools/mkversion.c create mode 100644 tools/randomize-js-names.tcl create mode 100644 tools/skintxt2config.c create mode 100644 tools/sqlcompattest.c create mode 100644 tools/translate.c (limited to 'tools') diff --git a/tools/co-rsync.tcl b/tools/co-rsync.tcl new file mode 100755 index 0000000..1193c50 --- /dev/null +++ b/tools/co-rsync.tcl @@ -0,0 +1,72 @@ +#!/bin/sh +# +# This is a TCL script that tries to sync the changes in a local +# Fossil checkout to another machine. The changes are gathered into +# a tarball, then sent via ssh to the remote and unpacked. +# +# Usage: +# +# co-rsync.tcl REMOTE +# +# Where REMOTE is the root of the remote repository into which changes +# are to be moved. +# +# Use Case: +# +# Sometimes while in the middle of an edit it is useful to transfer +# the incomplete changes to another machine for testing. This could +# be accomplished using scp, but doing it that was is tedious if many +# files in multiple directories have changed. This command does all +# the necessary transfer using a single command. +# +# A Tcl comment, whose contents don't matter \ +exec tclsh "$0" "$@" + +# Begin by changing directories to the root of the check-out. +# +set remote {} +set dryrun 0 +proc usage {} { + puts stderr "Usage: $::argv0 REMOTE" + puts stderr "Options:" + puts stderr " --dryrun No-op but print what would have happened" + exit 1 +} +foreach arg $argv { + if {$arg=="--dryrun" || $arg=="--dry-run"} { + set dryrun 1 + continue + } + if {$remote!=""} { + usage + } + set remote $arg +} +if {$remote==""} usage + +set in [open {|fossil status} rb] +set status [read $in] +if {[catch {close $in} msg]} { + puts stderr $msg + exit 1 +} +set root {} +regexp {local-root: +([^\n]+)} $status all root +if {$root==""} { + puts stderr "not in a fossil check-out" + exit 1 +} +cd $root +set tmpname filelist- +for {set i 0} {$i<3} {incr i} { + append tmpname [format %08x [expr {int(rand()*0xffffffff)}]] +} +set out [open $tmpname wb] +puts $out [exec fossil changes --no-classify --no-merge] +close $out +set cmd "rsync -v --files-from=$tmpname . $remote" +puts $cmd +if {!$dryrun} { + exec {*}$cmd +} +file delete $tmpname diff --git a/tools/codecheck1.c b/tools/codecheck1.c new file mode 100644 index 0000000..7a43d6f --- /dev/null +++ b/tools/codecheck1.c @@ -0,0 +1,700 @@ +/* +** 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 or HTML or a URL or JSON, +** detect and warn about possible injection attacks. +*/ +#include +#include +#include +#include +#include + +/* +** 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; izFName, pB->zFName); +} + +/* +** Determine if the identifier 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]. +** +** Store the number of initial literal characters of the format string +** in *pInit. +*/ +static int formatArgCount(const char *z, int nType, char *cType, int *pInit){ + int nArg = 0; + int i, k; + int len; + int eType; + int ln = 0; + *pInit = 0; + while( z[0] ){ + len = token_length(z, &eType, &ln); + if( eType==TK_STR ){ + for(i=1; inArg ){ + 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( fmtFlags & FMT_LIT ){ + if( !is_string_lit(zFmt) ){ + printf("%s:%d: argument %d to %.*s() should be a string literal\n", + zFilename, lnFCall, fmtArg, szFName, zFCall); + nErr++; + } + }else 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, &nInit))>=0 + && nArg!=fmtArg+k ){ + printf("%s:%d: too %s arguments to %.*s() " + "- got %d and expected %d\n", + zFilename, lnFCall, (nArg1 ){ + 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; + qsort(aFmtFunc, sizeof(aFmtFunc)/sizeof(aFmtFunc[0]), + sizeof(aFmtFunc[0]), fmtfunc_cmp); + for(i=1; i0 ) printf("Processing %s...\n", argv[i]); + zFile = read_file(argv[i]); + nErr += scan_file(argv[i], zFile); + free(zFile); + } + return nErr; +} diff --git a/tools/copland/dist/copland-skin.config b/tools/copland/dist/copland-skin.config new file mode 100644 index 0000000..02392e8 --- /dev/null +++ b/tools/copland/dist/copland-skin.config @@ -0,0 +1,827 @@ +# Copland Fossil skin configuration +# Generated deterministically by tools/copland/scripts/build-config.mjs. +# Import with: fossil configuration import dist/copland-skin.config -R REPOSITORY +config /config 12869 +1 'css' value ':root { + color-scheme: light dark; + --page-bg: #fff; + --surface: #fff; + --surface-subtle: #f5f5f5; + --surface-muted: #e9ecef; + --surface-active: #ddd; + --text: #212529; + --text-muted: #6c757d; + --text-faint: #767676; + --border: #ced4da; + --border-strong: #888; + --link: #0645d9; + --link-hover: #002f9f; + --primary: #0056d6; + --primary-hover: #0044aa; + --primary-text: #fff; + --danger: #b00020; + --danger-bg: #f8d7da; + --success: #146c2e; + --success-bg: #d4edda; + --warning-bg: #fff3cd; + --info-bg: #d1ecf1; + --code-bg: #f1f3f5; + --selection: #b9d6ff; + --focus: #ffbf47; + --shadow: rgba(0, 0, 0, 0.12); + --container: 71.25rem; + --gutter: 1rem; + --radius: 0; + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; +} + +@media (prefers-color-scheme: dark) { + :root { + --page-bg: #212529; + --surface: #212529; + --surface-subtle: #191c1f; + --surface-muted: #2d3237; + --surface-active: #3b4147; + --text: #f1f3f5; + --text-muted: #c2c7cc; + --text-faint: #adb5bd; + --border: #565e65; + --border-strong: #8b949c; + --link: #5c9cff; + --link-hover: #91bcff; + --primary: #4d8ee8; + --primary-hover: #70a7f2; + --primary-text: #101214; + --danger: #ff6b78; + --danger-bg: #57242a; + --success: #65d47d; + --success-bg: #183d24; + --warning-bg: #514318; + --info-bg: #193e47; + --code-bg: #17191b; + --selection: #173f70; + --focus: #ffd166; + --shadow: rgba(0, 0, 0, 0.4); + } +} +* { + box-sizing: border-box; +} + +html { + min-height: 100%; + scrollbar-gutter: stable; + font-size: 16px; +} + +body { + min-height: 100vh; + margin: 0; + padding: 0 0 1rem; + background: var(--page-bg); + color: var(--text); + font-family: var(--font-sans); + font-size: 1rem; + line-height: 1.5; + text-align: initial; +} + +::selection { + background: var(--selection); +} + +.container, +div.content { + width: 100%; + max-width: var(--container); + margin-inline: auto; + padding-inline: var(--gutter); +} + +div.content { + min-height: 45vh; +} + +body a { + color: var(--link); + text-decoration: underline; + text-underline-offset: 0.12em; +} + +body a:hover { + color: var(--link-hover); + text-decoration: none; +} + +a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, +textarea:focus-visible, [tabindex]:focus-visible { + outline: 3px solid var(--focus); + outline-offset: 2px; +} + +h1, h2, h3, h4, h5, h6 { + margin: 1rem 0 0.5rem; + color: var(--text); + font-weight: 500; + line-height: 1.2; +} + +h1 { + font-size: 1.75rem; +} + +h2 { + font-size: 1.45rem; +} + +h3 { + font-size: 1.15rem; + border-bottom: 1px solid var(--border); +} + +h4 { + font-size: 1rem; + border-bottom: 1px solid var(--border); +} + +p { + margin: 0 0 1rem; +} + +hr { + border: 0; + border-top: 1px solid var(--border); +} + +.site-header { + margin-bottom: 0; +} + +.site-header-row { + min-height: 3.25rem; + display: flex; + align-items: center; + gap: 1rem; +} + +.site-brand, +.resource-title a, +.account-nav a, +.mainmenu a { + text-decoration: none; +} + +.site-brand { + flex: 0 0 auto; + color: var(--text); + font-size: 1.25rem; + font-weight: 600; + letter-spacing: -0.025em; +} + +.site-brand::before { + content: ""; + display: inline-block; + width: 0.78rem; + height: 0.78rem; + margin-right: 0.42rem; + border: 2px solid currentColor; + border-radius: 50%; + vertical-align: 0.02rem; +} + +.site-brand:hover, +.resource-title a:hover, +.account-nav a:hover, +.mainmenu a:hover { + color: var(--text); + text-decoration: underline; +} + +.resource-title { + min-width: 0; + display: flex; + align-items: baseline; + gap: 0.4rem; + overflow: hidden; + white-space: nowrap; +} + +.resource-title a, +.resource-page { + overflow: hidden; + text-overflow: ellipsis; +} + +.resource-title a { + color: var(--text); + font-weight: 600; +} + +.resource-separator, .resource-page { + color: var(--text-muted); +} + +.account-nav { + margin-left: auto; + white-space: nowrap; + font-size: 0.9rem; +} + +.resource-nav { + border-bottom: 3px solid var(--surface-active); +} + +.mainmenu { + min-height: 2rem; + display: flex; + align-items: end; + gap: 0; + overflow-x: auto; + scrollbar-width: thin; +} + +.mainmenu a { + flex: 0 0 auto; + padding: 0.25rem 0.85rem 0.18rem; + color: var(--text-muted); + white-space: nowrap; +} + +.mainmenu a.active, +.mainmenu a.selected, +.mainmenu a:hover { + color: var(--text); +} + +.mainmenu a.active, +.mainmenu a.selected { + background: var(--surface-active); +} + +.page-title { + margin-top: 0.9rem; + margin-bottom: 0.75rem; + font-size: 1.35rem; + font-weight: 500; +} + +.site-footer { + margin-top: 2rem; + color: var(--text-muted); + font-size: 0.8rem; +} + +.site-footer .container { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.4rem; +} + +pre, code, kbd, samp, tt { + font-family: var(--font-mono); +} + +code, tt { + overflow-wrap: anywhere; +} + +pre { + max-width: 100%; + overflow: auto; + margin: 0 0 1rem; + padding: 0.75rem 1rem; + background: var(--code-bg); + color: var(--text); + font-size: 0.875rem; + line-height: 1.35; + tab-size: 4; +} + +pre a { + color: inherit; +} + +blockquote { + margin: 0 0 1rem; + padding-left: 1rem; + border-left: 4px solid var(--border); +} + +.org-document { + max-width: 100%; +} + +.org-document .org-title { + margin-top: 0; +} + +.org-metadata { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + gap: 0.15rem 0.75rem; + margin: 0 0 1rem; + color: var(--text-muted); + font-size: 0.92rem; +} + +.org-metadata dt { + font-weight: 600; +} + +.org-metadata dd { + margin: 0; +} + +.org-toc { + margin: 0 0 1.25rem; + padding: 0.75rem 1rem; + border: 1px solid var(--border); + background: var(--surface-subtle); +} + +.org-toc h2 { + margin-top: 0; + font-size: 1.05rem; +} + +.org-toc ol { + margin: 0; + padding-left: 1.5rem; +} + +.org-toc-level-2 { + margin-left: 1rem; +} + +.org-toc-level-3 { + margin-left: 2rem; +} + +.org-toc-level-4, .org-toc-level-5, .org-toc-level-6 { + margin-left: 3rem; +} + +.org-table { + display: block; + overflow-x: auto; +} + +.org-block { + border-left: 3px solid var(--border-strong); +} + +.org-example { + color: var(--text); +} + +.org-unknown-block { + border-left-color: var(--danger); +} + +table { + width: 100%; + margin-bottom: 1rem; + border-collapse: collapse; + color: var(--text); +} + +th { + text-align: left; + font-weight: 600; +} + +th, td { + padding: 0.28rem 0.5rem; + vertical-align: top; + border-top: 1px solid var(--border); +} + +thead th { + border-bottom: 2px solid var(--border-strong); +} + +tbody tr:nth-child(odd) { + background: color-mix(in srgb, var(--surface-subtle) 70%, transparent); +} + +table.browser, table.report, table.timelineTable { + font-size: 0.92rem; +} + +table.browser td:first-child, table.browser td:nth-child(2) { + font-family: var(--font-mono); +} + +input, button, select, textarea { + font: inherit; +} + +input[type=text], input[type=search], input[type=email], input[type=password], +input[type=url], input[type=number], textarea, select { + max-width: 100%; + padding: 0.35rem 0.5rem; + border: 1px solid var(--border-strong); + border-radius: var(--radius); + background: var(--surface); + color: var(--text); +} + +textarea { + width: 100%; +} + +label { + display: inline-block; + margin-bottom: 0.25rem; +} + +button, input[type=submit], input[type=button], .button, a.button { + display: inline-block; + padding: 0.35rem 0.7rem; + border: 1px solid var(--primary); + border-radius: var(--radius); + background: var(--primary); + color: var(--primary-text); + cursor: pointer; + line-height: 1.25; + text-decoration: none; +} + +button:hover, input[type=submit]:hover, input[type=button]:hover, .button:hover { + border-color: var(--primary-hover); + background: var(--primary-hover); +} + +button:disabled, input:disabled { + cursor: not-allowed; + opacity: 0.65; +} + +fieldset { + margin: 0 0 1rem; + border: 1px solid var(--border); +} + +legend { + padding-inline: 0.35rem; +} + +.submenu, .sectionmenu { + margin: 0 0 1rem; + padding: 0.4rem 0.6rem; + background: var(--surface-subtle); + border: 1px solid var(--border); +} + +.submenu a, .sectionmenu a { + margin-right: 0.75rem; +} + +.generalError, .error, .fatalError, .loginError, +.warning, .notice, .success { + margin: 0.75rem 0; + padding: 0.65rem 0.8rem; + border: 1px solid var(--border); +} + +.generalError, .error, .fatalError, .loginError { + background: var(--danger-bg); + color: var(--text); +} + +.warning { + background: var(--warning-bg); +} + +.notice { + background: var(--info-bg); +} + +.success { + background: var(--success-bg); +} + +.timelineDate { + margin-top: 1rem; + color: var(--text); + font-weight: 600; +} + +.timelineHistDsp { + color: var(--text-muted); +} + +.timelineModernCell, .timelineColumnarCell, .timelineDetailCell { + padding-block: 0.35rem; +} + +.timelineModernDetail { + opacity: 1; +} + +.timelineCompactComment, .timelineComment { + line-height: 1.35; +} + +.timelineTime { + color: var(--text-muted); + white-space: nowrap; +} + +.timelineGraph { + min-width: 2rem; +} + +.tl-node { + border-radius: 50%; +} + +.timelineModernCell a, +.timelineColumnarCell a, +.timelineDetailCell a { + color: var(--link) !important; +} + +.timelineModernCell a:hover, +.timelineColumnarCell a:hover, +.timelineDetailCell a:hover { + color: var(--link-hover) !important; +} + +.filetree { + font-family: var(--font-mono); + font-size: 0.9rem; +} + +.filetree ul { + padding-left: 1.25rem; +} + +.filetree a { + color: var(--text); +} + +.filetree a:hover { + color: var(--link); +} + +.fileage tr:hover, table.browser tr:hover { + background: var(--surface-active); +} + +.diff, .udiff, .sbsdiff { + font-family: var(--font-mono); + font-size: 0.82rem; +} + +.diff pre, .udiff pre, .sbsdiff pre { + background: transparent; +} + +.diffln, .diffhr { + color: var(--text-muted); + background: var(--surface-muted); +} + +.diffadd, .diffins { + background: var(--success-bg); +} + +.diffrm, .diffdel { + background: var(--danger-bg); +} + +.diffchng { + background: var(--warning-bg); +} + +.selectedText { + background: var(--selection); +} + +.forumPost, .forumTime, .forumSel, .forumHierRoot, .forumHier { + border-color: var(--border); +} + +.forumPost, .forumTime { + background: var(--surface-subtle); + color: var(--text); +} + +.forumPostBody { + overflow-wrap: anywhere; +} + +.forumPostBody img, .wiki-content img, .markdown img { + max-width: 100%; + height: auto; +} + +.ticketDspLabel, .ticketDspValue { + padding: 0.35rem 0.5rem; +} + +.ticketDspLabel { + color: var(--text-muted); + font-weight: 600; +} + +.ticketDspValue { + border-bottom: 1px solid var(--border); +} + +.branchname, .tagname, .wikiTagCancelled, .infoTagCancelled { + display: inline-block; + padding: 0.05rem 0.3rem; + background: var(--surface-muted); + color: var(--text); + font-size: 0.82rem; +} + +.statistics-report-table-events th, .statistics-report-table-events td { + text-align: right; +} + +.statistics-report-table-events th:first-child, .statistics-report-table-events td:first-child { + text-align: left; +} + +.accordion_panel { + border-color: var(--border); + background: var(--surface); +} + +.accordion_marker { + color: var(--text-muted); +} + +body.repolist .resource-title, +body.repolist .resource-nav, +body.repolist > .page-title { + display: none; +} + +body.repolist div.content { + padding-top: 1rem; +} + +body.repolist table td:first-child { + font-family: var(--font-mono); + font-weight: 600; +} + +@media (prefers-color-scheme: dark) { + img { + opacity: 0.92; + } + body .timelineModernCell, + body .timelineColumnarCell, + body .timelineDetailCell, + .timelineModernCell[style*=background-color], + .timelineColumnarCell[style*=background-color], + .timelineDetailCell[style*=background-color], + td[style*=background-color] { + background-color: var(--surface-subtle) !important; + color: var(--text) !important; + } + .diffadd, .diffins { + color: var(--text); + } + .diffrm, .diffdel { + color: var(--text); + } +} +@media (max-width: 48rem) { + :root { + --gutter: 0.75rem; + } + .site-header-row { + min-height: 2.8rem; + gap: 0.65rem; + } + .resource-page, .resource-separator { + display: none; + } + .mainmenu a { + padding-inline: 0.65rem; + } + .page-title { + font-size: 1.2rem; + } + table:not(.sbsdiffcols) { + display: block; + max-width: 100%; + overflow-x: auto; + } + .desktoponly { + display: none !important; + } +} +@media (max-width: 36rem) { + .site-brand { + font-size: 1.1rem; + } + .resource-title { + font-size: 0.9rem; + } + .account-nav { + font-size: 0.82rem; + } + .page-title { + margin-top: 0.7rem; + } + pre { + padding: 0.6rem 0.7rem; + } +} +@media print { + .resource-nav, .account-nav, .submenu, .sectionmenu, .site-footer { + display: none !important; + } + body, pre, code { + background: #fff !important; + color: #000 !important; + } + a { + color: #000; + text-decoration: underline; + } + div.content, .container { + max-width: none; + padding: 0; + } +} +' +config /config 1631 +1 'header' value '