prefer modules to src- dirs
authorThomas Walker Lynch <thomas.lynch@reasoningtechnology.com>
Thu, 28 Mar 2019 01:33:43 +0000 (02:33 +0100)
committerThomas Walker Lynch <thomas.lynch@reasoningtechnology.com>
Thu, 28 Mar 2019 01:33:43 +0000 (02:33 +0100)
207 files changed:
da/makefile [deleted file]
da/makefile-flags [deleted file]
da/src/da.lib.c [deleted file]
da/src/da.lib.h [deleted file]
da/test/makefile [deleted file]
da/test/makefile-dep [deleted file]
da/test/makefile-flags [deleted file]
da/test/results [deleted file]
da/test/test.dat [deleted file]
da/test/test_da.cli.c [deleted file]
da/test/test_da.cli.o [deleted file]
da/test/test_da.lib.c [deleted file]
da/test/test_da.lib.h [deleted file]
da/test/test_da.lib.o [deleted file]
db/0_makefile [deleted file]
db/0_makefile-flags [deleted file]
db/1_doc/return-from-transaction.txt [deleted file]
db/dbprintf.lib.c [deleted file]
dispatch/makefile [deleted file]
dispatch/makefile-flags [deleted file]
dispatch/src/dispatch.lib.c [deleted file]
makefile
module/da/makefile [new file with mode: 0644]
module/da/makefile-flags [new file with mode: 0644]
module/da/src/da.lib.c [new file with mode: 0644]
module/da/src/da.lib.h [new file with mode: 0644]
module/da/test/makefile [new file with mode: 0644]
module/da/test/makefile-dep [new file with mode: 0644]
module/da/test/makefile-flags [new file with mode: 0644]
module/da/test/results [new file with mode: 0644]
module/da/test/test.dat [new file with mode: 0644]
module/da/test/test_da.cli.c [new file with mode: 0644]
module/da/test/test_da.cli.o [new file with mode: 0644]
module/da/test/test_da.lib.c [new file with mode: 0644]
module/da/test/test_da.lib.h [new file with mode: 0644]
module/da/test/test_da.lib.o [new file with mode: 0644]
module/db/0_makefile [new file with mode: 0644]
module/db/0_makefile-flags [new file with mode: 0644]
module/db/1_doc/return-from-transaction.txt [new file with mode: 0644]
module/db/dbprintf.lib.c [new file with mode: 0644]
module/dispatch/makefile [new file with mode: 0644]
module/dispatch/makefile-flags [new file with mode: 0644]
module/dispatch/src/dispatch.lib.c [new file with mode: 0644]
module/share/include/da.h [new file with mode: 0644]
module/share/include/tranche.h [new file with mode: 0644]
module/subu-0/0_makefile [new file with mode: 0644]
module/subu-0/0_makefile-flags [new file with mode: 0644]
module/subu-0/1_deprecated/dispatch_exec.lib.c [new file with mode: 0644]
module/subu-0/1_deprecated/dispatch_f.lib.c [new file with mode: 0644]
module/subu-0/1_deprecated/dispatch_useradd.lib.c [new file with mode: 0644]
module/subu-0/1_deprecated/subu-rm-0.lib.c [new file with mode: 0644]
module/subu-0/1_deprecated/subudb-number-next.cli.c [new file with mode: 0644]
module/subu-0/1_doc/to_do.txt [new file with mode: 0644]
module/subu-0/1_tests/0_makefile [new file with mode: 0644]
module/subu-0/1_tests/0_makefile_flags [new file with mode: 0644]
module/subu-0/1_tests/1_tmp/makefile_deps [new file with mode: 0644]
module/subu-0/1_tests/da.cli.c [new file with mode: 0644]
module/subu-0/1_tests/libtests.a [new file with mode: 0644]
module/subu-0/1_tmp/da.lib.h [new file with mode: 0644]
module/subu-0/1_tmp/dbprintf.lib.h [new file with mode: 0644]
module/subu-0/1_tmp/dispatch.lib.h [new file with mode: 0644]
module/subu-0/1_tmp/subu-bind-all.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subu-bind.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subu-common.lib.h [new file with mode: 0644]
module/subu-0/1_tmp/subu-mk-0.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subu-rm-0.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subu.lib.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb-init.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb-number.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb-rel-get.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb-rel-put.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb-rel-rm.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb-subus.cli.h [new file with mode: 0644]
module/subu-0/1_tmp/subudb.lib.h [new file with mode: 0644]
module/subu-0/1_try/split.c [new file with mode: 0644]
module/subu-0/1_try/split_arg.c [new file with mode: 0644]
module/subu-0/1_try/subudb [new file with mode: 0644]
module/subu-0/1_try/voidptr.c [new file with mode: 0644]
module/subu-0/common.lib.c [new file with mode: 0644]
module/subu-0/db.lib.c [new file with mode: 0644]
module/subu-0/subu-bind-all.cli.c [new file with mode: 0644]
module/subu-0/subu-bind.cli.c [new file with mode: 0644]
module/subu-0/subu-mk-0.cli.c [new file with mode: 0644]
module/subu-0/subu-rm-0.cli.c [new file with mode: 0644]
module/subu-0/subu.lib.c [new file with mode: 0644]
module/subu-0/subudb-init.cli.c [new file with mode: 0644]
module/subu-0/subudb-number.cli.c [new file with mode: 0644]
module/subu-0/subudb-rel-get.cli.c [new file with mode: 0644]
module/subu-0/subudb-rel-put.cli.c [new file with mode: 0644]
module/subu-0/subudb-rel-rm.cli.c [new file with mode: 0644]
module/subu-0/subudb-subus.cli.c [new file with mode: 0644]
module/subu-1/subu-mk.py [new file with mode: 0644]
module/tranche/deprecated/0_makefile [new file with mode: 0644]
module/tranche/deprecated/0_makefile-flags [new file with mode: 0644]
module/tranche/doc/todo.txt [new file with mode: 0644]
module/tranche/makefile [new file with mode: 0644]
module/tranche/makefile-flags [new file with mode: 0644]
module/tranche/src/tranche.cli.c [new file with mode: 0644]
module/tranche/src/tranche.lib.c [new file with mode: 0644]
module/tranche/src/tranche.lib.h [new file with mode: 0644]
module/tranche/test/test1.dat [new file with mode: 0644]
module/tranche/test/test1.sh [new file with mode: 0644]
module/tranche/test/test11.dat.expected [new file with mode: 0644]
module/tranche/test/test12.dat.expected [new file with mode: 0644]
module/tranche/test/test13.dat.expected [new file with mode: 0644]
module/tranche/test/test14.dat.expected [new file with mode: 0644]
module/tranche/test/test15.dat.expected [new file with mode: 0644]
module/tranche/test/test1stdout.dat.expected [new file with mode: 0644]
module/tranche/test/test2.c.expected [new file with mode: 0644]
module/tranche/test/test2.h.expected [new file with mode: 0644]
module/tranche/test/test2.trc.c [new file with mode: 0644]
module/tranche/test/tranche [new symlink]
stage/include/da.h [deleted file]
stage/include/tranche.h [deleted file]
subu-0/0_makefile [deleted file]
subu-0/0_makefile-flags [deleted file]
subu-0/1_deprecated/dispatch_exec.lib.c [deleted file]
subu-0/1_deprecated/dispatch_f.lib.c [deleted file]
subu-0/1_deprecated/dispatch_useradd.lib.c [deleted file]
subu-0/1_deprecated/subu-rm-0.lib.c [deleted file]
subu-0/1_deprecated/subudb-number-next.cli.c [deleted file]
subu-0/1_doc/to_do.txt [deleted file]
subu-0/1_tests/0_makefile [deleted file]
subu-0/1_tests/0_makefile_flags [deleted file]
subu-0/1_tests/1_tmp/makefile_deps [deleted file]
subu-0/1_tests/da.cli.c [deleted file]
subu-0/1_tests/libtests.a [deleted file]
subu-0/1_tmp/da.lib.h [deleted file]
subu-0/1_tmp/dbprintf.lib.h [deleted file]
subu-0/1_tmp/dispatch.lib.h [deleted file]
subu-0/1_tmp/subu-bind-all.cli.h [deleted file]
subu-0/1_tmp/subu-bind.cli.h [deleted file]
subu-0/1_tmp/subu-common.lib.h [deleted file]
subu-0/1_tmp/subu-mk-0.cli.h [deleted file]
subu-0/1_tmp/subu-rm-0.cli.h [deleted file]
subu-0/1_tmp/subu.lib.h [deleted file]
subu-0/1_tmp/subudb-init.cli.h [deleted file]
subu-0/1_tmp/subudb-number.cli.h [deleted file]
subu-0/1_tmp/subudb-rel-get.cli.h [deleted file]
subu-0/1_tmp/subudb-rel-put.cli.h [deleted file]
subu-0/1_tmp/subudb-rel-rm.cli.h [deleted file]
subu-0/1_tmp/subudb-subus.cli.h [deleted file]
subu-0/1_tmp/subudb.lib.h [deleted file]
subu-0/1_try/split.c [deleted file]
subu-0/1_try/split_arg.c [deleted file]
subu-0/1_try/subudb [deleted file]
subu-0/1_try/voidptr.c [deleted file]
subu-0/common.lib.c [deleted file]
subu-0/db.lib.c [deleted file]
subu-0/subu-bind-all.cli.c [deleted file]
subu-0/subu-bind.cli.c [deleted file]
subu-0/subu-mk-0.cli.c [deleted file]
subu-0/subu-rm-0.cli.c [deleted file]
subu-0/subu.lib.c [deleted file]
subu-0/subudb-init.cli.c [deleted file]
subu-0/subudb-number.cli.c [deleted file]
subu-0/subudb-rel-get.cli.c [deleted file]
subu-0/subudb-rel-put.cli.c [deleted file]
subu-0/subudb-rel-rm.cli.c [deleted file]
subu-0/subudb-subus.cli.c [deleted file]
subu-1/subu-mk.py [deleted file]
temp [new file with mode: 0644]
tool/bin/gitadd [new file with mode: 0755]
tool/bin/makeheaders [new file with mode: 0755]
tool/bin/setuid_root.sh [new file with mode: 0755]
tool/bin/tranche [new file with mode: 0755]
tool/doc/makefile.txt [new file with mode: 0644]
tool/doc/makeheaders-notes.txt [new file with mode: 0644]
tool/doc/makeheaders.html [new file with mode: 0644]
tool/lib/bashrc [new file with mode: 0755]
tool/lib/dot_emacs [new file with mode: 0755]
tool/lib/makefile_cc [new file with mode: 0755]
tool/lib/makefile_trc [new file with mode: 0644]
tool/src/makeheaders.c [new file with mode: 0644]
tools/bin/gitadd [deleted file]
tools/bin/makeheaders [deleted file]
tools/bin/setuid_root.sh [deleted file]
tools/bin/tranche [deleted file]
tools/doc/makefile.txt [deleted file]
tools/doc/makeheaders-notes.txt [deleted file]
tools/doc/makeheaders.html [deleted file]
tools/lib/bashrc [deleted file]
tools/lib/dot_emacs [deleted file]
tools/lib/makefile_cc [deleted file]
tools/lib/makefile_cc.~82b14679df98a141dbf8dac2f51f30d5fc84863b~ [deleted file]
tools/lib/makefile_trc [deleted file]
tools/src/makeheaders.c [deleted file]
tranche/deprecated/0_makefile [deleted file]
tranche/deprecated/0_makefile-flags [deleted file]
tranche/doc/todo.txt [deleted file]
tranche/makefile [deleted file]
tranche/makefile-flags [deleted file]
tranche/src/tranche.cli.c [deleted file]
tranche/src/tranche.lib.c [deleted file]
tranche/src/tranche.lib.h [deleted file]
tranche/test/test1.dat [deleted file]
tranche/test/test1.sh [deleted file]
tranche/test/test11.dat.expected [deleted file]
tranche/test/test12.dat.expected [deleted file]
tranche/test/test13.dat.expected [deleted file]
tranche/test/test14.dat.expected [deleted file]
tranche/test/test15.dat.expected [deleted file]
tranche/test/test1stdout.dat.expected [deleted file]
tranche/test/test2.c.expected [deleted file]
tranche/test/test2.h.expected [deleted file]
tranche/test/test2.trc.c [deleted file]
tranche/test/tranche [deleted symlink]

diff --git a/da/makefile b/da/makefile
deleted file mode 100644 (file)
index 67fbdb9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# da/makefile
-
-SHELL=/bin/bash
-MAKE=
-
--include makefile-flags
-
-.PHONY: all
-all: version dep lib exec
-
-.PHONY: lib
-lib:
-       $(MAKE) $@
-       cp src/da.lib.h include/da.h
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/da/makefile-flags b/da/makefile-flags
deleted file mode 100644 (file)
index d732652..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-
-MODULE=da
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECDIR, INCDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=deprecated
-DOCDIR=doc
-EXECDIR=exec
-INCDIR=include
-LIBDIR=lib
-SRCDIR=src
-TESTDIR=test
-TMPDIR=tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=try
-
-# compiler and flags
-C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-Llib -lda 
-
-MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-
diff --git a/da/src/da.lib.c b/da/src/da.lib.c
deleted file mode 100644 (file)
index 0956d7e..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
-Dynamic Array
-
-*/
-
-#include "da.lib.h"
-
-#include<stdlib.h>
-#include<stdbool.h>
-#include<string.h>
-
-//--------------------------------------------------------------------------------
-// generic
-// We manipulate pointers to a smallest addressable unit. The sizeof operator
-// returns counts in these addressable units. Sizeof(char) is defined to be 1.
-
-void da_alloc(Da *dap, size_t element_size){
-  dap->element_size = element_size;
-  dap->size = 4 * element_size;
-  dap->base = malloc(dap->size);
-  dap->end = dap->base;
-}
-void da_free(Da *dap){
-  free(dap->base);
-  dap->size = 0;
-}
-void da_rewind(Da *dap){
-  dap->end = dap->base;
-}
-
-bool da_empty(Da *dap){
-  return dap->end == dap->base;
-}
-
-void da_rebase(Da *dap, char *old_base, void *pta){
-  char **pt = (char **)pta;
-  size_t offset = *pt - old_base;
-  *pt = dap->base + offset;
-}
-
-// Doubles size of of da.  Returns old base, so that existing pointers into the
-// array can be moved to the new array
-char *da_expand(Da *dap){
-  char *old_base = dap->base;
-  size_t end_offset = dap->end - old_base;
-  size_t new_size = dap->size << 1;
-  char *new_base = malloc( new_size );
-  memcpy( new_base, old_base, end_offset + dap->element_size);
-  free(old_base);
-  dap->base = new_base;
-  dap->end = new_base + end_offset;
-  dap->size = new_size;
-  return old_base;
-}
-
-// true when pt has run off the end of the area currently allocated for the array
-bool da_endq(Da *dap, void *pt){
-  return (char *)pt >= dap->end;
-}
-
-// true when pt has run off the end of the area allocated for the array
-bool da_boundq(Da *dap){
-  return dap->end >= dap->base + dap->size;
-}
-
-void da_push(Da *dap, void *element){
-  if( dap->end >= dap->base + dap->size ) da_expand(dap);
-  memcpy(dap->end, element, dap->element_size);
-  dap->end += dap->element_size;
-}
-
-bool da_pop(Da *dap, void *element){
-  bool flag = dap->end >= dap->base + dap->element_size;
-  if( flag ){
-    dap->end -= dap->element_size;
-    if(element) memcpy(element, dap->end, dap->element_size);
-  }
-  return flag;
-}
-
-char *da_index(Da *dap, size_t i){
-  size_t offset = i * dap->element_size;
-  char *pt = dap->base + offset;
-  return pt;
-}
-
-// passed in f(element_pt, arg_pt)
-// We have no language support closures, so we pass in an argument for it.
-// The closure may be set to NULL if it is not needed.
-void da_map(Da *dap, void f(void *, void *), void *closure){
-  char *pt = dap->base;
-  while( pt != dap->end ){
-    f(pt, closure);
-  pt += dap->element_size;
-  }
-}
-
-// da_lists are sometimes used as resource managers
-static void da_free_element(void *pt, void *closure){
-  free(*(char **)pt); // free does not care about the pointer type
-}
-
-void da_free_elements(Da *dap){
-  da_map(dap, da_free_element, NULL);
-  da_rewind(dap);
-}
-
-// for the case of an array of strings
-void da_strings_puts(Da *dap){
-  char *pt = dap->base;
-  while( pt != dap->end ){
-    puts(*(char **)pt);
-  pt += dap->element_size;
-  }
-}
-
-
-// Puts text from a line into buffer *dap. Does not push EOF or '\n' into the
-// buffer.  Returns the old_base so that external pointers can be rebased.
-// It is possible that the the base hasn't changed. Use feof(FILE *stream) to
-// test for EOF;
-char *da_fgets(Da *dap, FILE *file){
-  char *old_base = dap->base;
-  int c = fgetc(file);
-  while( c != EOF && c != '\n' ){
-    da_push(dap, &c);
-  c = fgetc(file);
-  }
-  int terminator = 0;
-  da_push(dap, &terminator);
-  return old_base;
-}
diff --git a/da/src/da.lib.h b/da/src/da.lib.h
deleted file mode 100644 (file)
index 6d3c43b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef DA_LIB_H
-#define DA_LIB_H
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdio.h>
-
-typedef struct Da{
-  char *base;
-  char *end; // one byte/one element off the end of the array
-  size_t size; // size >= (end - base) + 1;
-  size_t element_size;
-} Da;
-
-#define RETURN(dap, r)                      \
-  { da_map(dap, da_free, NULL); return r; }
-
-void da_alloc(Da *dap, size_t element_size);
-void da_free(Da *dap);
-void da_rewind(Da *dap);
-char *da_expand(Da *dap);
-void da_rebase(Da *dap, char *old_base, void *pta);
-bool da_endq(Da *dap, void *pt);
-bool da_boundq(Da *dap);
-void da_push(Da *dap, void *element);
-bool da_pop(Da *dap, void *element);
-char *da_index(Da *dap, size_t i);
-void da_map(Da *dap, void f(void *, void *), void *closure);
-void da_free_elements(Da *dap);
-void da_strings_puts(Da *dap);
-char *da_fgets(Da *dap, FILE *fd);
-
-#endif
-
diff --git a/da/test/makefile b/da/test/makefile
deleted file mode 100644 (file)
index dbd6be0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# da/test
-
-SHELL=/bin/bash
-
--include makefile-flags
-
-.PHONY: all
-all: version deps lib exec
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/da/test/makefile-dep b/da/test/makefile-dep
deleted file mode 100644 (file)
index cf61fb9..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-./test_da.lib.o: test_da.lib.c ../include/da.h test_da.lib.h
-./test_da.cli.o: test_da.cli.c test_da.lib.h
-
-./test_da : ./test_da.cli.o ./libtest.a
-       gcc -o ./test_da ./test_da.cli.o -L. -L../lib -ltest -lda
diff --git a/da/test/makefile-flags b/da/test/makefile-flags
deleted file mode 100644 (file)
index d916748..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-
-MODULE=test
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=
-DOCDIR=
-EXECDIR=.
-INCDIR=.
-LIBDIR=.
-SRCDIR=.
-TESTDIR=
-TMPDIR=.
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=
-
-# compiler and flags
-C=gcc
-CFLAGS=-std=gnu11 -fPIC -I../include -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I../include -Werror
-LINKFLAGS=-L. -L../lib -ltest -lda
-
-MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
diff --git a/da/test/results b/da/test/results
deleted file mode 100644 (file)
index 9e59b33..0000000
+++ /dev/null
@@ -1 +0,0 @@
-passed all 4 tests
diff --git a/da/test/test.dat b/da/test/test.dat
deleted file mode 100644 (file)
index 6b4b5bd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-this is a test
-ends without a newline
-(setq mode-require-final-newline nil)
\ No newline at end of file
diff --git a/da/test/test_da.cli.c b/da/test/test_da.cli.c
deleted file mode 100644 (file)
index bee5a6c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-
-#include <stdio.h>
-#include <stdbool.h>
-#include "test_da.lib.h"
-
-int main(){
-  bool da_0_passed = test_da_0();
-
-  unsigned int passed = 0;
-  unsigned int failed = 0;
-
-  // enumeration of tests
-  typedef bool (*test_fun)();
-  test_fun tests[] = {test_da_0, test_da_1, test_da_2, test_da_3, NULL};
-  char *test_names[] = {"test_da_0", "test_da_1", "test_da_2", "test_da_3", NULL};
-
-  // call tests
-  test_fun *tfp = tests;
-  char **tnp = test_names;
-  while(*tfp){
-    if( !(*tfp)() ){
-      failed++;
-      if(*tnp)
-        printf("%s failed\n", *tnp);
-      else
-        fprintf(stderr, "internal error, no test_names[] entry for test\n");
-    }else
-      passed++;
-  tfp++;
-  tnp++;
-  }
-
-  // summarize results
-
-  if( passed == 0 && failed == 0)
-    printf("no tests ran\n");
-  else if( passed == 0 )
-    printf("failed all %u tests\n", failed);
-  else if( failed == 0 )
-    printf("passed all %u tests\n", passed);
-  else
-    printf("failed %u of %u tests\n", failed, passed + failed);
-
-  if( passed == 0 || failed != 0 ) return 1;
-  return 0;
-}
diff --git a/da/test/test_da.cli.o b/da/test/test_da.cli.o
deleted file mode 100644 (file)
index d28221c..0000000
Binary files a/da/test/test_da.cli.o and /dev/null differ
diff --git a/da/test/test_da.lib.c b/da/test/test_da.lib.c
deleted file mode 100644 (file)
index 88a94c7..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
-Tests for Da.
-
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-#include <da.h>
-
-#include "test_da.lib.h"
-
-// tests push
-bool test_da_0(){
-  Da da;
-  da_alloc(&da, sizeof(int)); // leaves room for 4 ints
-  int i = 0;
-  int *pt = (int *)da.base;
-  // will double, 4 -> 8, then double 8 -> 16
-  while( i < 10 ){
-    da_push(&da, &i);
-  i++;
-  pt++;
-  }
-
-  bool f0 = da.size == sizeof(int) * 16;
-  bool f1 = 10 == (da.end - da.base) / sizeof(int);
-  bool f2 = true;
-  pt = (int *)da.base;
-  i = 0;
-  while( i < 10 ){
-    f2 = f2 && *pt == i && !da_endq(&da, pt);
-  i++;
-  pt++;
-  }
-  bool f3 = da_endq(&da, pt);
-
-  return f0 && f1 && f2 && f3;
-}
-
-// tests manual expansion
-bool test_da_1(){
-  Da da;
-  da_alloc(&da, sizeof(int)); // leaves room for 4 ints
-  int i = 0;
-  int *pt = (int *)da.base;
-  // will double, 4 -> 8, then double 8 -> 16
-  while( i < 10 ){
-    da.end += da.element_size;
-    if( da_boundq(&da) ){
-      char *old_base = da_expand(&da);
-      da_rebase(&da, old_base, &pt);
-    }
-    *pt = i;
-  i++;
-  pt++;
-  }
-
-  bool f0 = da.size == sizeof(int) * 16;
-  bool f1 = 10 == (da.end - da.base) / sizeof(int);
-  bool f2 = true;
-  pt = (int *)da.base;
-  i = 0;
-  while( i < 10 ){
-    f2 = f2 && *pt == i && !da_endq(&da, pt);
-  i++;
-  pt++;
-  }
-  bool f3 = da_endq(&da, pt);
-
-  return f0 && f1 && f2 && f3;
-}
-
-// da_fgets
-bool test_da_2(){
-
-  FILE *fd = fopen("test.dat","r");
-
-  Da da;
-  da_alloc(&da, sizeof(char));
-
-  da_fgets(&da, fd);
-  bool f0 = !strcmp(da.base, "this is a test");
-
-  char *old_base;
-  da_pop(&da, NULL); // pop the prior null terminator
-  char *s1 = da.end;
-  old_base = da_fgets(&da,fd);
-  da_rebase(&da, old_base, &s1);
-  bool f1 = !strcmp(s1, "ends without a newline");
-  
-  da_pop(&da, NULL); // pop the prior null terminator
-  char *s2 = da.end;
-  old_base = da_fgets(&da,fd);
-  da_rebase(&da, old_base, &s2);
-  bool f2 = !strcmp(s2, "(setq mode-require-final-newline nil)");
-
-  bool f3 = !strcmp(da.base, "this is a testends without a newline(setq mode-require-final-newline nil)");
-
-  fclose(fd);
-  return f0 && f1 && f2 && f3;
-}
-
-// da_fgets
-bool test_da_3(){
-
-  FILE *fd = fopen("test.dat","r");
-
-  Da da;
-  da_alloc(&da, sizeof(int));
-
-  int i = 5;
-  da_push(&da, &i);
-  i++;
-  da_push(&da, &i);
-  i++;
-  da_push(&da, &i);
-
-  int j;
-  bool f0 = da_pop(&da, &j) && j == 7;
-  bool f1 = da_pop(&da, &j) && j == 6;
-  bool f2 = da_pop(&da, NULL);
-  bool f3 = !da_pop(&da, &j);
-
-  return f0 && f1 && f2 && f3;
-}
-
-
-
-
diff --git a/da/test/test_da.lib.h b/da/test/test_da.lib.h
deleted file mode 100644 (file)
index 686b0d0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef DA_LIB_H
-#define DA_LIB_H
-
-bool test_da_0();
-bool test_da_1();
-bool test_da_2();
-bool test_da_3();
-
-#endif
diff --git a/da/test/test_da.lib.o b/da/test/test_da.lib.o
deleted file mode 100644 (file)
index 2a03683..0000000
Binary files a/da/test/test_da.lib.o and /dev/null differ
diff --git a/db/0_makefile b/db/0_makefile
deleted file mode 100644 (file)
index b8c7b9d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# src/0_makefile
-
-SHELL=/bin/bash
-
--include 0_makefile_flags
-
-SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
-MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-SOURCES=$(wildcard *.c)
-HFILES=$(wildcard *.h)
-
-all: version deps lib execs
-
-version:
-       $(MAKE) $@
-       @echo "SUID_TOOL: " $(SUID_TOOL)
-
-deps:
-       makeheaders $(SOURCES) $(HFILES)
-       sed -i '/^ *int *main *(.*)/d' *.h
-       $(MAKE) $@
-
-execs:
-       $(MAKE) $@
-       @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
-       cat $(SUID_TOOL)
-       @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
-       sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
-
-clean:
-       $(MAKE) $@
-       for i in $(HFILES); do rm $$i; done
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/db/0_makefile-flags b/db/0_makefile-flags
deleted file mode 100644 (file)
index 0da8b61..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=1_deprecated
-DOCDIR=1_doc
-EXECSDIR=1_execs
-HDIR=1_headers
-LIBDIR=1_lib
-TESTDIR=1_tests
-TMPDIR=1_tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=1_try
-
-
-# compiler and flags
-CC=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-L1_lib -lsubu -lsqlite3
-
-LIBFILE=$(LIBDIR)/libsubu.a
-
diff --git a/db/1_doc/return-from-transaction.txt b/db/1_doc/return-from-transaction.txt
deleted file mode 100644 (file)
index b7f8cbb..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-
-1.
-  This sql:
-
-    char *sql = 
-      "BEGIN TRANSACTION;"
-      "UPDATE Key_Int SET value = value + 1 WHERE key = 'max_subu_number';"
-      "SELECT value FROM Key_Int WHERE key = 'max_subu_number';"
-      "COMMIT;"
-      ;
-
-  with sqlite_exec, the call back is called with the data from the select.
-
-  with sqlite_prepare_v2, sqlite_step just returns SQLITE_DONE, and we never
-  get to see our data from the select.
diff --git a/db/dbprintf.lib.c b/db/dbprintf.lib.c
deleted file mode 100644 (file)
index d9d236b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-
-#include "dbprintf.lib.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-
-int dbprintf(const char *format, ...){
-  va_list args;
-  va_start(args,format);  
-  int ret = vfprintf(stdout, format, args);
-  fflush(stdout);
-  va_end(args);
-  return ret;
-}
diff --git a/dispatch/makefile b/dispatch/makefile
deleted file mode 100644 (file)
index 175b683..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# src-dispatch/makefile
-
-SHELL=/bin/bash
-
--include makefile-flags
-
-all: version dep lib
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/dispatch/makefile-flags b/dispatch/makefile-flags
deleted file mode 100644 (file)
index 48cadc2..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-# compiler and flags
-C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-
-LINKFLAGS=-L1_lib -lda 
-
-MODULE=dispatch
-
-MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_trc
-#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_trc
-
diff --git a/dispatch/src/dispatch.lib.c b/dispatch/src/dispatch.lib.c
deleted file mode 100644 (file)
index e34d020..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#tranche tmp/dispatch.trc.c
-
-#tranche include/dispatch.h
-/*
-  Runs a command or function as its own process.
-
-  The return status integer from command or function must be greater than ERR_DISPATCH.
-  In the case of dispatch_exec, we only have a promise from the user to not dispatch
-  non compliant commands.
-
-*/
-#ifndef DISPATCH_LIB_H
-#define DISPATCH_LIB_H
-#include <sys/types.h>
-#include <unistd.h>
-
-#define ERR_DISPATCH -1024
-#define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024
-#define ERR_DISPATCH_F_FORK -1025
-#define ERR_DISPATCH_F_SETEUID -1026
-#define ERR_DISPATCH_F_SETEGID -1027
-#define ERR_DISPATCH_NULL_EXECUTABLE -1028
-#define ERR_DISPATCH_EXEC -1029
-
-// currently both dispatcher and dispatchee strings are statically allocated
-struct dispatch_ctx{
-  char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.)
-  char *dispatchee; // name of the function being dispatched
-  int err; // error code as listed below, or status returned from dispatchee
-};
-#tranche-end
-
-#include "dispatch.h"
-
-// we need the declaration for uid_t etc.
-// without this #define execvpe is undefined
-#define _GNU_SOURCE   
-
-#include <wait.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-#tranche include/dispatch.h
-void dispatch_f_mess(char *fname, int err, char *dispatchee);
-#tranche-end
-void dispatch_f_mess(char *fname, int err, char *dispatchee){
-  if(err == 0) return;
-  fprintf(stderr, "%s: ", fname); // if fprintf gets an error, errno will be overwritten
-  if(err > ERR_DISPATCH){
-    fprintf(stderr, "dispatchee \"%s\" returned the error %d\n", dispatchee, err);
-    return;
-  }
-  switch(err){
-  case ERR_DISPATCH_NEGATIVE_RETURN_STATUS:
-    fprintf(stderr, " dispatchee \"%s\" returned a negative status.", dispatchee);
-    break;
-  case ERR_DISPATCH_F_FORK:
-  case ERR_DISPATCH_F_SETEUID:
-  case ERR_DISPATCH_F_SETEGID:
-    fputc(' ', stderr);
-    perror(dispatchee);
-    break;
-  case ERR_DISPATCH_NULL_EXECUTABLE:
-    fprintf(stderr, " executable was not specified");
-    break;
-  case ERR_DISPATCH_EXEC:
-    // exec is running in another process when it fails, so we can't see the errno value it set
-    fprintf(stderr, " exec of \"%s\" failed", dispatchee);
-    break;
-  default:
-    fprintf(stderr, " returned undefined status when dispatching \"%s\"", dispatchee);
-  }
-  fputc('\n', stderr);
-}
-
-//--------------------------------------------------------------------------------
-// interface call point, dispatch a function
-#tranche include/dispatch.h
-int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg);
-#tranche-end
-int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
-  #ifdef DEBUG
-  dbprintf("%s %s\n", "dispatch_f", fname);
-  #endif
-  pid_t pid = fork();
-  if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
-  if( pid == 0 ){ // we are the child
-    int status = (*f)(f_arg); // we require that f return a zero or positive value
-    if( status < ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS;
-    exit(status);
-  }else{ // we are the parent
-    int err;
-    waitpid(pid, &err, 0);
-    return err;
-  }
-}
-
-//--------------------------------------------------------------------------------
-// interface call point, dispatch a function with a given euid/egid
-// of course this will only work if our euid is root in the first place
-#tranche include/dispatch.h
-int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid);
-#tranche-end
-int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
-  #ifdef DEBUG
-  dbprintf("%s %s as euid:%u egid:%u\n", "dispatch_f_euid_egid", fname, euid, egid);
-  #endif
-  pid_t pid = fork();
-  if( pid == -1 ) return ERR_DISPATCH_F_FORK;
-  if( pid == 0 ){ // we are the child
-    int status;
-    if( seteuid(euid) == -1 )
-      status = ERR_DISPATCH_F_SETEUID;
-    else if( setegid(egid) == -1 )
-      status = ERR_DISPATCH_F_SETEGID;
-    else{
-      status = (*f)(f_arg);
-      if( status <= ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS;
-      exit(status);
-    }
-  }else{ // we are the parent
-    uint err;
-    waitpid(pid, &err, 0);
-    return err;
-  }
-}
-
-//--------------------------------------------------------------------------------
-// interface call point, dispatch a executable
-#tranche include/dispatch.h
-int dispatch_exec(char **argv, char **envp);
-#tranche-end
-int dispatch_exec(char **argv, char **envp){
-  char *command;
-  {
-    if( !argv || !argv[0] ) return ERR_DISPATCH_NULL_EXECUTABLE;
-    #ifdef DEBUG
-      dbprintf("dispatch_exec:");
-      char **apt = argv;
-      while( *apt ){
-        dbprintf(" %s",*apt);
-        apt++;
-      }
-      dbprintf("\n");
-    #endif
-    command = argv[0];
-  }
-  pid_t pid = fork();
-  if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
-  if( pid == 0 ){ // we are the child
-    execvpe(command, argv, envp); // exec will only return if it has an error
-    #ifdef DEBUG
-    dbprintf("dispatch_exec: exec returned, perror message:");
-    perror("dispatch_exec"); // our only chance to print this message, as this is the child process
-    #endif
-    fflush(stdout);
-    exit(ERR_DISPATCH_EXEC); 
-  }else{ // we are the parent
-    int err;
-    waitpid(pid, &err, 0);
-    return err;
-  }
-}
-
-#tranche-end
index ddad312..c7a88ed 100755 (executable)
--- a/makefile
+++ b/makefile
@@ -1,11 +1,11 @@
 #MAKEABLE=$(shell \
-#    find .\
+#    find src-*\
 #      \( -name 'makefile' -o -name 'Makefile' \)\
 #      -printf "%h\n"\
 #    | grep -v deprecated | grep -v doc | sort -u | sed ':a;N;$!ba;s/\n/ /g' \
 #)
 
-MAKEABLE= da da/test tranche
+MAKEABLE= module/da module/da/test module/tranche
 
 .PHONY: all info clean dist-clean
 
diff --git a/module/da/makefile b/module/da/makefile
new file mode 100644 (file)
index 0000000..67fbdb9
--- /dev/null
@@ -0,0 +1,21 @@
+# da/makefile
+
+SHELL=/bin/bash
+MAKE=
+
+-include makefile-flags
+
+.PHONY: all
+all: version dep lib exec
+
+.PHONY: lib
+lib:
+       $(MAKE) $@
+       cp src/da.lib.h include/da.h
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/da/makefile-flags b/module/da/makefile-flags
new file mode 100644 (file)
index 0000000..8bb0814
--- /dev/null
@@ -0,0 +1,35 @@
+
+MODULE=da
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECDIR, INCDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=deprecated
+DOCDIR=doc
+EXECDIR=exec
+INCDIR=include
+LIBDIR=lib
+SRCDIR=src
+TESTDIR=test
+TMPDIR=tmp
+TOOLDIR=$(realpath $(PROJECT_SUBU)/tool)
+TRYDIR=try
+
+# compiler and flags
+C=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-Llib -lda 
+
+MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tool/lib/makefile_cc
+#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tool/lib/makefile_cc
+
+
diff --git a/module/da/src/da.lib.c b/module/da/src/da.lib.c
new file mode 100644 (file)
index 0000000..0956d7e
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+Dynamic Array
+
+*/
+
+#include "da.lib.h"
+
+#include<stdlib.h>
+#include<stdbool.h>
+#include<string.h>
+
+//--------------------------------------------------------------------------------
+// generic
+// We manipulate pointers to a smallest addressable unit. The sizeof operator
+// returns counts in these addressable units. Sizeof(char) is defined to be 1.
+
+void da_alloc(Da *dap, size_t element_size){
+  dap->element_size = element_size;
+  dap->size = 4 * element_size;
+  dap->base = malloc(dap->size);
+  dap->end = dap->base;
+}
+void da_free(Da *dap){
+  free(dap->base);
+  dap->size = 0;
+}
+void da_rewind(Da *dap){
+  dap->end = dap->base;
+}
+
+bool da_empty(Da *dap){
+  return dap->end == dap->base;
+}
+
+void da_rebase(Da *dap, char *old_base, void *pta){
+  char **pt = (char **)pta;
+  size_t offset = *pt - old_base;
+  *pt = dap->base + offset;
+}
+
+// Doubles size of of da.  Returns old base, so that existing pointers into the
+// array can be moved to the new array
+char *da_expand(Da *dap){
+  char *old_base = dap->base;
+  size_t end_offset = dap->end - old_base;
+  size_t new_size = dap->size << 1;
+  char *new_base = malloc( new_size );
+  memcpy( new_base, old_base, end_offset + dap->element_size);
+  free(old_base);
+  dap->base = new_base;
+  dap->end = new_base + end_offset;
+  dap->size = new_size;
+  return old_base;
+}
+
+// true when pt has run off the end of the area currently allocated for the array
+bool da_endq(Da *dap, void *pt){
+  return (char *)pt >= dap->end;
+}
+
+// true when pt has run off the end of the area allocated for the array
+bool da_boundq(Da *dap){
+  return dap->end >= dap->base + dap->size;
+}
+
+void da_push(Da *dap, void *element){
+  if( dap->end >= dap->base + dap->size ) da_expand(dap);
+  memcpy(dap->end, element, dap->element_size);
+  dap->end += dap->element_size;
+}
+
+bool da_pop(Da *dap, void *element){
+  bool flag = dap->end >= dap->base + dap->element_size;
+  if( flag ){
+    dap->end -= dap->element_size;
+    if(element) memcpy(element, dap->end, dap->element_size);
+  }
+  return flag;
+}
+
+char *da_index(Da *dap, size_t i){
+  size_t offset = i * dap->element_size;
+  char *pt = dap->base + offset;
+  return pt;
+}
+
+// passed in f(element_pt, arg_pt)
+// We have no language support closures, so we pass in an argument for it.
+// The closure may be set to NULL if it is not needed.
+void da_map(Da *dap, void f(void *, void *), void *closure){
+  char *pt = dap->base;
+  while( pt != dap->end ){
+    f(pt, closure);
+  pt += dap->element_size;
+  }
+}
+
+// da_lists are sometimes used as resource managers
+static void da_free_element(void *pt, void *closure){
+  free(*(char **)pt); // free does not care about the pointer type
+}
+
+void da_free_elements(Da *dap){
+  da_map(dap, da_free_element, NULL);
+  da_rewind(dap);
+}
+
+// for the case of an array of strings
+void da_strings_puts(Da *dap){
+  char *pt = dap->base;
+  while( pt != dap->end ){
+    puts(*(char **)pt);
+  pt += dap->element_size;
+  }
+}
+
+
+// Puts text from a line into buffer *dap. Does not push EOF or '\n' into the
+// buffer.  Returns the old_base so that external pointers can be rebased.
+// It is possible that the the base hasn't changed. Use feof(FILE *stream) to
+// test for EOF;
+char *da_fgets(Da *dap, FILE *file){
+  char *old_base = dap->base;
+  int c = fgetc(file);
+  while( c != EOF && c != '\n' ){
+    da_push(dap, &c);
+  c = fgetc(file);
+  }
+  int terminator = 0;
+  da_push(dap, &terminator);
+  return old_base;
+}
diff --git a/module/da/src/da.lib.h b/module/da/src/da.lib.h
new file mode 100644 (file)
index 0000000..6d3c43b
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef DA_LIB_H
+#define DA_LIB_H
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef struct Da{
+  char *base;
+  char *end; // one byte/one element off the end of the array
+  size_t size; // size >= (end - base) + 1;
+  size_t element_size;
+} Da;
+
+#define RETURN(dap, r)                      \
+  { da_map(dap, da_free, NULL); return r; }
+
+void da_alloc(Da *dap, size_t element_size);
+void da_free(Da *dap);
+void da_rewind(Da *dap);
+char *da_expand(Da *dap);
+void da_rebase(Da *dap, char *old_base, void *pta);
+bool da_endq(Da *dap, void *pt);
+bool da_boundq(Da *dap);
+void da_push(Da *dap, void *element);
+bool da_pop(Da *dap, void *element);
+char *da_index(Da *dap, size_t i);
+void da_map(Da *dap, void f(void *, void *), void *closure);
+void da_free_elements(Da *dap);
+void da_strings_puts(Da *dap);
+char *da_fgets(Da *dap, FILE *fd);
+
+#endif
+
diff --git a/module/da/test/makefile b/module/da/test/makefile
new file mode 100644 (file)
index 0000000..dbd6be0
--- /dev/null
@@ -0,0 +1,15 @@
+# da/test
+
+SHELL=/bin/bash
+
+-include makefile-flags
+
+.PHONY: all
+all: version deps lib exec
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/da/test/makefile-dep b/module/da/test/makefile-dep
new file mode 100644 (file)
index 0000000..cf61fb9
--- /dev/null
@@ -0,0 +1,5 @@
+./test_da.lib.o: test_da.lib.c ../include/da.h test_da.lib.h
+./test_da.cli.o: test_da.cli.c test_da.lib.h
+
+./test_da : ./test_da.cli.o ./libtest.a
+       gcc -o ./test_da ./test_da.cli.o -L. -L../lib -ltest -lda
diff --git a/module/da/test/makefile-flags b/module/da/test/makefile-flags
new file mode 100644 (file)
index 0000000..a8adf4d
--- /dev/null
@@ -0,0 +1,33 @@
+
+MODULE=test
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=
+DOCDIR=
+EXECDIR=.
+INCDIR=.
+LIBDIR=.
+SRCDIR=.
+TESTDIR=
+TMPDIR=.
+TOOLDIR=$(realpath $(PROJECT_SUBU)/tool)
+TRYDIR=
+
+# compiler and flags
+C=gcc
+CFLAGS=-std=gnu11 -fPIC -I../include -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I../include -Werror
+LINKFLAGS=-L. -L../lib -ltest -lda
+
+MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tool/lib/makefile_cc
+#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tool/lib/makefile_cc
diff --git a/module/da/test/results b/module/da/test/results
new file mode 100644 (file)
index 0000000..9e59b33
--- /dev/null
@@ -0,0 +1 @@
+passed all 4 tests
diff --git a/module/da/test/test.dat b/module/da/test/test.dat
new file mode 100644 (file)
index 0000000..6b4b5bd
--- /dev/null
@@ -0,0 +1,3 @@
+this is a test
+ends without a newline
+(setq mode-require-final-newline nil)
\ No newline at end of file
diff --git a/module/da/test/test_da.cli.c b/module/da/test/test_da.cli.c
new file mode 100644 (file)
index 0000000..bee5a6c
--- /dev/null
@@ -0,0 +1,46 @@
+
+#include <stdio.h>
+#include <stdbool.h>
+#include "test_da.lib.h"
+
+int main(){
+  bool da_0_passed = test_da_0();
+
+  unsigned int passed = 0;
+  unsigned int failed = 0;
+
+  // enumeration of tests
+  typedef bool (*test_fun)();
+  test_fun tests[] = {test_da_0, test_da_1, test_da_2, test_da_3, NULL};
+  char *test_names[] = {"test_da_0", "test_da_1", "test_da_2", "test_da_3", NULL};
+
+  // call tests
+  test_fun *tfp = tests;
+  char **tnp = test_names;
+  while(*tfp){
+    if( !(*tfp)() ){
+      failed++;
+      if(*tnp)
+        printf("%s failed\n", *tnp);
+      else
+        fprintf(stderr, "internal error, no test_names[] entry for test\n");
+    }else
+      passed++;
+  tfp++;
+  tnp++;
+  }
+
+  // summarize results
+
+  if( passed == 0 && failed == 0)
+    printf("no tests ran\n");
+  else if( passed == 0 )
+    printf("failed all %u tests\n", failed);
+  else if( failed == 0 )
+    printf("passed all %u tests\n", passed);
+  else
+    printf("failed %u of %u tests\n", failed, passed + failed);
+
+  if( passed == 0 || failed != 0 ) return 1;
+  return 0;
+}
diff --git a/module/da/test/test_da.cli.o b/module/da/test/test_da.cli.o
new file mode 100644 (file)
index 0000000..d28221c
Binary files /dev/null and b/module/da/test/test_da.cli.o differ
diff --git a/module/da/test/test_da.lib.c b/module/da/test/test_da.lib.c
new file mode 100644 (file)
index 0000000..88a94c7
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+Tests for Da.
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <da.h>
+
+#include "test_da.lib.h"
+
+// tests push
+bool test_da_0(){
+  Da da;
+  da_alloc(&da, sizeof(int)); // leaves room for 4 ints
+  int i = 0;
+  int *pt = (int *)da.base;
+  // will double, 4 -> 8, then double 8 -> 16
+  while( i < 10 ){
+    da_push(&da, &i);
+  i++;
+  pt++;
+  }
+
+  bool f0 = da.size == sizeof(int) * 16;
+  bool f1 = 10 == (da.end - da.base) / sizeof(int);
+  bool f2 = true;
+  pt = (int *)da.base;
+  i = 0;
+  while( i < 10 ){
+    f2 = f2 && *pt == i && !da_endq(&da, pt);
+  i++;
+  pt++;
+  }
+  bool f3 = da_endq(&da, pt);
+
+  return f0 && f1 && f2 && f3;
+}
+
+// tests manual expansion
+bool test_da_1(){
+  Da da;
+  da_alloc(&da, sizeof(int)); // leaves room for 4 ints
+  int i = 0;
+  int *pt = (int *)da.base;
+  // will double, 4 -> 8, then double 8 -> 16
+  while( i < 10 ){
+    da.end += da.element_size;
+    if( da_boundq(&da) ){
+      char *old_base = da_expand(&da);
+      da_rebase(&da, old_base, &pt);
+    }
+    *pt = i;
+  i++;
+  pt++;
+  }
+
+  bool f0 = da.size == sizeof(int) * 16;
+  bool f1 = 10 == (da.end - da.base) / sizeof(int);
+  bool f2 = true;
+  pt = (int *)da.base;
+  i = 0;
+  while( i < 10 ){
+    f2 = f2 && *pt == i && !da_endq(&da, pt);
+  i++;
+  pt++;
+  }
+  bool f3 = da_endq(&da, pt);
+
+  return f0 && f1 && f2 && f3;
+}
+
+// da_fgets
+bool test_da_2(){
+
+  FILE *fd = fopen("test.dat","r");
+
+  Da da;
+  da_alloc(&da, sizeof(char));
+
+  da_fgets(&da, fd);
+  bool f0 = !strcmp(da.base, "this is a test");
+
+  char *old_base;
+  da_pop(&da, NULL); // pop the prior null terminator
+  char *s1 = da.end;
+  old_base = da_fgets(&da,fd);
+  da_rebase(&da, old_base, &s1);
+  bool f1 = !strcmp(s1, "ends without a newline");
+  
+  da_pop(&da, NULL); // pop the prior null terminator
+  char *s2 = da.end;
+  old_base = da_fgets(&da,fd);
+  da_rebase(&da, old_base, &s2);
+  bool f2 = !strcmp(s2, "(setq mode-require-final-newline nil)");
+
+  bool f3 = !strcmp(da.base, "this is a testends without a newline(setq mode-require-final-newline nil)");
+
+  fclose(fd);
+  return f0 && f1 && f2 && f3;
+}
+
+// da_fgets
+bool test_da_3(){
+
+  FILE *fd = fopen("test.dat","r");
+
+  Da da;
+  da_alloc(&da, sizeof(int));
+
+  int i = 5;
+  da_push(&da, &i);
+  i++;
+  da_push(&da, &i);
+  i++;
+  da_push(&da, &i);
+
+  int j;
+  bool f0 = da_pop(&da, &j) && j == 7;
+  bool f1 = da_pop(&da, &j) && j == 6;
+  bool f2 = da_pop(&da, NULL);
+  bool f3 = !da_pop(&da, &j);
+
+  return f0 && f1 && f2 && f3;
+}
+
+
+
+
diff --git a/module/da/test/test_da.lib.h b/module/da/test/test_da.lib.h
new file mode 100644 (file)
index 0000000..686b0d0
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef DA_LIB_H
+#define DA_LIB_H
+
+bool test_da_0();
+bool test_da_1();
+bool test_da_2();
+bool test_da_3();
+
+#endif
diff --git a/module/da/test/test_da.lib.o b/module/da/test/test_da.lib.o
new file mode 100644 (file)
index 0000000..2a03683
Binary files /dev/null and b/module/da/test/test_da.lib.o differ
diff --git a/module/db/0_makefile b/module/db/0_makefile
new file mode 100644 (file)
index 0000000..b8c7b9d
--- /dev/null
@@ -0,0 +1,40 @@
+# src/0_makefile
+
+SHELL=/bin/bash
+
+-include 0_makefile_flags
+
+SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
+
+SOURCES=$(wildcard *.c)
+HFILES=$(wildcard *.h)
+
+all: version deps lib execs
+
+version:
+       $(MAKE) $@
+       @echo "SUID_TOOL: " $(SUID_TOOL)
+
+deps:
+       makeheaders $(SOURCES) $(HFILES)
+       sed -i '/^ *int *main *(.*)/d' *.h
+       $(MAKE) $@
+
+execs:
+       $(MAKE) $@
+       @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+       cat $(SUID_TOOL)
+       @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
+       sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+
+clean:
+       $(MAKE) $@
+       for i in $(HFILES); do rm $$i; done
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/db/0_makefile-flags b/module/db/0_makefile-flags
new file mode 100644 (file)
index 0000000..d4df01f
--- /dev/null
@@ -0,0 +1,31 @@
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=1_deprecated
+DOCDIR=1_doc
+EXECSDIR=1_execs
+HDIR=1_headers
+LIBDIR=1_lib
+TESTDIR=1_tests
+TMPDIR=1_tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=1_try
+
+
+# compiler and flags
+CC=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-L1_lib -lsubu -lsqlite3
+
+LIBFILE=$(LIBDIR)/libsubu.a
+
diff --git a/module/db/1_doc/return-from-transaction.txt b/module/db/1_doc/return-from-transaction.txt
new file mode 100644 (file)
index 0000000..b7f8cbb
--- /dev/null
@@ -0,0 +1,15 @@
+
+1.
+  This sql:
+
+    char *sql = 
+      "BEGIN TRANSACTION;"
+      "UPDATE Key_Int SET value = value + 1 WHERE key = 'max_subu_number';"
+      "SELECT value FROM Key_Int WHERE key = 'max_subu_number';"
+      "COMMIT;"
+      ;
+
+  with sqlite_exec, the call back is called with the data from the select.
+
+  with sqlite_prepare_v2, sqlite_step just returns SQLITE_DONE, and we never
+  get to see our data from the select.
diff --git a/module/db/dbprintf.lib.c b/module/db/dbprintf.lib.c
new file mode 100644 (file)
index 0000000..d9d236b
--- /dev/null
@@ -0,0 +1,14 @@
+
+#include "dbprintf.lib.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+int dbprintf(const char *format, ...){
+  va_list args;
+  va_start(args,format);  
+  int ret = vfprintf(stdout, format, args);
+  fflush(stdout);
+  va_end(args);
+  return ret;
+}
diff --git a/module/dispatch/makefile b/module/dispatch/makefile
new file mode 100644 (file)
index 0000000..175b683
--- /dev/null
@@ -0,0 +1,14 @@
+# src-dispatch/makefile
+
+SHELL=/bin/bash
+
+-include makefile-flags
+
+all: version dep lib
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/dispatch/makefile-flags b/module/dispatch/makefile-flags
new file mode 100644 (file)
index 0000000..48cadc2
--- /dev/null
@@ -0,0 +1,20 @@
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+# compiler and flags
+C=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+
+LINKFLAGS=-L1_lib -lda 
+
+MODULE=dispatch
+
+MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_trc
+#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_trc
+
diff --git a/module/dispatch/src/dispatch.lib.c b/module/dispatch/src/dispatch.lib.c
new file mode 100644 (file)
index 0000000..e34d020
--- /dev/null
@@ -0,0 +1,166 @@
+#tranche tmp/dispatch.trc.c
+
+#tranche include/dispatch.h
+/*
+  Runs a command or function as its own process.
+
+  The return status integer from command or function must be greater than ERR_DISPATCH.
+  In the case of dispatch_exec, we only have a promise from the user to not dispatch
+  non compliant commands.
+
+*/
+#ifndef DISPATCH_LIB_H
+#define DISPATCH_LIB_H
+#include <sys/types.h>
+#include <unistd.h>
+
+#define ERR_DISPATCH -1024
+#define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024
+#define ERR_DISPATCH_F_FORK -1025
+#define ERR_DISPATCH_F_SETEUID -1026
+#define ERR_DISPATCH_F_SETEGID -1027
+#define ERR_DISPATCH_NULL_EXECUTABLE -1028
+#define ERR_DISPATCH_EXEC -1029
+
+// currently both dispatcher and dispatchee strings are statically allocated
+struct dispatch_ctx{
+  char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.)
+  char *dispatchee; // name of the function being dispatched
+  int err; // error code as listed below, or status returned from dispatchee
+};
+#tranche-end
+
+#include "dispatch.h"
+
+// we need the declaration for uid_t etc.
+// without this #define execvpe is undefined
+#define _GNU_SOURCE   
+
+#include <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#tranche include/dispatch.h
+void dispatch_f_mess(char *fname, int err, char *dispatchee);
+#tranche-end
+void dispatch_f_mess(char *fname, int err, char *dispatchee){
+  if(err == 0) return;
+  fprintf(stderr, "%s: ", fname); // if fprintf gets an error, errno will be overwritten
+  if(err > ERR_DISPATCH){
+    fprintf(stderr, "dispatchee \"%s\" returned the error %d\n", dispatchee, err);
+    return;
+  }
+  switch(err){
+  case ERR_DISPATCH_NEGATIVE_RETURN_STATUS:
+    fprintf(stderr, " dispatchee \"%s\" returned a negative status.", dispatchee);
+    break;
+  case ERR_DISPATCH_F_FORK:
+  case ERR_DISPATCH_F_SETEUID:
+  case ERR_DISPATCH_F_SETEGID:
+    fputc(' ', stderr);
+    perror(dispatchee);
+    break;
+  case ERR_DISPATCH_NULL_EXECUTABLE:
+    fprintf(stderr, " executable was not specified");
+    break;
+  case ERR_DISPATCH_EXEC:
+    // exec is running in another process when it fails, so we can't see the errno value it set
+    fprintf(stderr, " exec of \"%s\" failed", dispatchee);
+    break;
+  default:
+    fprintf(stderr, " returned undefined status when dispatching \"%s\"", dispatchee);
+  }
+  fputc('\n', stderr);
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a function
+#tranche include/dispatch.h
+int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg);
+#tranche-end
+int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
+  #ifdef DEBUG
+  dbprintf("%s %s\n", "dispatch_f", fname);
+  #endif
+  pid_t pid = fork();
+  if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
+  if( pid == 0 ){ // we are the child
+    int status = (*f)(f_arg); // we require that f return a zero or positive value
+    if( status < ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS;
+    exit(status);
+  }else{ // we are the parent
+    int err;
+    waitpid(pid, &err, 0);
+    return err;
+  }
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a function with a given euid/egid
+// of course this will only work if our euid is root in the first place
+#tranche include/dispatch.h
+int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid);
+#tranche-end
+int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
+  #ifdef DEBUG
+  dbprintf("%s %s as euid:%u egid:%u\n", "dispatch_f_euid_egid", fname, euid, egid);
+  #endif
+  pid_t pid = fork();
+  if( pid == -1 ) return ERR_DISPATCH_F_FORK;
+  if( pid == 0 ){ // we are the child
+    int status;
+    if( seteuid(euid) == -1 )
+      status = ERR_DISPATCH_F_SETEUID;
+    else if( setegid(egid) == -1 )
+      status = ERR_DISPATCH_F_SETEGID;
+    else{
+      status = (*f)(f_arg);
+      if( status <= ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS;
+      exit(status);
+    }
+  }else{ // we are the parent
+    uint err;
+    waitpid(pid, &err, 0);
+    return err;
+  }
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a executable
+#tranche include/dispatch.h
+int dispatch_exec(char **argv, char **envp);
+#tranche-end
+int dispatch_exec(char **argv, char **envp){
+  char *command;
+  {
+    if( !argv || !argv[0] ) return ERR_DISPATCH_NULL_EXECUTABLE;
+    #ifdef DEBUG
+      dbprintf("dispatch_exec:");
+      char **apt = argv;
+      while( *apt ){
+        dbprintf(" %s",*apt);
+        apt++;
+      }
+      dbprintf("\n");
+    #endif
+    command = argv[0];
+  }
+  pid_t pid = fork();
+  if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
+  if( pid == 0 ){ // we are the child
+    execvpe(command, argv, envp); // exec will only return if it has an error
+    #ifdef DEBUG
+    dbprintf("dispatch_exec: exec returned, perror message:");
+    perror("dispatch_exec"); // our only chance to print this message, as this is the child process
+    #endif
+    fflush(stdout);
+    exit(ERR_DISPATCH_EXEC); 
+  }else{ // we are the parent
+    int err;
+    waitpid(pid, &err, 0);
+    return err;
+  }
+}
+
+#tranche-end
diff --git a/module/share/include/da.h b/module/share/include/da.h
new file mode 100644 (file)
index 0000000..6d3c43b
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef DA_LIB_H
+#define DA_LIB_H
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef struct Da{
+  char *base;
+  char *end; // one byte/one element off the end of the array
+  size_t size; // size >= (end - base) + 1;
+  size_t element_size;
+} Da;
+
+#define RETURN(dap, r)                      \
+  { da_map(dap, da_free, NULL); return r; }
+
+void da_alloc(Da *dap, size_t element_size);
+void da_free(Da *dap);
+void da_rewind(Da *dap);
+char *da_expand(Da *dap);
+void da_rebase(Da *dap, char *old_base, void *pta);
+bool da_endq(Da *dap, void *pt);
+bool da_boundq(Da *dap);
+void da_push(Da *dap, void *element);
+bool da_pop(Da *dap, void *element);
+char *da_index(Da *dap, size_t i);
+void da_map(Da *dap, void f(void *, void *), void *closure);
+void da_free_elements(Da *dap);
+void da_strings_puts(Da *dap);
+char *da_fgets(Da *dap, FILE *fd);
+
+#endif
+
diff --git a/module/share/include/tranche.h b/module/share/include/tranche.h
new file mode 100644 (file)
index 0000000..27990a6
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef TRANCHE_LIB_H
+#define TRANCHE_LIB_H
+
+int tranche_send(FILE *src, Da *arg_fds);
+
+
+
+#endif
diff --git a/module/subu-0/0_makefile b/module/subu-0/0_makefile
new file mode 100644 (file)
index 0000000..b8c7b9d
--- /dev/null
@@ -0,0 +1,40 @@
+# src/0_makefile
+
+SHELL=/bin/bash
+
+-include 0_makefile_flags
+
+SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
+
+SOURCES=$(wildcard *.c)
+HFILES=$(wildcard *.h)
+
+all: version deps lib execs
+
+version:
+       $(MAKE) $@
+       @echo "SUID_TOOL: " $(SUID_TOOL)
+
+deps:
+       makeheaders $(SOURCES) $(HFILES)
+       sed -i '/^ *int *main *(.*)/d' *.h
+       $(MAKE) $@
+
+execs:
+       $(MAKE) $@
+       @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+       cat $(SUID_TOOL)
+       @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
+       sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+
+clean:
+       $(MAKE) $@
+       for i in $(HFILES); do rm $$i; done
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/subu-0/0_makefile-flags b/module/subu-0/0_makefile-flags
new file mode 100644 (file)
index 0000000..d4df01f
--- /dev/null
@@ -0,0 +1,31 @@
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=1_deprecated
+DOCDIR=1_doc
+EXECSDIR=1_execs
+HDIR=1_headers
+LIBDIR=1_lib
+TESTDIR=1_tests
+TMPDIR=1_tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=1_try
+
+
+# compiler and flags
+CC=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-L1_lib -lsubu -lsqlite3
+
+LIBFILE=$(LIBDIR)/libsubu.a
+
diff --git a/module/subu-0/1_deprecated/dispatch_exec.lib.c b/module/subu-0/1_deprecated/dispatch_exec.lib.c
new file mode 100644 (file)
index 0000000..024bff8
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ fork/execs/wait the command passed in argv[0];
+ Returns -1 upon failure.
+
+ The wstatus returned from wait() might be either the error returned by exec
+ when it failed, or the return value from the command.  An arbitary command is
+ passed in, so we don't know what its return values might be. Consquently, we
+ have no way of multiplexing a unique exec error code with the command return
+ value within wstatus.  If the prorgrammer knows the return values of the
+ command passed in, and wants better behavior, he or she can spin a special
+ version of dispatch for that command.
+*/
+#include "dispatch_exec.lib.h"
+
+// without this #define execvpe is undefined
+#define _GNU_SOURCE   
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+
+int dispatch_exec(char **argv, char **envp){
+  if( !argv || !argv[0] ){
+    fprintf(stderr, "argv[0] null. Null command passed into dispatch().\n");
+    return -1;
+  }
+  #ifdef DEBUG
+    dbprintf("dispatching exec, args follow:\n");
+    char **apt = argv;
+    while( *apt ){
+      dbprintf("\t%s",*apt);
+    apt++;
+    }
+    dbprintf("\n");
+  #endif
+  char *command = argv[0];
+  pid_t pid = fork();
+  if( pid == -1 ){
+    fprintf(stderr, "fork() failed in dispatch().\n");
+    return -1;
+  }
+  if( pid == 0 ){ // we are the child
+    execvpe(command, argv, envp);
+    // exec will only return if it has an error ..
+    perror(command);
+    return -1;
+  }else{ // we are the parent
+    int wstatus;
+    waitpid(pid, &wstatus, 0);
+    if(wstatus)
+      return -1;
+    else
+      return 0;
+  }
+}
diff --git a/module/subu-0/1_deprecated/dispatch_f.lib.c b/module/subu-0/1_deprecated/dispatch_f.lib.c
new file mode 100644 (file)
index 0000000..5c199f5
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+  Forks a new process and runs the a function in that new process.  I.e. it 'spawns' a function.
+
+  f must have the specified prototype. I.e. it accepts one void pointer and
+  returns a positive integer. (Negative integers are used for dispatch error codes.)
+
+  dispatch_f_euid_egid changes to the new euid and egid before running the function.
+
+  If the change to in euid/egid fails, the forked process exits with a negative status.
+  If the function has an error, it returns a positive status.  A status of zero means
+  that all went well.
+
+  Because f is running in a separate process, the return status is the only means
+  of communication going back to the calling process.
+
+
+*/
+#define _GNU_SOURCE
+
+#include "dispatch_f.lib.h"
+// we need the declaration for uid_t etc.
+// without this #define execvpe is undefined
+#define _GNU_SOURCE   
+
+#include <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#if INTERFACE
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+//--------------------------------------------------------------------------------
+// dispatch_f_ctx class
+//
+#if INTERFACE
+#define ERR_NEGATIVE_RETURN_STATUS -1
+#define ERR_DISPATCH_F_FORK -2
+#define ERR_DISPATCH_F_SETEUID -3
+#define ERR_DISPATCH_F_SETEGID -4
+
+// both name and fname are static allocations
+struct dispatch_f_ctx{
+  char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid")
+  char *dispatchee; // name of the function being dispatched
+  int err;
+  int status; // return value from the function
+};
+#endif
+dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){
+  dispatch_f_ctx *ctxp = malloc(sizeof(dispatch_f_ctx));
+  ctxp->dispatcher = name;
+  ctxp->dispatchee = fname;
+  ctxp->err = 0;
+  return ctxp;
+}
+void dispatch_f_ctx_free(dispatch_f_ctx *ctxp){
+   // no dynamic variables to be freed in ctx
+  free(ctxp); 
+}
+void dispatch_f_mess(struct dispatch_f_ctx *ctxp){
+  if(ctxp->err == 0) return;
+  switch(ctxp->err){
+  case ERR_NEGATIVE_RETURN_STATUS:
+    fprintf(stderr, "%s, function \"%s\" broke contract with a negative return value.", ctxp->dispatcher, ctxp->dispatchee);
+    break;
+  case ERR_DISPATCH_F_FORK:
+  case ERR_DISPATCH_F_SETEUID:
+  case ERR_DISPATCH_F_SETEGID:
+    fprintf(stderr, "%s, ", ctxp->dispatcher);
+    perror(ctxp->dispatcher);
+    break;
+  }
+  fputc('\n', stderr);
+}
+
+//--------------------------------------------------------------------------------
+// interface call point
+dispatch_f_ctx *dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
+  dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f", fname);
+  #ifdef DEBUG
+  dbprintf("%s %s\n", ctxp->dispatcher, ctxp->dispatchee);
+  #endif
+  pid_t pid = fork();
+  if( pid == -1 ){
+    ctxp->err = ERR_DISPATCH_F_FORK; // we are still in the parent process
+    return ctxp;
+  }
+  if( pid == 0 ){ // we are the child
+    int status = (*f)(f_arg); // we require that f return a zero or positive value
+    if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS;
+    exit(status);
+  }else{ // we are the parent
+    waitpid(pid, &(ctxp->status), 0);
+    return ctxp;
+  }
+}
+
+//--------------------------------------------------------------------------------
+// interface call point
+dispatch_f_ctx *dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
+  dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f_euid_egid", fname);
+  #ifdef DEBUG
+  dbprintf("%s %s as euid:%u egid:%u\n", ctxp->dispatcher, ctxp->dispatchee, euid, egid);
+  #endif
+  pid_t pid = fork();
+  if( pid == -1 ){
+    ctxp->err = ERR_DISPATCH_F_FORK;
+    return ctxp;
+  }
+  if( pid == 0 ){ // we are the child
+    int status;
+    if( seteuid(euid) == -1 )
+      status = ERR_DISPATCH_F_SETEUID;
+    else if( setegid(egid) == -1 )
+      status = ERR_DISPATCH_F_SETEGID;
+    else{
+      status = (*f)(f_arg);
+      if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS;
+      exit(status);
+    }
+  }else{ // we are the parent
+    waitpid(pid, &(ctxp->status), 0);
+    return ctxp;
+  }
+}
+
+
diff --git a/module/subu-0/1_deprecated/dispatch_useradd.lib.c b/module/subu-0/1_deprecated/dispatch_useradd.lib.c
new file mode 100644 (file)
index 0000000..7b75291
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+There is no C library interface to useradd(8), but if there were, this function
+would be found there instead.
+
+*/
+#include "dispatch_useradd.lib.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#if INTERFACE
+#include <sys/types.h>
+#include <pwd.h>
+#define ERR_DISPATCH_USERADD_ARGC 1
+#define ERR_DISPATCH_USERADD_DISPATCH 2
+#define ERR_DISPATCH_USERADD_PWREC 3
+struct dispatch_useradd_ret_t{
+  uint error;
+  struct passwd *pw_record;  
+};
+#endif
+
+
+// we have a contract with the caller that argv[1] is always the subuname
+struct dispatch_useradd_ret_t dispatch_useradd(char **argv, char **envp){
+  struct dispatch_useradd_ret_t ret;
+  {
+    if( !argv || !argv[0] || !argv[1]){
+      fprintf(stderr,"useradd() needs a first argument as the name of the user to be made");
+      ret.error = ERR_DISPATCH_USERADD_ARGC;
+      ret.pw_record = NULL;
+      return ret;
+    }
+
+    char *subu_name;
+    {
+      subu_name = argv[1];
+      if( dispatch_exec(argv, envp) == -1 ){
+        fprintf(stderr,"%s failed\n", argv[0]);
+        ret.error = ERR_DISPATCH_USERADD_DISPATCH;
+        ret.pw_record = NULL;
+        return ret;
+      }}
+
+    {
+      struct passwd *pw_record = getpwnam(subu_name);
+      uint count = 1;
+      while( !pw_record && count <= 3 ){
+        #ifdef DEBUG
+          printf("try %u, getpwnam failed, trying again\n", count);
+        #endif
+        sleep(1);
+        pw_record = getpwnam(subu_name);
+        count++;
+      }
+      if( !pw_record ){
+        ret.error = ERR_DISPATCH_USERADD_PWREC;
+        ret.pw_record = NULL;
+        return ret;
+      }
+      ret.error = 0;
+      ret.pw_record = pw_record;
+      return ret;
+    }}}
+
diff --git a/module/subu-0/1_deprecated/subu-rm-0.lib.c b/module/subu-0/1_deprecated/subu-rm-0.lib.c
new file mode 100644 (file)
index 0000000..ccad437
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+  subu-rm-0 subuname
+
+  1. get our uid and lookup masteru_name in /etc/passwd
+  2. lookup masteru_name/subuname in config file, which gives us subu_username
+  3. unmount subuland/subuname
+  4. userdel subu_username
+  5. rmdir subuland/subuname
+
+  Note, as per the man page, we are not allowed to free the memory allocated by getpwid().
+
+*/
+#include "subu-mk-0.lib.h"
+
+// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
+#define _GNU_SOURCE   
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#if INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+#endif
+
+//--------------------------------------------------------------------------------
+// an instance is subu_rm_0_ctx is returned by subu_rm_0
+//
+#if INTERFACE
+#define ERR_SUBU_RM_0_MKDIR_SUBUHOME 1
+#define ERR_SUBU_RM_0_RMDIR_SUBUHOME 2
+#define ERR_SUBU_RM_0_SUBUNAME_MALFORMED 3
+#define ERR_SUBU_RM_0_SETUID_ROOT 4
+#define ERR_SUBU_RM_0_MASTERU_HOMELESS 5
+#define ERR_SUBU_RM_0_MALLOC 6
+#define ERR_SUBU_RM_0_CONFIG_FILE 7
+#define ERR_SUBU_RM_0_SUBUHOME_EXISTS 8
+#define ERR_SUBU_RM_0_BUG_SSS 9
+#define ERR_SUBU_RM_0_FAILED_USERADD 10
+
+struct subu_rm_0_ctx{
+  char *name;
+  char *subuland;
+  char *subuhome;
+  char *subu_username;
+  bool free_aux;
+  char *aux;
+  uint err;
+};
+#endif
+struct subu_rm_0_ctx *subu_rm_0_ctx_mk(){
+  struct subu_rm_0_ctx *ctxp = malloc(sizeof(struct subu_rm_0_ctx));
+  ctxp->name = "subu_rm_0";
+  ctxp->subuland = 0;
+  ctxp->subuhome = 0;
+  ctxp->subu_username = 0;
+  ctxp->free_aux = false;
+  ctxp->aux = 0;
+}
+void subu_rm_0_ctx_free(struct subu_rm_0_ctx *ctxp){
+  free(ctxp->subuland);
+  free(ctxp->subuhome);
+  free(ctxp->subu_username);
+  if(ctxp->free_aux) free(ctxp->aux);
+  free(ctxp);
+}
+// must be called before any system calls, otherwise perror() will be messed up
+void subu_rm_0_mess(struct subu_rm_0_ctx *ctxp){
+  switch(ctxp->err){
+  case 0: return;
+  case ERR_SUBU_RM_0_MKDIR_SUBUHOME:
+    fprintf(stderr, "masteru could not make subuhome, \"%s\"", ctxp->subuhome);
+    break;
+  case ERR_SUBU_RM_0_SUBUNAME_MALFORMED:
+    fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", ctxp->aux);
+    break;
+  case ERR_SUBU_RM_0_SETUID_ROOT:
+    fprintf(stderr, "This program must be run setuid root from a user account.");
+    break;
+  case ERR_SUBU_RM_0_MASTERU_HOMELESS:
+    fprintf(stderr,"Masteru, \"%s\", has no home directory", ctxp->aux);
+    break;
+  case ERR_SUBU_RM_0_MALLOC:
+    perror(ctxp->name);
+  break;
+  case ERR_SUBU_RM_0_CONFIG_FILE:
+    fprintf(stderr, "config file error: %s", ctxp->aux);
+  break;
+  case ERR_SUBU_RM_0_SUBUHOME_EXISTS:
+    fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", ctxp->subuhome);
+  break;
+  case ERR_SUBU_RM_0_BUG_SSS:
+    perror(ctxp->name);
+  break;
+  case ERR_SUBU_RM_0_FAILED_USERADD:
+    fprintf(stderr, "%u useradd failed\n", ctxp->subu_username);
+  break;
+  default:
+    fprintf(stderr, "unknown error code %d\n", ctxp->err);
+  }
+  fputc('\n', stderr);
+}
+
+//--------------------------------------------------------------------------------
+// dispatched functions
+//
+// the making of subuhome is dispatched to its own process so as to give it its own uid/gid
+static int masteru_mkdir_subuhome(void *arg){
+  char *subuhome = (char *) arg;
+  if( mkdir( subuhome, subuhome_perms ) == -1 ){ // find subuhome perms in common
+    perror("masteru_mkdir_subuhome");
+    return ERR_SUBU_RM_0_MKDIR_SUBUHOME;
+  }
+  return 0;
+}
+static int masteru_rmdir_subuhome(void *arg){
+  char *subuhome = (char *) arg;
+  if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
+    perror("masteru_rmdir_subuhome");
+    return ERR_SUBU_RM_0_RMDIR_SUBUHOME;
+  }
+  return 0;
+}
+
+//--------------------------------------------------------------------------------
+//  the public call point
+struct subu_rm_0_ctx *subu_rm_0(sqlite3 *db, char *subuname){
+
+  struct subu_rm_0_ctx *ctxp = subu_rm_0_ctx_mk();
+
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("Checking that subuname is well formed and finding its length\n");
+  #endif
+  size_t subuname_len;
+  {
+    int ret = allowed_subuname(subuname, &subuname_len);
+    if( ret == -1 ){
+      ctxp->err = ERR_SUBU_RM_0_SUBUNAME_MALFORMED;
+      ctxp->aux = subuname;
+      return ctxp;
+    }}
+  
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("Checking that we are running from a user and are setuid root.\n");
+  #endif
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ){
+      ctxp->err = ERR_SUBU_RM_0_SETUID_ROOT;
+      return ctxp;
+    }
+  }
+
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("strings masteru_name and masteru_home\n");
+  #endif
+
+  char *masteru_name;
+  size_t masteru_name_len;
+  char *masteru_home;
+  size_t masteru_home_len;
+  size_t subuland_len;
+  {
+    struct passwd *masteru_pw_record_pt = getpwuid(masteru_uid); // reading /etc/passwd
+    masteru_name = masteru_pw_record_pt->pw_name;
+    masteru_name_len = strlen(masteru_name);
+    #ifdef DEBUG
+    dbprintf("masteru_name \"%s\" %zu\n", masteru_name, masteru_name_len);
+    #endif
+    masteru_home = masteru_pw_record_pt->pw_dir;
+    masteru_home_len = strlen(masteru_home);
+    #ifdef DEBUG
+    dbprintf("masteru_home \"%s\" %zu\n", masteru_home, masteru_home_len);
+    #endif
+    masteru_home_len = strlen(masteru_home);
+    if( masteru_home_len == 0 || masteru_home[0] == '(' ){
+      ctxp->err = ERR_SUBU_RM_0_MASTERU_HOMELESS;
+      ctxp->aux = masteru_name;  // we can not free a passwd struct, or its fields.  I assume then it isn't re-entrant safe.
+      return ctxp;
+    }
+    // char *subuland_extension = "/subuland/"; // moved to common.lib.c
+    size_t subuland_extension_len = strlen(subuland_extension);
+    ctxp->subuland = (char *)malloc( masteru_home_len + subuland_extension_len + 1 );
+    if(!ctxp->subuland){
+      ctxp->err = ERR_SUBU_RM_0_MALLOC;
+      return ctxp;
+    }
+    strcpy(ctxp->subuland, masteru_home);
+    strcpy(ctxp->subuland + masteru_home_len, subuland_extension);
+    subuland_len = masteru_home_len + subuland_extension_len;
+    #ifdef DEBUG
+    dbprintf("subuland \"%s\" %zu\n", ctxp->subuland, subuland_len);
+    #endif
+  }
+
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("lookup subu_username from masteru_name/subuname in config file\n");
+  #endif
+  char *subu_username; // this is part of ctx and must be freed
+  {
+    int ret = subu_get_masteru_subu(db, masteru_name, subuname, &subu_username);
+    if( ret != SQLITE_DONE ){
+      printf("get failed\n");
+      return 2;
+    }
+    #ifdef DEBUG
+    printf("subu_username: %s\n", subu_username);  
+    #endif
+    
+  }
+
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("strings subu_username and subuhome\n");
+  #endif
+  size_t subu_username_len;
+  size_t subuhome_len;
+  {
+    char *ns=0; // 'ns'  Number as String
+    char *mess=0;
+    if( subu_number_get( db, &ns, &mess ) != SQLITE_OK ){
+      ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
+      ctxp->aux = mess;
+      ctxp->free_aux = true;
+      return ctxp;
+    }
+    size_t ns_len = strlen(ns);
+    ctxp->subu_username = malloc(1 + ns_len + 1);
+    if( !ctxp->subu_username ){
+      ctxp->err = ERR_SUBU_RM_0_MALLOC;
+      return ctxp;
+    }
+    strcpy(ctxp->subu_username, "s");
+    strcpy(ctxp->subu_username + 1, ns);
+    subu_username_len = ns_len + 1;
+    #ifdef DEBUG
+    dbprintf("subu_username \"%s\" %zu\n", ctxp->subu_username, subu_username_len);
+    #endif
+
+    subuhome_len = subuland_len + subuname_len; 
+    ctxp->subuhome = (char *)malloc(subuhome_len + 1);
+    if( !ctxp->subuhome ){
+      ctxp->err = ERR_SUBU_RM_0_MALLOC;
+      return ctxp;
+    }
+    strcpy (ctxp->subuhome, ctxp->subuland);
+    strcpy (ctxp->subuhome + subuland_len, subuname);
+    #ifdef DEBUG
+    dbprintf("subuhome \"%s\" %zu\n", ctxp->subuhome, subuhome_len);
+    #endif
+  }
+
+  //--------------------------------------------------------------------------------
+  // By having masteru create the subuhome, we know that masteru has rights to 
+  // to access this directory. This will be the mount point for bindfs
+  {
+    #ifdef DEBUG
+    dbprintf("as masteru, making the directory \"%s\"\n", ctxp->subuhome);
+    #endif
+    struct stat st;
+    if( stat(ctxp->subuhome, &st) != -1 ){
+      ctxp->err = ERR_SUBU_RM_0_SUBUHOME_EXISTS;
+      return ctxp;
+    }
+    dispatch_ctx *dfr = dispatch_f_euid_egid
+      (
+       "masteru_mkdir_subuhome", 
+       masteru_mkdir_subuhome, 
+       (void *)ctxp->subuhome,
+       masteru_uid, 
+       masteru_gid
+       );
+    if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME ){
+      #ifdef DEBUG
+      if( dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME )
+        perror("mkdir");
+      else
+        dispatch_f_mess(dfr);
+      #endif
+      ctxp->err = ERR_SUBU_RM_0_MKDIR_SUBUHOME;
+      return ctxp;
+    }
+  }
+  #ifdef DEBUG
+  dbprintf("masteru made directory \"%s\"\n", ctxp->subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  //  Make the subservient user account, i.e. the subu
+  {
+    #ifdef DEBUG
+      dbprintf("making subu \"%s\" as user \"%s\"\n", subuname, ctxp->subu_username);
+    #endif
+    #if BUG_SSS_CACHE_RUID
+      #ifdef DEBUG
+        dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
+      #endif
+      if( setuid(0) == -1 ){
+        ctxp->err = ERR_SUBU_RM_0_BUG_SSS;
+        return ctxp;
+      }
+    #endif
+    char *command = "/usr/sbin/useradd";
+    char *argv[3];
+    argv[0] = command;
+    argv[1] = ctxp->subu_username;
+    argv[2] = (char *) NULL;
+    char *envp[1];
+    envp[0] = (char *) NULL;
+    dispatch_ctx *dfr = dispatch_exec(argv, envp);
+    if( dfr->err != 0 ){
+      #ifdef DEBUG 
+      if( dfr->err <= ERR_DISPATCH )
+        dispatch_f_mess(dfr);
+      else
+        perror("useradd");
+      #endif
+      // go back and remove the directory we made in subuland
+      dispatch_ctx *dfr = dispatch_f_euid_egid
+        (
+         "masteru_rmdir_subuhome", 
+         masteru_rmdir_subuhome, 
+         (void *)ctxp->subuhome,
+         masteru_uid, 
+         masteru_gid
+         );
+      #ifdef DEBUG
+        if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
+          if( dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
+            perror("rmdir");
+          else
+            dispatch_f_mess(dfr);
+      #endif
+      ctxp->err = ERR_SUBU_RM_0_FAILED_USERADD;
+      return ctxp;
+    }
+    #ifdef DEBUG
+    dbprintf("added user \"%s\"\n", ctxp->subu_username);
+    #endif
+  }  
+  
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("setting the masteru_name, subuname, subu_username relation\n");
+  #endif
+  {
+    int ret = subu_put_masteru_subu(db, masteru_name, subuname, ctxp->subu_username);
+    if( ret != SQLITE_DONE ){
+      ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
+      ctxp->aux = "insert of masteru subu relation failed";
+      return ctxp;
+    }
+  }
+
+  #ifdef DEBUG
+  dbprintf("finished subu-mk-0(%s)\n", subuname);
+  #endif
+  ctxp->err = 0;
+  return ctxp;
+}
diff --git a/module/subu-0/1_deprecated/subudb-number-next.cli.c b/module/subu-0/1_deprecated/subudb-number-next.cli.c
new file mode 100644 (file)
index 0000000..3373173
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include "subudb-number-next.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+  if( argc != 2 ){
+    fprintf(stderr, "usage: %s masteru_name \n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *masteru_name = argv[1];
+  
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    sqlite3_close(db);
+    fprintf(stderr, "error exit, could not open db file\n");
+    return SUBU_ERR_DB_FILE;
+  }
+
+  // read and print the current max
+  char *mess;
+  int n;
+  rc = subudb_number_next(db, masteru_name, &n, &mess);
+  if( rc == SQLITE_DONE ){
+    printf("%d\n", n);
+  }else{
+    fprintf(stderr, "subudb_number_next indicates failure by returning %d\n",rc);
+    fprintf(stderr, "and issues message, %s\n", sqlite3_errmsg(db));
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+  rc = sqlite3_close(db);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
diff --git a/module/subu-0/1_doc/to_do.txt b/module/subu-0/1_doc/to_do.txt
new file mode 100644 (file)
index 0000000..0b989cc
--- /dev/null
@@ -0,0 +1,38 @@
+2019-02-05T23:14:40Z
+  error can cause subu-mk-0 to leave the creating of a subu in an intermediate
+  state.  Rather than bailing on some of the errors we need to clean up instead.
+  Perhaps the yet to be written subu-rm program will be resilent enough to do
+  more general cleanup.
+
+2019-02-23T18:56:31Z
+  need to modify subu-init to take a configuration file name argument instead of
+  using a global variabel value.  might want to add arguments to other subu
+  commands also
+
+2019-03-11T13:48:03Z
+  in subu.lib.c append cascading rmdir failure mess to useradd failure mess
+
+2019-03-11T13:48:03Z
+  want to add subu-type to masteru_subu(),  I imagine there will be static,
+  permanent, and temporary subu types.
+
+2019-03-12T18:35:06Z
+  the masteru subu relation should contain the uid of the masteru as
+  well as the backup type for the subu:  git, rdiff, rsync, none.
+  and the persisitance fo the subu: indefinite, session.
+  seems that operations need to be logged, in case the db is lost
+  the transcript can be played back.  It should also be possible
+  to co-opt an existing user as a subu, though, would require
+  sudo privs.
+
+  need to add messages for subu errors I've added to the end of
+  the list in subu.lib.c
+  
+2019-03-14T10:43:50Z
+
+   should mod all to he subudb routines to return a message, probably
+   strdup(sqlite_errmsg(db)), then the callers to these routines can just pass
+   mess in rather than making up new ones for each situation. The error code
+   probably already carries the contexts specific message.  Or perhaps add
+   a string cat function for message strings, that would run through a stream
+   and free the originals.
diff --git a/module/subu-0/1_tests/0_makefile b/module/subu-0/1_tests/0_makefile
new file mode 100644 (file)
index 0000000..67cea25
--- /dev/null
@@ -0,0 +1,32 @@
+# src/1_tests/0_makefile
+
+SHELL=/bin/bash
+
+-include 0_makefile_flags
+
+MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
+
+SOURCES=$(wildcard *.c)
+HFILES=$(wildcard *.h)
+
+all: version deps lib execs
+
+deps:
+       makeheaders $(SOURCES) $(HFILES)
+       sed -i '/^ *int *main *(.*)/d' *.h
+       $(MAKE) $@
+
+clean:
+       $(MAKE) $@
+       for i in $(HFILES); do rm $$i; done
+
+dist-clean:
+       $(MAKE) $@
+       if [ -f subudb ]; then rm subudb; fi
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/subu-0/1_tests/0_makefile_flags b/module/subu-0/1_tests/0_makefile_flags
new file mode 100644 (file)
index 0000000..bc6bd25
--- /dev/null
@@ -0,0 +1,31 @@
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=
+DOCDIR=
+EXECSDIR=.
+HDIR=.
+LIBDIR=.
+TESTDIR=.
+TMPDIR=1_tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=
+
+
+# compiler and flags
+CC=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-L$(PROJECT_SUBU)/src/$(LIBDIR) -L. -lsubu -lsqlite3 -lsubutests
+
+LIBFILE=$(LIBDIR)/libtests.a
+
diff --git a/module/subu-0/1_tests/1_tmp/makefile_deps b/module/subu-0/1_tests/1_tmp/makefile_deps
new file mode 100644 (file)
index 0000000..9486ae8
--- /dev/null
@@ -0,0 +1,4 @@
+da.cli.o: da.cli.c da.cli.h
+
+./da : da.cli.o ./libtests.a
+       gcc -o ./da da.cli.o -L/home/morpheus/subu_land/subu/src/. -L. -lsubu -lsqlite3 -lsubutests
diff --git a/module/subu-0/1_tests/da.cli.c b/module/subu-0/1_tests/da.cli.c
new file mode 100644 (file)
index 0000000..910a15e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+Tests for da.
+
+*/
+
+#include <da.cli.h>
+#include <stdbool.h>
+
+int test_da_0(){
+  da da0;
+  da_alloc(&da0, sizeof(int)); // leaves room for 4 ints
+  int i = 0;
+  int *pt = da0->base;
+  // will double, 4 -> 8, then double 8 -> 16
+  while( i < 10 ){
+    if(da_boundq(&da0, pt)){
+      char *old_base = da_expand(&da);
+      da_rebase(&da, old_base, pt);
+    }
+    *pt = i;
+  i++;
+  pt++;
+  }
+
+  bool f0 = da.size == sizof(int) * 16;
+  bool f1 = 10 == (da.end - da.base) / sizeof(int);
+  bool f2 = true;
+  pt = da0->base;
+  while( i < 10 ){
+    f2 = f2 && *pt == i && !da_endq(&da, pt);
+  i++;
+  pt++;
+  }
+  bool f3 = da_endq(&da, pt);
+
+  return f0 && f1 && f2 && f3;
+}
+
+
+int main(){
+
+  bool da_0_passed = test_da_0();
+  if( da_0_passed ){
+    printf("da_0_passed");
+    return 0;
+  }
+  printf("da_0_failed");
+  return 1;
+
+}
diff --git a/module/subu-0/1_tests/libtests.a b/module/subu-0/1_tests/libtests.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/module/subu-0/1_tmp/da.lib.h b/module/subu-0/1_tmp/da.lib.h
new file mode 100644 (file)
index 0000000..4702189
--- /dev/null
@@ -0,0 +1,23 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <stdlib.h>
+#include <stdbool.h>
+void daps_map(char **base,char **end_pt,void f(void *));
+#define RETURN(rc) \
+  { daps_map(mrs, mrs_end, free); return rc; }
+void daps_alloc(char ***base,size_t *s);
+#define MK_MRS \
+  char **mrs;  \
+  char **mrs_end; \
+  size_t mrs_size; \
+  daps_alloc(&mrs, &mrs_size);\
+  mrs_end = mrs;
+void daps_push(char ***base,char ***pt,size_t *s,char *item);
+bool daps_bound(char **base,char **pt,size_t s);
+void daps_expand(char ***base,char ***pt,size_t *s);
+void da_map(void *base,void *end_pt,void f(void *),size_t item_size);
+void da_push(void **base,void **pt,size_t *s,void *item,size_t item_size);
+bool da_bound(void *base,void *pt,size_t s);
+void da_expand(void **base,void **pt,size_t *s);
+void da_alloc(void **base,size_t *s,size_t item_size);
+#define INTERFACE 0
diff --git a/module/subu-0/1_tmp/dbprintf.lib.h b/module/subu-0/1_tmp/dbprintf.lib.h
new file mode 100644 (file)
index 0000000..3056cf6
--- /dev/null
@@ -0,0 +1,3 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+int dbprintf(const char *format,...);
diff --git a/module/subu-0/1_tmp/dispatch.lib.h b/module/subu-0/1_tmp/dispatch.lib.h
new file mode 100644 (file)
index 0000000..07e2271
--- /dev/null
@@ -0,0 +1,24 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sys/types.h>
+#include <unistd.h>
+int dispatch_exec(char **argv,char **envp);
+typedef unsigned int uint;
+int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
+int dbprintf(const char *format,...);
+int dispatch_f(char *fname,int(*f)(void *arg),void *f_arg);
+void dispatch_f_mess(char *fname,int err,char *dispatchee);
+#define ERR_DISPATCH_EXEC -1029
+#define ERR_DISPATCH_NULL_EXECUTABLE -1028
+#define ERR_DISPATCH_F_SETEGID -1027
+#define ERR_DISPATCH_F_SETEUID -1026
+#define ERR_DISPATCH_F_FORK -1025
+#define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024
+#define ERR_DISPATCH -1024
+typedef struct dispatch_ctx dispatch_ctx;
+struct dispatch_ctx {
+  char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.)
+  char *dispatchee; // name of the function being dispatched
+  int err; // error code as listed below, or status returned from dispatchee
+};
+#define INTERFACE 0
diff --git a/module/subu-0/1_tmp/subu-bind-all.cli.h b/module/subu-0/1_tmp/subu-bind-all.cli.h
new file mode 100644 (file)
index 0000000..7e52675
--- /dev/null
@@ -0,0 +1,9 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+int subu_bind_all(char **mess,sqlite3 *db);
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subu-bind.cli.h b/module/subu-0/1_tmp/subu-bind.cli.h
new file mode 100644 (file)
index 0000000..af12d61
--- /dev/null
@@ -0,0 +1,7 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subu-common.lib.h b/module/subu-0/1_tmp/subu-common.lib.h
new file mode 100644 (file)
index 0000000..cfdc520
--- /dev/null
@@ -0,0 +1,9 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+extern char Subuland_Extension[];
+typedef unsigned int uint;
+extern uint First_Max_Subunumber;
+extern uint Subuhome_Perms;
+extern char DB_File[];
+#define BUG_SSS_CACHE_RUID 1
+#define INTERFACE 0
diff --git a/module/subu-0/1_tmp/subu-mk-0.cli.h b/module/subu-0/1_tmp/subu-mk-0.cli.h
new file mode 100644 (file)
index 0000000..487b509
--- /dev/null
@@ -0,0 +1,10 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+void subu_err(char *fname,int err,char *mess);
+int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subu-rm-0.cli.h b/module/subu-0/1_tmp/subu-rm-0.cli.h
new file mode 100644 (file)
index 0000000..070bfe8
--- /dev/null
@@ -0,0 +1,10 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+void subu_err(char *fname,int err,char *mess);
+int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subu.lib.h b/module/subu-0/1_tmp/subu.lib.h
new file mode 100644 (file)
index 0000000..69c5da7
--- /dev/null
@@ -0,0 +1,66 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+typedef unsigned int uint;
+#include <sqlite3.h>
+typedef struct subudb_subu_element subudb_subu_element;
+int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
+struct subudb_subu_element {
+  char *subuname;
+  char *subu_username;
+};
+#include <stdbool.h>
+#include <errno.h>
+int subu_bind_all(char **mess,sqlite3 *db);
+int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
+int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
+int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
+int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <sys/types.h>
+#include <unistd.h>
+int dispatch_exec(char **argv,char **envp);
+#define BUG_SSS_CACHE_RUID 1
+void dispatch_f_mess(char *fname,int err,char *dispatchee);
+#define ERR_DISPATCH -1024
+int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
+#include <stdlib.h>
+void daps_map(char **base,char **end_pt,void f(void *));
+#define RETURN(rc) \
+  { daps_map(mrs, mrs_end, free); return rc; }
+void daps_push(char ***base,char ***pt,size_t *s,char *item);
+int dbprintf(const char *format,...);
+void daps_alloc(char ***base,size_t *s);
+#define MK_MRS \
+  char **mrs;  \
+  char **mrs_end; \
+  size_t mrs_size; \
+  daps_alloc(&mrs, &mrs_size);\
+  mrs_end = mrs;
+int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
+extern char Subuland_Extension[];
+int db_commit(sqlite3 *db);
+int db_rollback(sqlite3 *db);
+int subudb_number_set(sqlite3 *db,int n);
+int subudb_number_get(sqlite3 *db,int *n);
+int db_begin(sqlite3 *db);
+extern uint Subuhome_Perms;
+extern char DB_File[];
+void subu_err(char *fname,int err,char *mess);
+#define SUBU_ERR_BIND 15
+#define SUBU_ERR_N 14
+#define SUBU_ERR_SUBU_NOT_FOUND 13
+#define SUBU_ERR_FAILED_USERDEL 12
+#define SUBU_ERR_FAILED_USERADD 11
+#define SUBU_ERR_BUG_SSS 10
+#define SUBU_ERR_SUBUHOME_EXISTS 9
+#define SUBU_ERR_DB_FILE 8
+#define SUBU_ERR_HOMELESS 7
+#define SUBU_ERR_SUBUNAME_MALFORMED 6
+#define SUBU_ERR_RMDIR_SUBUHOME 5
+#define SUBU_ERR_MKDIR_SUBUHOME 4
+#define SUBU_ERR_MALLOC 3
+#define SUBU_ERR_SETUID_ROOT 2
+#define SUBU_ERR_ARG_CNT 1
+char *userdel_mess(int err);
+char *useradd_mess(int err);
+#define INTERFACE 0
diff --git a/module/subu-0/1_tmp/subudb-init.cli.h b/module/subu-0/1_tmp/subudb-init.cli.h
new file mode 100644 (file)
index 0000000..4435103
--- /dev/null
@@ -0,0 +1,11 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int db_commit(sqlite3 *db);
+int db_rollback(sqlite3 *db);
+int subudb_schema(sqlite3 *db);
+int db_begin(sqlite3 *db);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
diff --git a/module/subu-0/1_tmp/subudb-number.cli.h b/module/subu-0/1_tmp/subudb-number.cli.h
new file mode 100644 (file)
index 0000000..c130fbb
--- /dev/null
@@ -0,0 +1,11 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_number_get(sqlite3 *db,int *n);
+int subudb_number_set(sqlite3 *db,int n);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_N 14
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subudb-rel-get.cli.h b/module/subu-0/1_tmp/subudb-rel-get.cli.h
new file mode 100644 (file)
index 0000000..4f335be
--- /dev/null
@@ -0,0 +1,9 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subudb-rel-put.cli.h b/module/subu-0/1_tmp/subudb-rel-put.cli.h
new file mode 100644 (file)
index 0000000..243b3a9
--- /dev/null
@@ -0,0 +1,8 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
diff --git a/module/subu-0/1_tmp/subudb-rel-rm.cli.h b/module/subu-0/1_tmp/subudb-rel-rm.cli.h
new file mode 100644 (file)
index 0000000..595427f
--- /dev/null
@@ -0,0 +1,8 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
diff --git a/module/subu-0/1_tmp/subudb-subus.cli.h b/module/subu-0/1_tmp/subudb-subus.cli.h
new file mode 100644 (file)
index 0000000..16310b7
--- /dev/null
@@ -0,0 +1,14 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+typedef struct subudb_subu_element subudb_subu_element;
+int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
+struct subudb_subu_element {
+  char *subuname;
+  char *subu_username;
+};
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
diff --git a/module/subu-0/1_tmp/subudb.lib.h b/module/subu-0/1_tmp/subudb.lib.h
new file mode 100644 (file)
index 0000000..be73823
--- /dev/null
@@ -0,0 +1,27 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <stdlib.h>
+#include <stdbool.h>
+void da_expand(void **base,void **pt,size_t *s);
+bool da_bound(void *base,void *pt,size_t s);
+typedef struct subudb_subu_element subudb_subu_element;
+int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
+void subu_element_free(subudb_subu_element *base,subudb_subu_element *end_pt);
+void da_alloc(void **base,size_t *s,size_t item_size);
+struct subudb_subu_element {
+  char *subuname;
+  char *subu_username;
+};
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
+int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+int subudb_number_set(sqlite3 *db,int n);
+int subudb_number_get(sqlite3 *db,int *n);
+typedef unsigned int uint;
+extern uint First_Max_Subunumber;
+int subudb_schema(sqlite3 *db);
+int db_rollback(sqlite3 *db);
+int db_commit(sqlite3 *db);
+int db_begin(sqlite3 *db);
+#define INTERFACE 0
diff --git a/module/subu-0/1_try/split.c b/module/subu-0/1_try/split.c
new file mode 100644 (file)
index 0000000..6d4c6ac
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Using preprocessor to make header file?
+
+gcc -E split.c -DPROTOTYPE
+
+Outputs source code source comment lines starting with a hash. Resolves all macro commands,
+hence the resulting header can not have macro commands.
+
+ */
+
+#if PROTOTYPE
+##define GREATNESS 21
+int f(int x);
+#endif
+
+#if IMPLEMENTATION
+int f(int x){
+  return x;
+}
+#endif
diff --git a/module/subu-0/1_try/split_arg.c b/module/subu-0/1_try/split_arg.c
new file mode 100644 (file)
index 0000000..6d4c6ac
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Using preprocessor to make header file?
+
+gcc -E split.c -DPROTOTYPE
+
+Outputs source code source comment lines starting with a hash. Resolves all macro commands,
+hence the resulting header can not have macro commands.
+
+ */
+
+#if PROTOTYPE
+##define GREATNESS 21
+int f(int x);
+#endif
+
+#if IMPLEMENTATION
+int f(int x){
+  return x;
+}
+#endif
diff --git a/module/subu-0/1_try/subudb b/module/subu-0/1_try/subudb
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/module/subu-0/1_try/voidptr.c b/module/subu-0/1_try/voidptr.c
new file mode 100644 (file)
index 0000000..bd9c3e5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+They say a cast is not required passing a typed pointer to a void * argument,
+but What about void **?
+
+gcc -std=gnu11 -o voidptr voidptr.c
+voidptr.c: In function ‘main’:
+voidptr.c:28:5: warning: passing argument 1 of ‘g’ from incompatible pointer type [-Wincompatible-pointer-types]
+   g(&pt, y);
+     ^~~
+voidptr.c:13:15: note: expected ‘void **’ but argument is of type ‘int **’
+ void g(void **pt0, void *pt1){
+        ~~~~~~~^~~
+
+*/
+#include <stdio.h>
+
+int f(void *pt){
+  return *(int *)pt;
+}
+
+/* fails
+void g(void **pt0, int *pt1){
+  *pt0 = pt1;
+}
+*/
+
+// passes
+void g(void *pt0, int *pt1){
+  *(int **)pt0 = pt1;
+}
+
+int main(){
+  int x = 5;
+  int *xp = &x;
+  printf("%d\n",f(xp));
+
+  int y[3];
+  y[0] = 10;
+  y[1] = 11;
+  y[2] = 12;
+
+  int *pt;
+  g(&pt, y);
+  printf("%d\n",*pt);
+
+  printf("that's all folks\n");
+  return 0;
+}
diff --git a/module/subu-0/common.lib.c b/module/subu-0/common.lib.c
new file mode 100644 (file)
index 0000000..9ce5a27
--- /dev/null
@@ -0,0 +1,20 @@
+
+#include "subu-common.lib.h"
+
+#if INTERFACE
+typedef unsigned int uint;
+/*
+  Fedora 29's sss_cache is checking the inherited uid instead of the effective
+  uid, so setuid root scripts will fail when calling sss_cache.
+
+  Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root 
+  program subu-mk-0.
+*/
+#define BUG_SSS_CACHE_RUID 1
+#endif
+
+//  char *DB_File = "/etc/subudb";
+char DB_File[] = "subudb";
+uint Subuhome_Perms = 0700;
+uint First_Max_Subunumber = 114;
+char Subuland_Extension[] = "/subuland/";
diff --git a/module/subu-0/db.lib.c b/module/subu-0/db.lib.c
new file mode 100644 (file)
index 0000000..17a5419
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+The db file is maintained in SQLite
+
+Because user names of are of limited length, subu user names are always named _s<number>.
+A separate table translates the numbers into the subu names.
+
+The first argument is the biggest subu number in the system, or one minus an 
+starting point for subu numbering.
+
+currently a unit converted to base 10 will always fit in a 21 bit buffer.
+
+Each of these returns SQLITE_OK upon success
+*/
+#include "subudb.lib.h"
+
+#if INTERFACE
+#include <sqlite3.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+//--------------------------------------------------------------------------------
+// sqlite transactions don't nest.  There is a way to use save points, but still
+// we can't just nest transactions.  Instead use these wrappers around the whole
+// of something that needs to be in a transaction.
+int db_begin(sqlite3 *db){
+  return sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
+}
+int db_commit(sqlite3 *db){
+  return sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
+}
+int db_rollback(sqlite3 *db){
+  return sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
+}
+
+//--------------------------------------------------------------------------------
+int subudb_schema(sqlite3 *db){
+  int rc;
+
+  { // build tables
+    char sql[] = 
+      "CREATE TABLE Masteru_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT);"
+      "CREATE TABLE Attribute_Int(attribute TEXT, value INT);"
+      ;
+    rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+    if(rc != SQLITE_OK) return rc;
+  }
+
+  { // data initialization
+    char *sql = "INSERT INTO Attribute_Int (attribute, value) VALUES ('Max_Subunumber', ?1);";
+    sqlite3_stmt *stmt;
+    sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+    sqlite3_bind_int(stmt, 1, First_Max_Subunumber);
+    rc = sqlite3_step(stmt);
+    sqlite3_finalize(stmt);
+    if( rc != SQLITE_DONE ) return rc;
+  }
+
+  return SQLITE_OK;
+}
+
+//--------------------------------------------------------------------------------
+int subudb_number_get(sqlite3 *db, int *n){
+  char *sql = "SELECT value FROM Attribute_Int WHERE attribute = 'Max_Subunumber';";
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+  int rc = sqlite3_step(stmt);
+  if( rc == SQLITE_ROW ){
+    *n = sqlite3_column_int(stmt,0);
+    rc = sqlite3_step(stmt);
+    sqlite3_finalize(stmt);
+    if( rc != SQLITE_DONE ) return rc;
+    return SQLITE_OK;
+  }
+  // should have a message return, suppose
+  sqlite3_finalize(stmt);
+  return SQLITE_NOTFOUND; 
+}
+
+int subudb_number_set(sqlite3 *db, int n){
+  int rc;
+  char *sql = "UPDATE Attribute_Int SET value = ?1 WHERE attribute = 'Max_Subunumber';";
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+  sqlite3_bind_int(stmt, 1, n);
+  rc = sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
+
+//--------------------------------------------------------------------------------
+// put relation into Masteru_Subu table
+int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
+  char *sql = "INSERT INTO Masteru_Subu VALUES (?1, ?2, ?3);";
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
+  int rc = sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
+
+//--------------------------------------------------------------------------------
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username){
+  char *sql = "SELECT subu_username FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2;";
+  size_t sql_len = strlen(sql);
+  sqlite3_stmt *stmt;
+  int rc;
+  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
+  if( rc != SQLITE_OK ) return rc;
+  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC);
+  rc = sqlite3_step(stmt);
+  if( rc == SQLITE_ROW ){
+    const char *username = sqlite3_column_text(stmt, 0);
+    *subu_username = strdup(username);
+  }else{
+    sqlite3_finalize(stmt);
+    return rc; // woops this needs to return an error!,  be sure it is not SQLITE_DONE
+  }
+  rc = sqlite3_step(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
+
+//--------------------------------------------------------------------------------
+
+// we return and array of subudb_subu_info
+#if INTERFACE
+struct subudb_subu_element{
+  char *subuname;
+  char *subu_username;
+};
+#endif
+
+int subudb_Masteru_Subu_get_subus
+(
+ sqlite3 *db,
+ char *masteru_name,
+ da *subus
+){
+  char *sql = "SELECT subuname, subu_username"
+              " FROM Masteru_Subu"
+              " WHERE masteru_name = ?1;";
+  size_t sql_len = strlen(sql);
+  sqlite3_stmt *stmt;
+  int rc;
+  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
+  if( rc != SQLITE_OK ) return rc;
+  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
+
+  da_alloc(subus, sizeof(subudb_subu_element));
+  subudb_subu_element *pt = (subudb_subu_element *)subus->base;
+  rc = sqlite3_step(stmt);
+  while( rc == SQLITE_ROW ){
+    if( da_boundq(subus, pt) ){
+      char *old_base = da_expand(subus);
+      da_rebase(subus, old_base, pt);
+    }
+    pt->subuname = strdup(sqlite3_column_text(stmt, 0));
+    pt->subu_username = strdup(sqlite3_column_text(stmt, 1));
+  rc = sqlite3_step(stmt);
+  pt++;
+  }
+  sqlite3_finalize(stmt);
+  if( rc != SQLITE_DONE ) return rc;
+  return SQLITE_OK;
+}
+
+//--------------------------------------------------------------------------------
+int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
+  char *sql = "DELETE FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2 AND subu_username = ?3;";
+  size_t sql_len = strlen(sql);
+  sqlite3_stmt *stmt;
+  int rc;
+  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
+  if( rc != SQLITE_OK ) return rc;
+  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
+  rc = sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
diff --git a/module/subu-0/subu-bind-all.cli.c b/module/subu-0/subu-bind-all.cli.c
new file mode 100644 (file)
index 0000000..e942909
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+mount all the subu user directories into master's subuland
+uses unmount to undo this
+
+*/
+#include "subu-bind-all.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+  if( argc != 1){
+    fprintf(stderr, "%s does not take arguments\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  char *mess;
+  rc = subu_bind_all(&mess, db);
+  if(rc != 0){
+    fprintf(stderr, "subu-bind: %s\n", mess);
+    return rc;
+  }
+  return 0;
+}
diff --git a/module/subu-0/subu-bind.cli.c b/module/subu-0/subu-bind.cli.c
new file mode 100644 (file)
index 0000000..f315823
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+mount a subu user directory into master's subuland
+uses unmount to undo this
+
+*/
+#include "subu-bind.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if( argc != 4){
+    fprintf(stderr, "usage: %s masteru subu_username subuhome\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  char *mess;
+  rc = subu_bind(&mess, argv[1], argv[2], argv[3]);
+  if(rc != 0){
+    fprintf(stderr, "subu-bind: %s\n", mess);
+    return rc;
+  }
+  return 0;
+}
diff --git a/module/subu-0/subu-mk-0.cli.c b/module/subu-0/subu-mk-0.cli.c
new file mode 100644 (file)
index 0000000..af0888b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  subu-mk-0 command
+
+*/
+#include "subu-mk-0.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+  char *command = argv[0];
+  if( argc != 2 ){
+    fprintf(stderr, "usage: %s subu", command);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *subuname = argv[1];
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "error when opening db, %s\n", DB_File);
+    fprintf(stderr, "sqlite3 says: %s\n", sqlite3_errmsg(db));
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  char *mess;
+  rc = subu_mk_0(&mess, db, subuname);
+  if( rc ){
+    subu_err("subu_mk_0", rc, mess);
+    free(mess);
+    sqlite3_close(db);
+    return rc;
+  }
+
+  rc = sqlite3_close(db);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+
+}
diff --git a/module/subu-0/subu-rm-0.cli.c b/module/subu-0/subu-rm-0.cli.c
new file mode 100644 (file)
index 0000000..a7e5926
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  subu-mk-0 command
+
+*/
+#include "subu-rm-0.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+  char *command = argv[0];
+  if( argc != 2 ){
+    fprintf(stderr, "usage: %s subu", command);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *subuname = argv[1];
+
+  sqlite3 *db;
+  {
+    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+    if( ret != SQLITE_OK ){
+      fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
+      return SUBU_ERR_DB_FILE;
+    }}
+
+  {
+    char *mess=0;
+    int ret = subu_rm_0(&mess, db, subuname);
+    subu_err("subu_rm_0", ret, mess);
+    free(mess);
+    return ret;
+  }
+}
diff --git a/module/subu-0/subu.lib.c b/module/subu-0/subu.lib.c
new file mode 100644 (file)
index 0000000..988bd28
--- /dev/null
@@ -0,0 +1,713 @@
+/*
+  sqllite3 is used to maintain the db file, which is currently compiled
+  in as /etc/subu.db, (or just subu.db for testing).
+
+  masteru is the user who ran this script. The masteru name comes from getuid
+  and /etc/passwd. 
+
+  subu is a subservient user.  The subuname is passed in as an argument.
+
+  subu-mk-0 synthesizes a new user user name s<number>, calls useradd to creat
+  the new uswer account, and enters the relationship between masteru, subu, and
+  s<number> in the db file.  It is this relation in the db file that
+  associates the subuname with the s<number> user.
+
+  subu-rm-0 uses userdel to delete the related s<number> user account.  It
+  then removes the relaton from the db file.
+
+  subu-mk-0 and subu-rm-0 are setuid root scripts.  
+
+*/
+#include "subu.lib.h"
+
+// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
+#define _GNU_SOURCE   
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#if INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+#endif
+
+//--------------------------------------------------------------------------------
+// dispatched command errors  .. should add mkdir and rmdir ...
+//
+char *useradd_mess(int err){
+  if(err <= 0) return NULL;
+  char *mess;
+  switch(err){
+  case 1: mess = "can't update password file"; break;
+  case 2: mess = "invalid command syntax"; break;
+  case 3: mess = "invalid argument to option"; break;
+  case 4: mess = "UID already in use (and no -o)"; break;
+  case 5: mess = "undefined"; break;
+  case 6: mess = "specified group doesn't exist"; break;
+  case 7:
+  case 8: mess = "undefined"; break;
+  case 9: mess = "username already in use"; break;
+  case 10: mess = "can't update group file:"; break;
+  case 11: mess = "undefined"; break;
+  case 12: mess = "can't create home directory"; break;
+  case 13: mess = "undefined"; break;
+  case 14: mess = "can't update SELinux user mapping"; break;
+  default: mess = "undefined"; break;
+  }
+  return strdup(mess);
+}
+char *userdel_mess(int err){
+  if(err <= 0) return NULL;
+  char *mess;
+  switch(err){
+  case 1: mess = "can't update password file"; break;
+  case 2: mess = "invalid command syntax"; break;
+  case 3:
+  case 4:
+  case 5: mess = "undefined"; break;
+  case 6: mess = "specified user doesn't exist"; break;
+  case 7:
+  case 8: 
+  case 9: mess = "undefined"; break;
+  case 10: mess = "can't update group file:"; break;
+  case 11: mess = "undefined"; break;
+  case 12: mess = "can't remove home directory"; break;
+  default: mess = "undefined"; break;
+  }
+  return strdup(mess);
+}
+
+
+//--------------------------------------------------------------------------------
+//
+#if INTERFACE
+#define SUBU_ERR_ARG_CNT 1
+#define SUBU_ERR_SETUID_ROOT 2
+#define SUBU_ERR_MALLOC 3
+#define SUBU_ERR_MKDIR_SUBUHOME 4
+#define SUBU_ERR_RMDIR_SUBUHOME 5
+#define SUBU_ERR_SUBUNAME_MALFORMED 6
+#define SUBU_ERR_HOMELESS 7
+#define SUBU_ERR_DB_FILE 8
+#define SUBU_ERR_SUBUHOME_EXISTS 9
+#define SUBU_ERR_BUG_SSS 10
+#define SUBU_ERR_FAILED_USERADD 11
+#define SUBU_ERR_FAILED_USERDEL 12
+#define SUBU_ERR_SUBU_NOT_FOUND 13
+#define SUBU_ERR_N 14
+#define SUBU_ERR_BIND 15
+#endif
+
+void subu_err(char *fname, int err, char *mess){
+  if(!mess) mess = "";
+  switch(err){
+  case 0: return;
+  case SUBU_ERR_ARG_CNT:
+    if(mess[0])
+      fprintf(stderr, "Incorrect number of arguments, %s", mess);
+    else
+      fprintf(stderr, "Incorrect number of arguments.", mess);
+    break;
+  case SUBU_ERR_SETUID_ROOT:
+    fprintf(stderr, "This program must be run setuid root from a user account.");
+    break;
+  case SUBU_ERR_MALLOC:
+    perror(fname);
+    break;
+  case SUBU_ERR_DB_FILE:
+    fprintf(stderr, "error on %s", DB_File); // DB_File is in common
+    fprintf(stderr, ": %s", mess);
+    break;
+  case SUBU_ERR_HOMELESS:
+    fprintf(stderr,"Masteru, \"%s\", has no home directory", mess);
+    break;
+  case SUBU_ERR_SUBUNAME_MALFORMED:
+    fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", mess);
+    break;
+  case SUBU_ERR_SUBUHOME_EXISTS:
+    fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", mess);
+    break;
+  case SUBU_ERR_MKDIR_SUBUHOME:
+    fprintf(stderr, "masteru could not make subuhome, \"%s\"", mess);
+    break;
+  case SUBU_ERR_BUG_SSS:
+    perror(fname);
+  break;
+  case SUBU_ERR_FAILED_USERADD:
+    fprintf(stderr, "%s useradd failed\n", mess);
+  break;
+  default:
+    fprintf(stderr, "unknown error code %d\n", err);
+  }
+  fputc('\n', stderr);
+}
+
+
+//--------------------------------------------------------------------------------
+// a well formed subuname
+// returns the length of the subuname, or -1
+//
+static int allowed_subuname(char **mess, char *subuname, size_t *subuname_len){
+  char *ch = subuname;
+  size_t i = 0;
+  while(
+        *ch
+        &&
+        ( *ch >= 'a' && *ch <= 'z'
+          ||
+          *ch >= 'A' && *ch <= 'Z'
+          ||
+          *ch >= '0' && *ch <= '9'
+          ||
+          *ch == '-'
+          ||
+          *ch == '_'
+          ||
+          *ch == '.'
+          ||
+          *ch == ' '
+          )
+        ){
+    ch++;
+    i++;
+  }
+  if( !*ch ){
+    *subuname_len = i;
+    return 0;
+  }else{
+    if(mess) *mess = strdup(subuname);
+    return SUBU_ERR_SUBUNAME_MALFORMED;
+  }
+}
+
+//--------------------------------------------------------------------------------
+// dispatched functions
+//
+static int masteru_mkdir_subuhome(void *arg){
+  char *subuhome = (char *) arg;
+  if( mkdir( subuhome, Subuhome_Perms ) == -1 ){ // find subuhome perms in common
+    perror("masteru_mkdir_subuhome");
+    return SUBU_ERR_MKDIR_SUBUHOME;
+  }
+  return 0;
+}
+static int masteru_rmdir_subuhome(void *arg){
+  char *subuhome = (char *) arg;
+  if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
+    perror("masteru_rmdir_subuhome");
+    return SUBU_ERR_RMDIR_SUBUHOME;
+  }
+  return 0;
+}
+
+//--------------------------------------------------------------------------------
+// build strings 
+//
+static int mk_subu_username(char **mess, sqlite3 *db, char **subu_username){
+  int rc,n;
+  db_begin(db);
+  if(
+    (rc = subudb_number_get(db, &n))
+    ||
+    (rc = subudb_number_set(db, ++n))
+     ){
+    db_rollback(db);
+    return SUBU_ERR_DB_FILE;
+  }
+  db_commit(db);
+
+  size_t len = 0;
+  FILE* name_stream = open_memstream(subu_username, &len);
+  fprintf(name_stream, "s%d", n);
+  fclose(name_stream);
+  return 0;
+}
+
+// man page says that getpwuid strings may not be freed, I don't know how long until they
+// are overwritten, so I just make my own copies that can be freed
+static int uid_to_name_and_home(uid_t uid, char **name, char **home ){
+  struct passwd *pw_record_pt = getpwuid(uid); // reading /etc/passwd
+  *name = strdup(pw_record_pt->pw_name);
+  *home = strdup(pw_record_pt->pw_dir);
+  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
+  return 0;
+}
+
+static int username_to_home(char *name, char **home ){
+  struct passwd *pw_record_pt = getpwnam(name); // reading /etc/passwd
+  *home = strdup(pw_record_pt->pw_dir);
+  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
+  return 0;
+}
+
+static int mk_subuland(char *masteru_home, char **subuland){
+  size_t masteru_home_len = strlen(masteru_home);
+  char *Subuland_Extension = "/subuland/";
+  size_t Subuland_Extension_len = strlen(Subuland_Extension);
+  *subuland = (char *)malloc( masteru_home_len + Subuland_Extension_len + 1 );
+  if(!*subuland) SUBU_ERR_MALLOC; 
+  strcpy(*subuland, masteru_home);
+  strcpy(*subuland + masteru_home_len, Subuland_Extension);
+  return 0;
+}
+
+static int mk_subuhome(char *subuland, char *subuname, char **subuhome){
+  size_t subuland_len = strlen(subuland);
+  size_t subuhome_len = subuland_len + strlen(subuname); // subuland has a trailing '/'
+  *subuhome = (char *)malloc(subuhome_len + 1);
+  if(!*subuhome) return SUBU_ERR_MALLOC;
+  strcpy (*subuhome, subuland);
+  strcpy (*subuhome + subuland_len, subuname);
+  return 0;
+}
+
+
+
+//===============================================================================
+int subu_mk_0(char **mess, sqlite3 *db, char *subuname){
+
+  int rc;
+  if(mess)*mess = 0;
+  da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  //--------------------------------------------------------------------------------
+  size_t subuname_len;
+  rc = allowed_subuname(mess, subuname, &subuname_len);
+  if(rc) return rc;
+  #ifdef DEBUG
+  dbprintf("subuname is well formed\n");
+  #endif
+
+  //--------------------------------------------------------------------------------
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
+  }
+
+  //--------------------------------------------------------------------------------
+  char *masteru_name = 0;
+  char *masteru_home = 0;
+  char *subu_username = 0;
+  char *subuland = 0;
+  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+  da_push(&resources, masteru_name);
+  da_push(&resources, masteru_home);
+  da_push(&resources, subu_username);
+  da_push(&resources, subuland);
+  da_push(&resources, subuhome);
+  rc =
+    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+    ||
+    mk_subu_username(mess, db, &subu_username)
+    ||
+    mk_subuland(masteru_home, &subuland)
+    ||
+    mk_subuhome(subuland, subuname, &subuhome)
+    ;
+  if(rc) RETURN(&resources, rc);
+  #ifdef DEBUG
+  dbprintf("subu_username, subuland, subuhome: \"%s\"\"%s\"\"%s\"\n", subu_username, subuland, subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  // By having masteru create the subuhome, we know that masteru has rights to 
+  // to access this directory. This will be the mount point for bindfs
+  {
+    struct stat st;
+    if( stat(subuhome, &st) != -1 ){
+      if(mess)*mess = strdup(subuhome);
+      RETURN(&resources, SUBU_ERR_SUBUHOME_EXISTS);
+    }
+    int dispatch_err = dispatch_f_euid_egid
+      (
+       "masteru_mkdir_subuhome", 
+       masteru_mkdir_subuhome, 
+       (void *)subuhome,
+       masteru_uid, 
+       masteru_gid
+       );
+    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_MKDIR_SUBUHOME ){
+      #ifdef DEBUG
+      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_mkdir_subuhome");
+      #endif
+      if(mess)*mess = strdup(subuhome);
+      RETURN(&resources, SUBU_ERR_MKDIR_SUBUHOME);
+    }
+  }
+  #ifdef DEBUG
+  dbprintf("made directory \"%s\"\n", subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  //  Make the subservient user account, i.e. the subu
+  {
+    #ifdef DEBUG
+      dbprintf("making subu \"%s\" as user \"%s\"\n", subuname, subu_username);
+    #endif
+    #if BUG_SSS_CACHE_RUID
+      #ifdef DEBUG
+        dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
+      #endif
+      if( setuid(0) == -1 ) RETURN(&resources, SUBU_ERR_BUG_SSS);
+    #endif
+    char *command = "/usr/sbin/useradd";
+    char *argv[3];
+    argv[0] = command;
+    argv[1] = subu_username;
+    argv[2] = (char *) NULL;
+    char *envp[1];
+    envp[0] = (char *) NULL;
+    int dispatch_err = dispatch_exec(argv, envp);
+    if( dispatch_err != 0 ){
+      #ifdef DEBUG 
+      dispatch_f_mess("dispatch_exec", dispatch_err, command);
+      #endif
+      // go back and remove the directory we made in subuland
+      int dispatch_err_rmdir = dispatch_f_euid_egid
+        (
+         "masteru_rmdir_subuhome", 
+         masteru_rmdir_subuhome, 
+         (void *)subuhome,
+         masteru_uid, 
+         masteru_gid
+         );
+      #ifdef DEBUG
+      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err_rmdir, "masteru_rmdir_subuhome");
+      #endif
+      if(mess)*mess = useradd_mess(dispatch_err);
+      RETURN(&resources, SUBU_ERR_FAILED_USERADD);
+    }
+    #ifdef DEBUG
+    dbprintf("added user \"%s\"\n", subu_username);
+    #endif
+  }  
+  
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  dbprintf("setting the masteru_name, subuname, subu_username relation\n");
+  #endif
+  {
+    int rc = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
+    if( rc != SQLITE_OK ){
+      if(mess)*mess = strdup("insert of masteru subu relation failed");
+      RETURN(&resources, SUBU_ERR_DB_FILE);
+    }
+  }
+  #ifdef DEBUG
+  dbprintf("finished subu-mk-0(%s)\n", subuname);
+  #endif
+  RETURN(&resources, 0);
+}
+
+//================================================================================
+int subu_rm_0(char **mess, sqlite3 *db, char *subuname){
+
+  int rc;
+  if(mess)*mess = 0;
+  da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  //--------------------------------------------------------------------------------
+  size_t subuname_len;
+  rc = allowed_subuname(mess, subuname, &subuname_len);
+  if(rc) return rc;
+  #ifdef DEBUG
+  dbprintf("subuname is well formed\n");
+  #endif
+  
+  //--------------------------------------------------------------------------------
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
+  }
+
+  //--------------------------------------------------------------------------------
+  // various strings that we will need
+  char *masteru_name = 0;
+  char *masteru_home = 0;
+  char *subuland = 0;
+  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+  da_push(&resources, masteru_name);
+  da_push(&resources, masteru_home);
+  da_push(&resources, subuland);
+  da_push(&resources, subuhome);
+  rc =
+    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+    ||
+    mk_subuland(masteru_home, &subuland)
+    ||
+    mk_subuhome(subuland, subuname, &subuhome)
+    ;
+  if(rc) RETURN(&resources, rc);
+  #ifdef DEBUG
+  dbprintf("masteru_home, subuhome: \"%s\", \"%s\"\n", masteru_home, subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  // removal from db
+  char *subu_username = 0;
+  da_push(&resources, subu_username);
+
+  db_begin(db);
+
+  rc = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
+  if( rc != SQLITE_OK ){
+    if(mess) *mess = strdup("subu requested for removal not found under this masteru in db file");
+    rc = SUBU_ERR_SUBU_NOT_FOUND;
+    db_rollback(db);
+    RETURN(&resources, rc);
+  }
+  #ifdef DEBUG
+  printf("subu_username: \"%s\"\n", subu_username);  
+  #endif
+
+  rc = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
+  if( rc != SQLITE_OK ){
+    if(mess)*mess = strdup("removal of masteru subu relation failed");
+    db_rollback(db);
+    RETURN(&resources, SUBU_ERR_DB_FILE);
+  }
+  #ifdef DEBUG
+  dbprintf("removed the masteru_name, subuname, subu_username relation\n");
+  #endif
+  
+  rc = db_commit(db);
+  if( rc != SQLITE_OK ){
+    if(mess)*mess = strdup("removal of masteru subu relation in unknown state, exiting");
+    RETURN(&resources, SUBU_ERR_DB_FILE);
+  }
+  
+  // even after removing the last masteru subu relation, we still do not remove
+  // the max subu count. Hence, a masteru will keep such for a life time.
+
+
+  //--------------------------------------------------------------------------------
+  // Only masteru can remove directories from masteru/subuland, so we switch to 
+  // masteru's uid to perform the rmdir.
+  //
+  {
+    #ifdef DEBUG
+    dbprintf("as masteru, removing the directory \"%s\"\n", subuhome);
+    #endif
+    int dispatch_err = dispatch_f_euid_egid
+      (
+       "masteru_rmdir_subuhome", 
+       masteru_rmdir_subuhome, 
+       (void *)subuhome,
+       masteru_uid, 
+       masteru_gid
+       );
+    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_RMDIR_SUBUHOME ){
+      #ifdef DEBUG
+      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_rmdir_subuhome");
+      #endif
+      if(mess)*mess = strdup(subuhome);
+      RETURN(&resources, SUBU_ERR_RMDIR_SUBUHOME);
+    }
+  }
+
+  //--------------------------------------------------------------------------------
+  //  Delete the subservient user account
+  {
+    #ifdef DEBUG
+    dbprintf("deleting user \"%s\"\n", subu_username);
+    #endif
+    #if BUG_SSS_CACHE_RUID
+      #ifdef DEBUG
+        dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
+      #endif
+      if( setuid(0) == -1 ){
+        RETURN(&resources, SUBU_ERR_BUG_SSS);
+      }
+    #endif
+    char *command = "/usr/sbin/userdel";
+    char *argv[4];
+    argv[0] = command;
+    argv[1] = subu_username;
+    argv[2] = "-r";  
+    argv[3] = (char *) NULL;
+    char *envp[1];
+    envp[0] = (char *) NULL;
+    int dispatch_err = dispatch_exec(argv, envp);
+    if( dispatch_err != 0 ){
+      #ifdef DEBUG 
+      dispatch_f_mess("dispatch_exec", dispatch_err, command);
+      #endif
+      if(mess)*mess = userdel_mess(dispatch_err);
+      RETURN(&resources, SUBU_ERR_FAILED_USERDEL);
+    }
+    #ifdef DEBUG
+    dbprintf("deleted user \"%s\"\n", subu_username);
+    #endif
+  }  
+
+  #ifdef DEBUG
+  dbprintf("finished subu-rm-0(%s)\n", subuname);
+  #endif
+  RETURN(&resources, 0);
+}
+
+//================================================================================
+// identifies masteru, the bindfs maps each subu_user's home to its mount point
+// in subuland.
+int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome){
+
+  int rc;
+  if(mess)*mess = 0;
+  da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  // lookup the subu_user_home
+  char *subu_user_home = 0;
+  da_push(&resources, subu_user_home);
+
+  rc = username_to_home(subu_username, &subu_user_home);
+  if( rc ){
+    if(mess) *mess = strdup("in subu_bind, subu user home directory lookup in /etc/passwd failed.");
+    RETURN(&resources, rc);
+  }
+
+  size_t len = 0;
+  char *map = 0;
+  da_push(&resources, map);
+
+  FILE* map_stream = open_memstream(&map, &len);
+  fprintf(map_stream, "--map=%s/%s:@%s/@%s", subu_username, masteru_name, subu_username, masteru_name);
+  fclose(map_stream);
+  
+  char *command = "/usr/bin/bindfs";
+  char *argv[5];
+  argv[0] = command;
+  argv[1] = map;
+  argv[2] = subu_user_home;
+  argv[3] = subuhome;
+  argv[4] = (char *) NULL;
+  char *envp[1];
+  envp[0] = (char *) NULL;
+  int dispatch_err = dispatch_exec(argv, envp);
+  if( dispatch_err != 0 ){
+    #ifdef DEBUG 
+    dispatch_f_mess(command, dispatch_err, "dispatch_exec");
+    #endif
+    if(mess)*mess = strdup("bind failed");
+    RETURN(&resources, SUBU_ERR_BIND);
+  }
+  #ifdef DEBUG
+  dbprintf("mapped \"%s\" as \"%s\"\n", subu_user_home, subuhome);
+  #endif
+  RETURN(&resources, 0);
+}
+
+int subu_bind_all(char **mess, sqlite3 *db){
+
+  int rc;
+  if(mess)*mess = 0;
+  da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  //--------------------------------------------------------------------------------
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
+  }
+
+  //--------------------------------------------------------------------------------
+  // various strings that we will need
+  char *masteru_name = 0;
+  char *masteru_home = 0;
+  char *subuland = 0;
+  da_push(&resources, masteru_name);
+  da_push(&resources, masteru_home);
+  da_push(&resources, subuland);
+  rc =
+    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+    ||
+    mk_subuland(masteru_home, &subuland)
+    ;
+  if(rc) RETURN(&resources, rc);
+  #ifdef DEBUG
+  if(masteru_name)  
+    dbprintf("masteru_name: \"%s\"", masteru_name);
+  else
+    dbprintf("masteru_name unknown");
+  if(subuland)
+    dbprintf("subuland: \"%s\"", subuland);
+  else
+    dbprintf("subuland unknown");
+  dbprintf("\n");
+  #endif
+
+  //--------------------------------------------------------------------------------
+  da subus;
+  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &subus);
+  if( rc != SQLITE_OK ){
+    if(mess)*mess = strdup("db access failed when fetching a list of subus");
+    return rc;
+  }
+  // a limitation of our error reporting approach is that we can only 
+  // return one error, but here is a loop that might generate many
+  rc = 0; 
+  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+  uint err_cnt = 0;
+  subudb_subu_element *pt = (subudb_subu_element *)(subus.base);
+  while( !da_endq(&subus,pt) ){
+    rc = mk_subuhome(subuland, pt->subuname, &subuhome);
+    #ifdef DEBUG
+    if(subuhome)
+      dbprintf("subuhome: \"%s\"\n", subuhome);
+    else
+      dbprintf("subuhome unknown \n");
+    #endif
+    if(!rc) rc = subu_bind(NULL, masteru_name, pt->subu_username, subuhome);
+    if(rc) err_cnt++;
+    free(subuhome);
+    subuhome=0;
+  pt++;
+  }
+  if(err_cnt==1){
+    RETURN(&resources, rc);
+  }
+  if(err_cnt > 1){
+    *mess = strdup("multiple errors occured while binding subus");
+    RETURN(&resources, SUBU_ERR_BIND);
+  }
+  RETURN(&resources, 0);
+}
diff --git a/module/subu-0/subudb-init.cli.c b/module/subu-0/subudb-init.cli.c
new file mode 100644 (file)
index 0000000..714c7e4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+This command initializes the db file.
+
+*/
+#include "subudb-init.cli.h"
+#include <stdio.h>
+
+int main(){
+  sqlite3 *db;
+  if( sqlite3_open(DB_File, &db) != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
+    return SUBU_ERR_DB_FILE;
+  }
+  db_begin(db);
+  if( subudb_schema(db) != SQLITE_OK ){
+    db_rollback(db);
+    fprintf(stderr, "error exit, opened db file but could not build schema\n");
+    return SUBU_ERR_DB_FILE;
+  }
+  db_commit(db);
+  if( sqlite3_close(db) != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not close the db\n");
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
diff --git a/module/subu-0/subudb-number.cli.c b/module/subu-0/subudb-number.cli.c
new file mode 100644 (file)
index 0000000..60304e3
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include "subudb-number.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+  if( argc < 1 || argc > 2){
+    fprintf(stderr, "usage: %s [n]\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not open db file\n");
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  // then arg[1] holds a number to set the max to
+  if(argc == 2){ 
+    long int i = strtol(argv[1], NULL, 10);
+    if( i < 0 ){
+      fprintf(stderr, "n must be positive\n");
+      sqlite3_close(db);
+      return SUBU_ERR_N;
+    }
+    if( i > INT_MAX ){
+      fprintf(stderr, "n is too big, max supported by this program is %d\n", INT_MAX);
+      sqlite3_close(db);
+      return SUBU_ERR_N;
+    }
+    rc = subudb_number_set(db, i);
+    if( rc != SQLITE_OK ){
+      fprintf(stderr, "couldn't set Max_Subunumber: %s\n", sqlite3_errmsg(db));
+      return SUBU_ERR_N;
+    }
+  }
+
+  // read and print the current max
+  int n;
+  rc = subudb_number_get(db, &n);
+  if( rc == SQLITE_OK ){
+    printf("%d\n", n);
+  }else{
+    fprintf(stderr, "couldn't get Max_Subunumber: %s\n", sqlite3_errmsg(db));
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+  rc = sqlite3_close(db);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+
+}
diff --git a/module/subu-0/subudb-rel-get.cli.c b/module/subu-0/subudb-rel-get.cli.c
new file mode 100644 (file)
index 0000000..9828b15
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+get the username from the db file
+for testing subudb_Masteru_Subu_get_subu_username
+
+*/
+#include "subudb-rel-get.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if(argc != 3){
+    fprintf(stderr, "usage: %s masteru_name subuname\n", argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  char *masteru_name = argv[1];
+  char *subuname = argv[2];
+  char *subu_username;
+
+  int ret = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
+  if( ret != SQLITE_DONE ){
+    fprintf(stderr, "subudb_Masteru_Subu_get_subu_username indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }
+  ret = sqlite3_close(db);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
diff --git a/module/subu-0/subudb-rel-put.cli.c b/module/subu-0/subudb-rel-put.cli.c
new file mode 100644 (file)
index 0000000..b19896e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+puts a relation in the masteru/subu table
+
+*/
+#include "subudb-rel-put.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if(argc != 4){
+    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
+    return 1;
+  }
+  char *masteru_name = argv[1];
+  char *subuname = argv[2];
+  char *subu_username = argv[3];
+
+  sqlite3 *db;
+  {
+    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+    if( ret != SQLITE_OK ){
+      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+      return SUBU_ERR_DB_FILE;
+    }}
+
+  int ret = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "subudb_Masteru_Subu_put indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }
+  ret = sqlite3_close(db);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
diff --git a/module/subu-0/subudb-rel-rm.cli.c b/module/subu-0/subudb-rel-rm.cli.c
new file mode 100644 (file)
index 0000000..3d15ca9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+puts a relation in the masteru/subu table
+
+*/
+#include "subudb-rel-rm.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if(argc != 4){
+    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
+    return 1;
+  }
+  char *masteru_name = argv[1];
+  char *subuname = argv[2];
+  char *subu_username = argv[3];
+
+  sqlite3 *db;
+  {
+    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+    if( ret != SQLITE_OK ){
+      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+      return SUBU_ERR_DB_FILE;
+    }}
+
+  int ret = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
+  if( ret != SQLITE_DONE ){
+    fprintf(stderr, "subudb_Masteru_Subu_rm indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+    printf("put failed\n");
+    return 2;
+  }
+  ret = sqlite3_close(db);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
diff --git a/module/subu-0/subudb-subus.cli.c b/module/subu-0/subudb-subus.cli.c
new file mode 100644 (file)
index 0000000..be3af20
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include "subudb-subus.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+  if( argc != 2){
+    fprintf(stderr, "usage: %s masteru_name\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *masteru_name = argv[1];
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not open db file\n");
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  subudb_subu_element *sa;
+  subudb_subu_element *sa_end;
+  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
+  if( rc == SQLITE_OK ){
+    subudb_subu_element *pt = sa;
+    while( pt != sa_end ){
+      printf("%s %s\n", pt->subuname, pt->subu_username);
+    pt++;
+    }
+    rc = sqlite3_close(db);
+    if( rc != SQLITE_OK ){
+      fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+      return SUBU_ERR_DB_FILE;
+    }    
+    return 0;
+  }
+  fprintf(stderr, "lookup failed %s\n", sqlite3_errmsg(db));
+  sqlite3_close(db);
+  return SUBU_ERR_DB_FILE;
+
+}
diff --git a/module/subu-1/subu-mk.py b/module/subu-1/subu-mk.py
new file mode 100644 (file)
index 0000000..203fab4
--- /dev/null
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+# see the help option for syntax
+# this script must be run from root or sudo
+#
+# on Fedora 29 os.getresuid returned all zeros for a script run from sudo.
+# Hence, I am using the environment variable SUDO_USER
+
+import getpass
+import os
+import sys
+import libuser
+from __future__ import print_function
+
+command = os.path.base(argv[0])
+
+#--------------------------------------------------------------------------------
+# utilities
+#
+def prn(str):
+  print(str,end='')
+
+#--------------------------------------------------------------------------------
+# help
+#
+def help():
+  print( command +
+""" [=help] [=version] [shell=<shell>][owner=<owner-username>] [subu=]<subu-username>
+Makes a subservient user.
+If no arguments are given, or if =help is given, this message is printed.
+When this command is invoked through sudo, $SUDO_USER is taken as the owner's username.
+Otherwise, when invoked directly from root, the owner= option must be provided.
+The subu-username argument is the username for the new subservient user
+The the new subu home directory is created in /home/owner/subu/.
+Facls are set to give the owner access to the new subu's home directory.
+The shell option is not implemented yet.  Probably need a number of other options also.
+"""
+  )
+
+def version():
+  print(" version 0")
+
+#--------------------------------------------------------------------------------
+# a manager for handling error messages
+#
+class class_err:
+"""
+An error record has the form [flag, message, args] 
+  class is fatal, warning, info  [currently not implemented]
+  flag is true if an error has occured [need to change this to a count]
+  args is an array of strings to be given after the error message is printed.
+
+The dict holds named error records.
+
+register() is used to name and place error records in the dict. register() is
+typically called multiple times to initialize and error instance.
+
+tattle() is used by the program at run time in order to signal errors.
+
+has_error() returns true if tattle was ever called
+
+report() prints an error report.  When errors have occured this 
+
+vector() [unimplemented] returns a bit vector with one bit per fatal error
+record, in the order they appear in the dictionary. The bit is set if the error
+ever occured.
+
+We check for as many errors as is convenient to do so rather than stopping on
+the first error.
+"""
+
+  # field offsets into the error record
+  flag_dex = 0;
+  message_dex = 1;
+  args_dex = 2;
+
+  def __init__(self):
+    self.total_cnt = 0
+    self.dict = {}
+
+  def register(name, message):
+    self.dict[name] = [False, message, []]
+
+  def tattle(name, *args):
+    self.total_cnt += 1
+    if name in self.dict:
+      self.dict[name][0] = True
+      self.dict[name][2].extend(args)
+
+  def report():
+    if self.total_cnt:
+      for k,v in self.dict.items():
+        if v[self.flag_dex]:
+          print(v[self.message_dex],end='')
+          args = v[self.args_dex]
+          if length(args) :
+            print(args[0],end='')
+            for arg in args[1:]:
+              print( " " + arg, end='')
+          print()
+
+#--------------------------------------------------------------------------------
+# parse the command line
+#
+err.register(
+  'impossible_split',
+  "It is not possible, yet this token split into other than one or two pieces: "
+  )
+err.register(
+  'lone_delim',
+  "No spaces should appear around the '=' delimiter."
+  )
+
+args = sys.argv[1:]
+if len(args) == 0 :
+  version()
+  help()
+  exit(1)
+#create a dictionary based on the command line arguments
+arg_dict = {}
+subu_cnt = 0
+delim = '='
+for token in args:
+  token_pair = split(token, delim);
+  if len(token_pair) == 1 : #means there was no '=' in the token
+    arg_dict['subu'] = token_pair
+    subu_cnt++
+  elif len(token_pair) == 2 :
+    if token_pair[0] == '' and token_pair[1] == '' :
+      err.tattle('lone_delim')
+    elif token_pair[1] == '' : # then has trailing delim, will treat the same as a leading delim
+      arg_dict[token_pair[0]] = None
+    elif token_pair[0] == '' : # then has leading delim
+      arg_dict[token_pair[1]] = None
+    else:
+      arg_dict[token_pair[0]] = token_pair[1]
+  else:
+    err.tattle('impossible_split', token)
+
+if not arg_dict or arg_dict.get('help'):
+  help()
+  err.report()
+  exit(1)
+
+if arg_dict.get('version'):
+  version()
+
+#--------------------------------------------------------------------------------
+# check that the command line arguments are well formed. 
+#
+err.register(
+  'too_many_args',
+  command + " takes at most one non-option argument, but we counted: "
+  )
+err.register(
+  'no_subu'
+  command + " missing subservient username."
+  )
+err.register(
+  'bad_username'
+  "Usernames match ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$, but found: "
+  )
+err.register(
+  'unknown_option'
+  command + " doesn't implement option: "
+  )
+
+subu = arg_dict.get('subu')
+if subu_cnt > 1:
+  err.tattle('too_many_args')
+elif not subu
+  err.tattle('no_subu')
+elif not re.match("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$", subu)
+  err.tattle('bad_username', subu)
+
+for k in arg_dict:
+  if k not in ['help', 'version', 'shell', 'owner', 'subu'] :
+    err.tattle('unkown_option', k)
+
+if arg_dict.get('shell') :
+  print "shell option aint implemented yet"
+
+
+
+#--------------------------------------------------------------------------------
+# check that we have root privilege
+#
+err.register(
+  'not_root'
+  command + "requires root privilege"
+  )
+
+uid = os.getuid()
+if uid != 0 :
+  err.tattle('not root')
+
+username = getpass.getuser()
+sudo_caller_username = os.environ.get('SUDO_USER')
+
+if !sudo_caller_username
+  if username not == "root":
+    err.tattle('not_root')
+  elif:
+    owner
+    
+
+  def has_error(*errs):
+    return self.cnt > 0
+
+
+
+#-----
+
+
+
+
+#--------------------------------------------------------------------------------
+#  pull out the owner_dir and subu_dir
+#
+admin= libuser.admin()
+
+err_arg_form = class_err()
+err_arg_form.register('too_many', "too many semicolon delineated parts in")
+
+owner_parts = args[0].split(":")
+subu_parts = args[1].split(":") 
+
+owner_user_name = owner_parts[0]
+if not owner_user_name:
+  err_arg_form.tattle('owner_user_name_missing', args[0])
+else:
+  owner_user = admin.lookupUserByName(owner_user_name)
+  if owner_user == None:
+    err_arg_form.tattle('no_such_user_name', owner_user_name)
+  else:
+    
+
+subu_user_name = subu_parts[0]
+
+
+if length(owner_parts) > 2:
+  err_arg_form.tattle('too_many', args[0])
+elif length(owner_parts) == 2:
+  owner_dir = owner_parts[1]
+else # get the home directory
+    
+  
+
+
+#--------------------------------------------------------------------------------
+# set the home directory
+#
+if len(args) > args_dir_index:
+  dir = args[args_dir_index]
+else:
+  dir = os.getcwd()
+
+home = dir + "/" + name
+home_flag = not os.path.exists(home)
+
+#--------------------------------------------------------------------------------
+# create the user, setfacls
+#
+err_cnt = 0
+name_available_flag = False
+
+if name_flag:
+  admin = libuser.admin()
+  name_available_flag = name not in admin.enumeratedUsers()
+
+if owner_flag and name_flag and name_available_flag and home_flag :
+  user = admin.initUser(name)
+  user[libuser.HOMEDIRECTORY] = home
+  if opt_shell : user[libuser.SHELL] = opt_shell
+  admin.addUser(user)
+  #setfacl -m d:u:plato:rwx,u:plato:rwx directory
+  setfacl = "setfacl -m d:u:" + name + ":rwx,u:" + name + ":rwx " + home
+  exit(0)
+
+#--------------------------------------------------------------------------------
+# error return
+#  .. need to grab the return code from setfacl above and delete the user if it fails
+#
+err_flags = 0
+if not owner_flag :
+  err_flags |= 2**2
+  print "missing owning username argument"
+if not name_flag :
+  err_flags |= 2**3
+  print name + "missing subservient username argument"
+if not name_available_flag :
+  err_flags |= 2**4
+  print name + "specified subservient username already exists"
+if not home_flag :
+  err_flags |= 2**5
+  print "user home directory already exists"
+
+exit(err_flags)
diff --git a/module/tranche/deprecated/0_makefile b/module/tranche/deprecated/0_makefile
new file mode 100644 (file)
index 0000000..b8c7b9d
--- /dev/null
@@ -0,0 +1,40 @@
+# src/0_makefile
+
+SHELL=/bin/bash
+
+-include 0_makefile_flags
+
+SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
+
+SOURCES=$(wildcard *.c)
+HFILES=$(wildcard *.h)
+
+all: version deps lib execs
+
+version:
+       $(MAKE) $@
+       @echo "SUID_TOOL: " $(SUID_TOOL)
+
+deps:
+       makeheaders $(SOURCES) $(HFILES)
+       sed -i '/^ *int *main *(.*)/d' *.h
+       $(MAKE) $@
+
+execs:
+       $(MAKE) $@
+       @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+       cat $(SUID_TOOL)
+       @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
+       sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+
+clean:
+       $(MAKE) $@
+       for i in $(HFILES); do rm $$i; done
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/tranche/deprecated/0_makefile-flags b/module/tranche/deprecated/0_makefile-flags
new file mode 100644 (file)
index 0000000..d4df01f
--- /dev/null
@@ -0,0 +1,31 @@
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=1_deprecated
+DOCDIR=1_doc
+EXECSDIR=1_execs
+HDIR=1_headers
+LIBDIR=1_lib
+TESTDIR=1_tests
+TMPDIR=1_tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=1_try
+
+
+# compiler and flags
+CC=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-L1_lib -lsubu -lsqlite3
+
+LIBFILE=$(LIBDIR)/libsubu.a
+
diff --git a/module/tranche/doc/todo.txt b/module/tranche/doc/todo.txt
new file mode 100644 (file)
index 0000000..1494e66
--- /dev/null
@@ -0,0 +1,11 @@
+
+2019-03-22T13:37:23Z
+1. indentation
+
+   the first non blank line after the #tranche keyword sets the indentation
+   level for the following text.  When echoing to the output file 
+   remove that many leading spaces.
+
+   Hmm,  or allow options among the tranche parameters,  -indent 3 or
+   -indent '  '.
+   
diff --git a/module/tranche/makefile b/module/tranche/makefile
new file mode 100644 (file)
index 0000000..4c20d5e
--- /dev/null
@@ -0,0 +1,22 @@
+# tranche/makefile
+
+SHELL=/bin/bash
+
+-include makefile-flags
+
+.PHONY: all version deps lib exec
+all: version deps lib exec
+
+lib:
+       $(MAKE) $@
+       cp src/tranche.lib.h include/tranche.h
+
+exec:
+       $(MAKE) $@
+
+%::
+       $(MAKE) $@
+
+
+
+
diff --git a/module/tranche/makefile-flags b/module/tranche/makefile-flags
new file mode 100644 (file)
index 0000000..1aa3d66
--- /dev/null
@@ -0,0 +1,31 @@
+MODULE=tranche
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECDIR, INCDIR hold the make results that might later be shared
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=deprecated
+DOCDIR=doc
+EXECDIR=exec
+INCDIR=include
+LIBDIR=lib
+SRCDIR=src
+TESTDIR=test
+TMPDIR=tmp
+TOOLDIR=$(realpath $(PROJECT_SUBU)/tool)
+TRYDIR=try
+
+C=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-Llib -L../share/lib/ -lda -ltranche
+
+MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tool/lib/makefile_cc
+#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tool/lib/makefile_cc
diff --git a/module/tranche/src/tranche.cli.c b/module/tranche/src/tranche.cli.c
new file mode 100644 (file)
index 0000000..8df4337
--- /dev/null
@@ -0,0 +1,25 @@
+
+#include <stdio.h>
+#include <unistd.h>
+#include <da.h>
+#include "tranche.lib.h"
+
+int main(int argc, char **argv, char **envp){
+  if(argc != 2){
+    fprintf(stderr, "usage: %s <source-file>\n",argv[0]);
+    return 1;
+  }
+  FILE *file = fopen(argv[1], "r");
+  if(!file){
+    fprintf(stderr,"could not open file %s\n", argv[1]);
+    return 2;
+  }
+  Da targets;
+  da_alloc(&targets, sizeof(int));
+  int fd = STDOUT_FILENO;
+  da_push(&targets, &fd);
+  tranche_send(file, &targets);
+  da_free(&targets);
+  fclose(file);
+  return 0;
+}
diff --git a/module/tranche/src/tranche.lib.c b/module/tranche/src/tranche.lib.c
new file mode 100644 (file)
index 0000000..9b824d3
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+The purpose of this tools is to facilitate putting prototypes (declarations) next
+to implementations (definitions) in a single source file of a C/C++ programs. 
+
+Splits a single source file into multiple files.  Scans through the single
+source file looking for lines of the form:
+
+  #tranche-begin filename ...
+
+With the # as the first non-space character on the line, and only filename
+following the tag. Upon finding such a line, copies all following lines into the
+listed files, until reaching the end marker:
+
+  #tranche-end
+
+A next improvement of this file would be to support variables to be passed in
+for the file names.  As it stands, changing the file name requires editing 
+the source file.
+
+Files are opened for create or append, so opening to the same file will append
+to the end.
+
+*/
+
+#include <da.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+//--------------------------------------------------------------------------------
+// parsing
+
+char newline = '\n';
+char terminator = 0;
+
+char tranche_begin_tag[] = "#tranche";
+size_t tranche_begin_tag_len = 8;
+
+char tranche_end_tag[] = "#tranche-end";
+size_t tranche_end_tag_len = 12;
+
+// given a line
+// returns beginning of file name list
+static char *is_tranche_begin(char *pt){
+  while( *pt && isspace(*pt) ) pt++;
+  if(!*pt) return NULL;
+  if( strncmp(pt, tranche_begin_tag, tranche_begin_tag_len) ) return NULL;
+  return pt + tranche_begin_tag_len;
+}
+
+static char *is_tranche_end(char *pt){
+  while( *pt && isspace(*pt) ) pt++;
+  if(!*pt) return NULL;
+  if( strncmp(pt, tranche_end_tag, tranche_end_tag_len) ) return NULL;
+  return pt + tranche_end_tag_len;
+}
+
+static bool parse_file_list(Da *file_names, char *pt0){
+  char *pt1;
+  while( *pt0 && isspace(*pt0) ) pt0++;
+  pt1 = pt0;
+  while( *pt0 ){
+    while( *pt1 && !isspace(*pt1) ) pt1++;
+    char *file_name = strndup(pt0, pt1 - pt0);
+    da_push(file_names, &file_name);
+    while( *pt1 && isspace(*pt1) ) pt1++;
+    pt0 = pt1;
+  }
+}
+
+
+
+//--------------------------------------------------------------------------------
+// da_map calls
+
+static void tranche_open_fd(void *fnp, void *closure){
+  char *file_name = *(char **)fnp;
+  Da *fdap = (Da *)closure;
+  int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, 0666);
+  if(fd == -1){
+    fprintf(stderr, "Could not open file %s\n", file_name);
+    return;
+  }
+  da_push(fdap, &fd);  
+  return;
+}
+static void tranche_open_fds(Da *fnap, Da *fdap){
+  da_map(fnap, tranche_open_fd, fdap);
+}
+
+static void tranche_close_fd(void *fdp, void *closure){
+  close(*(int *)fdp);
+}
+static void tranche_close_fds(Da *fdap){
+  da_map(fdap, tranche_close_fd, NULL);
+  da_rewind(fdap);
+}
+
+static void tranche_puts(void *fdp, void *string){
+  write(*(int *)fdp, string, strlen(string));
+}
+static void tranche_puts_all(Da *fdap, char *string){
+  da_map(fdap, tranche_puts, string);
+}
+
+
+
+//--------------------------------------------------------------------------------
+// we have a little problem if the user tries to tranche two things to the same file ..
+int tranche_send(FILE *src, Da *arg_fdap){
+  char *pt;
+  Da line;
+  Da file_name_arr;
+  Da fda;
+  da_alloc(&line, sizeof(char));
+  da_alloc(&file_name_arr, sizeof(char *));
+  da_alloc(&fda, sizeof(int));
+
+  while( !feof(src) ){
+    da_fgets(&line, src);
+    if( is_tranche_end(line.base) ) break;
+    pt = is_tranche_begin(line.base);
+    if(pt){ // then this line is the start of a nested tranche block
+      parse_file_list(&file_name_arr, pt);
+      tranche_open_fds(&file_name_arr, &fda);
+      da_free_elements(&file_name_arr);
+      tranche_send(src, &fda);
+      tranche_close_fds(&fda);
+    }else{
+      da_pop(&line, NULL); // pop the terminating zero
+      da_push(&line, &newline);
+      da_push(&line, &terminator);
+      tranche_puts_all(arg_fdap, line.base);
+    }
+    da_rewind(&line);
+  }
+
+  da_free(&line);
+  da_free(&file_name_arr);
+  da_free(&fda);
+  return 0;
+}
diff --git a/module/tranche/src/tranche.lib.h b/module/tranche/src/tranche.lib.h
new file mode 100644 (file)
index 0000000..27990a6
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef TRANCHE_LIB_H
+#define TRANCHE_LIB_H
+
+int tranche_send(FILE *src, Da *arg_fds);
+
+
+
+#endif
diff --git a/module/tranche/test/test1.dat b/module/tranche/test/test1.dat
new file mode 100644 (file)
index 0000000..b03df3f
--- /dev/null
@@ -0,0 +1,23 @@
+
+#tranche test11.dat test12.dat
+The little red hen said to Mick, no thank you not today sir.
+And then all the barnes animals shouted out in glee.
+No more misery!
+#tranche test13.dat
+apple banana pear
+kiwi
+#tranche-end
+cows
+and cats
+#tranche-end
+
+the between space
+
+#tranche test14.dat
+int float if while
+do
+function
+#tranche-end
+
+#tranche test15.dat
+#tranche-end
\ No newline at end of file
diff --git a/module/tranche/test/test1.sh b/module/tranche/test/test1.sh
new file mode 100644 (file)
index 0000000..c1140ca
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash -x
+./tranche test1.dat >test1stdout.dat
+diff test11.dat test11.dat.expected
+diff test12.dat test12.dat.expected
+diff test13.dat test13.dat.expected
+diff test14.dat test14.dat.expected
+diff test15.dat test15.dat.expected
+diff test1stdout.dat test1stdout.dat.expected
+rm test11.dat test12.dat test13.dat test14.dat test15.dat test1stdout.dat
+
diff --git a/module/tranche/test/test11.dat.expected b/module/tranche/test/test11.dat.expected
new file mode 100644 (file)
index 0000000..2c2904a
--- /dev/null
@@ -0,0 +1,5 @@
+The little red hen said to Mick, no thank you not today sir.
+And then all the barnes animals shouted out in glee.
+No more misery!
+cows
+and cats
diff --git a/module/tranche/test/test12.dat.expected b/module/tranche/test/test12.dat.expected
new file mode 100644 (file)
index 0000000..2c2904a
--- /dev/null
@@ -0,0 +1,5 @@
+The little red hen said to Mick, no thank you not today sir.
+And then all the barnes animals shouted out in glee.
+No more misery!
+cows
+and cats
diff --git a/module/tranche/test/test13.dat.expected b/module/tranche/test/test13.dat.expected
new file mode 100644 (file)
index 0000000..81fb20c
--- /dev/null
@@ -0,0 +1,2 @@
+apple banana pear
+kiwi
diff --git a/module/tranche/test/test14.dat.expected b/module/tranche/test/test14.dat.expected
new file mode 100644 (file)
index 0000000..0d8b89b
--- /dev/null
@@ -0,0 +1,3 @@
+int float if while
+do
+function
diff --git a/module/tranche/test/test15.dat.expected b/module/tranche/test/test15.dat.expected
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/module/tranche/test/test1stdout.dat.expected b/module/tranche/test/test1stdout.dat.expected
new file mode 100644 (file)
index 0000000..4e519ff
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+the between space
+
+
diff --git a/module/tranche/test/test2.c.expected b/module/tranche/test/test2.c.expected
new file mode 100644 (file)
index 0000000..a4876a1
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+#include "test2.h"
+
+
+int f(int x){
+  return x;
+}
+
+
diff --git a/module/tranche/test/test2.h.expected b/module/tranche/test/test2.h.expected
new file mode 100644 (file)
index 0000000..fdc4d72
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef TEST2_H
+#define TEST2_H
+int f(int x);
+#endif
diff --git a/module/tranche/test/test2.trc.c b/module/tranche/test/test2.trc.c
new file mode 100644 (file)
index 0000000..ff7d696
--- /dev/null
@@ -0,0 +1,23 @@
+
+#tranche test2.c
+
+#tranche test2.h
+#ifndef TEST2_H
+#define TEST2_H
+#tranche-end
+
+#include "test2.h"
+
+#tranche test2.h
+int f(int x);
+#tranche-end
+
+int f(int x){
+  return x;
+}
+
+#tranche test2.h
+#endif
+#tranche-end
+
+#tranche-end
diff --git a/module/tranche/test/tranche b/module/tranche/test/tranche
new file mode 120000 (symlink)
index 0000000..acf4a6f
--- /dev/null
@@ -0,0 +1 @@
+../1_execs/tranche
\ No newline at end of file
diff --git a/stage/include/da.h b/stage/include/da.h
deleted file mode 100644 (file)
index 6d3c43b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef DA_LIB_H
-#define DA_LIB_H
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdio.h>
-
-typedef struct Da{
-  char *base;
-  char *end; // one byte/one element off the end of the array
-  size_t size; // size >= (end - base) + 1;
-  size_t element_size;
-} Da;
-
-#define RETURN(dap, r)                      \
-  { da_map(dap, da_free, NULL); return r; }
-
-void da_alloc(Da *dap, size_t element_size);
-void da_free(Da *dap);
-void da_rewind(Da *dap);
-char *da_expand(Da *dap);
-void da_rebase(Da *dap, char *old_base, void *pta);
-bool da_endq(Da *dap, void *pt);
-bool da_boundq(Da *dap);
-void da_push(Da *dap, void *element);
-bool da_pop(Da *dap, void *element);
-char *da_index(Da *dap, size_t i);
-void da_map(Da *dap, void f(void *, void *), void *closure);
-void da_free_elements(Da *dap);
-void da_strings_puts(Da *dap);
-char *da_fgets(Da *dap, FILE *fd);
-
-#endif
-
diff --git a/stage/include/tranche.h b/stage/include/tranche.h
deleted file mode 100644 (file)
index 27990a6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef TRANCHE_LIB_H
-#define TRANCHE_LIB_H
-
-int tranche_send(FILE *src, Da *arg_fds);
-
-
-
-#endif
diff --git a/subu-0/0_makefile b/subu-0/0_makefile
deleted file mode 100644 (file)
index b8c7b9d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# src/0_makefile
-
-SHELL=/bin/bash
-
--include 0_makefile_flags
-
-SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
-MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-SOURCES=$(wildcard *.c)
-HFILES=$(wildcard *.h)
-
-all: version deps lib execs
-
-version:
-       $(MAKE) $@
-       @echo "SUID_TOOL: " $(SUID_TOOL)
-
-deps:
-       makeheaders $(SOURCES) $(HFILES)
-       sed -i '/^ *int *main *(.*)/d' *.h
-       $(MAKE) $@
-
-execs:
-       $(MAKE) $@
-       @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
-       cat $(SUID_TOOL)
-       @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
-       sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
-
-clean:
-       $(MAKE) $@
-       for i in $(HFILES); do rm $$i; done
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/subu-0/0_makefile-flags b/subu-0/0_makefile-flags
deleted file mode 100644 (file)
index 0da8b61..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=1_deprecated
-DOCDIR=1_doc
-EXECSDIR=1_execs
-HDIR=1_headers
-LIBDIR=1_lib
-TESTDIR=1_tests
-TMPDIR=1_tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=1_try
-
-
-# compiler and flags
-CC=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-L1_lib -lsubu -lsqlite3
-
-LIBFILE=$(LIBDIR)/libsubu.a
-
diff --git a/subu-0/1_deprecated/dispatch_exec.lib.c b/subu-0/1_deprecated/dispatch_exec.lib.c
deleted file mode 100644 (file)
index 024bff8..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- fork/execs/wait the command passed in argv[0];
- Returns -1 upon failure.
-
- The wstatus returned from wait() might be either the error returned by exec
- when it failed, or the return value from the command.  An arbitary command is
- passed in, so we don't know what its return values might be. Consquently, we
- have no way of multiplexing a unique exec error code with the command return
- value within wstatus.  If the prorgrammer knows the return values of the
- command passed in, and wants better behavior, he or she can spin a special
- version of dispatch for that command.
-*/
-#include "dispatch_exec.lib.h"
-
-// without this #define execvpe is undefined
-#define _GNU_SOURCE   
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <wait.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-
-
-int dispatch_exec(char **argv, char **envp){
-  if( !argv || !argv[0] ){
-    fprintf(stderr, "argv[0] null. Null command passed into dispatch().\n");
-    return -1;
-  }
-  #ifdef DEBUG
-    dbprintf("dispatching exec, args follow:\n");
-    char **apt = argv;
-    while( *apt ){
-      dbprintf("\t%s",*apt);
-    apt++;
-    }
-    dbprintf("\n");
-  #endif
-  char *command = argv[0];
-  pid_t pid = fork();
-  if( pid == -1 ){
-    fprintf(stderr, "fork() failed in dispatch().\n");
-    return -1;
-  }
-  if( pid == 0 ){ // we are the child
-    execvpe(command, argv, envp);
-    // exec will only return if it has an error ..
-    perror(command);
-    return -1;
-  }else{ // we are the parent
-    int wstatus;
-    waitpid(pid, &wstatus, 0);
-    if(wstatus)
-      return -1;
-    else
-      return 0;
-  }
-}
diff --git a/subu-0/1_deprecated/dispatch_f.lib.c b/subu-0/1_deprecated/dispatch_f.lib.c
deleted file mode 100644 (file)
index 5c199f5..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
-  Forks a new process and runs the a function in that new process.  I.e. it 'spawns' a function.
-
-  f must have the specified prototype. I.e. it accepts one void pointer and
-  returns a positive integer. (Negative integers are used for dispatch error codes.)
-
-  dispatch_f_euid_egid changes to the new euid and egid before running the function.
-
-  If the change to in euid/egid fails, the forked process exits with a negative status.
-  If the function has an error, it returns a positive status.  A status of zero means
-  that all went well.
-
-  Because f is running in a separate process, the return status is the only means
-  of communication going back to the calling process.
-
-
-*/
-#define _GNU_SOURCE
-
-#include "dispatch_f.lib.h"
-// we need the declaration for uid_t etc.
-// without this #define execvpe is undefined
-#define _GNU_SOURCE   
-
-#include <wait.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-#if INTERFACE
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-//--------------------------------------------------------------------------------
-// dispatch_f_ctx class
-//
-#if INTERFACE
-#define ERR_NEGATIVE_RETURN_STATUS -1
-#define ERR_DISPATCH_F_FORK -2
-#define ERR_DISPATCH_F_SETEUID -3
-#define ERR_DISPATCH_F_SETEGID -4
-
-// both name and fname are static allocations
-struct dispatch_f_ctx{
-  char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid")
-  char *dispatchee; // name of the function being dispatched
-  int err;
-  int status; // return value from the function
-};
-#endif
-dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){
-  dispatch_f_ctx *ctxp = malloc(sizeof(dispatch_f_ctx));
-  ctxp->dispatcher = name;
-  ctxp->dispatchee = fname;
-  ctxp->err = 0;
-  return ctxp;
-}
-void dispatch_f_ctx_free(dispatch_f_ctx *ctxp){
-   // no dynamic variables to be freed in ctx
-  free(ctxp); 
-}
-void dispatch_f_mess(struct dispatch_f_ctx *ctxp){
-  if(ctxp->err == 0) return;
-  switch(ctxp->err){
-  case ERR_NEGATIVE_RETURN_STATUS:
-    fprintf(stderr, "%s, function \"%s\" broke contract with a negative return value.", ctxp->dispatcher, ctxp->dispatchee);
-    break;
-  case ERR_DISPATCH_F_FORK:
-  case ERR_DISPATCH_F_SETEUID:
-  case ERR_DISPATCH_F_SETEGID:
-    fprintf(stderr, "%s, ", ctxp->dispatcher);
-    perror(ctxp->dispatcher);
-    break;
-  }
-  fputc('\n', stderr);
-}
-
-//--------------------------------------------------------------------------------
-// interface call point
-dispatch_f_ctx *dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
-  dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f", fname);
-  #ifdef DEBUG
-  dbprintf("%s %s\n", ctxp->dispatcher, ctxp->dispatchee);
-  #endif
-  pid_t pid = fork();
-  if( pid == -1 ){
-    ctxp->err = ERR_DISPATCH_F_FORK; // we are still in the parent process
-    return ctxp;
-  }
-  if( pid == 0 ){ // we are the child
-    int status = (*f)(f_arg); // we require that f return a zero or positive value
-    if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS;
-    exit(status);
-  }else{ // we are the parent
-    waitpid(pid, &(ctxp->status), 0);
-    return ctxp;
-  }
-}
-
-//--------------------------------------------------------------------------------
-// interface call point
-dispatch_f_ctx *dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
-  dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f_euid_egid", fname);
-  #ifdef DEBUG
-  dbprintf("%s %s as euid:%u egid:%u\n", ctxp->dispatcher, ctxp->dispatchee, euid, egid);
-  #endif
-  pid_t pid = fork();
-  if( pid == -1 ){
-    ctxp->err = ERR_DISPATCH_F_FORK;
-    return ctxp;
-  }
-  if( pid == 0 ){ // we are the child
-    int status;
-    if( seteuid(euid) == -1 )
-      status = ERR_DISPATCH_F_SETEUID;
-    else if( setegid(egid) == -1 )
-      status = ERR_DISPATCH_F_SETEGID;
-    else{
-      status = (*f)(f_arg);
-      if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS;
-      exit(status);
-    }
-  }else{ // we are the parent
-    waitpid(pid, &(ctxp->status), 0);
-    return ctxp;
-  }
-}
-
-
diff --git a/subu-0/1_deprecated/dispatch_useradd.lib.c b/subu-0/1_deprecated/dispatch_useradd.lib.c
deleted file mode 100644 (file)
index 7b75291..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-There is no C library interface to useradd(8), but if there were, this function
-would be found there instead.
-
-*/
-#include "dispatch_useradd.lib.h"
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-#if INTERFACE
-#include <sys/types.h>
-#include <pwd.h>
-#define ERR_DISPATCH_USERADD_ARGC 1
-#define ERR_DISPATCH_USERADD_DISPATCH 2
-#define ERR_DISPATCH_USERADD_PWREC 3
-struct dispatch_useradd_ret_t{
-  uint error;
-  struct passwd *pw_record;  
-};
-#endif
-
-
-// we have a contract with the caller that argv[1] is always the subuname
-struct dispatch_useradd_ret_t dispatch_useradd(char **argv, char **envp){
-  struct dispatch_useradd_ret_t ret;
-  {
-    if( !argv || !argv[0] || !argv[1]){
-      fprintf(stderr,"useradd() needs a first argument as the name of the user to be made");
-      ret.error = ERR_DISPATCH_USERADD_ARGC;
-      ret.pw_record = NULL;
-      return ret;
-    }
-
-    char *subu_name;
-    {
-      subu_name = argv[1];
-      if( dispatch_exec(argv, envp) == -1 ){
-        fprintf(stderr,"%s failed\n", argv[0]);
-        ret.error = ERR_DISPATCH_USERADD_DISPATCH;
-        ret.pw_record = NULL;
-        return ret;
-      }}
-
-    {
-      struct passwd *pw_record = getpwnam(subu_name);
-      uint count = 1;
-      while( !pw_record && count <= 3 ){
-        #ifdef DEBUG
-          printf("try %u, getpwnam failed, trying again\n", count);
-        #endif
-        sleep(1);
-        pw_record = getpwnam(subu_name);
-        count++;
-      }
-      if( !pw_record ){
-        ret.error = ERR_DISPATCH_USERADD_PWREC;
-        ret.pw_record = NULL;
-        return ret;
-      }
-      ret.error = 0;
-      ret.pw_record = pw_record;
-      return ret;
-    }}}
-
diff --git a/subu-0/1_deprecated/subu-rm-0.lib.c b/subu-0/1_deprecated/subu-rm-0.lib.c
deleted file mode 100644 (file)
index ccad437..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
-  subu-rm-0 subuname
-
-  1. get our uid and lookup masteru_name in /etc/passwd
-  2. lookup masteru_name/subuname in config file, which gives us subu_username
-  3. unmount subuland/subuname
-  4. userdel subu_username
-  5. rmdir subuland/subuname
-
-  Note, as per the man page, we are not allowed to free the memory allocated by getpwid().
-
-*/
-#include "subu-mk-0.lib.h"
-
-// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
-#define _GNU_SOURCE   
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#if INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-#endif
-
-//--------------------------------------------------------------------------------
-// an instance is subu_rm_0_ctx is returned by subu_rm_0
-//
-#if INTERFACE
-#define ERR_SUBU_RM_0_MKDIR_SUBUHOME 1
-#define ERR_SUBU_RM_0_RMDIR_SUBUHOME 2
-#define ERR_SUBU_RM_0_SUBUNAME_MALFORMED 3
-#define ERR_SUBU_RM_0_SETUID_ROOT 4
-#define ERR_SUBU_RM_0_MASTERU_HOMELESS 5
-#define ERR_SUBU_RM_0_MALLOC 6
-#define ERR_SUBU_RM_0_CONFIG_FILE 7
-#define ERR_SUBU_RM_0_SUBUHOME_EXISTS 8
-#define ERR_SUBU_RM_0_BUG_SSS 9
-#define ERR_SUBU_RM_0_FAILED_USERADD 10
-
-struct subu_rm_0_ctx{
-  char *name;
-  char *subuland;
-  char *subuhome;
-  char *subu_username;
-  bool free_aux;
-  char *aux;
-  uint err;
-};
-#endif
-struct subu_rm_0_ctx *subu_rm_0_ctx_mk(){
-  struct subu_rm_0_ctx *ctxp = malloc(sizeof(struct subu_rm_0_ctx));
-  ctxp->name = "subu_rm_0";
-  ctxp->subuland = 0;
-  ctxp->subuhome = 0;
-  ctxp->subu_username = 0;
-  ctxp->free_aux = false;
-  ctxp->aux = 0;
-}
-void subu_rm_0_ctx_free(struct subu_rm_0_ctx *ctxp){
-  free(ctxp->subuland);
-  free(ctxp->subuhome);
-  free(ctxp->subu_username);
-  if(ctxp->free_aux) free(ctxp->aux);
-  free(ctxp);
-}
-// must be called before any system calls, otherwise perror() will be messed up
-void subu_rm_0_mess(struct subu_rm_0_ctx *ctxp){
-  switch(ctxp->err){
-  case 0: return;
-  case ERR_SUBU_RM_0_MKDIR_SUBUHOME:
-    fprintf(stderr, "masteru could not make subuhome, \"%s\"", ctxp->subuhome);
-    break;
-  case ERR_SUBU_RM_0_SUBUNAME_MALFORMED:
-    fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", ctxp->aux);
-    break;
-  case ERR_SUBU_RM_0_SETUID_ROOT:
-    fprintf(stderr, "This program must be run setuid root from a user account.");
-    break;
-  case ERR_SUBU_RM_0_MASTERU_HOMELESS:
-    fprintf(stderr,"Masteru, \"%s\", has no home directory", ctxp->aux);
-    break;
-  case ERR_SUBU_RM_0_MALLOC:
-    perror(ctxp->name);
-  break;
-  case ERR_SUBU_RM_0_CONFIG_FILE:
-    fprintf(stderr, "config file error: %s", ctxp->aux);
-  break;
-  case ERR_SUBU_RM_0_SUBUHOME_EXISTS:
-    fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", ctxp->subuhome);
-  break;
-  case ERR_SUBU_RM_0_BUG_SSS:
-    perror(ctxp->name);
-  break;
-  case ERR_SUBU_RM_0_FAILED_USERADD:
-    fprintf(stderr, "%u useradd failed\n", ctxp->subu_username);
-  break;
-  default:
-    fprintf(stderr, "unknown error code %d\n", ctxp->err);
-  }
-  fputc('\n', stderr);
-}
-
-//--------------------------------------------------------------------------------
-// dispatched functions
-//
-// the making of subuhome is dispatched to its own process so as to give it its own uid/gid
-static int masteru_mkdir_subuhome(void *arg){
-  char *subuhome = (char *) arg;
-  if( mkdir( subuhome, subuhome_perms ) == -1 ){ // find subuhome perms in common
-    perror("masteru_mkdir_subuhome");
-    return ERR_SUBU_RM_0_MKDIR_SUBUHOME;
-  }
-  return 0;
-}
-static int masteru_rmdir_subuhome(void *arg){
-  char *subuhome = (char *) arg;
-  if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
-    perror("masteru_rmdir_subuhome");
-    return ERR_SUBU_RM_0_RMDIR_SUBUHOME;
-  }
-  return 0;
-}
-
-//--------------------------------------------------------------------------------
-//  the public call point
-struct subu_rm_0_ctx *subu_rm_0(sqlite3 *db, char *subuname){
-
-  struct subu_rm_0_ctx *ctxp = subu_rm_0_ctx_mk();
-
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("Checking that subuname is well formed and finding its length\n");
-  #endif
-  size_t subuname_len;
-  {
-    int ret = allowed_subuname(subuname, &subuname_len);
-    if( ret == -1 ){
-      ctxp->err = ERR_SUBU_RM_0_SUBUNAME_MALFORMED;
-      ctxp->aux = subuname;
-      return ctxp;
-    }}
-  
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("Checking that we are running from a user and are setuid root.\n");
-  #endif
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ){
-      ctxp->err = ERR_SUBU_RM_0_SETUID_ROOT;
-      return ctxp;
-    }
-  }
-
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("strings masteru_name and masteru_home\n");
-  #endif
-
-  char *masteru_name;
-  size_t masteru_name_len;
-  char *masteru_home;
-  size_t masteru_home_len;
-  size_t subuland_len;
-  {
-    struct passwd *masteru_pw_record_pt = getpwuid(masteru_uid); // reading /etc/passwd
-    masteru_name = masteru_pw_record_pt->pw_name;
-    masteru_name_len = strlen(masteru_name);
-    #ifdef DEBUG
-    dbprintf("masteru_name \"%s\" %zu\n", masteru_name, masteru_name_len);
-    #endif
-    masteru_home = masteru_pw_record_pt->pw_dir;
-    masteru_home_len = strlen(masteru_home);
-    #ifdef DEBUG
-    dbprintf("masteru_home \"%s\" %zu\n", masteru_home, masteru_home_len);
-    #endif
-    masteru_home_len = strlen(masteru_home);
-    if( masteru_home_len == 0 || masteru_home[0] == '(' ){
-      ctxp->err = ERR_SUBU_RM_0_MASTERU_HOMELESS;
-      ctxp->aux = masteru_name;  // we can not free a passwd struct, or its fields.  I assume then it isn't re-entrant safe.
-      return ctxp;
-    }
-    // char *subuland_extension = "/subuland/"; // moved to common.lib.c
-    size_t subuland_extension_len = strlen(subuland_extension);
-    ctxp->subuland = (char *)malloc( masteru_home_len + subuland_extension_len + 1 );
-    if(!ctxp->subuland){
-      ctxp->err = ERR_SUBU_RM_0_MALLOC;
-      return ctxp;
-    }
-    strcpy(ctxp->subuland, masteru_home);
-    strcpy(ctxp->subuland + masteru_home_len, subuland_extension);
-    subuland_len = masteru_home_len + subuland_extension_len;
-    #ifdef DEBUG
-    dbprintf("subuland \"%s\" %zu\n", ctxp->subuland, subuland_len);
-    #endif
-  }
-
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("lookup subu_username from masteru_name/subuname in config file\n");
-  #endif
-  char *subu_username; // this is part of ctx and must be freed
-  {
-    int ret = subu_get_masteru_subu(db, masteru_name, subuname, &subu_username);
-    if( ret != SQLITE_DONE ){
-      printf("get failed\n");
-      return 2;
-    }
-    #ifdef DEBUG
-    printf("subu_username: %s\n", subu_username);  
-    #endif
-    
-  }
-
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("strings subu_username and subuhome\n");
-  #endif
-  size_t subu_username_len;
-  size_t subuhome_len;
-  {
-    char *ns=0; // 'ns'  Number as String
-    char *mess=0;
-    if( subu_number_get( db, &ns, &mess ) != SQLITE_OK ){
-      ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
-      ctxp->aux = mess;
-      ctxp->free_aux = true;
-      return ctxp;
-    }
-    size_t ns_len = strlen(ns);
-    ctxp->subu_username = malloc(1 + ns_len + 1);
-    if( !ctxp->subu_username ){
-      ctxp->err = ERR_SUBU_RM_0_MALLOC;
-      return ctxp;
-    }
-    strcpy(ctxp->subu_username, "s");
-    strcpy(ctxp->subu_username + 1, ns);
-    subu_username_len = ns_len + 1;
-    #ifdef DEBUG
-    dbprintf("subu_username \"%s\" %zu\n", ctxp->subu_username, subu_username_len);
-    #endif
-
-    subuhome_len = subuland_len + subuname_len; 
-    ctxp->subuhome = (char *)malloc(subuhome_len + 1);
-    if( !ctxp->subuhome ){
-      ctxp->err = ERR_SUBU_RM_0_MALLOC;
-      return ctxp;
-    }
-    strcpy (ctxp->subuhome, ctxp->subuland);
-    strcpy (ctxp->subuhome + subuland_len, subuname);
-    #ifdef DEBUG
-    dbprintf("subuhome \"%s\" %zu\n", ctxp->subuhome, subuhome_len);
-    #endif
-  }
-
-  //--------------------------------------------------------------------------------
-  // By having masteru create the subuhome, we know that masteru has rights to 
-  // to access this directory. This will be the mount point for bindfs
-  {
-    #ifdef DEBUG
-    dbprintf("as masteru, making the directory \"%s\"\n", ctxp->subuhome);
-    #endif
-    struct stat st;
-    if( stat(ctxp->subuhome, &st) != -1 ){
-      ctxp->err = ERR_SUBU_RM_0_SUBUHOME_EXISTS;
-      return ctxp;
-    }
-    dispatch_ctx *dfr = dispatch_f_euid_egid
-      (
-       "masteru_mkdir_subuhome", 
-       masteru_mkdir_subuhome, 
-       (void *)ctxp->subuhome,
-       masteru_uid, 
-       masteru_gid
-       );
-    if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME ){
-      #ifdef DEBUG
-      if( dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME )
-        perror("mkdir");
-      else
-        dispatch_f_mess(dfr);
-      #endif
-      ctxp->err = ERR_SUBU_RM_0_MKDIR_SUBUHOME;
-      return ctxp;
-    }
-  }
-  #ifdef DEBUG
-  dbprintf("masteru made directory \"%s\"\n", ctxp->subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  //  Make the subservient user account, i.e. the subu
-  {
-    #ifdef DEBUG
-      dbprintf("making subu \"%s\" as user \"%s\"\n", subuname, ctxp->subu_username);
-    #endif
-    #if BUG_SSS_CACHE_RUID
-      #ifdef DEBUG
-        dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
-      #endif
-      if( setuid(0) == -1 ){
-        ctxp->err = ERR_SUBU_RM_0_BUG_SSS;
-        return ctxp;
-      }
-    #endif
-    char *command = "/usr/sbin/useradd";
-    char *argv[3];
-    argv[0] = command;
-    argv[1] = ctxp->subu_username;
-    argv[2] = (char *) NULL;
-    char *envp[1];
-    envp[0] = (char *) NULL;
-    dispatch_ctx *dfr = dispatch_exec(argv, envp);
-    if( dfr->err != 0 ){
-      #ifdef DEBUG 
-      if( dfr->err <= ERR_DISPATCH )
-        dispatch_f_mess(dfr);
-      else
-        perror("useradd");
-      #endif
-      // go back and remove the directory we made in subuland
-      dispatch_ctx *dfr = dispatch_f_euid_egid
-        (
-         "masteru_rmdir_subuhome", 
-         masteru_rmdir_subuhome, 
-         (void *)ctxp->subuhome,
-         masteru_uid, 
-         masteru_gid
-         );
-      #ifdef DEBUG
-        if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
-          if( dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
-            perror("rmdir");
-          else
-            dispatch_f_mess(dfr);
-      #endif
-      ctxp->err = ERR_SUBU_RM_0_FAILED_USERADD;
-      return ctxp;
-    }
-    #ifdef DEBUG
-    dbprintf("added user \"%s\"\n", ctxp->subu_username);
-    #endif
-  }  
-  
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("setting the masteru_name, subuname, subu_username relation\n");
-  #endif
-  {
-    int ret = subu_put_masteru_subu(db, masteru_name, subuname, ctxp->subu_username);
-    if( ret != SQLITE_DONE ){
-      ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
-      ctxp->aux = "insert of masteru subu relation failed";
-      return ctxp;
-    }
-  }
-
-  #ifdef DEBUG
-  dbprintf("finished subu-mk-0(%s)\n", subuname);
-  #endif
-  ctxp->err = 0;
-  return ctxp;
-}
diff --git a/subu-0/1_deprecated/subudb-number-next.cli.c b/subu-0/1_deprecated/subudb-number-next.cli.c
deleted file mode 100644 (file)
index 3373173..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-number-next.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
-  if( argc != 2 ){
-    fprintf(stderr, "usage: %s masteru_name \n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *masteru_name = argv[1];
-  
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    sqlite3_close(db);
-    fprintf(stderr, "error exit, could not open db file\n");
-    return SUBU_ERR_DB_FILE;
-  }
-
-  // read and print the current max
-  char *mess;
-  int n;
-  rc = subudb_number_next(db, masteru_name, &n, &mess);
-  if( rc == SQLITE_DONE ){
-    printf("%d\n", n);
-  }else{
-    fprintf(stderr, "subudb_number_next indicates failure by returning %d\n",rc);
-    fprintf(stderr, "and issues message, %s\n", sqlite3_errmsg(db));
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-  rc = sqlite3_close(db);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/subu-0/1_doc/to_do.txt b/subu-0/1_doc/to_do.txt
deleted file mode 100644 (file)
index 0b989cc..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-2019-02-05T23:14:40Z
-  error can cause subu-mk-0 to leave the creating of a subu in an intermediate
-  state.  Rather than bailing on some of the errors we need to clean up instead.
-  Perhaps the yet to be written subu-rm program will be resilent enough to do
-  more general cleanup.
-
-2019-02-23T18:56:31Z
-  need to modify subu-init to take a configuration file name argument instead of
-  using a global variabel value.  might want to add arguments to other subu
-  commands also
-
-2019-03-11T13:48:03Z
-  in subu.lib.c append cascading rmdir failure mess to useradd failure mess
-
-2019-03-11T13:48:03Z
-  want to add subu-type to masteru_subu(),  I imagine there will be static,
-  permanent, and temporary subu types.
-
-2019-03-12T18:35:06Z
-  the masteru subu relation should contain the uid of the masteru as
-  well as the backup type for the subu:  git, rdiff, rsync, none.
-  and the persisitance fo the subu: indefinite, session.
-  seems that operations need to be logged, in case the db is lost
-  the transcript can be played back.  It should also be possible
-  to co-opt an existing user as a subu, though, would require
-  sudo privs.
-
-  need to add messages for subu errors I've added to the end of
-  the list in subu.lib.c
-  
-2019-03-14T10:43:50Z
-
-   should mod all to he subudb routines to return a message, probably
-   strdup(sqlite_errmsg(db)), then the callers to these routines can just pass
-   mess in rather than making up new ones for each situation. The error code
-   probably already carries the contexts specific message.  Or perhaps add
-   a string cat function for message strings, that would run through a stream
-   and free the originals.
diff --git a/subu-0/1_tests/0_makefile b/subu-0/1_tests/0_makefile
deleted file mode 100644 (file)
index 67cea25..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# src/1_tests/0_makefile
-
-SHELL=/bin/bash
-
--include 0_makefile_flags
-
-MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-SOURCES=$(wildcard *.c)
-HFILES=$(wildcard *.h)
-
-all: version deps lib execs
-
-deps:
-       makeheaders $(SOURCES) $(HFILES)
-       sed -i '/^ *int *main *(.*)/d' *.h
-       $(MAKE) $@
-
-clean:
-       $(MAKE) $@
-       for i in $(HFILES); do rm $$i; done
-
-dist-clean:
-       $(MAKE) $@
-       if [ -f subudb ]; then rm subudb; fi
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/subu-0/1_tests/0_makefile_flags b/subu-0/1_tests/0_makefile_flags
deleted file mode 100644 (file)
index 8818691..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=
-DOCDIR=
-EXECSDIR=.
-HDIR=.
-LIBDIR=.
-TESTDIR=.
-TMPDIR=1_tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=
-
-
-# compiler and flags
-CC=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-L$(PROJECT_SUBU)/src/$(LIBDIR) -L. -lsubu -lsqlite3 -lsubutests
-
-LIBFILE=$(LIBDIR)/libtests.a
-
diff --git a/subu-0/1_tests/1_tmp/makefile_deps b/subu-0/1_tests/1_tmp/makefile_deps
deleted file mode 100644 (file)
index 9486ae8..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-da.cli.o: da.cli.c da.cli.h
-
-./da : da.cli.o ./libtests.a
-       gcc -o ./da da.cli.o -L/home/morpheus/subu_land/subu/src/. -L. -lsubu -lsqlite3 -lsubutests
diff --git a/subu-0/1_tests/da.cli.c b/subu-0/1_tests/da.cli.c
deleted file mode 100644 (file)
index 910a15e..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-Tests for da.
-
-*/
-
-#include <da.cli.h>
-#include <stdbool.h>
-
-int test_da_0(){
-  da da0;
-  da_alloc(&da0, sizeof(int)); // leaves room for 4 ints
-  int i = 0;
-  int *pt = da0->base;
-  // will double, 4 -> 8, then double 8 -> 16
-  while( i < 10 ){
-    if(da_boundq(&da0, pt)){
-      char *old_base = da_expand(&da);
-      da_rebase(&da, old_base, pt);
-    }
-    *pt = i;
-  i++;
-  pt++;
-  }
-
-  bool f0 = da.size == sizof(int) * 16;
-  bool f1 = 10 == (da.end - da.base) / sizeof(int);
-  bool f2 = true;
-  pt = da0->base;
-  while( i < 10 ){
-    f2 = f2 && *pt == i && !da_endq(&da, pt);
-  i++;
-  pt++;
-  }
-  bool f3 = da_endq(&da, pt);
-
-  return f0 && f1 && f2 && f3;
-}
-
-
-int main(){
-
-  bool da_0_passed = test_da_0();
-  if( da_0_passed ){
-    printf("da_0_passed");
-    return 0;
-  }
-  printf("da_0_failed");
-  return 1;
-
-}
diff --git a/subu-0/1_tests/libtests.a b/subu-0/1_tests/libtests.a
deleted file mode 100644 (file)
index 8b277f0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!<arch>
diff --git a/subu-0/1_tmp/da.lib.h b/subu-0/1_tmp/da.lib.h
deleted file mode 100644 (file)
index 4702189..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <stdlib.h>
-#include <stdbool.h>
-void daps_map(char **base,char **end_pt,void f(void *));
-#define RETURN(rc) \
-  { daps_map(mrs, mrs_end, free); return rc; }
-void daps_alloc(char ***base,size_t *s);
-#define MK_MRS \
-  char **mrs;  \
-  char **mrs_end; \
-  size_t mrs_size; \
-  daps_alloc(&mrs, &mrs_size);\
-  mrs_end = mrs;
-void daps_push(char ***base,char ***pt,size_t *s,char *item);
-bool daps_bound(char **base,char **pt,size_t s);
-void daps_expand(char ***base,char ***pt,size_t *s);
-void da_map(void *base,void *end_pt,void f(void *),size_t item_size);
-void da_push(void **base,void **pt,size_t *s,void *item,size_t item_size);
-bool da_bound(void *base,void *pt,size_t s);
-void da_expand(void **base,void **pt,size_t *s);
-void da_alloc(void **base,size_t *s,size_t item_size);
-#define INTERFACE 0
diff --git a/subu-0/1_tmp/dbprintf.lib.h b/subu-0/1_tmp/dbprintf.lib.h
deleted file mode 100644 (file)
index 3056cf6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-int dbprintf(const char *format,...);
diff --git a/subu-0/1_tmp/dispatch.lib.h b/subu-0/1_tmp/dispatch.lib.h
deleted file mode 100644 (file)
index 07e2271..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sys/types.h>
-#include <unistd.h>
-int dispatch_exec(char **argv,char **envp);
-typedef unsigned int uint;
-int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
-int dbprintf(const char *format,...);
-int dispatch_f(char *fname,int(*f)(void *arg),void *f_arg);
-void dispatch_f_mess(char *fname,int err,char *dispatchee);
-#define ERR_DISPATCH_EXEC -1029
-#define ERR_DISPATCH_NULL_EXECUTABLE -1028
-#define ERR_DISPATCH_F_SETEGID -1027
-#define ERR_DISPATCH_F_SETEUID -1026
-#define ERR_DISPATCH_F_FORK -1025
-#define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024
-#define ERR_DISPATCH -1024
-typedef struct dispatch_ctx dispatch_ctx;
-struct dispatch_ctx {
-  char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.)
-  char *dispatchee; // name of the function being dispatched
-  int err; // error code as listed below, or status returned from dispatchee
-};
-#define INTERFACE 0
diff --git a/subu-0/1_tmp/subu-bind-all.cli.h b/subu-0/1_tmp/subu-bind-all.cli.h
deleted file mode 100644 (file)
index 7e52675..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-int subu_bind_all(char **mess,sqlite3 *db);
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subu-bind.cli.h b/subu-0/1_tmp/subu-bind.cli.h
deleted file mode 100644 (file)
index af12d61..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subu-common.lib.h b/subu-0/1_tmp/subu-common.lib.h
deleted file mode 100644 (file)
index cfdc520..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-extern char Subuland_Extension[];
-typedef unsigned int uint;
-extern uint First_Max_Subunumber;
-extern uint Subuhome_Perms;
-extern char DB_File[];
-#define BUG_SSS_CACHE_RUID 1
-#define INTERFACE 0
diff --git a/subu-0/1_tmp/subu-mk-0.cli.h b/subu-0/1_tmp/subu-mk-0.cli.h
deleted file mode 100644 (file)
index 487b509..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-void subu_err(char *fname,int err,char *mess);
-int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subu-rm-0.cli.h b/subu-0/1_tmp/subu-rm-0.cli.h
deleted file mode 100644 (file)
index 070bfe8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-void subu_err(char *fname,int err,char *mess);
-int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subu.lib.h b/subu-0/1_tmp/subu.lib.h
deleted file mode 100644 (file)
index 69c5da7..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-typedef unsigned int uint;
-#include <sqlite3.h>
-typedef struct subudb_subu_element subudb_subu_element;
-int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
-struct subudb_subu_element {
-  char *subuname;
-  char *subu_username;
-};
-#include <stdbool.h>
-#include <errno.h>
-int subu_bind_all(char **mess,sqlite3 *db);
-int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
-int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
-int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
-int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <sys/types.h>
-#include <unistd.h>
-int dispatch_exec(char **argv,char **envp);
-#define BUG_SSS_CACHE_RUID 1
-void dispatch_f_mess(char *fname,int err,char *dispatchee);
-#define ERR_DISPATCH -1024
-int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
-#include <stdlib.h>
-void daps_map(char **base,char **end_pt,void f(void *));
-#define RETURN(rc) \
-  { daps_map(mrs, mrs_end, free); return rc; }
-void daps_push(char ***base,char ***pt,size_t *s,char *item);
-int dbprintf(const char *format,...);
-void daps_alloc(char ***base,size_t *s);
-#define MK_MRS \
-  char **mrs;  \
-  char **mrs_end; \
-  size_t mrs_size; \
-  daps_alloc(&mrs, &mrs_size);\
-  mrs_end = mrs;
-int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
-extern char Subuland_Extension[];
-int db_commit(sqlite3 *db);
-int db_rollback(sqlite3 *db);
-int subudb_number_set(sqlite3 *db,int n);
-int subudb_number_get(sqlite3 *db,int *n);
-int db_begin(sqlite3 *db);
-extern uint Subuhome_Perms;
-extern char DB_File[];
-void subu_err(char *fname,int err,char *mess);
-#define SUBU_ERR_BIND 15
-#define SUBU_ERR_N 14
-#define SUBU_ERR_SUBU_NOT_FOUND 13
-#define SUBU_ERR_FAILED_USERDEL 12
-#define SUBU_ERR_FAILED_USERADD 11
-#define SUBU_ERR_BUG_SSS 10
-#define SUBU_ERR_SUBUHOME_EXISTS 9
-#define SUBU_ERR_DB_FILE 8
-#define SUBU_ERR_HOMELESS 7
-#define SUBU_ERR_SUBUNAME_MALFORMED 6
-#define SUBU_ERR_RMDIR_SUBUHOME 5
-#define SUBU_ERR_MKDIR_SUBUHOME 4
-#define SUBU_ERR_MALLOC 3
-#define SUBU_ERR_SETUID_ROOT 2
-#define SUBU_ERR_ARG_CNT 1
-char *userdel_mess(int err);
-char *useradd_mess(int err);
-#define INTERFACE 0
diff --git a/subu-0/1_tmp/subudb-init.cli.h b/subu-0/1_tmp/subudb-init.cli.h
deleted file mode 100644 (file)
index 4435103..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int db_commit(sqlite3 *db);
-int db_rollback(sqlite3 *db);
-int subudb_schema(sqlite3 *db);
-int db_begin(sqlite3 *db);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
diff --git a/subu-0/1_tmp/subudb-number.cli.h b/subu-0/1_tmp/subudb-number.cli.h
deleted file mode 100644 (file)
index c130fbb..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_number_get(sqlite3 *db,int *n);
-int subudb_number_set(sqlite3 *db,int n);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_N 14
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subudb-rel-get.cli.h b/subu-0/1_tmp/subudb-rel-get.cli.h
deleted file mode 100644 (file)
index 4f335be..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subudb-rel-put.cli.h b/subu-0/1_tmp/subudb-rel-put.cli.h
deleted file mode 100644 (file)
index 243b3a9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
diff --git a/subu-0/1_tmp/subudb-rel-rm.cli.h b/subu-0/1_tmp/subudb-rel-rm.cli.h
deleted file mode 100644 (file)
index 595427f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
diff --git a/subu-0/1_tmp/subudb-subus.cli.h b/subu-0/1_tmp/subudb-subus.cli.h
deleted file mode 100644 (file)
index 16310b7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-typedef struct subudb_subu_element subudb_subu_element;
-int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
-struct subudb_subu_element {
-  char *subuname;
-  char *subu_username;
-};
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
diff --git a/subu-0/1_tmp/subudb.lib.h b/subu-0/1_tmp/subudb.lib.h
deleted file mode 100644 (file)
index be73823..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* \aThis file was automatically generated.  Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <stdlib.h>
-#include <stdbool.h>
-void da_expand(void **base,void **pt,size_t *s);
-bool da_bound(void *base,void *pt,size_t s);
-typedef struct subudb_subu_element subudb_subu_element;
-int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
-void subu_element_free(subudb_subu_element *base,subudb_subu_element *end_pt);
-void da_alloc(void **base,size_t *s,size_t item_size);
-struct subudb_subu_element {
-  char *subuname;
-  char *subu_username;
-};
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
-int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-int subudb_number_set(sqlite3 *db,int n);
-int subudb_number_get(sqlite3 *db,int *n);
-typedef unsigned int uint;
-extern uint First_Max_Subunumber;
-int subudb_schema(sqlite3 *db);
-int db_rollback(sqlite3 *db);
-int db_commit(sqlite3 *db);
-int db_begin(sqlite3 *db);
-#define INTERFACE 0
diff --git a/subu-0/1_try/split.c b/subu-0/1_try/split.c
deleted file mode 100644 (file)
index 6d4c6ac..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-Using preprocessor to make header file?
-
-gcc -E split.c -DPROTOTYPE
-
-Outputs source code source comment lines starting with a hash. Resolves all macro commands,
-hence the resulting header can not have macro commands.
-
- */
-
-#if PROTOTYPE
-##define GREATNESS 21
-int f(int x);
-#endif
-
-#if IMPLEMENTATION
-int f(int x){
-  return x;
-}
-#endif
diff --git a/subu-0/1_try/split_arg.c b/subu-0/1_try/split_arg.c
deleted file mode 100644 (file)
index 6d4c6ac..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-Using preprocessor to make header file?
-
-gcc -E split.c -DPROTOTYPE
-
-Outputs source code source comment lines starting with a hash. Resolves all macro commands,
-hence the resulting header can not have macro commands.
-
- */
-
-#if PROTOTYPE
-##define GREATNESS 21
-int f(int x);
-#endif
-
-#if IMPLEMENTATION
-int f(int x){
-  return x;
-}
-#endif
diff --git a/subu-0/1_try/subudb b/subu-0/1_try/subudb
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/subu-0/1_try/voidptr.c b/subu-0/1_try/voidptr.c
deleted file mode 100644 (file)
index bd9c3e5..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-They say a cast is not required passing a typed pointer to a void * argument,
-but What about void **?
-
-gcc -std=gnu11 -o voidptr voidptr.c
-voidptr.c: In function ‘main’:
-voidptr.c:28:5: warning: passing argument 1 of ‘g’ from incompatible pointer type [-Wincompatible-pointer-types]
-   g(&pt, y);
-     ^~~
-voidptr.c:13:15: note: expected ‘void **’ but argument is of type ‘int **’
- void g(void **pt0, void *pt1){
-        ~~~~~~~^~~
-
-*/
-#include <stdio.h>
-
-int f(void *pt){
-  return *(int *)pt;
-}
-
-/* fails
-void g(void **pt0, int *pt1){
-  *pt0 = pt1;
-}
-*/
-
-// passes
-void g(void *pt0, int *pt1){
-  *(int **)pt0 = pt1;
-}
-
-int main(){
-  int x = 5;
-  int *xp = &x;
-  printf("%d\n",f(xp));
-
-  int y[3];
-  y[0] = 10;
-  y[1] = 11;
-  y[2] = 12;
-
-  int *pt;
-  g(&pt, y);
-  printf("%d\n",*pt);
-
-  printf("that's all folks\n");
-  return 0;
-}
diff --git a/subu-0/common.lib.c b/subu-0/common.lib.c
deleted file mode 100644 (file)
index 9ce5a27..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-#include "subu-common.lib.h"
-
-#if INTERFACE
-typedef unsigned int uint;
-/*
-  Fedora 29's sss_cache is checking the inherited uid instead of the effective
-  uid, so setuid root scripts will fail when calling sss_cache.
-
-  Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root 
-  program subu-mk-0.
-*/
-#define BUG_SSS_CACHE_RUID 1
-#endif
-
-//  char *DB_File = "/etc/subudb";
-char DB_File[] = "subudb";
-uint Subuhome_Perms = 0700;
-uint First_Max_Subunumber = 114;
-char Subuland_Extension[] = "/subuland/";
diff --git a/subu-0/db.lib.c b/subu-0/db.lib.c
deleted file mode 100644 (file)
index 17a5419..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-The db file is maintained in SQLite
-
-Because user names of are of limited length, subu user names are always named _s<number>.
-A separate table translates the numbers into the subu names.
-
-The first argument is the biggest subu number in the system, or one minus an 
-starting point for subu numbering.
-
-currently a unit converted to base 10 will always fit in a 21 bit buffer.
-
-Each of these returns SQLITE_OK upon success
-*/
-#include "subudb.lib.h"
-
-#if INTERFACE
-#include <sqlite3.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-//--------------------------------------------------------------------------------
-// sqlite transactions don't nest.  There is a way to use save points, but still
-// we can't just nest transactions.  Instead use these wrappers around the whole
-// of something that needs to be in a transaction.
-int db_begin(sqlite3 *db){
-  return sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
-}
-int db_commit(sqlite3 *db){
-  return sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
-}
-int db_rollback(sqlite3 *db){
-  return sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
-}
-
-//--------------------------------------------------------------------------------
-int subudb_schema(sqlite3 *db){
-  int rc;
-
-  { // build tables
-    char sql[] = 
-      "CREATE TABLE Masteru_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT);"
-      "CREATE TABLE Attribute_Int(attribute TEXT, value INT);"
-      ;
-    rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
-    if(rc != SQLITE_OK) return rc;
-  }
-
-  { // data initialization
-    char *sql = "INSERT INTO Attribute_Int (attribute, value) VALUES ('Max_Subunumber', ?1);";
-    sqlite3_stmt *stmt;
-    sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-    sqlite3_bind_int(stmt, 1, First_Max_Subunumber);
-    rc = sqlite3_step(stmt);
-    sqlite3_finalize(stmt);
-    if( rc != SQLITE_DONE ) return rc;
-  }
-
-  return SQLITE_OK;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_number_get(sqlite3 *db, int *n){
-  char *sql = "SELECT value FROM Attribute_Int WHERE attribute = 'Max_Subunumber';";
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-  int rc = sqlite3_step(stmt);
-  if( rc == SQLITE_ROW ){
-    *n = sqlite3_column_int(stmt,0);
-    rc = sqlite3_step(stmt);
-    sqlite3_finalize(stmt);
-    if( rc != SQLITE_DONE ) return rc;
-    return SQLITE_OK;
-  }
-  // should have a message return, suppose
-  sqlite3_finalize(stmt);
-  return SQLITE_NOTFOUND; 
-}
-
-int subudb_number_set(sqlite3 *db, int n){
-  int rc;
-  char *sql = "UPDATE Attribute_Int SET value = ?1 WHERE attribute = 'Max_Subunumber';";
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-  sqlite3_bind_int(stmt, 1, n);
-  rc = sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
-
-//--------------------------------------------------------------------------------
-// put relation into Masteru_Subu table
-int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
-  char *sql = "INSERT INTO Masteru_Subu VALUES (?1, ?2, ?3);";
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
-  int rc = sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username){
-  char *sql = "SELECT subu_username FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2;";
-  size_t sql_len = strlen(sql);
-  sqlite3_stmt *stmt;
-  int rc;
-  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
-  if( rc != SQLITE_OK ) return rc;
-  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC);
-  rc = sqlite3_step(stmt);
-  if( rc == SQLITE_ROW ){
-    const char *username = sqlite3_column_text(stmt, 0);
-    *subu_username = strdup(username);
-  }else{
-    sqlite3_finalize(stmt);
-    return rc; // woops this needs to return an error!,  be sure it is not SQLITE_DONE
-  }
-  rc = sqlite3_step(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
-
-//--------------------------------------------------------------------------------
-
-// we return and array of subudb_subu_info
-#if INTERFACE
-struct subudb_subu_element{
-  char *subuname;
-  char *subu_username;
-};
-#endif
-
-int subudb_Masteru_Subu_get_subus
-(
- sqlite3 *db,
- char *masteru_name,
- da *subus
-){
-  char *sql = "SELECT subuname, subu_username"
-              " FROM Masteru_Subu"
-              " WHERE masteru_name = ?1;";
-  size_t sql_len = strlen(sql);
-  sqlite3_stmt *stmt;
-  int rc;
-  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
-  if( rc != SQLITE_OK ) return rc;
-  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
-
-  da_alloc(subus, sizeof(subudb_subu_element));
-  subudb_subu_element *pt = (subudb_subu_element *)subus->base;
-  rc = sqlite3_step(stmt);
-  while( rc == SQLITE_ROW ){
-    if( da_boundq(subus, pt) ){
-      char *old_base = da_expand(subus);
-      da_rebase(subus, old_base, pt);
-    }
-    pt->subuname = strdup(sqlite3_column_text(stmt, 0));
-    pt->subu_username = strdup(sqlite3_column_text(stmt, 1));
-  rc = sqlite3_step(stmt);
-  pt++;
-  }
-  sqlite3_finalize(stmt);
-  if( rc != SQLITE_DONE ) return rc;
-  return SQLITE_OK;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
-  char *sql = "DELETE FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2 AND subu_username = ?3;";
-  size_t sql_len = strlen(sql);
-  sqlite3_stmt *stmt;
-  int rc;
-  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
-  if( rc != SQLITE_OK ) return rc;
-  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
-  rc = sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
diff --git a/subu-0/subu-bind-all.cli.c b/subu-0/subu-bind-all.cli.c
deleted file mode 100644 (file)
index e942909..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-mount all the subu user directories into master's subuland
-uses unmount to undo this
-
-*/
-#include "subu-bind-all.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-  if( argc != 1){
-    fprintf(stderr, "%s does not take arguments\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  char *mess;
-  rc = subu_bind_all(&mess, db);
-  if(rc != 0){
-    fprintf(stderr, "subu-bind: %s\n", mess);
-    return rc;
-  }
-  return 0;
-}
diff --git a/subu-0/subu-bind.cli.c b/subu-0/subu-bind.cli.c
deleted file mode 100644 (file)
index f315823..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-mount a subu user directory into master's subuland
-uses unmount to undo this
-
-*/
-#include "subu-bind.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if( argc != 4){
-    fprintf(stderr, "usage: %s masteru subu_username subuhome\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  char *mess;
-  rc = subu_bind(&mess, argv[1], argv[2], argv[3]);
-  if(rc != 0){
-    fprintf(stderr, "subu-bind: %s\n", mess);
-    return rc;
-  }
-  return 0;
-}
diff --git a/subu-0/subu-mk-0.cli.c b/subu-0/subu-mk-0.cli.c
deleted file mode 100644 (file)
index af0888b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-  subu-mk-0 command
-
-*/
-#include "subu-mk-0.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-  char *command = argv[0];
-  if( argc != 2 ){
-    fprintf(stderr, "usage: %s subu", command);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *subuname = argv[1];
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "error when opening db, %s\n", DB_File);
-    fprintf(stderr, "sqlite3 says: %s\n", sqlite3_errmsg(db));
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  char *mess;
-  rc = subu_mk_0(&mess, db, subuname);
-  if( rc ){
-    subu_err("subu_mk_0", rc, mess);
-    free(mess);
-    sqlite3_close(db);
-    return rc;
-  }
-
-  rc = sqlite3_close(db);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-
-}
diff --git a/subu-0/subu-rm-0.cli.c b/subu-0/subu-rm-0.cli.c
deleted file mode 100644 (file)
index a7e5926..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-  subu-mk-0 command
-
-*/
-#include "subu-rm-0.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-  char *command = argv[0];
-  if( argc != 2 ){
-    fprintf(stderr, "usage: %s subu", command);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *subuname = argv[1];
-
-  sqlite3 *db;
-  {
-    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-    if( ret != SQLITE_OK ){
-      fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
-      return SUBU_ERR_DB_FILE;
-    }}
-
-  {
-    char *mess=0;
-    int ret = subu_rm_0(&mess, db, subuname);
-    subu_err("subu_rm_0", ret, mess);
-    free(mess);
-    return ret;
-  }
-}
diff --git a/subu-0/subu.lib.c b/subu-0/subu.lib.c
deleted file mode 100644 (file)
index 988bd28..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
-  sqllite3 is used to maintain the db file, which is currently compiled
-  in as /etc/subu.db, (or just subu.db for testing).
-
-  masteru is the user who ran this script. The masteru name comes from getuid
-  and /etc/passwd. 
-
-  subu is a subservient user.  The subuname is passed in as an argument.
-
-  subu-mk-0 synthesizes a new user user name s<number>, calls useradd to creat
-  the new uswer account, and enters the relationship between masteru, subu, and
-  s<number> in the db file.  It is this relation in the db file that
-  associates the subuname with the s<number> user.
-
-  subu-rm-0 uses userdel to delete the related s<number> user account.  It
-  then removes the relaton from the db file.
-
-  subu-mk-0 and subu-rm-0 are setuid root scripts.  
-
-*/
-#include "subu.lib.h"
-
-// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
-#define _GNU_SOURCE   
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#if INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-#endif
-
-//--------------------------------------------------------------------------------
-// dispatched command errors  .. should add mkdir and rmdir ...
-//
-char *useradd_mess(int err){
-  if(err <= 0) return NULL;
-  char *mess;
-  switch(err){
-  case 1: mess = "can't update password file"; break;
-  case 2: mess = "invalid command syntax"; break;
-  case 3: mess = "invalid argument to option"; break;
-  case 4: mess = "UID already in use (and no -o)"; break;
-  case 5: mess = "undefined"; break;
-  case 6: mess = "specified group doesn't exist"; break;
-  case 7:
-  case 8: mess = "undefined"; break;
-  case 9: mess = "username already in use"; break;
-  case 10: mess = "can't update group file:"; break;
-  case 11: mess = "undefined"; break;
-  case 12: mess = "can't create home directory"; break;
-  case 13: mess = "undefined"; break;
-  case 14: mess = "can't update SELinux user mapping"; break;
-  default: mess = "undefined"; break;
-  }
-  return strdup(mess);
-}
-char *userdel_mess(int err){
-  if(err <= 0) return NULL;
-  char *mess;
-  switch(err){
-  case 1: mess = "can't update password file"; break;
-  case 2: mess = "invalid command syntax"; break;
-  case 3:
-  case 4:
-  case 5: mess = "undefined"; break;
-  case 6: mess = "specified user doesn't exist"; break;
-  case 7:
-  case 8: 
-  case 9: mess = "undefined"; break;
-  case 10: mess = "can't update group file:"; break;
-  case 11: mess = "undefined"; break;
-  case 12: mess = "can't remove home directory"; break;
-  default: mess = "undefined"; break;
-  }
-  return strdup(mess);
-}
-
-
-//--------------------------------------------------------------------------------
-//
-#if INTERFACE
-#define SUBU_ERR_ARG_CNT 1
-#define SUBU_ERR_SETUID_ROOT 2
-#define SUBU_ERR_MALLOC 3
-#define SUBU_ERR_MKDIR_SUBUHOME 4
-#define SUBU_ERR_RMDIR_SUBUHOME 5
-#define SUBU_ERR_SUBUNAME_MALFORMED 6
-#define SUBU_ERR_HOMELESS 7
-#define SUBU_ERR_DB_FILE 8
-#define SUBU_ERR_SUBUHOME_EXISTS 9
-#define SUBU_ERR_BUG_SSS 10
-#define SUBU_ERR_FAILED_USERADD 11
-#define SUBU_ERR_FAILED_USERDEL 12
-#define SUBU_ERR_SUBU_NOT_FOUND 13
-#define SUBU_ERR_N 14
-#define SUBU_ERR_BIND 15
-#endif
-
-void subu_err(char *fname, int err, char *mess){
-  if(!mess) mess = "";
-  switch(err){
-  case 0: return;
-  case SUBU_ERR_ARG_CNT:
-    if(mess[0])
-      fprintf(stderr, "Incorrect number of arguments, %s", mess);
-    else
-      fprintf(stderr, "Incorrect number of arguments.", mess);
-    break;
-  case SUBU_ERR_SETUID_ROOT:
-    fprintf(stderr, "This program must be run setuid root from a user account.");
-    break;
-  case SUBU_ERR_MALLOC:
-    perror(fname);
-    break;
-  case SUBU_ERR_DB_FILE:
-    fprintf(stderr, "error on %s", DB_File); // DB_File is in common
-    fprintf(stderr, ": %s", mess);
-    break;
-  case SUBU_ERR_HOMELESS:
-    fprintf(stderr,"Masteru, \"%s\", has no home directory", mess);
-    break;
-  case SUBU_ERR_SUBUNAME_MALFORMED:
-    fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", mess);
-    break;
-  case SUBU_ERR_SUBUHOME_EXISTS:
-    fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", mess);
-    break;
-  case SUBU_ERR_MKDIR_SUBUHOME:
-    fprintf(stderr, "masteru could not make subuhome, \"%s\"", mess);
-    break;
-  case SUBU_ERR_BUG_SSS:
-    perror(fname);
-  break;
-  case SUBU_ERR_FAILED_USERADD:
-    fprintf(stderr, "%s useradd failed\n", mess);
-  break;
-  default:
-    fprintf(stderr, "unknown error code %d\n", err);
-  }
-  fputc('\n', stderr);
-}
-
-
-//--------------------------------------------------------------------------------
-// a well formed subuname
-// returns the length of the subuname, or -1
-//
-static int allowed_subuname(char **mess, char *subuname, size_t *subuname_len){
-  char *ch = subuname;
-  size_t i = 0;
-  while(
-        *ch
-        &&
-        ( *ch >= 'a' && *ch <= 'z'
-          ||
-          *ch >= 'A' && *ch <= 'Z'
-          ||
-          *ch >= '0' && *ch <= '9'
-          ||
-          *ch == '-'
-          ||
-          *ch == '_'
-          ||
-          *ch == '.'
-          ||
-          *ch == ' '
-          )
-        ){
-    ch++;
-    i++;
-  }
-  if( !*ch ){
-    *subuname_len = i;
-    return 0;
-  }else{
-    if(mess) *mess = strdup(subuname);
-    return SUBU_ERR_SUBUNAME_MALFORMED;
-  }
-}
-
-//--------------------------------------------------------------------------------
-// dispatched functions
-//
-static int masteru_mkdir_subuhome(void *arg){
-  char *subuhome = (char *) arg;
-  if( mkdir( subuhome, Subuhome_Perms ) == -1 ){ // find subuhome perms in common
-    perror("masteru_mkdir_subuhome");
-    return SUBU_ERR_MKDIR_SUBUHOME;
-  }
-  return 0;
-}
-static int masteru_rmdir_subuhome(void *arg){
-  char *subuhome = (char *) arg;
-  if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
-    perror("masteru_rmdir_subuhome");
-    return SUBU_ERR_RMDIR_SUBUHOME;
-  }
-  return 0;
-}
-
-//--------------------------------------------------------------------------------
-// build strings 
-//
-static int mk_subu_username(char **mess, sqlite3 *db, char **subu_username){
-  int rc,n;
-  db_begin(db);
-  if(
-    (rc = subudb_number_get(db, &n))
-    ||
-    (rc = subudb_number_set(db, ++n))
-     ){
-    db_rollback(db);
-    return SUBU_ERR_DB_FILE;
-  }
-  db_commit(db);
-
-  size_t len = 0;
-  FILE* name_stream = open_memstream(subu_username, &len);
-  fprintf(name_stream, "s%d", n);
-  fclose(name_stream);
-  return 0;
-}
-
-// man page says that getpwuid strings may not be freed, I don't know how long until they
-// are overwritten, so I just make my own copies that can be freed
-static int uid_to_name_and_home(uid_t uid, char **name, char **home ){
-  struct passwd *pw_record_pt = getpwuid(uid); // reading /etc/passwd
-  *name = strdup(pw_record_pt->pw_name);
-  *home = strdup(pw_record_pt->pw_dir);
-  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
-  return 0;
-}
-
-static int username_to_home(char *name, char **home ){
-  struct passwd *pw_record_pt = getpwnam(name); // reading /etc/passwd
-  *home = strdup(pw_record_pt->pw_dir);
-  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
-  return 0;
-}
-
-static int mk_subuland(char *masteru_home, char **subuland){
-  size_t masteru_home_len = strlen(masteru_home);
-  char *Subuland_Extension = "/subuland/";
-  size_t Subuland_Extension_len = strlen(Subuland_Extension);
-  *subuland = (char *)malloc( masteru_home_len + Subuland_Extension_len + 1 );
-  if(!*subuland) SUBU_ERR_MALLOC; 
-  strcpy(*subuland, masteru_home);
-  strcpy(*subuland + masteru_home_len, Subuland_Extension);
-  return 0;
-}
-
-static int mk_subuhome(char *subuland, char *subuname, char **subuhome){
-  size_t subuland_len = strlen(subuland);
-  size_t subuhome_len = subuland_len + strlen(subuname); // subuland has a trailing '/'
-  *subuhome = (char *)malloc(subuhome_len + 1);
-  if(!*subuhome) return SUBU_ERR_MALLOC;
-  strcpy (*subuhome, subuland);
-  strcpy (*subuhome + subuland_len, subuname);
-  return 0;
-}
-
-
-
-//===============================================================================
-int subu_mk_0(char **mess, sqlite3 *db, char *subuname){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  //--------------------------------------------------------------------------------
-  size_t subuname_len;
-  rc = allowed_subuname(mess, subuname, &subuname_len);
-  if(rc) return rc;
-  #ifdef DEBUG
-  dbprintf("subuname is well formed\n");
-  #endif
-
-  //--------------------------------------------------------------------------------
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
-  }
-
-  //--------------------------------------------------------------------------------
-  char *masteru_name = 0;
-  char *masteru_home = 0;
-  char *subu_username = 0;
-  char *subuland = 0;
-  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
-  da_push(&resources, masteru_name);
-  da_push(&resources, masteru_home);
-  da_push(&resources, subu_username);
-  da_push(&resources, subuland);
-  da_push(&resources, subuhome);
-  rc =
-    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
-    ||
-    mk_subu_username(mess, db, &subu_username)
-    ||
-    mk_subuland(masteru_home, &subuland)
-    ||
-    mk_subuhome(subuland, subuname, &subuhome)
-    ;
-  if(rc) RETURN(&resources, rc);
-  #ifdef DEBUG
-  dbprintf("subu_username, subuland, subuhome: \"%s\"\"%s\"\"%s\"\n", subu_username, subuland, subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  // By having masteru create the subuhome, we know that masteru has rights to 
-  // to access this directory. This will be the mount point for bindfs
-  {
-    struct stat st;
-    if( stat(subuhome, &st) != -1 ){
-      if(mess)*mess = strdup(subuhome);
-      RETURN(&resources, SUBU_ERR_SUBUHOME_EXISTS);
-    }
-    int dispatch_err = dispatch_f_euid_egid
-      (
-       "masteru_mkdir_subuhome", 
-       masteru_mkdir_subuhome, 
-       (void *)subuhome,
-       masteru_uid, 
-       masteru_gid
-       );
-    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_MKDIR_SUBUHOME ){
-      #ifdef DEBUG
-      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_mkdir_subuhome");
-      #endif
-      if(mess)*mess = strdup(subuhome);
-      RETURN(&resources, SUBU_ERR_MKDIR_SUBUHOME);
-    }
-  }
-  #ifdef DEBUG
-  dbprintf("made directory \"%s\"\n", subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  //  Make the subservient user account, i.e. the subu
-  {
-    #ifdef DEBUG
-      dbprintf("making subu \"%s\" as user \"%s\"\n", subuname, subu_username);
-    #endif
-    #if BUG_SSS_CACHE_RUID
-      #ifdef DEBUG
-        dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
-      #endif
-      if( setuid(0) == -1 ) RETURN(&resources, SUBU_ERR_BUG_SSS);
-    #endif
-    char *command = "/usr/sbin/useradd";
-    char *argv[3];
-    argv[0] = command;
-    argv[1] = subu_username;
-    argv[2] = (char *) NULL;
-    char *envp[1];
-    envp[0] = (char *) NULL;
-    int dispatch_err = dispatch_exec(argv, envp);
-    if( dispatch_err != 0 ){
-      #ifdef DEBUG 
-      dispatch_f_mess("dispatch_exec", dispatch_err, command);
-      #endif
-      // go back and remove the directory we made in subuland
-      int dispatch_err_rmdir = dispatch_f_euid_egid
-        (
-         "masteru_rmdir_subuhome", 
-         masteru_rmdir_subuhome, 
-         (void *)subuhome,
-         masteru_uid, 
-         masteru_gid
-         );
-      #ifdef DEBUG
-      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err_rmdir, "masteru_rmdir_subuhome");
-      #endif
-      if(mess)*mess = useradd_mess(dispatch_err);
-      RETURN(&resources, SUBU_ERR_FAILED_USERADD);
-    }
-    #ifdef DEBUG
-    dbprintf("added user \"%s\"\n", subu_username);
-    #endif
-  }  
-  
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  dbprintf("setting the masteru_name, subuname, subu_username relation\n");
-  #endif
-  {
-    int rc = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
-    if( rc != SQLITE_OK ){
-      if(mess)*mess = strdup("insert of masteru subu relation failed");
-      RETURN(&resources, SUBU_ERR_DB_FILE);
-    }
-  }
-  #ifdef DEBUG
-  dbprintf("finished subu-mk-0(%s)\n", subuname);
-  #endif
-  RETURN(&resources, 0);
-}
-
-//================================================================================
-int subu_rm_0(char **mess, sqlite3 *db, char *subuname){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  //--------------------------------------------------------------------------------
-  size_t subuname_len;
-  rc = allowed_subuname(mess, subuname, &subuname_len);
-  if(rc) return rc;
-  #ifdef DEBUG
-  dbprintf("subuname is well formed\n");
-  #endif
-  
-  //--------------------------------------------------------------------------------
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
-  }
-
-  //--------------------------------------------------------------------------------
-  // various strings that we will need
-  char *masteru_name = 0;
-  char *masteru_home = 0;
-  char *subuland = 0;
-  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
-  da_push(&resources, masteru_name);
-  da_push(&resources, masteru_home);
-  da_push(&resources, subuland);
-  da_push(&resources, subuhome);
-  rc =
-    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
-    ||
-    mk_subuland(masteru_home, &subuland)
-    ||
-    mk_subuhome(subuland, subuname, &subuhome)
-    ;
-  if(rc) RETURN(&resources, rc);
-  #ifdef DEBUG
-  dbprintf("masteru_home, subuhome: \"%s\", \"%s\"\n", masteru_home, subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  // removal from db
-  char *subu_username = 0;
-  da_push(&resources, subu_username);
-
-  db_begin(db);
-
-  rc = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
-  if( rc != SQLITE_OK ){
-    if(mess) *mess = strdup("subu requested for removal not found under this masteru in db file");
-    rc = SUBU_ERR_SUBU_NOT_FOUND;
-    db_rollback(db);
-    RETURN(&resources, rc);
-  }
-  #ifdef DEBUG
-  printf("subu_username: \"%s\"\n", subu_username);  
-  #endif
-
-  rc = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
-  if( rc != SQLITE_OK ){
-    if(mess)*mess = strdup("removal of masteru subu relation failed");
-    db_rollback(db);
-    RETURN(&resources, SUBU_ERR_DB_FILE);
-  }
-  #ifdef DEBUG
-  dbprintf("removed the masteru_name, subuname, subu_username relation\n");
-  #endif
-  
-  rc = db_commit(db);
-  if( rc != SQLITE_OK ){
-    if(mess)*mess = strdup("removal of masteru subu relation in unknown state, exiting");
-    RETURN(&resources, SUBU_ERR_DB_FILE);
-  }
-  
-  // even after removing the last masteru subu relation, we still do not remove
-  // the max subu count. Hence, a masteru will keep such for a life time.
-
-
-  //--------------------------------------------------------------------------------
-  // Only masteru can remove directories from masteru/subuland, so we switch to 
-  // masteru's uid to perform the rmdir.
-  //
-  {
-    #ifdef DEBUG
-    dbprintf("as masteru, removing the directory \"%s\"\n", subuhome);
-    #endif
-    int dispatch_err = dispatch_f_euid_egid
-      (
-       "masteru_rmdir_subuhome", 
-       masteru_rmdir_subuhome, 
-       (void *)subuhome,
-       masteru_uid, 
-       masteru_gid
-       );
-    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_RMDIR_SUBUHOME ){
-      #ifdef DEBUG
-      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_rmdir_subuhome");
-      #endif
-      if(mess)*mess = strdup(subuhome);
-      RETURN(&resources, SUBU_ERR_RMDIR_SUBUHOME);
-    }
-  }
-
-  //--------------------------------------------------------------------------------
-  //  Delete the subservient user account
-  {
-    #ifdef DEBUG
-    dbprintf("deleting user \"%s\"\n", subu_username);
-    #endif
-    #if BUG_SSS_CACHE_RUID
-      #ifdef DEBUG
-        dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
-      #endif
-      if( setuid(0) == -1 ){
-        RETURN(&resources, SUBU_ERR_BUG_SSS);
-      }
-    #endif
-    char *command = "/usr/sbin/userdel";
-    char *argv[4];
-    argv[0] = command;
-    argv[1] = subu_username;
-    argv[2] = "-r";  
-    argv[3] = (char *) NULL;
-    char *envp[1];
-    envp[0] = (char *) NULL;
-    int dispatch_err = dispatch_exec(argv, envp);
-    if( dispatch_err != 0 ){
-      #ifdef DEBUG 
-      dispatch_f_mess("dispatch_exec", dispatch_err, command);
-      #endif
-      if(mess)*mess = userdel_mess(dispatch_err);
-      RETURN(&resources, SUBU_ERR_FAILED_USERDEL);
-    }
-    #ifdef DEBUG
-    dbprintf("deleted user \"%s\"\n", subu_username);
-    #endif
-  }  
-
-  #ifdef DEBUG
-  dbprintf("finished subu-rm-0(%s)\n", subuname);
-  #endif
-  RETURN(&resources, 0);
-}
-
-//================================================================================
-// identifies masteru, the bindfs maps each subu_user's home to its mount point
-// in subuland.
-int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  // lookup the subu_user_home
-  char *subu_user_home = 0;
-  da_push(&resources, subu_user_home);
-
-  rc = username_to_home(subu_username, &subu_user_home);
-  if( rc ){
-    if(mess) *mess = strdup("in subu_bind, subu user home directory lookup in /etc/passwd failed.");
-    RETURN(&resources, rc);
-  }
-
-  size_t len = 0;
-  char *map = 0;
-  da_push(&resources, map);
-
-  FILE* map_stream = open_memstream(&map, &len);
-  fprintf(map_stream, "--map=%s/%s:@%s/@%s", subu_username, masteru_name, subu_username, masteru_name);
-  fclose(map_stream);
-  
-  char *command = "/usr/bin/bindfs";
-  char *argv[5];
-  argv[0] = command;
-  argv[1] = map;
-  argv[2] = subu_user_home;
-  argv[3] = subuhome;
-  argv[4] = (char *) NULL;
-  char *envp[1];
-  envp[0] = (char *) NULL;
-  int dispatch_err = dispatch_exec(argv, envp);
-  if( dispatch_err != 0 ){
-    #ifdef DEBUG 
-    dispatch_f_mess(command, dispatch_err, "dispatch_exec");
-    #endif
-    if(mess)*mess = strdup("bind failed");
-    RETURN(&resources, SUBU_ERR_BIND);
-  }
-  #ifdef DEBUG
-  dbprintf("mapped \"%s\" as \"%s\"\n", subu_user_home, subuhome);
-  #endif
-  RETURN(&resources, 0);
-}
-
-int subu_bind_all(char **mess, sqlite3 *db){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  //--------------------------------------------------------------------------------
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
-  }
-
-  //--------------------------------------------------------------------------------
-  // various strings that we will need
-  char *masteru_name = 0;
-  char *masteru_home = 0;
-  char *subuland = 0;
-  da_push(&resources, masteru_name);
-  da_push(&resources, masteru_home);
-  da_push(&resources, subuland);
-  rc =
-    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
-    ||
-    mk_subuland(masteru_home, &subuland)
-    ;
-  if(rc) RETURN(&resources, rc);
-  #ifdef DEBUG
-  if(masteru_name)  
-    dbprintf("masteru_name: \"%s\"", masteru_name);
-  else
-    dbprintf("masteru_name unknown");
-  if(subuland)
-    dbprintf("subuland: \"%s\"", subuland);
-  else
-    dbprintf("subuland unknown");
-  dbprintf("\n");
-  #endif
-
-  //--------------------------------------------------------------------------------
-  da subus;
-  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &subus);
-  if( rc != SQLITE_OK ){
-    if(mess)*mess = strdup("db access failed when fetching a list of subus");
-    return rc;
-  }
-  // a limitation of our error reporting approach is that we can only 
-  // return one error, but here is a loop that might generate many
-  rc = 0; 
-  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
-  uint err_cnt = 0;
-  subudb_subu_element *pt = (subudb_subu_element *)(subus.base);
-  while( !da_endq(&subus,pt) ){
-    rc = mk_subuhome(subuland, pt->subuname, &subuhome);
-    #ifdef DEBUG
-    if(subuhome)
-      dbprintf("subuhome: \"%s\"\n", subuhome);
-    else
-      dbprintf("subuhome unknown \n");
-    #endif
-    if(!rc) rc = subu_bind(NULL, masteru_name, pt->subu_username, subuhome);
-    if(rc) err_cnt++;
-    free(subuhome);
-    subuhome=0;
-  pt++;
-  }
-  if(err_cnt==1){
-    RETURN(&resources, rc);
-  }
-  if(err_cnt > 1){
-    *mess = strdup("multiple errors occured while binding subus");
-    RETURN(&resources, SUBU_ERR_BIND);
-  }
-  RETURN(&resources, 0);
-}
diff --git a/subu-0/subudb-init.cli.c b/subu-0/subudb-init.cli.c
deleted file mode 100644 (file)
index 714c7e4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-This command initializes the db file.
-
-*/
-#include "subudb-init.cli.h"
-#include <stdio.h>
-
-int main(){
-  sqlite3 *db;
-  if( sqlite3_open(DB_File, &db) != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
-    return SUBU_ERR_DB_FILE;
-  }
-  db_begin(db);
-  if( subudb_schema(db) != SQLITE_OK ){
-    db_rollback(db);
-    fprintf(stderr, "error exit, opened db file but could not build schema\n");
-    return SUBU_ERR_DB_FILE;
-  }
-  db_commit(db);
-  if( sqlite3_close(db) != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not close the db\n");
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/subu-0/subudb-number.cli.c b/subu-0/subudb-number.cli.c
deleted file mode 100644 (file)
index 60304e3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-number.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
-  if( argc < 1 || argc > 2){
-    fprintf(stderr, "usage: %s [n]\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not open db file\n");
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  // then arg[1] holds a number to set the max to
-  if(argc == 2){ 
-    long int i = strtol(argv[1], NULL, 10);
-    if( i < 0 ){
-      fprintf(stderr, "n must be positive\n");
-      sqlite3_close(db);
-      return SUBU_ERR_N;
-    }
-    if( i > INT_MAX ){
-      fprintf(stderr, "n is too big, max supported by this program is %d\n", INT_MAX);
-      sqlite3_close(db);
-      return SUBU_ERR_N;
-    }
-    rc = subudb_number_set(db, i);
-    if( rc != SQLITE_OK ){
-      fprintf(stderr, "couldn't set Max_Subunumber: %s\n", sqlite3_errmsg(db));
-      return SUBU_ERR_N;
-    }
-  }
-
-  // read and print the current max
-  int n;
-  rc = subudb_number_get(db, &n);
-  if( rc == SQLITE_OK ){
-    printf("%d\n", n);
-  }else{
-    fprintf(stderr, "couldn't get Max_Subunumber: %s\n", sqlite3_errmsg(db));
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-  rc = sqlite3_close(db);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-
-}
diff --git a/subu-0/subudb-rel-get.cli.c b/subu-0/subudb-rel-get.cli.c
deleted file mode 100644 (file)
index 9828b15..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-get the username from the db file
-for testing subudb_Masteru_Subu_get_subu_username
-
-*/
-#include "subudb-rel-get.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if(argc != 3){
-    fprintf(stderr, "usage: %s masteru_name subuname\n", argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  char *masteru_name = argv[1];
-  char *subuname = argv[2];
-  char *subu_username;
-
-  int ret = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
-  if( ret != SQLITE_DONE ){
-    fprintf(stderr, "subudb_Masteru_Subu_get_subu_username indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }
-  ret = sqlite3_close(db);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/subu-0/subudb-rel-put.cli.c b/subu-0/subudb-rel-put.cli.c
deleted file mode 100644 (file)
index b19896e..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-puts a relation in the masteru/subu table
-
-*/
-#include "subudb-rel-put.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if(argc != 4){
-    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
-    return 1;
-  }
-  char *masteru_name = argv[1];
-  char *subuname = argv[2];
-  char *subu_username = argv[3];
-
-  sqlite3 *db;
-  {
-    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-    if( ret != SQLITE_OK ){
-      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-      return SUBU_ERR_DB_FILE;
-    }}
-
-  int ret = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "subudb_Masteru_Subu_put indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }
-  ret = sqlite3_close(db);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/subu-0/subudb-rel-rm.cli.c b/subu-0/subudb-rel-rm.cli.c
deleted file mode 100644 (file)
index 3d15ca9..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-puts a relation in the masteru/subu table
-
-*/
-#include "subudb-rel-rm.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if(argc != 4){
-    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
-    return 1;
-  }
-  char *masteru_name = argv[1];
-  char *subuname = argv[2];
-  char *subu_username = argv[3];
-
-  sqlite3 *db;
-  {
-    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-    if( ret != SQLITE_OK ){
-      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-      return SUBU_ERR_DB_FILE;
-    }}
-
-  int ret = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
-  if( ret != SQLITE_DONE ){
-    fprintf(stderr, "subudb_Masteru_Subu_rm indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
-    printf("put failed\n");
-    return 2;
-  }
-  ret = sqlite3_close(db);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/subu-0/subudb-subus.cli.c b/subu-0/subudb-subus.cli.c
deleted file mode 100644 (file)
index be3af20..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-subus.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
-  if( argc != 2){
-    fprintf(stderr, "usage: %s masteru_name\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *masteru_name = argv[1];
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not open db file\n");
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  subudb_subu_element *sa;
-  subudb_subu_element *sa_end;
-  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
-  if( rc == SQLITE_OK ){
-    subudb_subu_element *pt = sa;
-    while( pt != sa_end ){
-      printf("%s %s\n", pt->subuname, pt->subu_username);
-    pt++;
-    }
-    rc = sqlite3_close(db);
-    if( rc != SQLITE_OK ){
-      fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-      return SUBU_ERR_DB_FILE;
-    }    
-    return 0;
-  }
-  fprintf(stderr, "lookup failed %s\n", sqlite3_errmsg(db));
-  sqlite3_close(db);
-  return SUBU_ERR_DB_FILE;
-
-}
diff --git a/subu-1/subu-mk.py b/subu-1/subu-mk.py
deleted file mode 100644 (file)
index 203fab4..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-#!/usr/bin/python
-# see the help option for syntax
-# this script must be run from root or sudo
-#
-# on Fedora 29 os.getresuid returned all zeros for a script run from sudo.
-# Hence, I am using the environment variable SUDO_USER
-
-import getpass
-import os
-import sys
-import libuser
-from __future__ import print_function
-
-command = os.path.base(argv[0])
-
-#--------------------------------------------------------------------------------
-# utilities
-#
-def prn(str):
-  print(str,end='')
-
-#--------------------------------------------------------------------------------
-# help
-#
-def help():
-  print( command +
-""" [=help] [=version] [shell=<shell>][owner=<owner-username>] [subu=]<subu-username>
-Makes a subservient user.
-If no arguments are given, or if =help is given, this message is printed.
-When this command is invoked through sudo, $SUDO_USER is taken as the owner's username.
-Otherwise, when invoked directly from root, the owner= option must be provided.
-The subu-username argument is the username for the new subservient user
-The the new subu home directory is created in /home/owner/subu/.
-Facls are set to give the owner access to the new subu's home directory.
-The shell option is not implemented yet.  Probably need a number of other options also.
-"""
-  )
-
-def version():
-  print(" version 0")
-
-#--------------------------------------------------------------------------------
-# a manager for handling error messages
-#
-class class_err:
-"""
-An error record has the form [flag, message, args] 
-  class is fatal, warning, info  [currently not implemented]
-  flag is true if an error has occured [need to change this to a count]
-  args is an array of strings to be given after the error message is printed.
-
-The dict holds named error records.
-
-register() is used to name and place error records in the dict. register() is
-typically called multiple times to initialize and error instance.
-
-tattle() is used by the program at run time in order to signal errors.
-
-has_error() returns true if tattle was ever called
-
-report() prints an error report.  When errors have occured this 
-
-vector() [unimplemented] returns a bit vector with one bit per fatal error
-record, in the order they appear in the dictionary. The bit is set if the error
-ever occured.
-
-We check for as many errors as is convenient to do so rather than stopping on
-the first error.
-"""
-
-  # field offsets into the error record
-  flag_dex = 0;
-  message_dex = 1;
-  args_dex = 2;
-
-  def __init__(self):
-    self.total_cnt = 0
-    self.dict = {}
-
-  def register(name, message):
-    self.dict[name] = [False, message, []]
-
-  def tattle(name, *args):
-    self.total_cnt += 1
-    if name in self.dict:
-      self.dict[name][0] = True
-      self.dict[name][2].extend(args)
-
-  def report():
-    if self.total_cnt:
-      for k,v in self.dict.items():
-        if v[self.flag_dex]:
-          print(v[self.message_dex],end='')
-          args = v[self.args_dex]
-          if length(args) :
-            print(args[0],end='')
-            for arg in args[1:]:
-              print( " " + arg, end='')
-          print()
-
-#--------------------------------------------------------------------------------
-# parse the command line
-#
-err.register(
-  'impossible_split',
-  "It is not possible, yet this token split into other than one or two pieces: "
-  )
-err.register(
-  'lone_delim',
-  "No spaces should appear around the '=' delimiter."
-  )
-
-args = sys.argv[1:]
-if len(args) == 0 :
-  version()
-  help()
-  exit(1)
-#create a dictionary based on the command line arguments
-arg_dict = {}
-subu_cnt = 0
-delim = '='
-for token in args:
-  token_pair = split(token, delim);
-  if len(token_pair) == 1 : #means there was no '=' in the token
-    arg_dict['subu'] = token_pair
-    subu_cnt++
-  elif len(token_pair) == 2 :
-    if token_pair[0] == '' and token_pair[1] == '' :
-      err.tattle('lone_delim')
-    elif token_pair[1] == '' : # then has trailing delim, will treat the same as a leading delim
-      arg_dict[token_pair[0]] = None
-    elif token_pair[0] == '' : # then has leading delim
-      arg_dict[token_pair[1]] = None
-    else:
-      arg_dict[token_pair[0]] = token_pair[1]
-  else:
-    err.tattle('impossible_split', token)
-
-if not arg_dict or arg_dict.get('help'):
-  help()
-  err.report()
-  exit(1)
-
-if arg_dict.get('version'):
-  version()
-
-#--------------------------------------------------------------------------------
-# check that the command line arguments are well formed. 
-#
-err.register(
-  'too_many_args',
-  command + " takes at most one non-option argument, but we counted: "
-  )
-err.register(
-  'no_subu'
-  command + " missing subservient username."
-  )
-err.register(
-  'bad_username'
-  "Usernames match ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$, but found: "
-  )
-err.register(
-  'unknown_option'
-  command + " doesn't implement option: "
-  )
-
-subu = arg_dict.get('subu')
-if subu_cnt > 1:
-  err.tattle('too_many_args')
-elif not subu
-  err.tattle('no_subu')
-elif not re.match("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$", subu)
-  err.tattle('bad_username', subu)
-
-for k in arg_dict:
-  if k not in ['help', 'version', 'shell', 'owner', 'subu'] :
-    err.tattle('unkown_option', k)
-
-if arg_dict.get('shell') :
-  print "shell option aint implemented yet"
-
-
-
-#--------------------------------------------------------------------------------
-# check that we have root privilege
-#
-err.register(
-  'not_root'
-  command + "requires root privilege"
-  )
-
-uid = os.getuid()
-if uid != 0 :
-  err.tattle('not root')
-
-username = getpass.getuser()
-sudo_caller_username = os.environ.get('SUDO_USER')
-
-if !sudo_caller_username
-  if username not == "root":
-    err.tattle('not_root')
-  elif:
-    owner
-    
-
-  def has_error(*errs):
-    return self.cnt > 0
-
-
-
-#-----
-
-
-
-
-#--------------------------------------------------------------------------------
-#  pull out the owner_dir and subu_dir
-#
-admin= libuser.admin()
-
-err_arg_form = class_err()
-err_arg_form.register('too_many', "too many semicolon delineated parts in")
-
-owner_parts = args[0].split(":")
-subu_parts = args[1].split(":") 
-
-owner_user_name = owner_parts[0]
-if not owner_user_name:
-  err_arg_form.tattle('owner_user_name_missing', args[0])
-else:
-  owner_user = admin.lookupUserByName(owner_user_name)
-  if owner_user == None:
-    err_arg_form.tattle('no_such_user_name', owner_user_name)
-  else:
-    
-
-subu_user_name = subu_parts[0]
-
-
-if length(owner_parts) > 2:
-  err_arg_form.tattle('too_many', args[0])
-elif length(owner_parts) == 2:
-  owner_dir = owner_parts[1]
-else # get the home directory
-    
-  
-
-
-#--------------------------------------------------------------------------------
-# set the home directory
-#
-if len(args) > args_dir_index:
-  dir = args[args_dir_index]
-else:
-  dir = os.getcwd()
-
-home = dir + "/" + name
-home_flag = not os.path.exists(home)
-
-#--------------------------------------------------------------------------------
-# create the user, setfacls
-#
-err_cnt = 0
-name_available_flag = False
-
-if name_flag:
-  admin = libuser.admin()
-  name_available_flag = name not in admin.enumeratedUsers()
-
-if owner_flag and name_flag and name_available_flag and home_flag :
-  user = admin.initUser(name)
-  user[libuser.HOMEDIRECTORY] = home
-  if opt_shell : user[libuser.SHELL] = opt_shell
-  admin.addUser(user)
-  #setfacl -m d:u:plato:rwx,u:plato:rwx directory
-  setfacl = "setfacl -m d:u:" + name + ":rwx,u:" + name + ":rwx " + home
-  exit(0)
-
-#--------------------------------------------------------------------------------
-# error return
-#  .. need to grab the return code from setfacl above and delete the user if it fails
-#
-err_flags = 0
-if not owner_flag :
-  err_flags |= 2**2
-  print "missing owning username argument"
-if not name_flag :
-  err_flags |= 2**3
-  print name + "missing subservient username argument"
-if not name_available_flag :
-  err_flags |= 2**4
-  print name + "specified subservient username already exists"
-if not home_flag :
-  err_flags |= 2**5
-  print "user home directory already exists"
-
-exit(err_flags)
diff --git a/temp b/temp
new file mode 100644 (file)
index 0000000..10ac0e2
--- /dev/null
+++ b/temp
@@ -0,0 +1,23 @@
+./tool/lib/makefile_cc:        @echo "TOOLSDIR: " $(TOOLSDIR)
+./module/db/0_makefile:SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+./module/db/0_makefile:        @echo "SUID_TOOL: " $(SUID_TOOL)
+./module/db/0_makefile:        @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+./module/db/0_makefile:        cat $(SUID_TOOL)
+./module/db/0_makefile:        sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+./module/db/0_makefile-flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+./module/subu-0/1_tests/0_makefile_flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+./module/subu-0/0_makefile:SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+./module/subu-0/0_makefile:    @echo "SUID_TOOL: " $(SUID_TOOL)
+./module/subu-0/0_makefile:    @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+./module/subu-0/0_makefile:    cat $(SUID_TOOL)
+./module/subu-0/0_makefile:    sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+./module/subu-0/0_makefile-flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+./module/tranche/deprecated/0_makefile:SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+./module/tranche/deprecated/0_makefile:        @echo "SUID_TOOL: " $(SUID_TOOL)
+./module/tranche/deprecated/0_makefile:        @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+./module/tranche/deprecated/0_makefile:        cat $(SUID_TOOL)
+./module/tranche/deprecated/0_makefile:        sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+./module/tranche/deprecated/0_makefile-flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+./module/tranche/makefile-flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+./module/da/test/makefile-flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+./module/da/makefile-flags:TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
diff --git a/tool/bin/gitadd b/tool/bin/gitadd
new file mode 100755 (executable)
index 0000000..9355724
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+set -x
+make dist-clean
+git add "$@"
+
diff --git a/tool/bin/makeheaders b/tool/bin/makeheaders
new file mode 100755 (executable)
index 0000000..a50d9a0
Binary files /dev/null and b/tool/bin/makeheaders differ
diff --git a/tool/bin/setuid_root.sh b/tool/bin/setuid_root.sh
new file mode 100755 (executable)
index 0000000..aedd564
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+chown root "$@" && \
+chmod u+rsx,u-w,go+rx-s-w "$@"
+
diff --git a/tool/bin/tranche b/tool/bin/tranche
new file mode 100755 (executable)
index 0000000..eb63c28
Binary files /dev/null and b/tool/bin/tranche differ
diff --git a/tool/doc/makefile.txt b/tool/doc/makefile.txt
new file mode 100644 (file)
index 0000000..722de84
--- /dev/null
@@ -0,0 +1,91 @@
+these are the comments from my RT makefile:
+
+#
+# 2010 11 20 TWL Created
+# 2011 05 26 TWL Modified to generalize
+# 2012 02 23 NLS Add ECHO variable to use on different environnement
+#                corrected setup macro --> add include directory in the path to copy
+#                corrected install macro --> change the name of installed library : lib$(LIB)$(LIBSUFFIX)
+#                changed DOC_DIR directory name to 5_documents
+# 2012 02 23 TWL removed LIB variable which is now set from the command line so
+#                so that all source dirs can use the same makefile
+# 2012 02 23 TWL added target make dist_clean which also deletes the 2_makefile_deps file
+# 2012 04 11 AWW added creation of temporary disk before each test is run 
+# 2012 06 05 TWL moved tests and try .cc files to directories. caused rtmake tests to
+#                dist_clean and make deps
+#
+#
+#----------------------------------------------------------------------------
+#      use this makefile to compile and test the code:
+#
+#               for a first time run, or for regression use the following:
+#
+#                   $ make setup  # makes the directories, though should already exist
+#                   $ make regress 
+#
+#               the usual development workflow makes use of these:
+#
+#                   $ make deps              # only when needed, for example if headers includes change or new files introduced
+#                   $ cd tests; make deps    # only when needed
+#                   $ make lib               # this makes the local library
+#                   $ make tests             # this updates tests and compiles
+#                   $ make clean             # deletes the .o files and library to force a recompile
+#                   $ cd 1_tests; make clean
+#
+#               for a release of a component
+# 
+#                   $ make regress
+#                   $ make install  # this will only work if all the tests in 1_tests are passing 
+#
+#               before a checkin
+# 
+#                   $ make dist_clean # will also clean the tests and try directories
+#
+#               .lib.cc c++ files taken as source of object files for local build library
+#               .exl.cc c++ files taken to have main calls and are linked against local build libary
+#               .ex.cc  c++ files taken to have main calls and are not linked against the local build library
+#               there are no rules for other files in this makefile
+#
+#      about dependencies
+#               The makefile has no way of knowing if an edit changed the dependencies.  Often they do not
+#               and it would be unwieldy to make the deps every time.  Hence *the programmer* must delete
+#               the deps file if he has made any changes that change the dependencies.
+#
+#               The makefile will make the 2_makefile_deps if the file is missing.
+# 
+#
+#      about testing
+#  
+#                the name of the directory you run make in is taken to also be: the name of the library,
+#                the name of the main include file (with a .h added), and the name of the include directory
+#                where the individual headers are found. It is called LIB
+#
+#               test programs are kept in a subdirectory called 1_tests, and are either .exl.cc, ex.cc,
+#                .sh files. When 'make tests' target is invoked they are all run. Test executables return 0
+#                if the test fails, non-zero otherwise.  
+#
+#                to remove a test from the pool move it into the subdirectory in 1_tests, 9_broken,
+#                5_more_tests of 5_scratch.  broken tests are things that are known but must be fixed
+#                before a release.  5_more_tests are tests being worked on.  5_scratch is stuff that is
+#                probably going to be deleted.  if there is a 5_deprecated, that is for good stuff but it
+#                is no longer used for some reason or other.
+#
+#                There is a standard source code template and a
+#                messaging convention.  Also, the names, by convention,are test_xxxx_ where xxx is a
+#                hexadecimal series nummber.  If all the test executables pass the file 1_TESTS_PASSED is
+#                left in the directory.  Otherwise the file 1_TESTS_FAILED is left in the directory.
+#
+#     about release directory
+#
+#               this is set in the ApplicationBase variable by rt_init
+#
+#               after the tests pass stuff might be copied to the release directory using
+# 
+#                  make install
+#
+#               the release directory must have these subdirectories:  
+#
+#                  bin documents include src
+#
+#
+#
diff --git a/tool/doc/makeheaders-notes.txt b/tool/doc/makeheaders-notes.txt
new file mode 100644 (file)
index 0000000..5aebda9
--- /dev/null
@@ -0,0 +1,16 @@
+
+This worked to force the include to be part of the interface:
+
+#if INTERFACE
+#include <sqlite3.h>
+#endif
+
+But this did not:
+
+#if INTERFACE
+  #include <sqlite3.h>
+#endif
+
+makeheaders looks to be sensitive to indentation
+
+
diff --git a/tool/doc/makeheaders.html b/tool/doc/makeheaders.html
new file mode 100644 (file)
index 0000000..289da58
--- /dev/null
@@ -0,0 +1,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 &#8220;<code>.h</code>&#8221;
+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> &#8220;<code>extern</code>&#8221; 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 &#8220;<code>.h</code>&#8221; suffix and definitions are
+placed in &#8220;<code>.c</code>&#8221; files.
+The .c files contain &#8220;<code>#include</code>&#8221; 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>&lt;stdio.h&gt</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 &#8220;exportable&#8221;.
+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
+&#8220;<code>alpha.c</code>&#8221;,
+&#8220;<code>beta.c</code>&#8221; and
+&#8220;<code>gamma.c</code>&#8221;
+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 &#8220;<code>-f</code>&#8221; 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 &#8220;<code>mkhdr.dat</code>&#8221;
+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 &#8220;<code>-local</code>&#8221; option causes makeheaders to
+generate of prototypes for &#8220;<code>static</code>&#8221; functions and
+procedures.
+Such prototypes are normally omitted.
+</p>
+
+<p>
+Finally, makeheaders also includes a &#8220;<code>-doc</code>&#8221; 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 &#8220;<code>--help</code>&#8221; or
+&#8220;<code>-?</code>&#8221;)
+and it will print a summary of the available options on standard
+error.
+If you need to process a file whose name begins with
+&#8220;<code>-</code>&#8221;,
+you can prepend a &#8220;<code>./</code>&#8221; to its name in order to get it
+accepted by the command line parser.
+Or, you can insert the special option &#8220;<code>--</code>&#8221; on the
+command line to cause all subsequent command line arguments to be treated as
+filenames even if their names begin with &#8220;<code>-</code>&#8221;.
+</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)
+&#8220;<code>alpha.c</code>&#8221;
+makeheaders will attempt to generate a corresponding header file
+named &#8220;<code>alpha.h</code>&#8221;.
+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 &#8220;<code>#include</code>&#8221; to the
+top of the file that sources the header file that makeheaders will generate.
+Hence, the beginning of a source file named &#8220;<code>alpha.c</code>&#8221;
+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
+&#8220;<code>#if</code>&#8221; 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 &#8220;<code>beta.h</code>&#8221;,
+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 &#8220;<code>#if</code>&#8221; 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,
+&#8220;<code>*.[ch]</code>&#8221;,
+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 &#8220;<code>static</code>&#8221; keyword of C appears at the
+beginning of the function definition, the prototype is suppressed.
+If you use the &#8220;<code>LOCAL</code>&#8221; keyword where you would normally
+say &#8220;<code>static</code>&#8221;, 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 &#8220;<code>LOCAL</code>&#8221; 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 &#8220;<code>-local</code>&#8221;
+command-line option, then it treats the &#8220;<code>static</code>&#8221;
+keyword like &#8220;<code>LOCAL</code>&#8221; 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
+&#8220;<code>extern</code>&#8221;
+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 &#8220;<code>struct</code>&#8221;, &#8220;<code>union</code>&#8221; or
+&#8220;<code>enum</code>&#8221; 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 &#8220;<code>X</code>&#8221; requires a
+prior declaration of another structure &#8220;<code>Y</code>&#8221;, 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
+&#8220;<code>#if INTERFACE</code>&#8221; but before the corresponding
+&#8220;<code>#endif</code>&#8221; are eligable to be copied into the
+automatically generated
+.h files of other .c files.
+</p>
+
+<p>
+If you use the &#8220;<code>#if INTERFACE</code>&#8221; 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
+&#8220;<code>#if INTERFACE</code>&#8221; 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
+&#8220;<code>#if INTERFACE</code>&#8221; 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 &#8220;<code>export</code>&#8221;.
+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 &#8220;<code>static</code>&#8221; 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: &#8220;<code>EXPORT</code>&#8221;
+</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 &#8220;<code>#if EXPORT_INTERFACE</code>&#8221; mechanism can be used in
+either .c or .h files.
+(The &#8220;<code>#if INTERFACE</code>&#8221; 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 &#8220;<code>private</code>&#8221;.
+</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 &#8220;<code>LOCAL_INTERFACE</code>&#8221; block works very much like the
+&#8220;<code>INTERFACE</code>&#8221; and
+&#8220;<code>EXPORT_INTERFACE</code>&#8221;
+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 &#8220;<code>class</code>&#8221;
+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 &#8220;<code>alpha.cpp</code>&#8221; will induce makeheaders to
+generate a header file named &#8220;<code>alpha.hpp</code>&#8221;.
+</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&amp;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&amp;R function.
+Therefore you should take care to avoid putting K&amp;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. &#8220;<code>enum {X, Y, Z};</code>&#8221;.
+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 &#8220;<code>-doc</code>&#8221; 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 &#8220;<code>-doc</code>&#8221; 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: &#8220;<code>#define</code>&#8221;)
+</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
+     (&#8220;<code>#if</code>&#8221;) 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>
diff --git a/tool/lib/bashrc b/tool/lib/bashrc
new file mode 100755 (executable)
index 0000000..b2f3ded
--- /dev/null
@@ -0,0 +1,20 @@
+#
+
+umask 0077
+
+if [ $INSIDE_EMACS ]; then 
+  echo Hello Emacs
+fi
+export PS1='\n$(/usr/local/bin/Z)\n\u@\h§\w§\n> '
+export PS2='>>'
+PATH=~/bin:$PATH
+
+#temporarily while active in subu code development
+export PROJECT_SUBU=~/subu
+PATH="$PROJECT_SUBU"/tool/bin:$PATH
+
+export PS_FORMAT=user:15,pid,%cpu,%mem,vsz,rss,tty,stat,start,time,command
+
+export EDITOR=emacs
+
+
diff --git a/tool/lib/dot_emacs b/tool/lib/dot_emacs
new file mode 100755 (executable)
index 0000000..27132b6
--- /dev/null
@@ -0,0 +1,202 @@
+
+(defun undedicate-window (&optional window)
+  (interactive)
+  (set-window-dedicated-p (or window (get-buffer-window)) nil))
+
+;; Removing annoying dedicated buffer nonsense
+(defun switch-to-buffer! (buffer-or-name &optional norecord force-same-window)
+  "Like switch-to-buffer but works for dedicated buffers \(though
+it will ask first)."
+  (interactive
+   (list (read-buffer-to-switch "Switch to buffer: ") nil 'force-same-window))
+  (when (and (window-dedicated-p (get-buffer-window))
+             (yes-or-no-p "This window is dedicated, undedicate it? "))
+    (undedicate-window))
+  (switch-to-buffer buffer-or-name norecord force-same-window))
+
+(defun toggle-window-dedication (&optional window)
+  (interactive)
+  (let ((window (or window (get-buffer-window))))
+    (set-window-dedicated-p window (not (window-dedicated-p window)))))
+
+(global-set-key (kbd "C-x d") 'toggle-window-dedication)
+
+;; fix 'feature' of broken gdb where it takes control of an
+;; emacs window, and locks the user out from switching from it
+;;
+;; yes and this fix breaks file name completion...
+;;
+;;  (defun set-window-undedicated-p (window flag)
+;;   "Never set window dedicated."
+;;   flag)
+;;  (advice-add 'set-window-dedicated-p :override #'set-window-undedicated-p)
+;;
+;; Toggle window dedication
+
+  (defun toggle-window-dedicated ()
+  "Toggle whether the current active window is dedicated or not"
+  (interactive)
+  (message 
+   (if (let (window (get-buffer-window (current-buffer)))
+         (set-window-dedicated-p window 
+          (not (window-dedicated-p window))))
+      "Window '%s' is dedicated"
+      "Window '%s' is normal")
+   (current-buffer)))
+
+   (global-set-key "\C-q" 'toggle-window-dedicated)
+
+;; (setq ring-bell-function (lambda ()
+;;                            (call-process-shell-command
+;;                              "xset led 3; xset -led 3" nil 0 nil)))
+;;
+;; (setq ring-bell-function nil)
+
+ (setq ring-bell-function
+       (lambda ()
+        (call-process-shell-command "xset led named 'Scroll Lock'")
+        (call-process-shell-command "xset -led named 'Scroll Lock'")))
+
+
+;; preferable to have keys for the characters, but the keyboard is already overloaded ..
+;; (define-key key-translation-map (kbd "<f9> p") (kbd "¬"))
+;; (set-input-method “latin-9-prefix)
+
+  (global-set-key [f1] 'help-command)
+  (global-set-key "\C-h" 'nil)
+  (define-key key-translation-map (kbd "M-S") (kbd "§"))
+
+  (global-set-key (kbd "C-x g phi SPC") [?φ]) ; phi for phase
+  (global-set-key (kbd "C-x g Phi SPC") [?Φ]) 
+
+  (global-set-key (kbd "C-x g d SPC") [?δ])
+  (global-set-key (kbd "C-x g D SPC") [?Δ]) ; this is 'delta' is not 'increment'!
+  (global-set-key (kbd "C-x g delta SPC") [?δ])
+  (global-set-key (kbd "C-x g Delta SPC") [?Δ]) ; this is 'delta' is not 'increment'!
+
+
+  (global-set-key (kbd "C-x g g SPC") [?γ])
+  (global-set-key (kbd "C-x g G SPC") [?Γ])
+  (global-set-key (kbd "C-x g gamma SPC") [?γ])
+  (global-set-key (kbd "C-x g Gamma SPC") [?Γ])
+
+  (global-set-key (kbd "C-x g l SPC") [?λ])
+  (global-set-key (kbd "C-x g L SPC") [?Λ])
+  (global-set-key (kbd "C-x g lambda SPC") [?λ])
+  (global-set-key (kbd "C-x g Lambda SPC") [?Λ])
+
+  (global-set-key (kbd "C-x g p SPC") [?π])
+  (global-set-key (kbd "C-x g P SPC") [?Π])
+  (global-set-key (kbd "C-x g pi SPC") [?π])
+  (global-set-key (kbd "C-x g Pi SPC") [?Π])
+
+  (global-set-key (kbd "C-x g > = SPC") [?≥])
+  (global-set-key (kbd "C-x g < = SPC") [?≤])
+  (global-set-key (kbd "C-x g ! = SPC") [?≠])
+  (global-set-key (kbd "C-x g neq SPC") [?≠])
+      
+  (global-set-key (kbd "C-x g nil SPC") [?∅])
+
+  (global-set-key (kbd "C-x g not SPC") [?¬])
+
+  (global-set-key (kbd "C-x g and SPC") [?∧])
+  (global-set-key (kbd "C-x g or SPC") [?∨])
+
+  (global-set-key (kbd "C-x g exists SPC") [?∃])
+  (global-set-key (kbd "C-x g all SPC") [?∀])
+
+  (global-set-key (kbd "C-x g do SPC") [?⟳]) ; do
+  (global-set-key (kbd "C-x g rb SPC") [?◨])
+  (global-set-key (kbd "C-x g lb SPC") [?◧])
+
+  (global-set-key (kbd "C-x g cont SPC") [?➜]) ; continue
+  (global-set-key (kbd "C-x g thread SPC") [?☥]) ; thread
+
+  (global-set-key (kbd "C-x g in SPC") [?∈]) ; set membership
+
+
+
+;; lisp
+;;
+  (setq lisp-indent-offset 2)
+  (setq inferior-lisp-program "sbcl")      
+
+  (modify-syntax-entry ?[ "(]" lisp-mode-syntax-table)
+  (modify-syntax-entry ?] ")[" lisp-mode-syntax-table)
+  (modify-syntax-entry ?{ "(}" lisp-mode-syntax-table)
+  (modify-syntax-entry ?} "){" lisp-mode-syntax-table)
+
+;; get the pwd in shell mode from the prompt rather than guessing by
+;; watching the commands typed .. yes! now shell variables and source
+;; scripts will work
+;;   in bashrc: export PS1='\n$(/usr/local/bin/Z)\u@\h§\w§\n> '
+;;
+  (add-hook 'shell-mode-hook
+           (lambda ()
+             (shell-dirtrack-mode -1)
+             (dirtrack-mode 1)))
+
+  (add-hook 'dirtrack-directory-change-hook
+            (lambda ()
+              (message default-directory)))
+
+  (setq dirtrack-list '("§\\(.*\\)§\n> " 1))
+
+;; use a backrevs dir rather than leaving ~file droppings everywhere
+;;
+  (setq backup-directory-alist `(("." . "~/emacs_backrevs")))
+  (setq backup-by-copying t)
+
+;; stop the 'tab' character polution
+;;
+  (setq-default indent-tabs-mode nil)
+
+;; turn off the poison C-z key.  Use C-x C-z or the command suspend-emacs
+;;
+  (global-set-key (kbd "C-z") nil)
+
+;; truncate rather than wrapping lines (use horizontal scroll to see to the right)
+;;
+  (set-default 'truncate-lines t)
+  (setq truncate-partial-width-windows nil)
+  (setq-default fill-column 80)
+
+;; recover some window real estate
+;;   c-x mode-line to toggle the mode-line on and off
+;;
+  (defun mode-line () "toggles the modeline on and off"
+    (interactive) 
+    (setq mode-line-format
+      (if (equal mode-line-format nil)
+          (default-value 'mode-line-format)) )
+    (redraw-display))
+
+  (tool-bar-mode -1)
+  (menu-bar-mode -1)
+
+
+(put 'upcase-region 'disabled nil)
+(put 'narrow-to-region 'disabled nil)
+(put 'downcase-region 'disabled nil)
+(put 'set-goal-column 'disabled nil)
+
+
+(custom-set-variables
+ ;; custom-set-variables was added by Custom.
+ ;; If you edit it by hand, you could mess it up, so be careful.
+ ;; Your init file should contain only one such instance.
+ ;; If there is more than one, they won't work right.
+  '(ansi-color-names-vector
+     ["#212526" "#ff4b4b" "#b4fa70" "#fce94f" "#729fcf" "#e090d7" "#8cc4ff" "#eeeeec"])
+ '(custom-enabled-themes (quote (wheatgrass)))
+ '(geiser-racket-binary "racket")
+ '(send-mail-function (quote smtpmail-send-it))
+ '(tool-bar-mode nil))
+(custom-set-faces
+ ;; custom-set-faces was added by Custom.
+ ;; If you edit it by hand, you could mess it up, so be careful.
+ ;; Your init file should contain only one such instance.
+ ;; If there is more than one, they won't work right.
+ '(default ((t (:family "DejaVu Sans Mono" :foundry "PfEd" :slant normal :weight bold :height 98 :width normal)))))
+
+(put 'erase-buffer 'disabled nil)
diff --git a/tool/lib/makefile_cc b/tool/lib/makefile_cc
new file mode 100755 (executable)
index 0000000..3cbb5fe
--- /dev/null
@@ -0,0 +1,168 @@
+
+#should add test that incdir is not pwd before deleting the include file in
+#dist-clean currently make is looking for module.h while the include file is
+#always module.lib.h so the lib include is not getting clobbered
+
+SHELL=/bin/bash
+
+# these are the sources edited by the programmer
+C_SOURCE_LIB=  $(wildcard $(SRCDIR)/*.lib.c)
+C_SOURCE_CLI=  $(wildcard $(SRCDIR)/*.cli.c)
+CC_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc)
+CC_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.cc)
+
+#remove the suffix to get base name
+C_BASE_LIB=  $(sort $(patsubst %.lib.c,  %, $(notdir $(C_SOURCE_LIB))))
+C_BASE_CLI=  $(sort $(patsubst %.cli.c,  %, $(notdir $(C_SOURCE_CLI))))
+CC_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CC_SOURCE_LIB))))
+CC_BASE_CLI= $(sort $(patsubst %.cli.cc, %, $(notdir $(CC_SOURCE_CLI))))
+
+# two sets of object files, one for the lib, and one for the command line interface progs
+OBJECT_LIB= $(patsubst %, $(TMPDIR)/%.lib.o, $(C_BASE_LIB) $(CC_BASE_LIB))
+OBJECT_CLI= $(patsubst %, $(TMPDIR)/%.cli.o, $(C_BASE_CLI) $(CC_BASE_CLI))
+
+# executables are made from CLI sources
+EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI))
+
+#otherwise make provides default values for these
+C=
+CC=
+
+DEPFILE=$(TMPDIR)/makefile-dep
+LIBFILE=$(LIBDIR)/lib$(MODULE).a
+INCFILE=$(INCDIR)/$(MODULE).h
+
+-include makefile-flags
+
+# a single space literal, for example if you wanted to subsitute commas to
+# spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send
+# multiple separate command arguments to a shell script from one variable value
+blank :=
+space :=$(blank)  $(blank)
+
+.PHONY: all
+all: version dep lib exec
+
+.PHONY: version
+version:
+       @echo makefile version 4.0
+       @echo "PWD: " $(PWD)
+       @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST)
+       @echo "C: " $(C)
+       @echo "CFLAGS: " $(CFLAGS)
+       @echo "CC: " $(CC)
+       @echo "CCFLAGS: " $(CCFLAGS)
+       @echo "LINKFLAGS: " $(LINKFLAGS)
+
+.PHONY: info
+info:
+       @echo "DEPRDIR: " $(DEPRDIR)
+       @echo "DOCDIR: " $(DOCDIR)
+       @echo "EXECDIR: " $(EXECDIR)
+       @echo "INCDIR: " $(INCDIR)
+       @echo "LIBDIR: " $(LIBDIR)
+       @echo "TESTDIR: " $(TESTDIR)
+       @echo "TMPDIR: " $(TMPDIR)
+       @echo "TOOLDIR: " $(TOOLDIR)
+       @echo "TRYDIR: " $(TRYDIR)
+       @echo "DEPFILE: " $(DEPFILE)
+       @echo "LIBFILE: " $(LIBFILE)
+       @echo "INCFILE: " $(INCFILE)
+       @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB)
+       @echo "C_SOURCE_CLI: " $(C_SOURCE_CLI)
+       @echo "CC_SOURCE_LIB: " $(CC_SOURCE_LIB)
+       @echo "CC_SOURCE_CLI: " $(CC_SOURCE_CLI)
+       @echo "C_BASE_LIB: " $(C_BASE_LIB)
+       @echo "C_BASE_CLI: " $(C_BASE_CLI)
+       @echo "CC_BASE_LIB: " $(CC_BASE_LIB)
+       @echo "CC_BASE_CLI: " $(CC_BASE_CLI)
+       @echo "OBJECT_LIB: " $(OBJECT_LIB)
+       @echo "OBJECT_CLI: " $(OBJECT_CLI)
+       @echo "EXEC: " $(EXEC)
+
+# should be safe to run this in an already setup or partially setup directory
+.PHONY: setup
+setup:
+       [ ! -e $(DEPRDIR) ] && mkdir $(DEPRDIR) || true
+       [ ! -e $(DOCDIR) ]  && mkdir $(DOCDIR)  || true
+       [ ! -e $(EXECDIR) ] && mkdir $(EXECDIR) || true
+       [ ! -e $(INCDIR) ]  && mkdir $(INCDIR)  || true
+       [ ! -e $(LIBDIR) ]  && mkdir $(LIBDIR)  || true
+       [ ! -e $(SRCDIR) ]  && mkdir $(SRCDIR)  || true
+       [ ! -e $(TESTDIR) ] && mkdir $(TESTDIR) || true
+       [ ! -e $(TMPDIR) ]  && mkdir $(TMPDIR)  || true
+       [ ! -e $(TRYDIR) ]  && mkdir $(TRYDIR)  || true
+
+#better to put the dependency generation into a loop on the source file and specify -MT for the target
+#also should be redirecting only stdout so stderr messages will be displayed >>1 depfile
+.PHONY: dep
+dep: 
+       @if [ -z "$(CC)" ]; then\
+         if [ -z "$C()" ]; then\
+           echo "No compiler specified";\
+           exit 1;\
+         else\
+           echo "C compiler only deps" ;\
+           $(C) $(CFLAGS) -MM  $(C_SOURCE_LIB) $(C_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\
+           echo "deps for C linking";\
+           for i in $(C_BASE_CLI) ; do\
+             $(ECHO) >> $(DEPFILE);\
+             $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
+             $(ECHO) " $(C) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
+           done;\
+         fi;\
+       else\
+         $(CC) $(CCFLAGS) -MM  $(CC_SOURCE_LIB) $(CC_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\
+         if [ -z "$C()" ]; then\
+           echo "CC compiler only deps" ;\
+         else\
+           echo "CC and C mixed compile deps" ;\
+           $(C) $(CFLAGS) -MM   $(C_SOURCE_LIB) $(C_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\
+         fi;\
+         echo "deps for CC linking";\
+         for i in $(CC_BASE_CLI) $(C_BASE_CLI) ; do\
+           $(ECHO) >> $(DEPFILE);\
+           $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
+           $(ECHO) "   $(CC) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
+         done;\
+       fi
+
+.PHONY: lib
+lib: $(LIBFILE)
+
+$(LIBFILE): $(OBJECT_LIB)
+       ar rcs $(LIBFILE) $(OBJECT_LIB)
+
+.PHONY: exec
+exec: $(LIBFILE)
+       make sub_exec
+
+.PHONY: sub_exec
+sub_exec: $(EXEC)
+
+.PHONY: stage
+stage:
+       [ -f $(LIBFILE) ] && cp $(LIBFILE) $(PROJECT_SUBU)/stage/lib || true
+       [ -f $(INCFILE) ] && cp $(INCFILE) $(PROJECT_SUBU)/stage/include || true
+       [ $(shell ls -A $(EXECDIR)) ] && cp $(EXECDIR)/* $(PROJECT_SUBU)/stage/bin || true
+
+.PHONY: clean
+clean:
+       for i in $(wildcard tmp/*); do rm $$i || true; done 
+
+.PHONY: dist-clean
+dist-clean: clean
+       for i in $(EXEC); do [ -e $$i ] && rm $$i || true; done 
+       rm $(INCFILE) || true
+       rm $(LIBFILE) || true
+
+-include $(DEPFILE)
+
+# recipes
+
+$(TMPDIR)/%.o : $(SRCDIR)/%.c
+       $(C) $(CFLAGS) -o $@ -c $<
+
+$(TMPDIR)/%.o : $(SRCDIR)/%.cc
+       $(CC) $(CCFLAGS) -o $@ -c $<
+
diff --git a/tool/lib/makefile_trc b/tool/lib/makefile_trc
new file mode 100644 (file)
index 0000000..1edc8b3
--- /dev/null
@@ -0,0 +1,188 @@
+
+# We should read the tranche sources and see what files they output, and then
+# build the deps accordingly, but this makefile is more primitive approach.
+# Here the programmer must have one output .c file or .cc file per input tranche
+# file and it must be name <base>.{lib,cli}.{c,cc} and the {.c,.cc} output
+# tranche must be named <base>.trc.{c,cc}
+
+# will re-orgnaize the directory structure .. will name the src-da .. etc. to the
+# name of the module, then have a source dir inside that has only the stuff
+# programmer's edit, then get rid of the numbers
+
+SHELL=/bin/bash
+
+#LIDBIR, EXECDIR, HDIR hold the make results that might later be staged
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=deprecated
+DOCDIR=doc
+EXECDIR=exec
+INCDIR=include
+LIBDIR=lib
+SRCDIR=src
+TESTDIR=test
+TMPDIR=tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=try
+
+LIBFILE=$(LIBDIR)/lib$(MODULE).a
+INCFILE=$(MODULE).h
+
+# these are the sources edited by the programmer
+C_SOURCE_LIB=  $(wildcard $(SRCDIR)/*.lib.c)
+C_SOURCE_CLI=  $(wildcard $(SRCDIR)/*.cli.c)
+CC_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc)
+CC_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.cc)
+
+#remove the suffix to get base name
+C_BASE_LIB=  $(sort $(patsubst %.lib.c,  %, $(notdir $(C_SOURCE_LIB))))
+C_BASE_CLI=  $(sort $(patsubst %.cli.c,  %, $(notdir $(C_SOURCE_CLI))))
+CC_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CC_SOURCE_LIB))))
+CC_BASE_CLI= $(sort $(patsubst %.cli.cc, %, $(notdir $(CC_SOURCE_CLI))))
+
+# the progreammer must name the c and cc tranches accordingly:
+C_TRC_LIB= $(patasubst %, $(TMPDIR)/%.trc.c, C_BASE_LIB)
+C_TRC_CLI= $(patasubst %, $(TMPDIR)/%.trc.c, C_BASE_CLI)
+CC_TRC_LIB= $(patasubst %, $(TMPDIR)/%.trc.cc, CC_BASE_LIB)
+CC_TRC_CLI= $(patasubst %, $(TMPDIR)/%.trc.cc, CC_BASE_CLI)
+
+# two sets of object files, one for the lib, and one for the command line interface progs
+OBJECT_LIB= $(patsubst %, $(TMDIR)/%.o, $(C_BASE_LIB) $(CC_BASE_LIB))
+OBJECT_CLI= $(patsubst %, $(TMDIR)/%.o, $(C_BASE_CLI) $(CC_BASE_CLI))
+
+# executables are made from CLI sources
+EXEC= (patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI))
+
+#otherwise make provides default values for these
+C=
+CC=
+
+-include makefile-flags
+
+DEPFILE=$(TMPDIR)/makefile_dep
+
+# a single space literal, for example if you wanted to subsitute commas to
+# spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send
+# multiple separate command arguments to a shell script from one variable value
+blank :=
+space :=$(blank)  $(blank)
+
+all: version deps lib execs
+
+version:
+       @echo makefile version 3.0
+       @echo "PWD: " $(PWD)
+       @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST)
+       @echo "C: " $(C)
+       @echo "CFLAGS: " $(CFLAGS)
+       @echo "CC: " $(CC)
+       @echo "CCFLAGS: " $(CCFLAGS)
+       @echo "LINKFLAGS: " $(LINKFLAGS)
+
+info:
+       @echo "DEPDIR: " $(DEPDIR)
+       @echo "DOCDIR: " $(DOCDIR)
+       @echo "EXECSDIR: " $(EXECSDIR)
+       @echo "INCDIR: " $(INCDIR)
+       @echo "LIBDIR: " $(LIBDIR)
+       @echo "TESTDIR: " $(TESTDIR)
+       @echo "TMPDIR: " $(TMPDIR)
+       @echo "TOOLSDIR: " $(TOOLSDIR)
+       @echo "TRYDIR: " $(TRYDIR)
+       @echo "DEPSFILE: " $(DEPSFILE)
+       @echo "LIBFILE: " $(LIBFILE)
+        @echo "TRC_TRC: " $(TRC_TRC)
+       @echo "C_BASE_LIB: " $(C_BASE_LIB)
+       @echo "C_BASE_CLI: " $(C_BASE_CLI)
+       @echo "CC_BASE_LIB: " $(CC_BASE_LIB)
+       @echo "CC_BASE_CLI: " $(CC_BASE_CLI)
+
+# should be safe to run this in an already setup or partially setup directory
+setup:
+       if [ ! -e $(DEPRDIR) ]; then mkdir $(DEPRDIR); fi
+       if [ ! -e $(DOCDIR) ]; then mkdir $(DOCDIR); fi
+       if [ ! -e $(EXECSDIR) ]; then mkdir $(EXECSDIR); fi
+       if [ ! -e $(INCDIR) ]; then mkdir $(INCDIR); fi
+       if [ ! -e $(LIBDIR) ]; then mkdir $(LIBDIR); fi
+       if [ ! -e $(SRCDIR) ]; then mkdir $(SRCDIR); fi
+       if [ ! -e $(TESTDIR) ]; then mkdir $(TESTDIR); fi
+       if [ ! -e $(TMPDIR) ]; then mkdir $(TMPDIR); fi
+       if [ ! -e $(TRYDIR) ]; then mkdir $(TRYDIR); fi
+
+dep: $(C_TRC_LIB) $(C_TRC_CLI) $(CC_TRC_LIB) $(CC_TRC_CLI)
+       if [ -z "$(CC)" ]; then\
+         if [ -z "$C()" ]; then\
+           echo "No compiler specified";\
+           exit 1;\
+         else\
+           echo "C compiler only deps" ;\
+           $(C) $(CFLAGS) -MM  $(C_TRC_LIB) $(C_TRC_CLI) 1> $(DEPSFILE);\
+           echo "deps for C linking";\
+           for i in $(EXECS) ; do\
+             $(ECHO) >> $(DEPSFILE);\
+             $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\
+             $(ECHO) " $(C) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\
+           done;\
+         fi;\
+       else\
+         $(CC) $(CCFLAGS) -MM  $(CC_TRC_LIB) $(CC_TRC_CLI) 1> $(DEPSFILE);\
+         if [ -z "$C()" ]; then\
+           echo "CC compiler only deps" ;\
+         else\
+           echo "CC and C mixed compile deps" ;\
+           $(C) $(CFLAGS) -MM   $(C_TRC_LIB) $(C_TRC_CLI) 1>> $(DEPSFILE);\
+         fi;\
+         echo "deps for CC linking";\
+         for i in $(EXECS) ; do\
+           $(ECHO) >> $(DEPSFILE);\
+           $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\
+           $(ECHO) "   $(CC) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\
+         done;\
+       fi
+
+lib: 
+       make $(LIBDIR)/$(LIBFILE)
+
+$(LIBDIR)/$(LIBFILE) : $(OBJECTS_LIB)
+       ar rcs $(LIBDIR)/$(LIBFILE) $(OBJECTS_LIB)
+
+exec: $(LIBDIR)/$(LIBFILE)
+       make sub_exec
+
+sub_exec: $(patsubst %,  $(EXECSDIR)/%, $(EXECS))
+
+stage:
+       if [ -f $(LIBDIR)/$(LIBFILE) ]; then cp $(LIBDIR)/$(LIBFILE) $(PROJECT_SUBU)/stage/lib; fi
+       if [ -f $(INCDIR)/$(INCFILE) ]; then cp $(INCDIR)/$(INCFILE) $(PROJECT_SUBU)/stage/include; fi
+       -cp $(EXECSDIR)/* $(PROJECT_SUBU)/stage/bin
+
+clean:
+       for i in $(wildcard *~); do mv $$i $(TMPDIR); done
+       for i in $(wildcard *.lib.o) $(wildcard *.cli.o); do rm $$i; done 
+       for i in $(EXECS); do if [ -e $(EXECSDIR)/$$i ]; then rm $(EXECSDIR)/$$i; fi; done 
+       if [ -f $(LIBDIR)/$(LIBFILE) ]; then rm $(LIBDIR)/$(LIBFILE); fi
+       if [ -f $(DEPSFILE) ]; then rm $(DEPSFILE); fi
+
+-include $(DEPSFILE)
+
+# recipes
+#
+%.trc.c : %.lib.c
+       $(TRANCHE) $<
+
+%.trc.c : %.cli.c
+       $(TRANCHE) $<
+
+%.trc.cc : %.lib.cc
+       $(TRANCHE) $<
+
+%.trc.cc : %.cli.cc
+       $(TRANCHE) $<
+
+%.o : %.c
+       $(C) $(CFLAGS) -c $<
+
+%.o : %.cc
+       $(CC) $(CCFLAGS) -c $<
+
diff --git a/tool/src/makeheaders.c b/tool/src/makeheaders.c
new file mode 100644 (file)
index 0000000..b58e787
--- /dev/null
@@ -0,0 +1,3739 @@
+<!DOCTYPE html>
+<html>
+<head>
+<base href="https://fossil-scm.org/fossil/doc/8cecc544/src/makeheaders.c" />
+<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: ; script-src 'self' 'nonce-e2f4709a3deeafd8212401c84e2a082e1fbd3068470984f2' ; style-src 'self' 'unsafe-inline'" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Fossil: File Content</title>
+<link rel="alternate" type="application/rss+xml" title="RSS Feed"  href="/fossil/timeline.rss" />
+<link rel="stylesheet" href="/fossil/style.css?id=9eb7de39" type="text/css"  media="screen" />
+</head>
+<body>
+<div class="header">\r
+  <div class="title"><h1>Fossil</h1>File Content</div>\r
+    <div class="status"><a href='/fossil/login'>Login</a>
+</div>\r
+</div>\r
+<div class="mainmenu">\r
+<a id='hbbtn' href='#'>&#9776;</a><a href='/fossil/doc/trunk/www/index.wiki' class=''>Home</a>
+<a href='/fossil/timeline' class=''>Timeline</a>
+<a href='/fossil/doc/trunk/www/permutedindex.html' class=''>Docs</a>
+<a href='https://fossil-scm.org/forum'>Forum</a><a href='/fossil/uv/download.html' class='desktoponly'>Download</a>
+</div>\r
+<div id='hbdrop'></div>\r
+<form id='f01' method='GET' action='/fossil/file'>
+<input type='hidden' name='udc' value='1'>
+<div class="submenu">
+<a class="label" href="/fossil/artifact/49c76a69">Artifact</a>
+<a class="label" href="/fossil/timeline?n=200&amp;uf=49c76a6973d579ff0b346e5f73182fa72dd797cbb07e8b20612849dc2adef85d">Check-ins Using</a>
+<a class="label" href="/fossil/raw/src/makeheaders.c?name=49c76a6973d579ff0b346e5f73182fa72dd797cbb07e8b20612849dc2adef85d">Download</a>
+<a class="label" href="/fossil/hexdump?name=49c76a6973d579ff0b346e5f73182fa72dd797cbb07e8b20612849dc2adef85d">Hex</a>
+<label class='submenuctrl submenuckbox'><input type='checkbox' name='ln' id='submenuctrl-0' >Line Numbers</label>
+</div>
+<input type="hidden" name="name" value="src/makeheaders.c">
+</form>
+<script src='/fossil/builtin/menu.js?id=6f60cb38'></script>
+<div class="content">
+<h2>Latest version of file 'src/makeheaders.c':</h2>
+<ul>
+<li>File
+<a data-href='/fossil/finfo?name=src/makeheaders.c&m=49c76a6973d579ff' href='/fossil/honeypot'>src/makeheaders.c</a>
+&mdash; part of check-in
+<span class="timelineHistDsp">[8cecc544]</span>
+at
+2018-11-02 15:21:54
+on branch <a data-href='/fossil/timeline?r=trunk' href='/fossil/honeypot'>trunk</a>
+&mdash; Enhance makeheaders so that it is able to deal with static_assert() statements.
+(These do not come up in Fossil itself.  This check-in is in response to use
+of Makeheaders by external projects.)
+ (user:
+drh
+size: 100011)
+<a data-href='/fossil/whatis/49c76a6973d579ff' href='/fossil/honeypot'>[more...]</a>
+</ul>
+<hr />
+<blockquote>
+<pre>
+/*
+** 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 &quot;2-Clause License&quot; or &quot;FreeBSD License&quot;.)
+**
+** 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 &quot;as is&quot; 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 &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;ctype.h&gt;
+#include &lt;memory.h&gt;
+#include &lt;sys/stat.h&gt;
+#include &lt;assert.h&gt;
+#include &lt;string.h&gt;
+
+#if defined( __MINGW32__) ||  defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#else
+# include &lt;unistd.h&gt;
+#endif
+
+/*
+** Macros for debugging.
+*/
+#ifdef DEBUG
+static int debugMask = 0;
+# define debug0(F,M)       if( (F)&amp;debugMask ){ fprintf(stderr,M); }
+# define debug1(F,M,A)     if( (F)&amp;debugMask ){ fprintf(stderr,M,A); }
+# define debug2(F,M,A,B)   if( (F)&amp;debugMask ){ fprintf(stderr,M,A,B); }
+# define debug3(F,M,A,B,C) if( (F)&amp;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&#39;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&#39;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 &quot;forward declaration&quot; is a declaration that an object exists that
+** doesn&#39;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 &quot;Properties&quot; below */
+  Token *pComment;   /* A block comment associated with this declaration */
+  Token tokenCode;   /* Implementation of functions and procedures */
+  Decl *pSameName;   /* Next declaration with the same &quot;zName&quot; */
+  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 &quot;typedef struct Abc Abc;&quot; and the
+** full declaration is &quot;struct Abc { int a; float b; };&quot;.)
+**
+** 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&#39;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 &#39;extern &quot;C&quot;&#39; in a C++ header.
+                                ** Prepend nothing in a C header */
+#define DP_ExternReqd   0x080   /* Prepend &#39;extern &quot;C&quot;&#39; in a C++ header if
+                                ** DP_Cplusplus is not also set. If DP_Cplusplus
+                                ** is set or this is a C header then
+                                ** prepend &#39;extern&#39; */
+
+/*
+** Convenience macros for dealing with declaration properties
+*/
+#define DeclHasProperty(D,P)    (((D)-&gt;flags&amp;(P))==(P))
+#define DeclHasAnyProperty(D,P) (((D)-&gt;flags&amp;(P))!=0)
+#define DeclSetProperty(D,P)    (D)-&gt;flags |= (P)
+#define DeclClearProperty(D,P)  (D)-&gt;flags &amp;= ~(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 &quot;flags&quot; 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    /* &quot;extern&quot; has been seen */
+#define PS_Export        0x001000    /* If between &quot;#if EXPORT_INTERFACE&quot;
+                                     ** and &quot;#endif&quot; */
+#define PS_Export2       0x002000    /* If &quot;EXPORT&quot; seen */
+#define PS_Typedef       0x004000    /* If &quot;typedef&quot; has been seen */
+#define PS_Static        0x008000    /* If &quot;static&quot; has been seen */
+#define PS_Interface     0x010000    /* If within #if INTERFACE..#endif */
+#define PS_Method        0x020000    /* If &quot;::&quot; token has been seen */
+#define PS_Local         0x040000    /* If within #if LOCAL_INTERFACE..#endif */
+#define PS_Local2        0x080000    /* If &quot;LOCAL&quot; seen. */
+#define PS_Public        0x100000    /* If &quot;PUBLIC&quot; seen. */
+#define PS_Protected     0x200000    /* If &quot;PROTECTED&quot; seen. */
+#define PS_Private       0x400000    /* If &quot;PRIVATE&quot; seen. */
+#define PS_PPP           0x700000    /* If any of PUBLIC, PRIVATE, PROTECTED */
+
+/*
+** The following set of flags are ORed into the &quot;flags&quot; 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 &quot;&quot; or &lt;&gt; */
+  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 &quot;#undef INTERFACE&quot; part is a hack to work around a name collision
+** in MSVC 2008.
+*/
+const char zTopLine[] =
+  &quot;/* \aThis file was automatically generated.  Do not edit! */\n&quot;
+  &quot;#undef INTERFACE\n&quot;;
+#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,&quot;Assertion failed on line %d\n&quot;,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,&quot;Out of memory.  Can&#39;t allocate %d bytes.\n&quot;,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,
+        &quot;Out of memory.  Can&#39;t enlarge an allocation to %d bytes\n&quot;,nByte);
+      exit(1);
+    }
+  }
+  return p;
+}
+static char *StrDup(const char *zSrc, int nByte){
+  char *zDest;
+  if( nByte&lt;=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)==&#39;_&#39; || isalnum(X))
+
+/*
+** Routines for dealing with unbounded strings.
+*/
+static void StringInit(String *pStr){
+  pStr-&gt;nAlloc = 0;
+  pStr-&gt;nUsed = 0;
+  pStr-&gt;zText = 0;
+}
+static void StringReset(String *pStr){
+  SafeFree(pStr-&gt;zText);
+  StringInit(pStr);
+}
+static void StringAppend(String *pStr, const char *zText, int nByte){
+  if( nByte&lt;=0 ){
+    nByte = strlen(zText);
+  }
+  if( pStr-&gt;nUsed + nByte &gt;= pStr-&gt;nAlloc ){
+    if( pStr-&gt;nAlloc==0 ){
+      pStr-&gt;nAlloc = nByte + 100;
+      pStr-&gt;zText = SafeMalloc( pStr-&gt;nAlloc );
+    }else{
+      pStr-&gt;nAlloc = pStr-&gt;nAlloc*2 + nByte;
+      pStr-&gt;zText = SafeRealloc(pStr-&gt;zText, pStr-&gt;nAlloc);
+    }
+  }
+  strncpy(&amp;pStr-&gt;zText[pStr-&gt;nUsed],zText,nByte);
+  pStr-&gt;nUsed += nByte;
+  pStr-&gt;zText[pStr-&gt;nUsed] = 0;
+}
+#define StringGet(S) ((S)-&gt;zText?(S)-&gt;zText:&quot;&quot;)
+
+/*
+** 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&lt;=0 ){
+    n = strlen(z);
+  }
+  while( n-- ){
+    h = h ^ (h&lt;&lt;5) ^ *z++;
+  }
+  return h &amp; 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&lt;=0 ){
+    len = strlen(zName);
+  }
+  h = Hash(zName,len) % DECL_HASH_SIZE;
+  p = apTable[h];
+  while( p &amp;&amp; (strncmp(p-&gt;zName,zName,len)!=0 || p-&gt;zName[len]!=0) ){
+    p = p-&gt;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-&gt;zName,0) % DECL_HASH_SIZE;
+  pOther = apTable[h];
+  while( pOther &amp;&amp; strcmp(pDecl-&gt;zName,pOther-&gt;zName)!=0 ){
+    pOther = pOther-&gt;pSameHash;
+  }
+  if( pOther ){
+    pDecl-&gt;pSameName = pOther-&gt;pSameName;
+    pOther-&gt;pSameName = pDecl;
+  }else{
+    pDecl-&gt;pSameName = 0;
+    pDecl-&gt;pSameHash = apTable[h];
+    apTable[h] = pDecl;
+  }
+  pDecl-&gt;pNext = 0;
+  if( pDeclFirst==0 ){
+    pDeclFirst = pDeclLast = pDecl;
+  }else{
+    pDeclLast-&gt;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-&gt;pNext){
+    if( pIf-&gt;zCondition==0 || *pIf-&gt;zCondition==0 ) continue;
+    if( !hasIf ){
+      hasIf = 1;
+      StringInit(&amp;str);
+    }else{
+      StringAppend(&amp;str,&quot; &amp;&amp; &quot;,4);
+    }
+    StringAppend(&amp;str,pIf-&gt;zCondition,0);
+  }
+  if( hasIf ){
+    zResult = StrDup(StringGet(&amp;str),0);
+    StringReset(&amp;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-&gt;zName = (char*)&amp;pDecl[1];
+  sprintf(pDecl-&gt;zName,&quot;%.*s&quot;,nName,zName);
+  pDecl-&gt;zFile = zFilename;
+  pDecl-&gt;pInclude = includeList;
+  pDecl-&gt;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&lt;=0 ){
+    nId = strlen(zId);
+  }
+  h = Hash(zId,nId) % IDENT_HASH_SIZE;
+  for(pId = pTable-&gt;apTable[h]; pId; pId=pId-&gt;pCollide){
+    if( strncmp(zId,pId-&gt;zName,nId)==0 &amp;&amp; pId-&gt;zName[nId]==0 ){
+      /* printf(&quot;Already in table: %.*s\n&quot;,nId,zId); */
+      return 0;
+    }
+  }
+  pId = SafeMalloc( sizeof(Ident) + nId + 1 );
+  pId-&gt;zName = (char*)&amp;pId[1];
+  sprintf(pId-&gt;zName,&quot;%.*s&quot;,nId,zId);
+  pId-&gt;pNext = pTable-&gt;pList;
+  pTable-&gt;pList = pId;
+  pId-&gt;pCollide = pTable-&gt;apTable[h];
+  pTable-&gt;apTable[h] = pId;
+  /* printf(&quot;Add to table: %.*s\n&quot;,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&lt;=0 ){
+    nId = strlen(zId);
+  }
+  h = Hash(zId,nId) % IDENT_HASH_SIZE;
+  for(pId = pTable-&gt;apTable[h]; pId; pId=pId-&gt;pCollide){
+    if( strncmp(zId,pId-&gt;zName,nId)==0 &amp;&amp; pId-&gt;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-&gt;pList; pId; pId = pNext){
+    pNext = pId-&gt;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-&gt;pList; pId; pId = pId-&gt;pNext){
+    fprintf(pOut,&quot;%s\n&quot;,pId-&gt;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,&amp;sStat)!=0
+#ifndef WIN32
+    || !S_ISREG(sStat.st_mode)
+#endif
+  ){
+    return 0;
+  }
+  pIn = fopen(zFilename,&quot;r&quot;);
+  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,&quot;w&quot;);
+  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. &quot;..&quot; or &#39;.&#39; */
+#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 &quot;low-level token&quot; 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 &quot;..&quot; or &#39;..&#39; */
+  int nErr = 0;    /* Number of errors seen */
+
+  z = pIn-&gt;z;
+  i = pIn-&gt;i;
+  pToken-&gt;nLine = pIn-&gt;nLine;
+  pToken-&gt;zText = &amp;z[i];
+  switch( z[i] ){
+    case 0:
+      pToken-&gt;eType = TT_EOF;
+      pToken-&gt;nText = 0;
+      break;
+
+    case &#39;#&#39;:
+      if( i==0 || z[i-1]==&#39;\n&#39; || (i&gt;1 &amp;&amp; z[i-1]==&#39;\r&#39; &amp;&amp; z[i-2]==&#39;\n&#39;)){
+        /* We found a preprocessor statement */
+        pToken-&gt;eType = TT_Preprocessor;
+        i++;
+        while( z[i]!=0 &amp;&amp; z[i]!=&#39;\n&#39; ){
+          if( z[i]==&#39;\\&#39; ){
+            i++;
+            if( z[i]==&#39;\n&#39; ) pIn-&gt;nLine++;
+          }
+          i++;
+        }
+        pToken-&gt;nText = i - pIn-&gt;i;
+      }else{
+        /* Just an operator */
+        pToken-&gt;eType = TT_Other;
+        pToken-&gt;nText = 1;
+      }
+      break;
+
+    case &#39; &#39;:
+    case &#39;\t&#39;:
+    case &#39;\r&#39;:
+    case &#39;\f&#39;:
+    case &#39;\n&#39;:
+      while( isspace(z[i]) ){
+        if( z[i]==&#39;\n&#39; ) pIn-&gt;nLine++;
+        i++;
+      }
+      pToken-&gt;eType = TT_Space;
+      pToken-&gt;nText = i - pIn-&gt;i;
+      break;
+
+    case &#39;\\&#39;:
+      pToken-&gt;nText = 2;
+      pToken-&gt;eType = TT_Other;
+      if( z[i+1]==&#39;\n&#39; ){
+        pIn-&gt;nLine++;
+        pToken-&gt;eType = TT_Space;
+      }else if( z[i+1]==0 ){
+        pToken-&gt;nText = 1;
+      }
+      break;
+
+    case &#39;\&#39;&#39;:
+    case &#39;\&quot;&#39;:
+      cStart = z[i];
+      startLine = pIn-&gt;nLine;
+      do{
+        i++;
+        c = z[i];
+        if( c==&#39;\n&#39; ){
+          if( !nlisc ){
+            fprintf(stderr,
+              &quot;%s:%d: (warning) Newline in string or character literal.\n&quot;,
+              zFilename, pIn-&gt;nLine);
+            nlisc = 1;
+          }
+          pIn-&gt;nLine++;
+        }
+        if( c==&#39;\\&#39; ){
+          i++;
+          c = z[i];
+          if( c==&#39;\n&#39; ){
+            pIn-&gt;nLine++;
+          }
+        }else if( c==cStart ){
+          i++;
+          c = 0;
+        }else if( c==0 ){
+          fprintf(stderr, &quot;%s:%d: Unterminated string or character literal.\n&quot;,
+             zFilename, startLine);
+          nErr++;
+        }
+      }while( c );
+      pToken-&gt;eType = TT_String;
+      pToken-&gt;nText = i - pIn-&gt;i;
+      break;
+
+    case &#39;/&#39;:
+      if( z[i+1]==&#39;/&#39; ){
+        /* C++ style comment */
+        while( z[i] &amp;&amp; z[i]!=&#39;\n&#39; ){ i++; }
+        pToken-&gt;eType = TT_Comment;
+        pToken-&gt;nText = i - pIn-&gt;i;
+      }else if( z[i+1]==&#39;*&#39; ){
+        /* C style comment */
+        int isBlockComment = i==0 || z[i-1]==&#39;\n&#39;;
+        i += 2;
+        startLine = pIn-&gt;nLine;
+        while( z[i] &amp;&amp; (z[i]!=&#39;*&#39; || z[i+1]!=&#39;/&#39;) ){
+          if( z[i]==&#39;\n&#39; ){
+            pIn-&gt;nLine++;
+            if( isBlockComment ){
+              if( z[i+1]==&#39;*&#39; || z[i+2]==&#39;*&#39; ){
+                 isBlockComment = 2;
+              }else{
+                 isBlockComment = 0;
+              }
+            }
+          }
+          i++;
+        }
+        if( z[i] ){
+          i += 2;
+        }else{
+          isBlockComment = 0;
+          fprintf(stderr,&quot;%s:%d: Unterminated comment\n&quot;,
+            zFilename, startLine);
+          nErr++;
+        }
+        pToken-&gt;eType = isBlockComment==2 ? TT_BlockComment : TT_Comment;
+        pToken-&gt;nText = i - pIn-&gt;i;
+      }else{
+        /* A divide operator */
+        pToken-&gt;eType = TT_Other;
+        pToken-&gt;nText = 1 + (z[i+1]==&#39;+&#39;);
+      }
+      break;
+
+    case &#39;0&#39;:
+      if( z[i+1]==&#39;x&#39; || z[i+1]==&#39;X&#39; ){
+        /* A hex constant */
+        i += 2;
+        while( isxdigit(z[i]) ){ i++; }
+      }else{
+        /* An octal constant */
+        while( isdigit(z[i]) ){ i++; }
+      }
+      pToken-&gt;eType = TT_Number;
+      pToken-&gt;nText = i - pIn-&gt;i;
+      break;
+
+    case &#39;1&#39;: case &#39;2&#39;: case &#39;3&#39;: case &#39;4&#39;:
+    case &#39;5&#39;: case &#39;6&#39;: case &#39;7&#39;: case &#39;8&#39;: case &#39;9&#39;:
+      while( isdigit(z[i]) ){ i++; }
+      if( (c=z[i])==&#39;.&#39; ){
+         i++;
+         while( isdigit(z[i]) ){ i++; }
+         c = z[i];
+         if( c==&#39;e&#39; || c==&#39;E&#39; ){
+           i++;
+           if( ((c=z[i])==&#39;+&#39; || c==&#39;-&#39;) &amp;&amp; isdigit(z[i+1]) ){ i++; }
+           while( isdigit(z[i]) ){ i++; }
+           c = z[i];
+         }
+         if( c==&#39;f&#39; || c==&#39;F&#39; || c==&#39;l&#39; || c==&#39;L&#39; ){ i++; }
+      }else if( c==&#39;e&#39; || c==&#39;E&#39; ){
+         i++;
+         if( ((c=z[i])==&#39;+&#39; || c==&#39;-&#39;) &amp;&amp; isdigit(z[i+1]) ){ i++; }
+         while( isdigit(z[i]) ){ i++; }
+      }else if( c==&#39;L&#39; || c==&#39;l&#39; ){
+         i++;
+         c = z[i];
+         if( c==&#39;u&#39; || c==&#39;U&#39; ){ i++; }
+      }else if( c==&#39;u&#39; || c==&#39;U&#39; ){
+         i++;
+         c = z[i];
+         if( c==&#39;l&#39; || c==&#39;L&#39; ){ i++; }
+      }
+      pToken-&gt;eType = TT_Number;
+      pToken-&gt;nText = i - pIn-&gt;i;
+      break;
+
+    case &#39;a&#39;: case &#39;b&#39;: case &#39;c&#39;: case &#39;d&#39;: case &#39;e&#39;: case &#39;f&#39;: case &#39;g&#39;:
+    case &#39;h&#39;: case &#39;i&#39;: case &#39;j&#39;: case &#39;k&#39;: case &#39;l&#39;: case &#39;m&#39;: case &#39;n&#39;:
+    case &#39;o&#39;: case &#39;p&#39;: case &#39;q&#39;: case &#39;r&#39;: case &#39;s&#39;: case &#39;t&#39;: case &#39;u&#39;:
+    case &#39;v&#39;: case &#39;w&#39;: case &#39;x&#39;: case &#39;y&#39;: case &#39;z&#39;: case &#39;A&#39;: case &#39;B&#39;:
+    case &#39;C&#39;: case &#39;D&#39;: case &#39;E&#39;: case &#39;F&#39;: case &#39;G&#39;: case &#39;H&#39;: case &#39;I&#39;:
+    case &#39;J&#39;: case &#39;K&#39;: case &#39;L&#39;: case &#39;M&#39;: case &#39;N&#39;: case &#39;O&#39;: case &#39;P&#39;:
+    case &#39;Q&#39;: case &#39;R&#39;: case &#39;S&#39;: case &#39;T&#39;: case &#39;U&#39;: case &#39;V&#39;: case &#39;W&#39;:
+    case &#39;X&#39;: case &#39;Y&#39;: case &#39;Z&#39;: case &#39;_&#39;:
+      while( isalnum(z[i]) || z[i]==&#39;_&#39; ){ i++; };
+      pToken-&gt;eType = TT_Id;
+      pToken-&gt;nText = i - pIn-&gt;i;
+      break;
+
+    case &#39;:&#39;:
+      pToken-&gt;eType = TT_Other;
+      pToken-&gt;nText = 1 + (z[i+1]==&#39;:&#39;);
+      break;
+
+    case &#39;=&#39;:
+    case &#39;&lt;&#39;:
+    case &#39;&gt;&#39;:
+    case &#39;+&#39;:
+    case &#39;-&#39;:
+    case &#39;*&#39;:
+    case &#39;%&#39;:
+    case &#39;^&#39;:
+    case &#39;&amp;&#39;:
+    case &#39;|&#39;:
+      pToken-&gt;eType = TT_Other;
+      pToken-&gt;nText = 1 + (z[i+1]==&#39;=&#39;);
+      break;
+
+    default:
+      pToken-&gt;eType = TT_Other;
+      pToken-&gt;nText = 1;
+      break;
+  }
+  pIn-&gt;i += pToken-&gt;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 &quot;#if 0&quot; and &quot;#endif&quot;.
+**
+** This routine returns the number of errors encountered.  An error
+** is an unterminated token or unmatched &quot;#if 0&quot;.
+**
+** 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-&gt;nLine;
+  while( 1 ){
+    nErr += GetToken(pIn,pToken);
+    /* printf(&quot;%04d: Type=%d nIf=%d [%.*s]\n&quot;,
+       pToken-&gt;nLine,pToken-&gt;eType,nIf,pToken-&gt;nText,
+       pToken-&gt;eType!=TT_Space ? pToken-&gt;zText : &quot;&lt;space&gt;&quot;); */
+    pToken-&gt;pComment = blockComment;
+    switch( pToken-&gt;eType ){
+      case TT_Comment:          /*0123456789 12345678 */
+       if( strncmp(pToken-&gt;zText, &quot;/*MAKEHEADERS-STOP&quot;, 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,&quot;%s:%d: Unterminated \&quot;#if\&quot;\n&quot;,
+             zFilename, startLine);
+          nErr++;
+        }
+        return nErr;
+
+      case TT_Preprocessor:
+        z = &amp;pToken-&gt;zText[1];
+        while( *z==&#39; &#39; || *z==&#39;\t&#39; ) z++;
+        if( sscanf(z,&quot;if %d&quot;,&amp;value)==1 &amp;&amp; value==0 ){
+          nIf++;
+          inZero = 1;
+        }else if( inZero ){
+          if( strncmp(z,&quot;if&quot;,2)==0 ){
+            nIf++;
+          }else if( strncmp(z,&quot;endif&quot;,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-&gt;zText;
+  sIn.i = 1;
+  sIn.nLine = 1;
+  while( go &amp;&amp; sIn.i &lt; pToken-&gt;nText ){
+    GetToken(&amp;sIn,&amp;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-&gt;eType ){
+    case TT_Id:
+      if( pTable!=0 ){
+        IdentTableInsert(pTable,pToken-&gt;zText,pToken-&gt;nText);
+      }
+      return nErr;
+
+    case TT_Preprocessor:
+      if( pTable!=0 ){
+        FindIdentifiersInMacro(pToken,pTable);
+      }
+      return nErr;
+
+    case TT_Other:
+      if( pToken-&gt;zText[0]==&#39;{&#39; ) break;
+      return nErr;
+
+    default:
+      return nErr;
+  }
+
+  iStart = pIn-&gt;i;
+  zStart = pToken-&gt;zText;
+  nLine = pToken-&gt;nLine;
+  nBrace = 1;
+  while( nBrace ){
+    nErr += GetNonspaceToken(pIn,pToken);
+    /* printf(&quot;%04d: nBrace=%d [%.*s]\n&quot;,pToken-&gt;nLine,nBrace,
+       pToken-&gt;nText,pToken-&gt;zText); */
+    switch( pToken-&gt;eType ){
+      case TT_EOF:
+        fprintf(stderr,&quot;%s:%d: Unterminated \&quot;{\&quot;\n&quot;,
+           zFilename, nLine);
+        nErr++;
+        pToken-&gt;eType = TT_Error;
+        return nErr;
+
+      case TT_Id:
+        if( pTable ){
+          IdentTableInsert(pTable,pToken-&gt;zText,pToken-&gt;nText);
+        }
+        break;
+
+      case TT_Preprocessor:
+        if( pTable!=0 ){
+          FindIdentifiersInMacro(pToken,pTable);
+        }
+        break;
+
+      case TT_Other:
+        if( (c = pToken-&gt;zText[0])==&#39;{&#39; ){
+          nBrace++;
+        }else if( c==&#39;}&#39; ){
+          nBrace--;
+        }
+        break;
+
+      default:
+        break;
+    }
+  }
+  pToken-&gt;eType = TT_Braces;
+  pToken-&gt;nText = 1 + pIn-&gt;i - iStart;
+  pToken-&gt;zText = zStart;
+  pToken-&gt;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-&gt;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(&amp;sIn,pNew,pTable);
+    debug3(TOKENIZER, &quot;Token on line %d: [%.*s]\n&quot;,
+       pNew-&gt;nLine, pNew-&gt;nText&lt;50 ? pNew-&gt;nText : 50, pNew-&gt;zText);
+    if( pFirst==0 ){
+      pFirst = pLast = pNew;
+      pNew-&gt;pPrev = 0;
+    }else{
+      pLast-&gt;pNext = pNew;
+      pNew-&gt;pPrev = pLast;
+      pLast = pNew;
+    }
+    if( pNew-&gt;eType==TT_EOF ) break;
+  }
+  if( pLast ) pLast-&gt;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,&quot;Usage: %s filename\n&quot;,*argv);
+    exit(1);
+  }
+  memset(&amp;sTable,0,sizeof(sTable));
+  zFile = ReadFile(argv[1]);
+  if( zFile==0 ){
+    fprintf(stderr,&quot;Can&#39;t read file \&quot;%s\&quot;\n&quot;,argv[1]);
+    exit(1);
+  }
+  pList = TokenizeFile(zFile,&amp;sTable);
+  for(p=pList; p; p=p-&gt;pNext){
+    int j;
+    switch( p-&gt;eType ){
+      case TT_Space:
+        printf(&quot;%4d: Space\n&quot;,p-&gt;nLine);
+        break;
+      case TT_Id:
+        printf(&quot;%4d: Id           %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
+        break;
+      case TT_Preprocessor:
+        printf(&quot;%4d: Preprocessor %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
+        break;
+      case TT_Comment:
+        printf(&quot;%4d: Comment\n&quot;,p-&gt;nLine);
+        break;
+      case TT_BlockComment:
+        printf(&quot;%4d: Block Comment\n&quot;,p-&gt;nLine);
+        break;
+      case TT_Number:
+        printf(&quot;%4d: Number       %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
+        break;
+      case TT_String:
+        printf(&quot;%4d: String       %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
+        break;
+      case TT_Other:
+        printf(&quot;%4d: Other        %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
+        break;
+      case TT_Braces:
+        for(j=0; j&lt;p-&gt;nText &amp;&amp; j&lt;30 &amp;&amp; p-&gt;zText[j]!=&#39;\n&#39;; j++){}
+        printf(&quot;%4d: Braces       %.*s...}\n&quot;,p-&gt;nLine,j,p-&gt;zText);
+        break;
+      case TT_EOF:
+        printf(&quot;%4d: End of file\n&quot;,p-&gt;nLine);
+        break;
+      default:
+        printf(&quot;%4d: type %d\n&quot;,p-&gt;nLine,p-&gt;eType);
+        break;
+    }
+  }
+  FreeTokenList(pList);
+  SafeFree(zFile);
+  IdentTablePrint(&amp;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-&gt;pNext;
+  while( pFirst!=pLast ){
+    switch( pFirst-&gt;eType ){
+      case TT_Preprocessor:
+        printf(&quot;\n%.*s\n&quot;,pFirst-&gt;nText,pFirst-&gt;zText);
+        needSpace = 0;
+        break;
+
+      case TT_Id:
+      case TT_Number:
+        printf(&quot;%s%.*s&quot;, needSpace ? &quot; &quot; : &quot;&quot;, pFirst-&gt;nText, pFirst-&gt;zText);
+        needSpace = 1;
+        break;
+
+      default:
+        c = pFirst-&gt;zText[0];
+        printf(&quot;%s%.*s&quot;,
+          (needSpace &amp;&amp; (c==&#39;*&#39; || c==&#39;{&#39;)) ? &quot; &quot; : &quot;&quot;,
+          pFirst-&gt;nText, pFirst-&gt;zText);
+        needSpace = pFirst-&gt;zText[0]==&#39;,&#39;;
+        break;
+    }
+    pFirst = pFirst-&gt;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(&amp;str);
+  pLast = pLast-&gt;pNext;
+  while( pFirst!=pLast ){
+    if( pFirst==pSkip ){ iSkip = nSkip; }
+    if( iSkip&gt;0 ){
+      iSkip--;
+      pFirst=pFirst-&gt;pNext;
+      continue;
+    }
+    switch( pFirst-&gt;eType ){
+      case TT_Preprocessor:
+        StringAppend(&amp;str,&quot;\n&quot;,1);
+        StringAppend(&amp;str,pFirst-&gt;zText,pFirst-&gt;nText);
+        StringAppend(&amp;str,&quot;\n&quot;,1);
+        needSpace = 0;
+        break;
+
+      case TT_Id:
+        switch( pFirst-&gt;zText[0] ){
+          case &#39;E&#39;:
+            if( pFirst-&gt;nText==6 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;EXPORT&quot;,6)==0 ){
+              skipOne = 1;
+            }
+            break;
+          case &#39;P&#39;:
+            switch( pFirst-&gt;nText ){
+              case 6:  skipOne = !strncmp(pFirst-&gt;zText,&quot;PUBLIC&quot;, 6);    break;
+              case 7:  skipOne = !strncmp(pFirst-&gt;zText,&quot;PRIVATE&quot;,7);    break;
+              case 9:  skipOne = !strncmp(pFirst-&gt;zText,&quot;PROTECTED&quot;,9);  break;
+              default: break;
+            }
+            break;
+          default:
+            break;
+        }
+        if( skipOne ){
+          pFirst = pFirst-&gt;pNext;
+          continue;
+        }
+        /* Fall thru to the next case */
+      case TT_Number:
+        if( needSpace ){
+          StringAppend(&amp;str,&quot; &quot;,1);
+        }
+        StringAppend(&amp;str,pFirst-&gt;zText,pFirst-&gt;nText);
+        needSpace = 1;
+        break;
+
+      default:
+        c = pFirst-&gt;zText[0];
+        if( needSpace &amp;&amp; (c==&#39;*&#39; || c==&#39;{&#39;) ){
+          StringAppend(&amp;str,&quot; &quot;,1);
+        }
+        StringAppend(&amp;str,pFirst-&gt;zText,pFirst-&gt;nText);
+        /* needSpace = pFirst-&gt;zText[0]==&#39;,&#39;; */
+        needSpace = 0;
+        break;
+    }
+    pFirst = pFirst-&gt;pNext;
+  }
+  if( zTerm &amp;&amp; *zTerm ){
+    StringAppend(&amp;str,zTerm,strlen(zTerm));
+  }
+  zReturn = StrDup(StringGet(&amp;str),0);
+  StringReset(&amp;str);
+  return zReturn;
+}
+
+/*
+** This routine is called when we see one of the keywords &quot;struct&quot;,
+** &quot;enum&quot;, &quot;union&quot; or &quot;class&quot;.  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&#39;t also a variable definition)
+** then set *pReset to &#39;;&#39;.  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-&gt;pNext==0 || pList-&gt;pNext-&gt;eType!=TT_Id ){
+    return 0;
+  }
+  pName = pList-&gt;pNext;
+
+  /* Catch the case of &quot;struct Foo;&quot; and skip it. */
+  if( pName-&gt;pNext &amp;&amp; pName-&gt;pNext-&gt;zText[0]==&#39;;&#39; ){
+    *pReset = &#39;;&#39;;
+    return 0;
+  }
+
+  for(pEnd=pName-&gt;pNext; pEnd &amp;&amp; pEnd-&gt;eType!=TT_Braces; pEnd=pEnd-&gt;pNext){
+    switch( pEnd-&gt;zText[0] ){
+      case &#39;(&#39;:
+      case &#39;)&#39;:
+      case &#39;*&#39;:
+      case &#39;[&#39;:
+      case &#39;=&#39;:
+      case &#39;;&#39;:
+        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-&gt;pNext==0 || pEnd-&gt;pNext-&gt;zText[0]==&#39;;&#39; ){
+    *pReset = &#39;;&#39;;
+    need_to_collapse = 0;
+  }else{
+    need_to_collapse = 1;
+  }
+
+  if( proto_static==0 &amp;&amp; (flags &amp; (PS_Local|PS_Export|PS_Interface))==0 ){
+    /* Ignore these objects unless they are explicitly declared as interface,
+    ** or unless the &quot;-local&quot; command line option was specified. */
+    *pReset = &#39;;&#39;;
+    return 0;
+  }
+
+#ifdef DEBUG
+  if( debugMask &amp; PARSER ){
+    printf(&quot;**** Found type: %.*s %.*s...\n&quot;,
+      pList-&gt;nText, pList-&gt;zText, pName-&gt;nText, pName-&gt;zText);
+    PrintTokens(pList,pEnd);
+    printf(&quot;;\n&quot;);
+  }
+#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-&gt;zText ){
+    case &#39;c&#39;:  type = TY_Class;        break;
+    case &#39;s&#39;:  type = TY_Structure;    break;
+    case &#39;e&#39;:  type = TY_Enumeration;  break;
+    case &#39;u&#39;:  type = TY_Union;        break;
+    default:   /* Can&#39;t Happen */      break;
+  }
+  if( type!=TY_Class ){
+    pDecl = 0;
+  }else{
+    pDecl = FindDecl(pName-&gt;zText, pName-&gt;nText);
+    if( pDecl &amp;&amp; (pDecl-&gt;flags &amp; type)!=type ) pDecl = 0;
+  }
+  if( pDecl==0 ){
+    pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
+  }
+  if( (flags &amp; PS_Static) || !(flags &amp; (PS_Interface|PS_Export)) ){
+    DeclSetProperty(pDecl,DP_Local);
+  }
+  DeclSetProperty(pDecl,type);
+
+  /* The object has a full declaration only if it is contained within
+  ** &quot;#if INTERFACE...#endif&quot; or &quot;#if EXPORT_INTERFACE...#endif&quot; or
+  ** &quot;#if LOCAL_INTERFACE...#endif&quot;.  Otherwise, we only give it a
+  ** forward declaration.
+  */
+  if( flags &amp; (PS_Local | PS_Export | PS_Interface)  ){
+    pDecl-&gt;zDecl = TokensToString(pList,pEnd,&quot;;\n&quot;,0,0);
+  }else{
+    pDecl-&gt;zDecl = 0;
+  }
+  pDecl-&gt;pComment = pList-&gt;pComment;
+  StringInit(&amp;str);
+  StringAppend(&amp;str,&quot;typedef &quot;,0);
+  StringAppend(&amp;str,pList-&gt;zText,pList-&gt;nText);
+  StringAppend(&amp;str,&quot; &quot;,0);
+  StringAppend(&amp;str,pName-&gt;zText,pName-&gt;nText);
+  StringAppend(&amp;str,&quot; &quot;,0);
+  StringAppend(&amp;str,pName-&gt;zText,pName-&gt;nText);
+  StringAppend(&amp;str,&quot;;\n&quot;,2);
+  pDecl-&gt;zFwd = StrDup(StringGet(&amp;str),0);
+  StringReset(&amp;str);
+  StringInit(&amp;str);
+  StringAppend(&amp;str,pList-&gt;zText,pList-&gt;nText);
+  StringAppend(&amp;str,&quot; &quot;,0);
+  StringAppend(&amp;str,pName-&gt;zText,pName-&gt;nText);
+  StringAppend(&amp;str,&quot;;\n&quot;,2);
+  pDecl-&gt;zFwdCpp = StrDup(StringGet(&amp;str),0);
+  StringReset(&amp;str);
+  if( flags &amp; PS_Export ){
+    DeclSetProperty(pDecl,DP_Export);
+  }else if( flags &amp; PS_Local ){
+    DeclSetProperty(pDecl,DP_Local);
+  }
+
+  /* Here&#39;s something weird.  ANSI-C doesn&#39;t allow a forward declaration
+  ** of an enumeration.  So we have to build the typedef into the
+  ** definition.
+  */
+  if( pDecl-&gt;zDecl &amp;&amp; DeclHasProperty(pDecl, TY_Enumeration) ){
+    StringInit(&amp;str);
+    StringAppend(&amp;str,pDecl-&gt;zDecl,0);
+    StringAppend(&amp;str,pDecl-&gt;zFwd,0);
+    SafeFree(pDecl-&gt;zDecl);
+    SafeFree(pDecl-&gt;zFwd);
+    pDecl-&gt;zFwd = 0;
+    pDecl-&gt;zDecl = StrDup(StringGet(&amp;str),0);
+    StringReset(&amp;str);
+  }
+
+  if( pName-&gt;pNext-&gt;zText[0]==&#39;:&#39; ){
+    DeclSetProperty(pDecl,DP_Cplusplus);
+  }
+  if( pName-&gt;nText==5 &amp;&amp; strncmp(pName-&gt;zText,&quot;class&quot;,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-&gt;pPrev;
+      pPrev-&gt;pNext = pEnd-&gt;pNext;
+      pEnd-&gt;pNext-&gt;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 &quot;[&quot;, or
+**
+**     2.  The first identifier that is followed by a &quot;(&quot; where the
+**         &quot;(&quot; is followed by another identifier, or
+**
+**     3.  The first identifier followed by &quot;::&quot;, or
+**
+**     4.  If none of the above, then the last identifier.
+**
+**   In all of the above, certain reserved words (like &quot;char&quot;) 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-&gt;pNext;
+  for(p=pFirst; p &amp;&amp; p!=pLast; p=p-&gt;pNext){
+    if( p-&gt;eType==TT_Id ){
+      static IdentTable sReserved;
+      static int isInit = 0;
+      static const char *aWords[] = { &quot;char&quot;, &quot;class&quot;,
+       &quot;const&quot;, &quot;double&quot;, &quot;enum&quot;, &quot;extern&quot;, &quot;EXPORT&quot;, &quot;ET_PROC&quot;,
+       &quot;float&quot;, &quot;int&quot;, &quot;long&quot;,
+       &quot;PRIVATE&quot;, &quot;PROTECTED&quot;, &quot;PUBLIC&quot;,
+       &quot;register&quot;, &quot;static&quot;, &quot;struct&quot;, &quot;sizeof&quot;, &quot;signed&quot;, &quot;typedef&quot;,
+       &quot;union&quot;, &quot;volatile&quot;, &quot;virtual&quot;, &quot;void&quot;, };
+
+      if( !isInit ){
+        int i;
+        for(i=0; i&lt;sizeof(aWords)/sizeof(aWords[0]); i++){
+          IdentTableInsert(&amp;sReserved,aWords[i],0);
+        }
+        isInit = 1;
+      }
+      if( !IdentTableTest(&amp;sReserved,p-&gt;zText,p-&gt;nText) ){
+        pName = p;
+      }
+    }else if( p==pFirst ){
+      continue;
+    }else if( (c=p-&gt;zText[0])==&#39;[&#39; &amp;&amp; pName ){
+      break;
+    }else if( c==&#39;(&#39; &amp;&amp; p-&gt;pNext &amp;&amp; p-&gt;pNext-&gt;eType==TT_Id &amp;&amp; pName ){
+      break;
+    }else if( c==&#39;:&#39; &amp;&amp; p-&gt;zText[1]==&#39;:&#39; &amp;&amp; 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-&gt;pPrev;
+  while( pFirst-&gt;zText[0]==&#39;P&#39; ){
+    int rc = 1;
+    switch( pFirst-&gt;nText ){
+      case 6:  rc = strncmp(pFirst-&gt;zText,&quot;PUBLIC&quot;,6); break;
+      case 7:  rc = strncmp(pFirst-&gt;zText,&quot;PRIVATE&quot;,7); break;
+      case 9:  rc = strncmp(pFirst-&gt;zText,&quot;PROTECTED&quot;,9); break;
+      default:  break;
+    }
+    if( rc ) break;
+    pFirst = pFirst-&gt;pNext;
+  }
+  pClass = FindDeclName(pFirst,pLast);
+  if( pClass==0 ){
+    fprintf(stderr,&quot;%s:%d: Unable to find the class name for this method\n&quot;,
+       zFilename, pFirst-&gt;nLine);
+    return 1;
+  }
+  pDecl = FindDecl(pClass-&gt;zText, pClass-&gt;nText);
+  if( pDecl==0 || (pDecl-&gt;flags &amp; TY_Class)!=TY_Class ){
+    pDecl = CreateDecl(pClass-&gt;zText, pClass-&gt;nText);
+    DeclSetProperty(pDecl, TY_Class);
+  }
+  StringInit(&amp;str);
+  if( pDecl-&gt;zExtra ){
+    StringAppend(&amp;str, pDecl-&gt;zExtra, 0);
+    SafeFree(pDecl-&gt;zExtra);
+    pDecl-&gt;zExtra = 0;
+  }
+  type = flags &amp; PS_PPP;
+  if( pDecl-&gt;extraType!=type ){
+    if( type &amp; PS_Public ){
+      StringAppend(&amp;str, &quot;public:\n&quot;, 0);
+      pDecl-&gt;extraType = PS_Public;
+    }else if( type &amp; PS_Protected ){
+      StringAppend(&amp;str, &quot;protected:\n&quot;, 0);
+      pDecl-&gt;extraType = PS_Protected;
+    }else if( type &amp; PS_Private ){
+      StringAppend(&amp;str, &quot;private:\n&quot;, 0);
+      pDecl-&gt;extraType = PS_Private;
+    }
+  }
+  StringAppend(&amp;str, &quot;  &quot;, 0);
+  zDecl = TokensToString(pFirst, pLast, &quot;;\n&quot;, pClass, 2);
+  StringAppend(&amp;str, zDecl, 0);
+  SafeFree(zDecl);
+  pDecl-&gt;zExtra = StrDup(StringGet(&amp;str), 0);
+  StringReset(&amp;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 &amp; PS_Method ){
+    if( flags &amp; PS_PPP ){
+      return ProcessMethodDef(pFirst, pLast, flags);
+    }else{
+      return 0;
+    }
+  }
+  if( (flags &amp; PS_Static)!=0 &amp;&amp; !proto_static ){
+    return 0;
+  }
+  pCode = pLast;
+  while( pLast &amp;&amp; pLast!=pFirst &amp;&amp; pLast-&gt;zText[0]!=&#39;)&#39; ){
+    pLast = pLast-&gt;pPrev;
+  }
+  if( pLast==0 || pLast==pFirst || pFirst-&gt;pNext==pLast ){
+    fprintf(stderr,&quot;%s:%d: Unrecognized syntax.\n&quot;,
+      zFilename, pFirst-&gt;nLine);
+    return 1;
+  }
+  if( flags &amp; (PS_Interface|PS_Export|PS_Local) ){
+    fprintf(stderr,&quot;%s:%d: Missing \&quot;inline\&quot; on function or procedure.\n&quot;,
+      zFilename, pFirst-&gt;nLine);
+    return 1;
+  }
+  pName = FindDeclName(pFirst,pLast);
+  if( pName==0 ){
+    fprintf(stderr,&quot;%s:%d: Malformed function or procedure definition.\n&quot;,
+      zFilename, pFirst-&gt;nLine);
+    return 1;
+  }
+
+  /*
+  ** At this point we&#39;ve isolated a procedure declaration between pFirst
+  ** and pLast with the name pName.
+  */
+#ifdef DEBUG
+  if( debugMask &amp; PARSER ){
+    printf(&quot;**** Found routine: %.*s on line %d...\n&quot;, pName-&gt;nText,
+       pName-&gt;zText, pFirst-&gt;nLine);
+    PrintTokens(pFirst,pLast);
+    printf(&quot;;\n&quot;);
+  }
+#endif
+  pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
+  pDecl-&gt;pComment = pFirst-&gt;pComment;
+  if( pCode &amp;&amp; pCode-&gt;eType==TT_Braces ){
+    pDecl-&gt;tokenCode = *pCode;
+  }
+  DeclSetProperty(pDecl,TY_Subroutine);
+  pDecl-&gt;zDecl = TokensToString(pFirst,pLast,&quot;;\n&quot;,0,0);
+  if( (flags &amp; (PS_Static|PS_Local2))!=0 ){
+    DeclSetProperty(pDecl,DP_Local);
+  }else if( (flags &amp; (PS_Export2))!=0 ){
+    DeclSetProperty(pDecl,DP_Export);
+  }
+
+  if( flags &amp; DP_Cplusplus ){
+    DeclSetProperty(pDecl,DP_Cplusplus);
+  }else{
+    DeclSetProperty(pDecl,DP_ExternCReqd);
+  }
+
+  return 0;
+}
+
+/*
+** This routine is called whenever we see the &quot;inline&quot; 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-&gt;pNext){
+    if( pEnd-&gt;zText[0]==&#39;{&#39; || pEnd-&gt;zText[0]==&#39;;&#39; ){
+      *pReset = pEnd-&gt;zText[0];
+      break;
+    }
+  }
+  if( pEnd==0 ){
+    *pReset = &#39;;&#39;;
+    fprintf(stderr,&quot;%s:%d: incomplete inline procedure definition\n&quot;,
+      zFilename, pFirst-&gt;nLine);
+    return 1;
+  }
+  pName = FindDeclName(pFirst,pEnd);
+  if( pName==0 ){
+    fprintf(stderr,&quot;%s:%d: malformed inline procedure definition\n&quot;,
+      zFilename, pFirst-&gt;nLine);
+    return 1;
+  }
+
+#ifdef DEBUG
+  if( debugMask &amp; PARSER ){
+    printf(&quot;**** Found inline routine: %.*s on line %d...\n&quot;,
+       pName-&gt;nText, pName-&gt;zText, pFirst-&gt;nLine);
+    PrintTokens(pFirst,pEnd);
+    printf(&quot;\n&quot;);
+  }
+#endif
+  pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
+  pDecl-&gt;pComment = pFirst-&gt;pComment;
+  DeclSetProperty(pDecl,TY_Subroutine);
+  pDecl-&gt;zDecl = TokensToString(pFirst,pEnd,&quot;;\n&quot;,0,0);
+  if( (flags &amp; (PS_Static|PS_Local|PS_Local2)) ){
+    DeclSetProperty(pDecl,DP_Local);
+  }else if( flags &amp; (PS_Export|PS_Export2) ){
+    DeclSetProperty(pDecl,DP_Export);
+  }
+
+  if( flags &amp; 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 &#39;;&#39; or
+** a &#39;=&#39;.  If it is &#39;=&#39;, then assume we have a variable definition.
+**
+** If pEnd is &#39;;&#39;, then the determination is more difficult.  We have
+** to search for an occurrence of an ID followed immediately by &#39;(&#39;.
+** If found, we have a prototype.  Otherwise we are dealing with a
+** variable definition.
+*/
+static int isVariableDef(Token *pFirst, Token *pEnd){
+  if( pEnd &amp;&amp; pEnd-&gt;zText[0]==&#39;=&#39; &amp;&amp;
+    (pEnd-&gt;pPrev-&gt;nText!=8 || strncmp(pEnd-&gt;pPrev-&gt;zText,&quot;operator&quot;,8)!=0)
+  ){
+    return 1;
+  }
+  while( pFirst &amp;&amp; pFirst!=pEnd &amp;&amp; pFirst-&gt;pNext &amp;&amp; pFirst-&gt;pNext!=pEnd ){
+    if( pFirst-&gt;eType==TT_Id &amp;&amp; pFirst-&gt;pNext-&gt;zText[0]==&#39;(&#39; ){
+      return 0;
+    }
+    pFirst = pFirst-&gt;pNext;
+  }
+  return 1;
+}
+
+/*
+** Return TRUE if pFirst is the first token of a static assert.
+*/
+static int isStaticAssert(Token *pFirst){
+  if( (pFirst-&gt;nText==13 &amp;&amp; strncmp(pFirst-&gt;zText, &quot;static_assert&quot;, 13)==0)
+   || (pFirst-&gt;nText==14 &amp;&amp; strncmp(pFirst-&gt;zText, &quot;_Static_assert&quot;, 14)==0)
+  ){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+
+/*
+** This routine is called whenever we encounter a &quot;;&quot; or &quot;=&quot;.  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 &amp; PS_Typedef ){
+    if( (flags &amp; (PS_Export2|PS_Local2))!=0 ){
+      fprintf(stderr,&quot;%s:%d: \&quot;EXPORT\&quot; or \&quot;LOCAL\&quot; ignored before typedef.\n&quot;,
+        zFilename, pFirst-&gt;nLine);
+      nErr++;
+    }
+    if( (flags &amp; (PS_Interface|PS_Export|PS_Local|DP_Cplusplus))==0 ){
+      /* It is illegal to duplicate a typedef in C (but OK in C++).
+      ** So don&#39;t record typedefs that aren&#39;t within a C++ file or
+      ** within #if INTERFACE..#endif */
+      return nErr;
+    }
+    if( (flags &amp; (PS_Interface|PS_Export|PS_Local))==0 &amp;&amp; proto_static==0 ){
+      /* Ignore typedefs that are not with &quot;#if INTERFACE..#endif&quot; unless
+      ** the &quot;-local&quot; command line option is used. */
+      return nErr;
+    }
+    if( (flags &amp; (PS_Interface|PS_Export))==0 ){
+      /* typedefs are always local, unless within #if INTERFACE..#endif */
+      isLocal = 1;
+    }
+  }else if( flags &amp; (PS_Static|PS_Local2) ){
+    if( proto_static==0 &amp;&amp; (flags &amp; PS_Local2)==0 ){
+      /* Don&#39;t record static variables unless the &quot;-local&quot; command line
+      ** option was specified or the &quot;LOCAL&quot; keyword is used. */
+      return nErr;
+    }
+    while( pFirst!=0 &amp;&amp; pFirst-&gt;pNext!=pEnd &amp;&amp;
+       ((pFirst-&gt;nText==6 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;static&quot;,6)==0)
+        || (pFirst-&gt;nText==5 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;LOCAL&quot;,6)==0))
+    ){
+      /* Lose the initial &quot;static&quot; or local from local variables.
+      ** We&#39;ll prepend &quot;extern&quot; later. */
+      pFirst = pFirst-&gt;pNext;
+      isLocal = 1;
+    }
+    if( pFirst==0 || !isLocal ){
+      return nErr;
+    }
+  }else if( flags &amp; PS_Method ){
+    /* Methods are declared by their class.  Don&#39;t declare separately. */
+    return nErr;
+  }else if( isStaticAssert(pFirst) ){
+    return 0;
+  }
+  isVar =  (flags &amp; (PS_Typedef|PS_Method))==0 &amp;&amp; isVariableDef(pFirst,pEnd);
+  if( isVar &amp;&amp; (flags &amp; (PS_Interface|PS_Export|PS_Local))!=0
+  &amp;&amp; (flags &amp; PS_Extern)==0 ){
+    fprintf(stderr,&quot;%s:%d: Can&#39;t define a variable in this context\n&quot;,
+      zFilename, pFirst-&gt;nLine);
+    nErr++;
+  }
+  pName = FindDeclName(pFirst,pEnd-&gt;pPrev);
+  if( pName==0 ){
+    if( pFirst-&gt;nText==4 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;enum&quot;,4)==0 ){
+      /* Ignore completely anonymous enums.  See documentation section 3.8.1. */
+      return nErr;
+    }else{
+      fprintf(stderr,&quot;%s:%d: Can&#39;t find a name for the object declared here.\n&quot;,
+        zFilename, pFirst-&gt;nLine);
+      return nErr+1;
+    }
+  }
+
+#ifdef DEBUG
+  if( debugMask &amp; PARSER ){
+    if( flags &amp; PS_Typedef ){
+      printf(&quot;**** Found typedef %.*s at line %d...\n&quot;,
+        pName-&gt;nText, pName-&gt;zText, pName-&gt;nLine);
+    }else if( isVar ){
+      printf(&quot;**** Found variable %.*s at line %d...\n&quot;,
+        pName-&gt;nText, pName-&gt;zText, pName-&gt;nLine);
+    }else{
+      printf(&quot;**** Found prototype %.*s at line %d...\n&quot;,
+        pName-&gt;nText, pName-&gt;zText, pName-&gt;nLine);
+    }
+    PrintTokens(pFirst,pEnd-&gt;pPrev);
+    printf(&quot;;\n&quot;);
+  }
+#endif
+
+  pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
+  if( (flags &amp; PS_Typedef) ){
+    DeclSetProperty(pDecl, TY_Typedef);
+  }else if( isVar ){
+    DeclSetProperty(pDecl,DP_ExternReqd | TY_Variable);
+    if( !(flags &amp; DP_Cplusplus) ){
+      DeclSetProperty(pDecl,DP_ExternCReqd);
+    }
+  }else{
+    DeclSetProperty(pDecl, TY_Subroutine);
+    if( !(flags &amp; DP_Cplusplus) ){
+      DeclSetProperty(pDecl,DP_ExternCReqd);
+    }
+  }
+  pDecl-&gt;pComment = pFirst-&gt;pComment;
+  pDecl-&gt;zDecl = TokensToString(pFirst,pEnd-&gt;pPrev,&quot;;\n&quot;,0,0);
+  if( isLocal || (flags &amp; (PS_Local|PS_Local2))!=0 ){
+    DeclSetProperty(pDecl,DP_Local);
+  }else if( flags &amp; (PS_Export|PS_Export2) ){
+    DeclSetProperty(pDecl,DP_Export);
+  }
+  if( flags &amp; 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 &quot;define&quot; or &quot;!&quot; */
+  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-&gt;zCondition = (char*)&amp;pIf[1];
+    if( zPrefix ){
+      sprintf(pIf-&gt;zCondition,&quot;%s(%.*s)&quot;,zPrefix,nText,zText);
+    }else{
+      sprintf(pIf-&gt;zCondition,&quot;%.*s&quot;,nText,zText);
+    }
+  }else{
+    pIf-&gt;zCondition = 0;
+  }
+  pIf-&gt;nLine = nLine;
+  pIf-&gt;flags = flags;
+  pIf-&gt;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 &quot;#if INTERFACE&quot; 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 = &amp;pToken-&gt;zText[1];
+  while( isspace(*zCmd) &amp;&amp; *zCmd!=&#39;\n&#39; ){
+    zCmd++;
+  }
+  if( !isalpha(*zCmd) ){
+    return 0;
+  }
+  nCmd = 1;
+  while( isalpha(zCmd[nCmd]) ){
+    nCmd++;
+  }
+
+  if( nCmd==5 &amp;&amp; strncmp(zCmd,&quot;endif&quot;,5)==0 ){
+    /*
+    ** Pop the if stack
+    */
+    pIf = ifStack;
+    if( pIf==0 ){
+      fprintf(stderr,&quot;%s:%d: extra &#39;#endif&#39;.\n&quot;,zFilename,pToken-&gt;nLine);
+      return 1;
+    }
+    ifStack = pIf-&gt;pNext;
+    SafeFree(pIf);
+  }else if( nCmd==6 &amp;&amp; strncmp(zCmd,&quot;define&quot;,6)==0 ){
+    /*
+    ** Record a #define if we are in PS_Interface or PS_Export
+    */
+    Decl *pDecl;
+    if( !(flags &amp; (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
+    zArg = &amp;zCmd[6];
+    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
+      zArg++;
+    }
+    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
+    for(nArg=0; ISALNUM(zArg[nArg]); nArg++){}
+    if( nArg==0 ){ return 0; }
+    pDecl = CreateDecl(zArg,nArg);
+    pDecl-&gt;pComment = pToken-&gt;pComment;
+    DeclSetProperty(pDecl,TY_Macro);
+    pDecl-&gt;zDecl = SafeMalloc( pToken-&gt;nText + 2 );
+    sprintf(pDecl-&gt;zDecl,&quot;%.*s\n&quot;,pToken-&gt;nText,pToken-&gt;zText);
+    if( flags &amp; PS_Export ){
+      DeclSetProperty(pDecl,DP_Export);
+    }else if( flags &amp; PS_Local ){
+      DeclSetProperty(pDecl,DP_Local);
+    }
+  }else if( nCmd==7 &amp;&amp; strncmp(zCmd,&quot;include&quot;,7)==0 ){
+    /*
+    ** Record an #include if we are in PS_Interface or PS_Export
+    */
+    Include *pInclude;
+    char *zIf;
+
+    if( !(flags &amp; (PS_Interface|PS_Export)) ){ return 0; }
+    zArg = &amp;zCmd[7];
+    while( *zArg &amp;&amp; isspace(*zArg) ){ zArg++; }
+    for(nArg=0; !isspace(zArg[nArg]); nArg++){}
+    if( (zArg[0]==&#39;&quot;&#39; &amp;&amp; zArg[nArg-1]!=&#39;&quot;&#39;)
+      ||(zArg[0]==&#39;&lt;&#39; &amp;&amp; zArg[nArg-1]!=&#39;&gt;&#39;)
+    ){
+      fprintf(stderr,&quot;%s:%d: malformed #include statement.\n&quot;,
+        zFilename,pToken-&gt;nLine);
+      return 1;
+    }
+    zIf = GetIfString();
+    if( zIf ){
+      pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 );
+      pInclude-&gt;zFile = (char*)&amp;pInclude[1];
+      pInclude-&gt;zLabel = &amp;pInclude-&gt;zFile[nArg+1];
+      sprintf(pInclude-&gt;zFile,&quot;%.*s&quot;,nArg,zArg);
+      sprintf(pInclude-&gt;zLabel,&quot;%.*s:%s&quot;,nArg,zArg,zIf);
+      pInclude-&gt;zIf = &amp;pInclude-&gt;zLabel[nArg+1];
+      SafeFree(zIf);
+    }else{
+      pInclude = SafeMalloc( sizeof(Include) + nArg + 1 );
+      pInclude-&gt;zFile = (char*)&amp;pInclude[1];
+      sprintf(pInclude-&gt;zFile,&quot;%.*s&quot;,nArg,zArg);
+      pInclude-&gt;zIf = 0;
+      pInclude-&gt;zLabel = pInclude-&gt;zFile;
+    }
+    pInclude-&gt;pNext = includeList;
+    includeList = pInclude;
+  }else if( nCmd==2 &amp;&amp; strncmp(zCmd,&quot;if&quot;,2)==0 ){
+    /*
+    ** Push an #if.  Watch for the special cases of INTERFACE
+    ** and EXPORT_INTERFACE and LOCAL_INTERFACE
+    */
+    zArg = &amp;zCmd[2];
+    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
+      zArg++;
+    }
+    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
+    nArg = pToken-&gt;nText + (int)(pToken-&gt;zText - zArg);
+    if( nArg==9 &amp;&amp; strncmp(zArg,&quot;INTERFACE&quot;,9)==0 ){
+      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Interface);
+    }else if( nArg==16 &amp;&amp; strncmp(zArg,&quot;EXPORT_INTERFACE&quot;,16)==0 ){
+      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Export);
+    }else if( nArg==15 &amp;&amp; strncmp(zArg,&quot;LOCAL_INTERFACE&quot;,15)==0 ){
+      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Local);
+    }else if( nArg==15 &amp;&amp; strncmp(zArg,&quot;MAKEHEADERS_STOPLOCAL_INTERFACE&quot;,15)==0 ){
+      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Local);
+    }else{
+      PushIfMacro(0,zArg,nArg,pToken-&gt;nLine,0);
+    }
+  }else if( nCmd==5 &amp;&amp; strncmp(zCmd,&quot;ifdef&quot;,5)==0 ){
+    /*
+    ** Push an #ifdef.
+    */
+    zArg = &amp;zCmd[5];
+    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
+      zArg++;
+    }
+    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
+    nArg = pToken-&gt;nText + (int)(pToken-&gt;zText - zArg);
+    PushIfMacro(&quot;defined&quot;,zArg,nArg,pToken-&gt;nLine,0);
+  }else if( nCmd==6 &amp;&amp; strncmp(zCmd,&quot;ifndef&quot;,6)==0 ){
+    /*
+    ** Push an #ifndef.
+    */
+    zArg = &amp;zCmd[6];
+    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
+      zArg++;
+    }
+    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
+    nArg = pToken-&gt;nText + (int)(pToken-&gt;zText - zArg);
+    PushIfMacro(&quot;!defined&quot;,zArg,nArg,pToken-&gt;nLine,0);
+  }else if( nCmd==4 &amp;&amp; strncmp(zCmd,&quot;else&quot;,4)==0 ){
+    /*
+    ** Invert the #if on the top of the stack
+    */
+    if( ifStack==0 ){
+      fprintf(stderr,&quot;%s:%d: &#39;#else&#39; without an &#39;#if&#39;\n&quot;,zFilename,
+         pToken-&gt;nLine);
+      return 1;
+    }
+    pIf = ifStack;
+    if( pIf-&gt;zCondition ){
+      ifStack = ifStack-&gt;pNext;
+      PushIfMacro(&quot;!&quot;,pIf-&gt;zCondition,strlen(pIf-&gt;zCondition),pIf-&gt;nLine,0);
+      SafeFree(pIf);
+    }else{
+      pIf-&gt;flags = 0;
+    }
+  }else{
+    /*
+    ** This directive can be safely ignored
+    */
+    return 0;
+  }
+
+  /*
+  ** Recompute the preset flags
+  */
+  *pPresetFlags = 0;
+  for(pIf = ifStack; pIf; pIf=pIf-&gt;pNext){
+    *pPresetFlags |= pIf-&gt;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-&gt;eType ){
+    case TT_EOF:
+      goto end_of_loop;
+
+    case TT_Preprocessor:
+      nErr += ParsePreprocessor(pList,flags,&amp;presetFlags);
+      pStart = 0;
+      presetFlags |= initFlags;
+      flags = presetFlags;
+      break;
+
+    case TT_Other:
+      switch( pList-&gt;zText[0] ){
+      case &#39;;&#39;:
+        nErr += ProcessDecl(pStart,pList,flags);
+        pStart = 0;
+        flags = presetFlags;
+        break;
+
+      case &#39;=&#39;:
+        if( pList-&gt;pPrev-&gt;nText==8
+            &amp;&amp; strncmp(pList-&gt;pPrev-&gt;zText,&quot;operator&quot;,8)==0 ){
+          break;
+        }
+        nErr += ProcessDecl(pStart,pList,flags);
+        pStart = 0;
+        while( pList &amp;&amp; pList-&gt;zText[0]!=&#39;;&#39; ){
+          pList = pList-&gt;pNext;
+        }
+        if( pList==0 ) goto end_of_loop;
+        flags = presetFlags;
+        break;
+
+      case &#39;:&#39;:
+        if( pList-&gt;zText[1]==&#39;:&#39; ){
+          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-&gt;zText[0] ){
+       case &#39;c&#39;:
+         if( pList-&gt;nText==5 &amp;&amp; strncmp(pList-&gt;zText,&quot;class&quot;,5)==0 ){
+           nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
+         }
+         break;
+
+       case &#39;E&#39;:
+         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;EXPORT&quot;,6)==0 ){
+           flags |= PS_Export2;
+           /* pStart = 0; */
+         }
+         break;
+
+       case &#39;e&#39;:
+         if( pList-&gt;nText==4 &amp;&amp; strncmp(pList-&gt;zText,&quot;enum&quot;,4)==0 ){
+           if( pList-&gt;pNext &amp;&amp; pList-&gt;pNext-&gt;eType==TT_Braces ){
+             pList = pList-&gt;pNext;
+           }else{
+             nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
+           }
+         }else if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;extern&quot;,6)==0 ){
+           pList = pList-&gt;pNext;
+           if( pList &amp;&amp; pList-&gt;nText==3 &amp;&amp; strncmp(pList-&gt;zText,&quot;\&quot;C\&quot;&quot;,3)==0 ){
+             pList = pList-&gt;pNext;
+             flags &amp;= ~DP_Cplusplus;
+           }else{
+             flags |= PS_Extern;
+           }
+           pStart = pList;
+         }
+         break;
+
+       case &#39;i&#39;:
+         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;inline&quot;,6)==0
+          &amp;&amp; (flags &amp; PS_Static)==0
+         ){
+           nErr += ProcessInlineProc(pList,flags,&amp;resetFlag);
+         }
+         break;
+
+       case &#39;L&#39;:
+         if( pList-&gt;nText==5 &amp;&amp; strncmp(pList-&gt;zText,&quot;LOCAL&quot;,5)==0 ){
+           flags |= PS_Local2;
+           pStart = pList;
+         }
+         break;
+
+       case &#39;P&#39;:
+         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText, &quot;PUBLIC&quot;,6)==0 ){
+           flags |= PS_Public;
+           pStart = pList;
+         }else if( pList-&gt;nText==7 &amp;&amp; strncmp(pList-&gt;zText, &quot;PRIVATE&quot;,7)==0 ){
+           flags |= PS_Private;
+           pStart = pList;
+         }else if( pList-&gt;nText==9 &amp;&amp; strncmp(pList-&gt;zText,&quot;PROTECTED&quot;,9)==0 ){
+           flags |= PS_Protected;
+           pStart = pList;
+         }
+         break;
+
+       case &#39;s&#39;:
+         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;struct&quot;,6)==0 ){
+           if( pList-&gt;pNext &amp;&amp; pList-&gt;pNext-&gt;eType==TT_Braces ){
+             pList = pList-&gt;pNext;
+           }else{
+             nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
+           }
+         }else if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;static&quot;,6)==0 ){
+           flags |= PS_Static;
+         }
+         break;
+
+       case &#39;t&#39;:
+         if( pList-&gt;nText==7 &amp;&amp; strncmp(pList-&gt;zText,&quot;typedef&quot;,7)==0 ){
+           flags |= PS_Typedef;
+         }
+         break;
+
+       case &#39;u&#39;:
+         if( pList-&gt;nText==5 &amp;&amp; strncmp(pList-&gt;zText,&quot;union&quot;,5)==0 ){
+           if( pList-&gt;pNext &amp;&amp; pList-&gt;pNext-&gt;eType==TT_Braces ){
+             pList = pList-&gt;pNext;
+           }else{
+             nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
+           }
+         }
+         break;
+
+       default:
+         break;
+       }
+       if( resetFlag!=0 ){
+         while( pList &amp;&amp; pList-&gt;zText[0]!=resetFlag ){
+           pList = pList-&gt;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-&gt;pNext;
+  }
+  end_of_loop:
+
+  /* Verify that all #ifs have a matching &quot;#endif&quot; */
+  while( ifStack ){
+    Ifmacro *pIf = ifStack;
+    ifStack = pIf-&gt;pNext;
+    fprintf(stderr,&quot;%s:%d: This &#39;#if&#39; has no &#39;#endif&#39;\n&quot;,zFilename,
+      pIf-&gt;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 &quot;}&quot; 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-&gt;zExtra==0 || pDecl-&gt;zDecl==0 ) return;
+  i = strlen(pDecl-&gt;zDecl) - 1;
+  while( i&gt;0 &amp;&amp; pDecl-&gt;zDecl[i]!=&#39;}&#39; ){ i--; }
+  StringInit(&amp;str);
+  StringAppend(&amp;str, pDecl-&gt;zDecl, i);
+  StringAppend(&amp;str, pDecl-&gt;zExtra, 0);
+  StringAppend(&amp;str, &amp;pDecl-&gt;zDecl[i], 0);
+  SafeFree(pDecl-&gt;zDecl);
+  SafeFree(pDecl-&gt;zExtra);
+  pDecl-&gt;zDecl = StrDup(StringGet(&amp;str), 0);
+  StringReset(&amp;str);
+  pDecl-&gt;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&#39;t
+** in the file zFilename so that it won&#39;t be printing in other files.
+*/
+static void ResetDeclFlags(char *zFilename){
+  Decl *pDecl;
+
+  for(pDecl = pDeclFirst; pDecl; pDecl = pDecl-&gt;pNext){
+    DeclClearProperty(pDecl,DP_Forward|DP_Declared);
+    if( DeclHasProperty(pDecl,DP_Local) &amp;&amp; pDecl-&gt;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 &quot;#if NEW&quot; 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-&gt;zIf==0 ) return;
+    StringAppend(pState-&gt;pStr,&quot;#endif\n&quot;,0);
+    pState-&gt;zIf = 0;
+  }else{
+    if( pState-&gt;zIf ){
+      if( strcmp(zIf,pState-&gt;zIf)==0 ) return;
+      StringAppend(pState-&gt;pStr,&quot;#endif\n&quot;,0);
+      pState-&gt;zIf = 0;
+    }
+    ScanText(zIf, pState);
+    if( pState-&gt;zIf!=0 ){
+      StringAppend(pState-&gt;pStr,&quot;#endif\n&quot;,0);
+    }
+    StringAppend(pState-&gt;pStr,&quot;#if &quot;,0);
+    StringAppend(pState-&gt;pStr,zIf,0);
+    StringAppend(pState-&gt;pStr,&quot;\n&quot;,0);
+    pState-&gt;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&#39;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-&gt;pNext ){
+      AddIncludes(pInclude-&gt;pNext,pState);
+    }
+    if( IdentTableInsert(pState-&gt;pTable,pInclude-&gt;zLabel,0) ){
+      ChangeIfContext(pInclude-&gt;zIf,pState);
+      StringAppend(pState-&gt;pStr,&quot;#include &quot;,0);
+      StringAppend(pState-&gt;pStr,pInclude-&gt;zFile,0);
+      StringAppend(pState-&gt;pStr,&quot;\n&quot;,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&#39;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(&quot;BEGIN %s of %s\n&quot;,needFullDecl?&quot;FULL&quot;:&quot;PROTOTYPE&quot;,pDecl-&gt;zName);*/
+  /*
+  ** For any object that has a forward declaration, go ahead and do the
+  ** forward declaration first.
+  */
+  isCpp = (pState-&gt;flags &amp; DP_Cplusplus) != 0;
+  for(p=pDecl; p; p=p-&gt;pSameName){
+    if( p-&gt;zFwd ){
+      if( !DeclHasProperty(p,DP_Forward) ){
+        DeclSetProperty(p,DP_Forward);
+        if( strncmp(p-&gt;zFwd,&quot;typedef&quot;,7)==0 ){
+          if( doneTypedef ) continue;
+          doneTypedef = 1;
+        }
+        ChangeIfContext(p-&gt;zIf,pState);
+        StringAppend(pState-&gt;pStr,isCpp ? p-&gt;zFwdCpp : p-&gt;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-&gt;pSameName){
+    if( !DeclHasProperty(p,flag) ) break;
+  }
+  if( p==0 ){
+    return;
+  }
+
+  /*
+  ** Make sure we have all necessary #includes
+  */
+  for(p=pDecl; p; p=p-&gt;pSameName){
+    AddIncludes(p-&gt;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&#39;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-&gt;pSameName){
+    if( !DeclHasProperty(p,DP_Declared)
+     &amp;&amp; (p-&gt;zFwd==0 || needFullDecl)
+     &amp;&amp; p-&gt;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-&gt;pSameName){
+    if( DeclHasProperty(p,DP_Flag) ){
+      if( p-&gt;zDecl[0]==&#39;#&#39; ){
+        ScanText(&amp;p-&gt;zDecl[1],pState);
+      }else{
+        InsertExtraDecl(p);
+        ScanText(p-&gt;zDecl,pState);
+      }
+    }
+  }
+
+  /*
+  ** Output the declarations.  Do this in two passes.  First
+  ** output everything that isn&#39;t a typedef.  Then go back and
+  ** get the typedefs by the same name.
+  */
+  for(p=pDecl; p; p=p-&gt;pSameName){
+    if( DeclHasProperty(p,DP_Flag) &amp;&amp; !DeclHasProperty(p,TY_Typedef) ){
+      if( DeclHasAnyProperty(p,TY_Enumeration) ){
+        if( doneTypedef ) continue;
+        doneTypedef = 1;
+      }
+      ChangeIfContext(p-&gt;zIf,pState);
+      if( !isCpp &amp;&amp; DeclHasAnyProperty(p,DP_ExternReqd) ){
+        StringAppend(pState-&gt;pStr,&quot;extern &quot;,0);
+      }else if( isCpp &amp;&amp; DeclHasProperty(p,DP_Cplusplus|DP_ExternReqd) ){
+        StringAppend(pState-&gt;pStr,&quot;extern &quot;,0);
+      }else if( isCpp &amp;&amp; DeclHasAnyProperty(p,DP_ExternCReqd|DP_ExternReqd) ){
+        StringAppend(pState-&gt;pStr,&quot;extern \&quot;C\&quot; &quot;,0);
+      }
+      InsertExtraDecl(p);
+      StringAppend(pState-&gt;pStr,p-&gt;zDecl,0);
+      if( !isCpp &amp;&amp; DeclHasProperty(p,DP_Cplusplus) ){
+        fprintf(stderr,
+          &quot;%s: C code ought not reference the C++ object \&quot;%s\&quot;\n&quot;,
+          pState-&gt;zFilename, p-&gt;zName);
+        pState-&gt;nErr++;
+      }
+      DeclClearProperty(p,DP_Flag);
+    }
+  }
+  for(p=pDecl; p &amp;&amp; !doneTypedef; p=p-&gt;pSameName){
+    if( DeclHasProperty(p,DP_Flag) ){
+      /* This has to be a typedef */
+      doneTypedef = 1;
+      ChangeIfContext(p-&gt;zIf,pState);
+      InsertExtraDecl(p);
+      StringAppend(pState-&gt;pStr,p-&gt;zDecl,0);
+    }
+  }
+}
+
+/*
+** This routine scans the input text given, and appends to the
+** string in pState-&gt;pStr the text of any declarations that must
+** occur before the text in zText.
+**
+** If an identifier in zText is immediately followed by &#39;*&#39;, then
+** only forward declarations are needed for that identifier.  If the
+** identifier name is not followed immediately by &#39;*&#39;, 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(&quot;BEGIN SCAN TEXT on %s\n&quot;, zText); */
+
+  sIn.z = zText;
+  sIn.i = 0;
+  sIn.nLine = 1;
+  while( sIn.z[sIn.i]!=0 ){
+    if( nextValid ){
+      sToken = sNext;
+      nextValid = 0;
+    }else{
+      GetNonspaceToken(&amp;sIn,&amp;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&#39;ve found an identifier that has a
+      ** declaration in the database.  Now see if we the full declaration
+      ** or just a forward declaration.
+      */
+      GetNonspaceToken(&amp;sIn,&amp;sNext);
+      if( sNext.zText[0]==&#39;*&#39; ){
+        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(&quot;END SCANTEXT\n&quot;); */
+}
+
+/*
+** 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-&gt;pNext){
+      if( DeclHasProperty(pDecl,DP_Forward)
+       &amp;&amp; !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-&gt;zHdr==0 || *pFile-&gt;zHdr==0 ) return 0;
+  sState.pStr = &amp;outStr;
+  StringInit(&amp;outStr);
+  StringAppend(&amp;outStr,zTopLine,nTopLine);
+  sState.pTable = &amp;includeTable;
+  memset(&amp;includeTable,0,sizeof(includeTable));
+  sState.zIf = 0;
+  sState.nErr = 0;
+  sState.zFilename = pFile-&gt;zSrc;
+  sState.flags = pFile-&gt;flags &amp; DP_Cplusplus;
+  ResetDeclFlags(nolocal_flag ? &quot;no&quot; : pFile-&gt;zSrc);
+  for(pId = pFile-&gt;idTable.pList; pId; pId=pId-&gt;pNext){
+    Decl *pDecl = FindDecl(pId-&gt;zName,0);
+    if( pDecl ){
+      DeclareObject(pDecl,&amp;sState,1);
+    }
+  }
+  CompleteForwardDeclarations(&amp;sState);
+  ChangeIfContext(0,&amp;sState);
+  nErr += sState.nErr;
+  zOldVersion = ReadFile(pFile-&gt;zHdr);
+  zNewVersion = StringGet(&amp;outStr);
+  if( report ) fprintf(report,&quot;%s: &quot;,pFile-&gt;zHdr);
+  if( zOldVersion==0 ){
+    if( report ) fprintf(report,&quot;updated\n&quot;);
+    if( WriteFile(pFile-&gt;zHdr,zNewVersion) ){
+      fprintf(stderr,&quot;%s: Can&#39;t write to file\n&quot;,pFile-&gt;zHdr);
+      nErr++;
+    }
+  }else if( strncmp(zOldVersion,zTopLine,nTopLine)!=0 ){
+    if( report ) fprintf(report,&quot;error!\n&quot;);
+    fprintf(stderr,
+       &quot;%s: Can&#39;t overwrite this file because it wasn&#39;t previously\n&quot;
+       &quot;%*s  generated by &#39;makeheaders&#39;.\n&quot;,
+       pFile-&gt;zHdr, (int)strlen(pFile-&gt;zHdr), &quot;&quot;);
+    nErr++;
+  }else if( strcmp(zOldVersion,zNewVersion)!=0 ){
+    if( report ) fprintf(report,&quot;updated\n&quot;);
+    if( WriteFile(pFile-&gt;zHdr,zNewVersion) ){
+      fprintf(stderr,&quot;%s: Can&#39;t write to file\n&quot;,pFile-&gt;zHdr);
+      nErr++;
+    }
+  }else if( report ){
+    fprintf(report,&quot;unchanged\n&quot;);
+  }
+  SafeFree(zOldVersion);
+  IdentTableReset(&amp;includeTable);
+  StringReset(&amp;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 = &amp;outStr;
+  StringInit(&amp;outStr);
+  /* StringAppend(&amp;outStr,zTopLine,nTopLine); */
+  sState.pTable = &amp;includeTable;
+  memset(&amp;includeTable,0,sizeof(includeTable));
+  sState.zIf = 0;
+  sState.nErr = 0;
+  sState.zFilename = &quot;(all)&quot;;
+  sState.flags = 0;
+  ResetDeclFlags(0);
+  for(pDecl=pDeclFirst; pDecl; pDecl=pDecl-&gt;pNext){
+    if( forExport==0 || DeclHasProperty(pDecl,DP_Export) ){
+      DeclareObject(pDecl,&amp;sState,1);
+    }
+  }
+  ChangeIfContext(0,&amp;sState);
+  printf(&quot;%s&quot;,StringGet(&amp;outStr));
+  IdentTableReset(&amp;includeTable);
+  StringReset(&amp;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&gt;0 &amp;&amp; (z[n-1]==&#39;\n&#39; || z[n-1]==&#39;\r&#39;) ){ n--; }
+  return n;
+}
+
+/*
+** Dump the entire declaration list for debugging purposes
+*/
+static void DumpDeclList(void){
+  Decl *pDecl;
+
+  for(pDecl = pDeclFirst; pDecl; pDecl=pDecl-&gt;pNext){
+    printf(&quot;**** %s from file %s ****\n&quot;,pDecl-&gt;zName,pDecl-&gt;zFile);
+    if( pDecl-&gt;zIf ){
+      printf(&quot;If: [%.*s]\n&quot;,ClipTrailingNewline(pDecl-&gt;zIf),pDecl-&gt;zIf);
+    }
+    if( pDecl-&gt;zFwd ){
+      printf(&quot;Decl: [%.*s]\n&quot;,ClipTrailingNewline(pDecl-&gt;zFwd),pDecl-&gt;zFwd);
+    }
+    if( pDecl-&gt;zDecl ){
+      InsertExtraDecl(pDecl);
+      printf(&quot;Def: [%.*s]\n&quot;,ClipTrailingNewline(pDecl-&gt;zDecl),pDecl-&gt;zDecl);
+    }
+    if( pDecl-&gt;flags ){
+      static struct {
+        int mask;
+        char *desc;
+      } flagSet[] = {
+        { TY_Class,       &quot;class&quot; },
+        { TY_Enumeration, &quot;enum&quot; },
+        { TY_Structure,   &quot;struct&quot; },
+        { TY_Union,       &quot;union&quot; },
+        { TY_Variable,    &quot;variable&quot; },
+        { TY_Subroutine,  &quot;function&quot; },
+        { TY_Typedef,     &quot;typedef&quot; },
+        { TY_Macro,       &quot;macro&quot; },
+        { DP_Export,      &quot;export&quot; },
+        { DP_Local,       &quot;local&quot; },
+        { DP_Cplusplus,   &quot;C++&quot; },
+      };
+      int i;
+      printf(&quot;flags:&quot;);
+      for(i=0; i&lt;sizeof(flagSet)/sizeof(flagSet[0]); i++){
+        if( flagSet[i].mask &amp; pDecl-&gt;flags ){
+          printf(&quot; %s&quot;, flagSet[i].desc);
+        }
+      }
+      printf(&quot;\n&quot;);
+    }
+    if( pDecl-&gt;pInclude ){
+      Include *p;
+      printf(&quot;includes:&quot;);
+      for(p=pDecl-&gt;pInclude; p; p=p-&gt;pNext){
+        printf(&quot; %s&quot;,p-&gt;zFile);
+      }
+      printf(&quot;\n&quot;);
+    }
+  }
+}
+#endif
+
+/*
+** When the &quot;-doc&quot; 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,       &#39;c&#39; },
+    { TY_Enumeration, &#39;e&#39; },
+    { TY_Structure,   &#39;s&#39; },
+    { TY_Union,       &#39;u&#39; },
+    { TY_Variable,    &#39;v&#39; },
+    { TY_Subroutine,  &#39;f&#39; },
+    { TY_Typedef,     &#39;t&#39; },
+    { TY_Macro,       &#39;m&#39; },
+    { DP_Export,      &#39;x&#39; },
+    { DP_Local,       &#39;l&#39; },
+    { DP_Cplusplus,   &#39;+&#39; },
+  };
+
+  for(pDecl = pDeclFirst; pDecl; pDecl=pDecl-&gt;pNext){
+    int i;
+    int nLabel = 0;
+    char *zDecl;
+    char zLabel[50];
+    for(i=0; i&lt;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-&gt;zDecl;
+    if( zDecl==0 ) zDecl = pDecl-&gt;zFwd;
+    printf(&quot;%s %s %s %p %d %d %d %d %d\n&quot;,
+       pDecl-&gt;zName,
+       zLabel,
+       pDecl-&gt;zFile,
+       pDecl-&gt;pComment,
+       pDecl-&gt;pComment ? pDecl-&gt;pComment-&gt;nText+1 : 0,
+       pDecl-&gt;zIf ? (int)strlen(pDecl-&gt;zIf)+1 : 0,
+       zDecl ? (int)strlen(zDecl) : 0,
+       pDecl-&gt;pComment ? pDecl-&gt;pComment-&gt;nLine : 0,
+       pDecl-&gt;tokenCode.nText ? pDecl-&gt;tokenCode.nText+1 : 0
+    );
+    if( pDecl-&gt;pComment ){
+      printf(&quot;%.*s\n&quot;,pDecl-&gt;pComment-&gt;nText, pDecl-&gt;pComment-&gt;zText);
+    }
+    if( pDecl-&gt;zIf ){
+      printf(&quot;%s\n&quot;,pDecl-&gt;zIf);
+    }
+    if( zDecl ){
+      printf(&quot;%s&quot;,zDecl);
+    }
+    if( pDecl-&gt;tokenCode.nText ){
+      printf(&quot;%.*s\n&quot;,pDecl-&gt;tokenCode.nText, pDecl-&gt;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!=&#39;/&#39; || zFile[1]!=&#39;*&#39; ) return;
+  for(i=2; zFile[i] &amp;&amp; (zFile[i-1]!=&#39;/&#39; || zFile[i-2]!=&#39;*&#39;); i++){}
+  if( zFile[i]==0 ) return;
+  printf(&quot;%s M %s %d %d 0 0 0 0\n%.*s\n&quot;,
+    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 &#39;:&#39; or the whole file if no &#39;:&#39; is seen.
+  **
+  ** Except, on windows, ignore any &#39;:&#39; that occurs as the second character
+  ** since it might be part of the drive specifier.  So really, the &quot;:&#39; 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] &amp;&amp; zArg[nSrc]!=&#39;:&#39;; nSrc++){}
+  pFile = SafeMalloc( sizeof(InFile) );
+  memset(pFile,0,sizeof(InFile));
+  pFile-&gt;zSrc = StrDup(zSrc,nSrc);
+
+  /* Figure out if we are dealing with C or C++ code.  Assume any
+  ** file with &quot;.c&quot; or &quot;.h&quot; is C code and all else is C++.
+  */
+  if( nSrc&gt;2 &amp;&amp; zSrc[nSrc-2]==&#39;.&#39; &amp;&amp; (zSrc[nSrc-1]==&#39;c&#39; || zSrc[nSrc-1]==&#39;h&#39;)){
+    pFile-&gt;flags &amp;= ~DP_Cplusplus;
+  }else{
+    pFile-&gt;flags |= DP_Cplusplus;
+  }
+
+  /*
+  ** If a separate header file is specified, use it
+  */
+  if( zSrc[nSrc]==&#39;:&#39; ){
+    int nHdr;
+    char *zHdr;
+    zHdr = &amp;zSrc[nSrc+1];
+    for(nHdr=0; zHdr[nHdr]; nHdr++){}
+    pFile-&gt;zHdr = StrDup(zHdr,nHdr);
+  }
+
+  /* Look for any &#39;c&#39; or &#39;C&#39; in the suffix of the file name and change
+  ** that character to &#39;h&#39; or &#39;H&#39; respectively.  If no &#39;c&#39; or &#39;C&#39; is found,
+  ** then assume we are dealing with a header.
+  */
+  else{
+    int foundC = 0;
+    pFile-&gt;zHdr = StrDup(zSrc,nSrc);
+    for(i = nSrc-1; i&gt;0 &amp;&amp; pFile-&gt;zHdr[i]!=&#39;.&#39;; i--){
+      if( pFile-&gt;zHdr[i]==&#39;c&#39; ){
+        foundC = 1;
+        pFile-&gt;zHdr[i] = &#39;h&#39;;
+      }else if( pFile-&gt;zHdr[i]==&#39;C&#39; ){
+        foundC = 1;
+        pFile-&gt;zHdr[i] = &#39;H&#39;;
+      }
+    }
+    if( !foundC ){
+      SafeFree(pFile-&gt;zHdr);
+      pFile-&gt;zHdr = 0;
+    }
+  }
+
+  /*
+  ** If pFile-&gt;zSrc contains no &#39;c&#39; or &#39;C&#39; in its extension, it
+  ** must be a header file.   In that case, we need to set the
+  ** PS_Interface flag.
+  */
+  pFile-&gt;flags |= PS_Interface;
+  for(i=nSrc-1; i&gt;0 &amp;&amp; zSrc[i]!=&#39;.&#39;; i--){
+    if( zSrc[i]==&#39;c&#39; || zSrc[i]==&#39;C&#39; ){
+      pFile-&gt;flags &amp;= ~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 &quot;-f FILENAME&quot; 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 &quot;FILENAME&quot; argument
+** in the original argument list.
+**
+** This first parameter to this routine is the index of the &quot;-f&quot;
+** 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 &#39;#&#39; 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,&quot;r&quot;);
+  if( in==0 ){
+    fprintf(stderr,&quot;Can&#39;t open input file \&quot;%s\&quot;\n&quot;,zFile);
+    exit(1);
+  }
+  c = &#39; &#39;;
+  while( c!=EOF ){
+    while( c!=EOF &amp;&amp; isspace(c) ){
+      if( c==&#39;\n&#39; ){
+        startOfLine = 1;
+      }
+      c = getc(in);
+      if( startOfLine &amp;&amp; c==&#39;#&#39; ){
+        while( c!=EOF &amp;&amp; c!=&#39;\n&#39; ){
+          c = getc(in);
+        }
+      }
+    }
+    n = 0;
+    while( c!=EOF &amp;&amp; !isspace(c) ){
+      if( n&lt;sizeof(zBuf)-1 ){ zBuf[n++] = c; }
+      startOfLine = 0;
+      c = getc(in);
+    }
+    zBuf[n] = 0;
+    if( n&gt;0 ){
+      nNew++;
+      if( nNew + argc &gt; 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&lt;=index; i++){
+    zNew[i] = argv[i];
+  }
+  for(i=nNew + index + 1; i&lt;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&#39;t
+** locate the file (because, for example, it doesn&#39;t exist), then
+** return 0.
+*/
+static unsigned int ModTime(const char *zFilename){
+  unsigned int mTime = 0;
+  struct stat sStat;
+  if( stat(zFilename,&amp;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,&quot;%s: Illegal argument \&quot;%s\&quot;\n&quot;,argv0,argvN);
+  fprintf(stderr,&quot;Usage: %s [options] filename...\n&quot;
+    &quot;Options:\n&quot;
+    &quot;  -h          Generate a single .h to standard output.\n&quot;
+    &quot;  -H          Like -h, but only output EXPORT declarations.\n&quot;
+    &quot;  -v          (verbose) Write status information to the screen.\n&quot;
+    &quot;  -doc        Generate no header files.  Instead, output information\n&quot;
+    &quot;              that can be used by an automatic program documentation\n&quot;
+    &quot;              and cross-reference generator.\n&quot;
+    &quot;  -local      Generate prototypes for \&quot;static\&quot; functions and\n&quot;
+    &quot;              procedures.\n&quot;
+    &quot;  -f FILE     Read additional command-line arguments from the file named\n&quot;
+    &quot;              \&quot;FILE\&quot;.\n&quot;
+#ifdef DEBUG
+    &quot;  -! MASK     Set the debugging mask to the number \&quot;MASK\&quot;.\n&quot;
+#endif
+    &quot;  --          Treat all subsequent comment-line parameters as filenames,\n&quot;
+    &quot;              even if they begin with \&quot;-\&quot;.\n&quot;,
+    argv0
+  );
+}
+
+/*
+** The following text contains a few simple #defines that we want
+** to be available to every file.
+*/
+static const char zInit[] =
+  &quot;#define INTERFACE 0\n&quot;
+  &quot;#define EXPORT_INTERFACE 0\n&quot;
+  &quot;#define LOCAL_INTERFACE 0\n&quot;
+  &quot;#define EXPORT\n&quot;
+  &quot;#define LOCAL static\n&quot;
+  &quot;#define PUBLIC\n&quot;
+  &quot;#define PRIVATE\n&quot;
+  &quot;#define PROTECTED\n&quot;
+;
+
+#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&lt;argc; i++){
+    if( argv[i][0]==&#39;-&#39; &amp;&amp; !noMoreFlags ){
+      switch( argv[i][1] ){
+        case &#39;h&#39;:   h_flag = 1;   break;
+        case &#39;H&#39;:   H_flag = 1;   break;
+        case &#39;v&#39;:   v_flag = 1;   break;
+        case &#39;d&#39;:   doc_flag = 1; proto_static = 1; break;
+        case &#39;l&#39;:   proto_static = 1; break;
+        case &#39;f&#39;:   AddParameters(i, &amp;argc, &amp;argv); break;
+        case &#39;-&#39;:   noMoreFlags = 1;   break;
+#ifdef DEBUG
+        case &#39;!&#39;:   i++;  debugMask = strtol(argv[i],0,0); break;
+#endif
+        default:    Usage(argv[0],argv[i]); return 1;
+      }
+    }else{
+      pFile = CreateInFile(argv[i],&amp;nErr);
+      if( pFile ){
+        if( pFileList ){
+          pTail-&gt;pNext = pFile;
+          pTail = pFile;
+        }else{
+          pFileList = pTail = pFile;
+        }
+      }
+    }
+  }
+  if( h_flag &amp;&amp; H_flag ){
+    h_flag = 0;
+  }
+  if( v_flag ){
+    report = (h_flag || H_flag) ? stderr : stdout;
+  }else{
+    report = 0;
+  }
+  if( nErr&gt;0 ){
+    return nErr;
+  }
+  for(pFile=pFileList; pFile; pFile=pFile-&gt;pNext){
+    char *zFile;
+
+    zFilename = pFile-&gt;zSrc;
+    if( zFilename==0 ) continue;
+    zFile = ReadFile(zFilename);
+    if( zFile==0 ){
+      fprintf(stderr,&quot;Can&#39;t read input file \&quot;%s\&quot;\n&quot;,zFilename);
+      nErr++;
+      continue;
+    }
+    if( strncmp(zFile,zTopLine,nTopLine)==0 ){
+      pFile-&gt;zSrc = 0;
+    }else{
+      if( report ) fprintf(report,&quot;Reading %s...\n&quot;,zFilename);
+      pList = TokenizeFile(zFile,&amp;pFile-&gt;idTable);
+      if( pList ){
+        nErr += ParseFile(pList,pFile-&gt;flags);
+        FreeTokenList(pList);
+      }else if( zFile[0]==0 ){
+        fprintf(stderr,&quot;Input file \&quot;%s\&quot; is empty.\n&quot;, zFilename);
+        nErr++;
+      }else{
+        fprintf(stderr,&quot;Errors while processing \&quot;%s\&quot;\n&quot;, zFilename);
+        nErr++;
+      }
+    }
+    if( !doc_flag ) SafeFree(zFile);
+    if( doc_flag ) PrintModuleRecord(zFile,zFilename);
+  }
+  if( nErr&gt;0 ){
+    return nErr;
+  }
+#ifdef DEBUG
+  if( debugMask &amp; DECL_DUMP ){
+    DumpDeclList();
+    return nErr;
+  }
+#endif
+  if( doc_flag ){
+    DocumentationDump();
+    return nErr;
+  }
+  zFilename = &quot;--internal--&quot;;
+  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-&gt;pNext){
+      if( pFile-&gt;zSrc==0 ) continue;
+      nErr += MakeHeader(pFile,report,0);
+    }
+  }
+  return nErr;
+}
+#endif
+
+</pre>
+</blockquote>
+</div>
+<div class="footer">\r
+This page was generated in about\r
+0.007s by\r
+Fossil 2.9 [6f60cb3881] 2019-02-27 14:34:30\r
+</div>\r
+<script nonce="e2f4709a3deeafd8212401c84e2a082e1fbd3068470984f2">\r
+/*\r
+** Copyright © 2018 Warren Young\r
+**\r
+** This program is free software; you can redistribute it and/or\r
+** modify it under the terms of the Simplified BSD License (also\r
+** known as the "2-Clause License" or "FreeBSD License".)\r
+**\r
+** This program is distributed in the hope that it will be useful,\r
+** but without any warranty; without even the implied warranty of\r
+** merchantability or fitness for a particular purpose.\r
+**\r
+** Contact: wyoung on the Fossil forum, https://fossil-scm.org/forum/\r
+**\r
+*******************************************************************************\r
+**\r
+** This file contains the JS code specific to the Fossil default skin.\r
+** Currently, the only thing this does is handle clicks on its hamburger\r
+** menu button.\r
+*/\r
+(function() {\r
+  var hbButton = document.getElementById("hbbtn");\r
+  if (!hbButton) return;   // no hamburger button\r
+  if (!document.addEventListener) {\r
+    // Turn the button into a link to the sitemap for incompatible browsers.\r
+    hbButton.href = "/fossil/sitemap";\r
+    return;\r
+  }\r
+  var panel = document.getElementById("hbdrop");\r
+  if (!panel) return;   // site admin might've nuked it\r
+  if (!panel.style) return;  // shouldn't happen, but be sure\r
+  var panelBorder = panel.style.border;\r
+  var panelInitialized = false;   // reset if browser window is resized\r
+  var panelResetBorderTimerID = 0;   // used to cancel post-animation tasks\r
+\r
+  // Disable animation if this browser doesn't support CSS transitions.\r
+  //\r
+  // We need this ugly calling form for old browsers that don't allow\r
+  // panel.style.hasOwnProperty('transition'); catering to old browsers\r
+  // is the whole point here.\r
+  var animate = panel.style.transition !== null && (typeof(panel.style.transition) == "string");\r
+\r
+  // The duration of the animation can be overridden from the default skin\r
+  // header.txt by setting the "data-anim-ms" attribute of the panel.\r
+  var animMS = panel.getAttribute("data-anim-ms");\r
+  if (animMS) {           // not null or empty string, parse it\r
+    animMS = parseInt(animMS);\r
+    if (isNaN(animMS) || animMS == 0)\r
+      animate = false;    // disable animation if non-numeric or zero\r
+    else if (animMS < 0)\r
+      animMS = 400;       // set default animation duration if negative\r
+  }\r
+  else                    // attribute is null or empty string, use default\r
+    animMS = 400;\r
+\r
+  // Calculate panel height despite its being hidden at call time.\r
+  // Based on https://stackoverflow.com/a/29047447/142454\r
+  var panelHeight;  // computed on first panel display\r
+  function calculatePanelHeight() {\r
+\r
+    // Clear the max-height CSS property in case the panel size is recalculated\r
+    // after the browser window was resized.\r
+    panel.style.maxHeight = '';\r
+\r
+    // Get initial panel styles so we can restore them below.\r
+    var es   = window.getComputedStyle(panel),\r
+        edis = es.display,\r
+        epos = es.position,\r
+        evis = es.visibility;\r
+\r
+    // Restyle the panel so we can measure its height while invisible.\r
+    panel.style.visibility = 'hidden';\r
+    panel.style.position   = 'absolute';\r
+    panel.style.display    = 'block';\r
+    panelHeight = panel.offsetHeight + 'px';\r
+\r
+    // Revert styles now that job is done.\r
+    panel.style.display    = edis;\r
+    panel.style.position   = epos;\r
+    panel.style.visibility = evis;\r
+  }\r
+\r
+  // Show the panel by changing the panel height, which kicks off the\r
+  // slide-open/closed transition set up in the XHR onload handler.\r
+  //\r
+  // Schedule the change for a near-future time in case this is the\r
+  // first call, where the div was initially invisible.  If we were\r
+  // to change the panel's visibility and height at the same time\r
+  // instead, that would prevent the browser from seeing the height\r
+  // change as a state transition, so it'd skip the CSS transition:\r
+  //\r
+  // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#JavaScript_examples\r
+  function showPanel() {\r
+    // Cancel the timer to remove the panel border after the closing animation,\r
+    // otherwise double-clicking the hamburger button with the panel opened will\r
+    // remove the borders from the (closed and immediately reopened) panel.\r
+    if (panelResetBorderTimerID) {\r
+      clearTimeout(panelResetBorderTimerID);\r
+      panelResetBorderTimerID = 0;\r
+    }\r
+    if (animate) {\r
+      if (!panelInitialized) {\r
+        panelInitialized = true;\r
+        // Set up a CSS transition to animate the panel open and\r
+        // closed.  Only needs to be done once per page load.\r
+        // Based on https://stackoverflow.com/a/29047447/142454\r
+        calculatePanelHeight();\r
+        panel.style.transition = 'max-height ' + animMS +\r
+            'ms ease-in-out';\r
+        panel.style.overflowY  = 'hidden';\r
+        panel.style.maxHeight  = '0';\r
+      }\r
+      setTimeout(function() {\r
+        panel.style.maxHeight = panelHeight;\r
+        panel.style.border    = panelBorder;\r
+      }, 40);   // 25ms is insufficient with Firefox 62\r
+    }\r
+    panel.style.display = 'block';\r
+    document.addEventListener('keydown',panelKeydown,/* useCapture == */true);\r
+    document.addEventListener('click',panelClick,false);\r
+  }\r
+\r
+  var panelKeydown = function(event) {\r
+    var key = event.which || event.keyCode;\r
+    if (key == 27) {\r
+      event.stopPropagation();   // ignore other keydown handlers\r
+      panelToggle(true);\r
+    }\r
+  };\r
+\r
+  var panelClick = function(event) {\r
+    if (!panel.contains(event.target)) {\r
+      // Call event.preventDefault() to have clicks outside the opened panel\r
+      // just close the panel, and swallow clicks on links or form elements.\r
+      //event.preventDefault();\r
+      panelToggle(true);\r
+    }\r
+  };\r
+\r
+  // Return true if the panel is showing.\r
+  function panelShowing() {\r
+    if (animate) {\r
+      return panel.style.maxHeight == panelHeight;\r
+    }\r
+    else {\r
+      return panel.style.display == 'block';\r
+    }\r
+  }\r
+\r
+  // Check if the specified HTML element has any child elements. Note that plain\r
+  // text nodes, comments, and any spaces (presentational or not) are ignored.\r
+  function hasChildren(element) {\r
+    var childElement = element.firstChild;\r
+    while (childElement) {\r
+      if (childElement.nodeType == 1) // Node.ELEMENT_NODE == 1\r
+        return true;\r
+      childElement = childElement.nextSibling;\r
+    }\r
+    return false;\r
+  }\r
+\r
+  // Reset the state of the panel to uninitialized if the browser window is\r
+  // resized, so the dimensions are recalculated the next time it's opened.\r
+  window.addEventListener('resize',function(event) {\r
+    panelInitialized = false;\r
+  },false);\r
+\r
+  // Click handler for the hamburger button.\r
+  hbButton.addEventListener('click',function(event) {\r
+    // Break the event handler chain, or the handler for document → click\r
+    // (about to be installed) may already be triggered by the current event.\r
+    event.stopPropagation();\r
+    event.preventDefault();  // prevent browser from acting on <a> click\r
+    panelToggle(false);\r
+  },false);\r
+\r
+  function panelToggle(suppressAnimation) {\r
+    if (panelShowing()) {\r
+      document.removeEventListener('keydown',panelKeydown,/* useCapture == */true);\r
+      document.removeEventListener('click',panelClick,false);\r
+      // Transition back to hidden state.\r
+      if (animate) {\r
+        if (suppressAnimation) {\r
+          var transition = panel.style.transition;\r
+          panel.style.transition = '';\r
+          panel.style.maxHeight = '0';\r
+          panel.style.border = 'none';\r
+          setTimeout(function() {\r
+            // Make sure CSS transition won't take effect now, so restore it\r
+            // asynchronously. Outer variable 'transition' still valid here.\r
+            panel.style.transition = transition;\r
+          }, 40);   // 25ms is insufficient with Firefox 62\r
+        }\r
+        else {\r
+          panel.style.maxHeight = '0';\r
+          panelResetBorderTimerID = setTimeout(function() {\r
+            // Browsers show a 1px high border line when maxHeight == 0,\r
+            // our "hidden" state, so hide the borders in that state, too.\r
+            panel.style.border = 'none';\r
+            panelResetBorderTimerID = 0;   // clear ID of completed timer\r
+          }, animMS);\r
+        }\r
+      }\r
+      else {\r
+        panel.style.display = 'none';\r
+      }\r
+    }\r
+    else {\r
+      if (!hasChildren(panel)) {\r
+        // Only get the sitemap once per page load: it isn't likely to\r
+        // change on us.\r
+        var xhr = new XMLHttpRequest();\r
+        xhr.onload = function() {\r
+          var doc = xhr.responseXML;\r
+          if (doc) {\r
+            var sm = doc.querySelector("ul#sitemap");\r
+            if (sm && xhr.status == 200) {\r
+              // Got sitemap.  Insert it into the drop-down panel.\r
+              panel.innerHTML = sm.outerHTML;\r
+              // Display the panel\r
+              showPanel();\r
+            }\r
+          }\r
+          // else, can't parse response as HTML or XML\r
+        }\r
+        xhr.open("GET", "/fossil/sitemap?popup");   // note the TH1 substitution!\r
+        xhr.responseType = "document";\r
+        xhr.send();\r
+      }\r
+      else {\r
+        showPanel();   // just show what we built above\r
+      }\r
+    }\r
+  }\r
+})();\r
+\r
+</script>\r
+<script id='href-data' type='application/json'>{"delay":10,"mouseover":0}</script>
+<script nonce="e2f4709a3deeafd8212401c84e2a082e1fbd3068470984f2">
+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()
+</script>
+</body>
+</html>
diff --git a/tools/bin/gitadd b/tools/bin/gitadd
deleted file mode 100755 (executable)
index 9355724..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-set -x
-make dist-clean
-git add "$@"
-
diff --git a/tools/bin/makeheaders b/tools/bin/makeheaders
deleted file mode 100755 (executable)
index a50d9a0..0000000
Binary files a/tools/bin/makeheaders and /dev/null differ
diff --git a/tools/bin/setuid_root.sh b/tools/bin/setuid_root.sh
deleted file mode 100755 (executable)
index aedd564..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-chown root "$@" && \
-chmod u+rsx,u-w,go+rx-s-w "$@"
-
diff --git a/tools/bin/tranche b/tools/bin/tranche
deleted file mode 100755 (executable)
index eb63c28..0000000
Binary files a/tools/bin/tranche and /dev/null differ
diff --git a/tools/doc/makefile.txt b/tools/doc/makefile.txt
deleted file mode 100644 (file)
index 722de84..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-these are the comments from my RT makefile:
-
-#
-# 2010 11 20 TWL Created
-# 2011 05 26 TWL Modified to generalize
-# 2012 02 23 NLS Add ECHO variable to use on different environnement
-#                corrected setup macro --> add include directory in the path to copy
-#                corrected install macro --> change the name of installed library : lib$(LIB)$(LIBSUFFIX)
-#                changed DOC_DIR directory name to 5_documents
-# 2012 02 23 TWL removed LIB variable which is now set from the command line so
-#                so that all source dirs can use the same makefile
-# 2012 02 23 TWL added target make dist_clean which also deletes the 2_makefile_deps file
-# 2012 04 11 AWW added creation of temporary disk before each test is run 
-# 2012 06 05 TWL moved tests and try .cc files to directories. caused rtmake tests to
-#                dist_clean and make deps
-#
-#
-#----------------------------------------------------------------------------
-#      use this makefile to compile and test the code:
-#
-#               for a first time run, or for regression use the following:
-#
-#                   $ make setup  # makes the directories, though should already exist
-#                   $ make regress 
-#
-#               the usual development workflow makes use of these:
-#
-#                   $ make deps              # only when needed, for example if headers includes change or new files introduced
-#                   $ cd tests; make deps    # only when needed
-#                   $ make lib               # this makes the local library
-#                   $ make tests             # this updates tests and compiles
-#                   $ make clean             # deletes the .o files and library to force a recompile
-#                   $ cd 1_tests; make clean
-#
-#               for a release of a component
-# 
-#                   $ make regress
-#                   $ make install  # this will only work if all the tests in 1_tests are passing 
-#
-#               before a checkin
-# 
-#                   $ make dist_clean # will also clean the tests and try directories
-#
-#               .lib.cc c++ files taken as source of object files for local build library
-#               .exl.cc c++ files taken to have main calls and are linked against local build libary
-#               .ex.cc  c++ files taken to have main calls and are not linked against the local build library
-#               there are no rules for other files in this makefile
-#
-#      about dependencies
-#               The makefile has no way of knowing if an edit changed the dependencies.  Often they do not
-#               and it would be unwieldy to make the deps every time.  Hence *the programmer* must delete
-#               the deps file if he has made any changes that change the dependencies.
-#
-#               The makefile will make the 2_makefile_deps if the file is missing.
-# 
-#
-#      about testing
-#  
-#                the name of the directory you run make in is taken to also be: the name of the library,
-#                the name of the main include file (with a .h added), and the name of the include directory
-#                where the individual headers are found. It is called LIB
-#
-#               test programs are kept in a subdirectory called 1_tests, and are either .exl.cc, ex.cc,
-#                .sh files. When 'make tests' target is invoked they are all run. Test executables return 0
-#                if the test fails, non-zero otherwise.  
-#
-#                to remove a test from the pool move it into the subdirectory in 1_tests, 9_broken,
-#                5_more_tests of 5_scratch.  broken tests are things that are known but must be fixed
-#                before a release.  5_more_tests are tests being worked on.  5_scratch is stuff that is
-#                probably going to be deleted.  if there is a 5_deprecated, that is for good stuff but it
-#                is no longer used for some reason or other.
-#
-#                There is a standard source code template and a
-#                messaging convention.  Also, the names, by convention,are test_xxxx_ where xxx is a
-#                hexadecimal series nummber.  If all the test executables pass the file 1_TESTS_PASSED is
-#                left in the directory.  Otherwise the file 1_TESTS_FAILED is left in the directory.
-#
-#     about release directory
-#
-#               this is set in the ApplicationBase variable by rt_init
-#
-#               after the tests pass stuff might be copied to the release directory using
-# 
-#                  make install
-#
-#               the release directory must have these subdirectories:  
-#
-#                  bin documents include src
-#
-#
-#
diff --git a/tools/doc/makeheaders-notes.txt b/tools/doc/makeheaders-notes.txt
deleted file mode 100644 (file)
index 5aebda9..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-
-This worked to force the include to be part of the interface:
-
-#if INTERFACE
-#include <sqlite3.h>
-#endif
-
-But this did not:
-
-#if INTERFACE
-  #include <sqlite3.h>
-#endif
-
-makeheaders looks to be sensitive to indentation
-
-
diff --git a/tools/doc/makeheaders.html b/tools/doc/makeheaders.html
deleted file mode 100644 (file)
index 289da58..0000000
+++ /dev/null
@@ -1,1150 +0,0 @@
-<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 &#8220;<code>.h</code>&#8221;
-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> &#8220;<code>extern</code>&#8221; 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 &#8220;<code>.h</code>&#8221; suffix and definitions are
-placed in &#8220;<code>.c</code>&#8221; files.
-The .c files contain &#8220;<code>#include</code>&#8221; 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>&lt;stdio.h&gt</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 &#8220;exportable&#8221;.
-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
-&#8220;<code>alpha.c</code>&#8221;,
-&#8220;<code>beta.c</code>&#8221; and
-&#8220;<code>gamma.c</code>&#8221;
-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 &#8220;<code>-f</code>&#8221; 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 &#8220;<code>mkhdr.dat</code>&#8221;
-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 &#8220;<code>-local</code>&#8221; option causes makeheaders to
-generate of prototypes for &#8220;<code>static</code>&#8221; functions and
-procedures.
-Such prototypes are normally omitted.
-</p>
-
-<p>
-Finally, makeheaders also includes a &#8220;<code>-doc</code>&#8221; 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 &#8220;<code>--help</code>&#8221; or
-&#8220;<code>-?</code>&#8221;)
-and it will print a summary of the available options on standard
-error.
-If you need to process a file whose name begins with
-&#8220;<code>-</code>&#8221;,
-you can prepend a &#8220;<code>./</code>&#8221; to its name in order to get it
-accepted by the command line parser.
-Or, you can insert the special option &#8220;<code>--</code>&#8221; on the
-command line to cause all subsequent command line arguments to be treated as
-filenames even if their names begin with &#8220;<code>-</code>&#8221;.
-</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)
-&#8220;<code>alpha.c</code>&#8221;
-makeheaders will attempt to generate a corresponding header file
-named &#8220;<code>alpha.h</code>&#8221;.
-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 &#8220;<code>#include</code>&#8221; to the
-top of the file that sources the header file that makeheaders will generate.
-Hence, the beginning of a source file named &#8220;<code>alpha.c</code>&#8221;
-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
-&#8220;<code>#if</code>&#8221; 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 &#8220;<code>beta.h</code>&#8221;,
-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 &#8220;<code>#if</code>&#8221; 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,
-&#8220;<code>*.[ch]</code>&#8221;,
-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 &#8220;<code>static</code>&#8221; keyword of C appears at the
-beginning of the function definition, the prototype is suppressed.
-If you use the &#8220;<code>LOCAL</code>&#8221; keyword where you would normally
-say &#8220;<code>static</code>&#8221;, 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 &#8220;<code>LOCAL</code>&#8221; 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 &#8220;<code>-local</code>&#8221;
-command-line option, then it treats the &#8220;<code>static</code>&#8221;
-keyword like &#8220;<code>LOCAL</code>&#8221; 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
-&#8220;<code>extern</code>&#8221;
-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 &#8220;<code>struct</code>&#8221;, &#8220;<code>union</code>&#8221; or
-&#8220;<code>enum</code>&#8221; 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 &#8220;<code>X</code>&#8221; requires a
-prior declaration of another structure &#8220;<code>Y</code>&#8221;, 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
-&#8220;<code>#if INTERFACE</code>&#8221; but before the corresponding
-&#8220;<code>#endif</code>&#8221; are eligable to be copied into the
-automatically generated
-.h files of other .c files.
-</p>
-
-<p>
-If you use the &#8220;<code>#if INTERFACE</code>&#8221; 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
-&#8220;<code>#if INTERFACE</code>&#8221; 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
-&#8220;<code>#if INTERFACE</code>&#8221; 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 &#8220;<code>export</code>&#8221;.
-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 &#8220;<code>static</code>&#8221; 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: &#8220;<code>EXPORT</code>&#8221;
-</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 &#8220;<code>#if EXPORT_INTERFACE</code>&#8221; mechanism can be used in
-either .c or .h files.
-(The &#8220;<code>#if INTERFACE</code>&#8221; 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 &#8220;<code>private</code>&#8221;.
-</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 &#8220;<code>LOCAL_INTERFACE</code>&#8221; block works very much like the
-&#8220;<code>INTERFACE</code>&#8221; and
-&#8220;<code>EXPORT_INTERFACE</code>&#8221;
-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 &#8220;<code>class</code>&#8221;
-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 &#8220;<code>alpha.cpp</code>&#8221; will induce makeheaders to
-generate a header file named &#8220;<code>alpha.hpp</code>&#8221;.
-</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&amp;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&amp;R function.
-Therefore you should take care to avoid putting K&amp;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. &#8220;<code>enum {X, Y, Z};</code>&#8221;.
-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 &#8220;<code>-doc</code>&#8221; 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 &#8220;<code>-doc</code>&#8221; 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: &#8220;<code>#define</code>&#8221;)
-</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
-     (&#8220;<code>#if</code>&#8221;) 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>
diff --git a/tools/lib/bashrc b/tools/lib/bashrc
deleted file mode 100755 (executable)
index 79c23ec..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-
-umask 0077
-
-if [ $INSIDE_EMACS ]; then 
-  echo Hello Emacs
-fi
-export PS1='\n$(/usr/local/bin/Z)\n\u@\h§\w§\n> '
-export PS2='>>'
-PATH=~/bin:$PATH
-
-#temporarily while active in subu code development
-export PROJECT_SUBU=~/subu
-PATH="$PROJECT_SUBU"/tools/bin:$PATH
-
-export PS_FORMAT=user:15,pid,%cpu,%mem,vsz,rss,tty,stat,start,time,command
-
-export EDITOR=emacs
-
-
diff --git a/tools/lib/dot_emacs b/tools/lib/dot_emacs
deleted file mode 100755 (executable)
index 27132b6..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-
-(defun undedicate-window (&optional window)
-  (interactive)
-  (set-window-dedicated-p (or window (get-buffer-window)) nil))
-
-;; Removing annoying dedicated buffer nonsense
-(defun switch-to-buffer! (buffer-or-name &optional norecord force-same-window)
-  "Like switch-to-buffer but works for dedicated buffers \(though
-it will ask first)."
-  (interactive
-   (list (read-buffer-to-switch "Switch to buffer: ") nil 'force-same-window))
-  (when (and (window-dedicated-p (get-buffer-window))
-             (yes-or-no-p "This window is dedicated, undedicate it? "))
-    (undedicate-window))
-  (switch-to-buffer buffer-or-name norecord force-same-window))
-
-(defun toggle-window-dedication (&optional window)
-  (interactive)
-  (let ((window (or window (get-buffer-window))))
-    (set-window-dedicated-p window (not (window-dedicated-p window)))))
-
-(global-set-key (kbd "C-x d") 'toggle-window-dedication)
-
-;; fix 'feature' of broken gdb where it takes control of an
-;; emacs window, and locks the user out from switching from it
-;;
-;; yes and this fix breaks file name completion...
-;;
-;;  (defun set-window-undedicated-p (window flag)
-;;   "Never set window dedicated."
-;;   flag)
-;;  (advice-add 'set-window-dedicated-p :override #'set-window-undedicated-p)
-;;
-;; Toggle window dedication
-
-  (defun toggle-window-dedicated ()
-  "Toggle whether the current active window is dedicated or not"
-  (interactive)
-  (message 
-   (if (let (window (get-buffer-window (current-buffer)))
-         (set-window-dedicated-p window 
-          (not (window-dedicated-p window))))
-      "Window '%s' is dedicated"
-      "Window '%s' is normal")
-   (current-buffer)))
-
-   (global-set-key "\C-q" 'toggle-window-dedicated)
-
-;; (setq ring-bell-function (lambda ()
-;;                            (call-process-shell-command
-;;                              "xset led 3; xset -led 3" nil 0 nil)))
-;;
-;; (setq ring-bell-function nil)
-
- (setq ring-bell-function
-       (lambda ()
-        (call-process-shell-command "xset led named 'Scroll Lock'")
-        (call-process-shell-command "xset -led named 'Scroll Lock'")))
-
-
-;; preferable to have keys for the characters, but the keyboard is already overloaded ..
-;; (define-key key-translation-map (kbd "<f9> p") (kbd "¬"))
-;; (set-input-method “latin-9-prefix)
-
-  (global-set-key [f1] 'help-command)
-  (global-set-key "\C-h" 'nil)
-  (define-key key-translation-map (kbd "M-S") (kbd "§"))
-
-  (global-set-key (kbd "C-x g phi SPC") [?φ]) ; phi for phase
-  (global-set-key (kbd "C-x g Phi SPC") [?Φ]) 
-
-  (global-set-key (kbd "C-x g d SPC") [?δ])
-  (global-set-key (kbd "C-x g D SPC") [?Δ]) ; this is 'delta' is not 'increment'!
-  (global-set-key (kbd "C-x g delta SPC") [?δ])
-  (global-set-key (kbd "C-x g Delta SPC") [?Δ]) ; this is 'delta' is not 'increment'!
-
-
-  (global-set-key (kbd "C-x g g SPC") [?γ])
-  (global-set-key (kbd "C-x g G SPC") [?Γ])
-  (global-set-key (kbd "C-x g gamma SPC") [?γ])
-  (global-set-key (kbd "C-x g Gamma SPC") [?Γ])
-
-  (global-set-key (kbd "C-x g l SPC") [?λ])
-  (global-set-key (kbd "C-x g L SPC") [?Λ])
-  (global-set-key (kbd "C-x g lambda SPC") [?λ])
-  (global-set-key (kbd "C-x g Lambda SPC") [?Λ])
-
-  (global-set-key (kbd "C-x g p SPC") [?π])
-  (global-set-key (kbd "C-x g P SPC") [?Π])
-  (global-set-key (kbd "C-x g pi SPC") [?π])
-  (global-set-key (kbd "C-x g Pi SPC") [?Π])
-
-  (global-set-key (kbd "C-x g > = SPC") [?≥])
-  (global-set-key (kbd "C-x g < = SPC") [?≤])
-  (global-set-key (kbd "C-x g ! = SPC") [?≠])
-  (global-set-key (kbd "C-x g neq SPC") [?≠])
-      
-  (global-set-key (kbd "C-x g nil SPC") [?∅])
-
-  (global-set-key (kbd "C-x g not SPC") [?¬])
-
-  (global-set-key (kbd "C-x g and SPC") [?∧])
-  (global-set-key (kbd "C-x g or SPC") [?∨])
-
-  (global-set-key (kbd "C-x g exists SPC") [?∃])
-  (global-set-key (kbd "C-x g all SPC") [?∀])
-
-  (global-set-key (kbd "C-x g do SPC") [?⟳]) ; do
-  (global-set-key (kbd "C-x g rb SPC") [?◨])
-  (global-set-key (kbd "C-x g lb SPC") [?◧])
-
-  (global-set-key (kbd "C-x g cont SPC") [?➜]) ; continue
-  (global-set-key (kbd "C-x g thread SPC") [?☥]) ; thread
-
-  (global-set-key (kbd "C-x g in SPC") [?∈]) ; set membership
-
-
-
-;; lisp
-;;
-  (setq lisp-indent-offset 2)
-  (setq inferior-lisp-program "sbcl")      
-
-  (modify-syntax-entry ?[ "(]" lisp-mode-syntax-table)
-  (modify-syntax-entry ?] ")[" lisp-mode-syntax-table)
-  (modify-syntax-entry ?{ "(}" lisp-mode-syntax-table)
-  (modify-syntax-entry ?} "){" lisp-mode-syntax-table)
-
-;; get the pwd in shell mode from the prompt rather than guessing by
-;; watching the commands typed .. yes! now shell variables and source
-;; scripts will work
-;;   in bashrc: export PS1='\n$(/usr/local/bin/Z)\u@\h§\w§\n> '
-;;
-  (add-hook 'shell-mode-hook
-           (lambda ()
-             (shell-dirtrack-mode -1)
-             (dirtrack-mode 1)))
-
-  (add-hook 'dirtrack-directory-change-hook
-            (lambda ()
-              (message default-directory)))
-
-  (setq dirtrack-list '("§\\(.*\\)§\n> " 1))
-
-;; use a backrevs dir rather than leaving ~file droppings everywhere
-;;
-  (setq backup-directory-alist `(("." . "~/emacs_backrevs")))
-  (setq backup-by-copying t)
-
-;; stop the 'tab' character polution
-;;
-  (setq-default indent-tabs-mode nil)
-
-;; turn off the poison C-z key.  Use C-x C-z or the command suspend-emacs
-;;
-  (global-set-key (kbd "C-z") nil)
-
-;; truncate rather than wrapping lines (use horizontal scroll to see to the right)
-;;
-  (set-default 'truncate-lines t)
-  (setq truncate-partial-width-windows nil)
-  (setq-default fill-column 80)
-
-;; recover some window real estate
-;;   c-x mode-line to toggle the mode-line on and off
-;;
-  (defun mode-line () "toggles the modeline on and off"
-    (interactive) 
-    (setq mode-line-format
-      (if (equal mode-line-format nil)
-          (default-value 'mode-line-format)) )
-    (redraw-display))
-
-  (tool-bar-mode -1)
-  (menu-bar-mode -1)
-
-
-(put 'upcase-region 'disabled nil)
-(put 'narrow-to-region 'disabled nil)
-(put 'downcase-region 'disabled nil)
-(put 'set-goal-column 'disabled nil)
-
-
-(custom-set-variables
- ;; custom-set-variables was added by Custom.
- ;; If you edit it by hand, you could mess it up, so be careful.
- ;; Your init file should contain only one such instance.
- ;; If there is more than one, they won't work right.
-  '(ansi-color-names-vector
-     ["#212526" "#ff4b4b" "#b4fa70" "#fce94f" "#729fcf" "#e090d7" "#8cc4ff" "#eeeeec"])
- '(custom-enabled-themes (quote (wheatgrass)))
- '(geiser-racket-binary "racket")
- '(send-mail-function (quote smtpmail-send-it))
- '(tool-bar-mode nil))
-(custom-set-faces
- ;; custom-set-faces was added by Custom.
- ;; If you edit it by hand, you could mess it up, so be careful.
- ;; Your init file should contain only one such instance.
- ;; If there is more than one, they won't work right.
- '(default ((t (:family "DejaVu Sans Mono" :foundry "PfEd" :slant normal :weight bold :height 98 :width normal)))))
-
-(put 'erase-buffer 'disabled nil)
diff --git a/tools/lib/makefile_cc b/tools/lib/makefile_cc
deleted file mode 100755 (executable)
index bcf2475..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-
-#should add test that incdir is not pwd before deleting the include file in
-#dist-clean currently make is looking for module.h while the include file is
-#always module.lib.h so the lib include is not getting clobbered
-
-SHELL=/bin/bash
-
-# these are the sources edited by the programmer
-C_SOURCE_LIB=  $(wildcard $(SRCDIR)/*.lib.c)
-C_SOURCE_CLI=  $(wildcard $(SRCDIR)/*.cli.c)
-CC_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc)
-CC_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.cc)
-
-#remove the suffix to get base name
-C_BASE_LIB=  $(sort $(patsubst %.lib.c,  %, $(notdir $(C_SOURCE_LIB))))
-C_BASE_CLI=  $(sort $(patsubst %.cli.c,  %, $(notdir $(C_SOURCE_CLI))))
-CC_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CC_SOURCE_LIB))))
-CC_BASE_CLI= $(sort $(patsubst %.cli.cc, %, $(notdir $(CC_SOURCE_CLI))))
-
-# two sets of object files, one for the lib, and one for the command line interface progs
-OBJECT_LIB= $(patsubst %, $(TMPDIR)/%.lib.o, $(C_BASE_LIB) $(CC_BASE_LIB))
-OBJECT_CLI= $(patsubst %, $(TMPDIR)/%.cli.o, $(C_BASE_CLI) $(CC_BASE_CLI))
-
-# executables are made from CLI sources
-EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI))
-
-#otherwise make provides default values for these
-C=
-CC=
-
-DEPFILE=$(TMPDIR)/makefile-dep
-LIBFILE=$(LIBDIR)/lib$(MODULE).a
-INCFILE=$(INCDIR)/$(MODULE).h
-
--include makefile-flags
-
-# a single space literal, for example if you wanted to subsitute commas to
-# spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send
-# multiple separate command arguments to a shell script from one variable value
-blank :=
-space :=$(blank)  $(blank)
-
-.PHONY: all
-all: version dep lib exec
-
-.PHONY: version
-version:
-       @echo makefile version 4.0
-       @echo "PWD: " $(PWD)
-       @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST)
-       @echo "C: " $(C)
-       @echo "CFLAGS: " $(CFLAGS)
-       @echo "CC: " $(CC)
-       @echo "CCFLAGS: " $(CCFLAGS)
-       @echo "LINKFLAGS: " $(LINKFLAGS)
-
-.PHONY: info
-info:
-       @echo "DEPRDIR: " $(DEPRDIR)
-       @echo "DOCDIR: " $(DOCDIR)
-       @echo "EXECDIR: " $(EXECDIR)
-       @echo "INCDIR: " $(INCDIR)
-       @echo "LIBDIR: " $(LIBDIR)
-       @echo "TESTDIR: " $(TESTDIR)
-       @echo "TMPDIR: " $(TMPDIR)
-       @echo "TOOLSDIR: " $(TOOLSDIR)
-       @echo "TRYDIR: " $(TRYDIR)
-       @echo "DEPFILE: " $(DEPFILE)
-       @echo "LIBFILE: " $(LIBFILE)
-       @echo "INCFILE: " $(INCFILE)
-       @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB)
-       @echo "C_SOURCE_CLI: " $(C_SOURCE_CLI)
-       @echo "CC_SOURCE_LIB: " $(CC_SOURCE_LIB)
-       @echo "CC_SOURCE_CLI: " $(CC_SOURCE_CLI)
-       @echo "C_BASE_LIB: " $(C_BASE_LIB)
-       @echo "C_BASE_CLI: " $(C_BASE_CLI)
-       @echo "CC_BASE_LIB: " $(CC_BASE_LIB)
-       @echo "CC_BASE_CLI: " $(CC_BASE_CLI)
-       @echo "OBJECT_LIB: " $(OBJECT_LIB)
-       @echo "OBJECT_CLI: " $(OBJECT_CLI)
-       @echo "EXEC: " $(EXEC)
-
-# should be safe to run this in an already setup or partially setup directory
-.PHONY: setup
-setup:
-       [ ! -e $(DEPRDIR) ] && mkdir $(DEPRDIR) || true
-       [ ! -e $(DOCDIR) ]  && mkdir $(DOCDIR)  || true
-       [ ! -e $(EXECDIR) ] && mkdir $(EXECDIR) || true
-       [ ! -e $(INCDIR) ]  && mkdir $(INCDIR)  || true
-       [ ! -e $(LIBDIR) ]  && mkdir $(LIBDIR)  || true
-       [ ! -e $(SRCDIR) ]  && mkdir $(SRCDIR)  || true
-       [ ! -e $(TESTDIR) ] && mkdir $(TESTDIR) || true
-       [ ! -e $(TMPDIR) ]  && mkdir $(TMPDIR)  || true
-       [ ! -e $(TRYDIR) ]  && mkdir $(TRYDIR)  || true
-
-#better to put the dependency generation into a loop on the source file and specify -MT for the target
-#also should be redirecting only stdout so stderr messages will be displayed >>1 depfile
-.PHONY: dep
-dep: 
-       @if [ -z "$(CC)" ]; then\
-         if [ -z "$C()" ]; then\
-           echo "No compiler specified";\
-           exit 1;\
-         else\
-           echo "C compiler only deps" ;\
-           $(C) $(CFLAGS) -MM  $(C_SOURCE_LIB) $(C_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\
-           echo "deps for C linking";\
-           for i in $(C_BASE_CLI) ; do\
-             $(ECHO) >> $(DEPFILE);\
-             $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
-             $(ECHO) " $(C) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
-           done;\
-         fi;\
-       else\
-         $(CC) $(CCFLAGS) -MM  $(CC_SOURCE_LIB) $(CC_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\
-         if [ -z "$C()" ]; then\
-           echo "CC compiler only deps" ;\
-         else\
-           echo "CC and C mixed compile deps" ;\
-           $(C) $(CFLAGS) -MM   $(C_SOURCE_LIB) $(C_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\
-         fi;\
-         echo "deps for CC linking";\
-         for i in $(CC_BASE_CLI) $(C_BASE_CLI) ; do\
-           $(ECHO) >> $(DEPFILE);\
-           $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\
-           $(ECHO) "   $(CC) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\
-         done;\
-       fi
-
-.PHONY: lib
-lib: $(LIBFILE)
-
-$(LIBFILE): $(OBJECT_LIB)
-       ar rcs $(LIBFILE) $(OBJECT_LIB)
-
-.PHONY: exec
-exec: $(LIBFILE)
-       make sub_exec
-
-.PHONY: sub_exec
-sub_exec: $(EXEC)
-
-.PHONY: stage
-stage:
-       [ -f $(LIBFILE) ] && cp $(LIBFILE) $(PROJECT_SUBU)/stage/lib || true
-       [ -f $(INCFILE) ] && cp $(INCFILE) $(PROJECT_SUBU)/stage/include || true
-       [ $(shell ls -A $(EXECDIR)) ] && cp $(EXECDIR)/* $(PROJECT_SUBU)/stage/bin || true
-
-.PHONY: clean
-clean:
-       for i in $(wildcard tmp/*); do rm $$i || true; done 
-
-.PHONY: dist-clean
-dist-clean: clean
-       for i in $(EXEC); do [ -e $$i ] && rm $$i || true; done 
-       rm $(INCFILE) || true
-       rm $(LIBFILE) || true
-
--include $(DEPFILE)
-
-# recipes
-
-$(TMPDIR)/%.o : $(SRCDIR)/%.c
-       $(C) $(CFLAGS) -o $@ -c $<
-
-$(TMPDIR)/%.o : $(SRCDIR)/%.cc
-       $(CC) $(CCFLAGS) -o $@ -c $<
-
diff --git a/tools/lib/makefile_cc.~82b14679df98a141dbf8dac2f51f30d5fc84863b~ b/tools/lib/makefile_cc.~82b14679df98a141dbf8dac2f51f30d5fc84863b~
deleted file mode 100644 (file)
index 6de582b..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-
-SHELL=/bin/bash
-
--include 0_makefile-flags
-
-DEPSFILE=$(TMPDIR)/makefile_deps
-
-# a single space literal, for example if you wanted to subsitute commas to
-# spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send
-# multiple separate command arguments to a shell script from one variable value
-blank :=
-space :=$(blank)  $(blank)
-
-# files used by the compiler
-SOURCES_LIB= $(wildcard *.lib.c)
-SOURCES_CLI= $(wildcard *.cli.c)
-SOURCES= $(SOURCES_LIB) $(SOURCES_CLI)
-
-HFILES = $(wildcard *.lib.h) $(wildcard *.cli.h)
-
-OBJECTS_LIB= $(patsubst %.c, %.o, $(SOURCES_LIB))
-OBJECTS_CLI= $(patsubst %.c, %.o, $(SOURCES_CLI))
-OBJECTS= $(OBJECTS_LIB) $(OBJECTS_CLI)
-
-EXECS= $(sort $(patsubst %.cli.c,  %, $(wildcard *.cli.c)))
-
-all: version deps lib execs
-
-version:
-       @echo makefile version 3.0
-       @echo "PWD: " $(PWD)
-       @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST)
-       @echo "CC: " $(CC)
-       @echo "CFLAGS: " $(CFLAGS)
-       @echo "LINKFLAGS: " $(LINKFLAGS)
-
-info:
-       @echo "DEPDIR: " $(DEPDIR)
-       @echo "DOCDIR: " $(DOCDIR)
-       @echo "EXECSDIR: " $(EXECSDIR)
-       @echo "INCDIR: " $(INCDIR)
-       @echo "LIBDIR: " $(LIBDIR)
-       @echo "TESTDIR: " $(TESTDIR)
-       @echo "TMPDIR: " $(TMPDIR)
-       @echo "TOOLSDIR: " $(TOOLSDIR)
-       @echo "TRYDIR: " $(TRYDIR)
-       @echo "DEPSFILE: " $(DEPSFILE)
-       @echo "LIBFILE: " $(LIBFILE)
-       @echo "SOURCES_LIB: " $(SOURCES_LIB)
-       @echo "SOURCES_CLI: " $(SOURCES_CLI)
-       @echo "SOURCES: " $(SOURCES)
-       @echo "HFILES: " $(HFILES)
-       @echo "OBJECTS_LIB: " $(OBJECTS_LIB)
-       @echo "OBJECTS_CLI: " $(OBJECTS_CLI)
-       @echo "OBJECTS: " $(OBJECTS)
-       @echo "EXECS: " $(EXECS)
-
-# should be safe to run this in an already setup or partially setup directory
-setup:
-       if [ ! -e $(DEPRDIR) ]; then mkdir $(DEPRDIR); fi
-       if [ ! -e $(DOCDIR) ]; then mkdir $(DOCDIR); fi
-       if [ ! -e $(EXECSDIR) ]; then mkdir $(EXECSDIR); fi
-       if [ ! -e $(INCDIR) ]; then mkdir $(INCDIR); fi
-       if [ ! -e $(LIBDIR) ]; then mkdir $(LIBDIR); fi
-       if [ ! -e $(TESTDIR) ]; then mkdir $(TESTDIR); fi
-       if [ ! -e $(TMPDIR) ]; then mkdir $(TMPDIR); fi
-       if [ ! -e $(TRYDIR) ]; then mkdir $(TRYDIR); fi
-
-deps:
-       $(CC) $(CFLAGS) -MM $(SOURCES) 1> $(DEPSFILE)
-       for i in $(EXECS) ; do\
-           $(ECHO) >> $(DEPSFILE);\
-           $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\
-           $(ECHO) "   $(CC) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\
-        done
-
-lib: 
-       if [ ! -e $(DEPSFILE) ]; then make deps; fi
-       make sub_lib
-
-sub_lib: $(LIBDIR)/$(LIBFILE)
-
-
-execs: $(LIBDIR)/$(LIBFILE)
-       if [ ! -e $(DEPSFILE) ]; then make deps; fi
-       make sub_execs
-
-sub_execs: $(patsubst %,  $(EXECSDIR)/%, $(EXECS))
-
-stage:
-       if [ -f $(LIBDIR)/$(LIBFILE) ]; then cp $(LIBDIR)/$(LIBFILE) $(PROJECT_SUBU)/stage/lib; fi
-       if [ -f $(INCDIR)/$(INCFILE) ]; then cp $(INCDIR)/$(INCFILE) $(PROJECT_SUBU)/stage/include; fi
-       cp $(EXECSDIR)/* $(PROJECT_SUBU)/stage/bin
-
-clean:
-       for i in $(wildcard *~); do mv $$i $(TMPDIR); done
-       for i in $(wildcard *.lib.o) $(wildcard *.cli.o); do rm $$i; done 
-       for i in $(EXECS); do if [ -e $(EXECSDIR)/$$i ]; then rm $(EXECSDIR)/$$i; fi; done 
-       if [ -f $(LIBDIR)/$(LIBFILE) ]; then rm $(LIBDIR)/$(LIBFILE); fi
-       if [ -f $(DEPSFILE) ]; then rm $(DEPSFILE); fi
-
-#
-$(LIBDIR)/$(LIBFILE) : $(OBJECTS_LIB)
-       ar rcs $(LIBDIR)/$(LIBFILE) $(OBJECTS_LIB)
-
--include $(DEPSFILE)
-
-# recipe for making object files:
-#
-%.o : %.c
-       $(CC) $(CFLAGS) -c $<
-
-
diff --git a/tools/lib/makefile_trc b/tools/lib/makefile_trc
deleted file mode 100644 (file)
index 1edc8b3..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-
-# We should read the tranche sources and see what files they output, and then
-# build the deps accordingly, but this makefile is more primitive approach.
-# Here the programmer must have one output .c file or .cc file per input tranche
-# file and it must be name <base>.{lib,cli}.{c,cc} and the {.c,.cc} output
-# tranche must be named <base>.trc.{c,cc}
-
-# will re-orgnaize the directory structure .. will name the src-da .. etc. to the
-# name of the module, then have a source dir inside that has only the stuff
-# programmer's edit, then get rid of the numbers
-
-SHELL=/bin/bash
-
-#LIDBIR, EXECDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=deprecated
-DOCDIR=doc
-EXECDIR=exec
-INCDIR=include
-LIBDIR=lib
-SRCDIR=src
-TESTDIR=test
-TMPDIR=tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=try
-
-LIBFILE=$(LIBDIR)/lib$(MODULE).a
-INCFILE=$(MODULE).h
-
-# these are the sources edited by the programmer
-C_SOURCE_LIB=  $(wildcard $(SRCDIR)/*.lib.c)
-C_SOURCE_CLI=  $(wildcard $(SRCDIR)/*.cli.c)
-CC_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc)
-CC_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.cc)
-
-#remove the suffix to get base name
-C_BASE_LIB=  $(sort $(patsubst %.lib.c,  %, $(notdir $(C_SOURCE_LIB))))
-C_BASE_CLI=  $(sort $(patsubst %.cli.c,  %, $(notdir $(C_SOURCE_CLI))))
-CC_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CC_SOURCE_LIB))))
-CC_BASE_CLI= $(sort $(patsubst %.cli.cc, %, $(notdir $(CC_SOURCE_CLI))))
-
-# the progreammer must name the c and cc tranches accordingly:
-C_TRC_LIB= $(patasubst %, $(TMPDIR)/%.trc.c, C_BASE_LIB)
-C_TRC_CLI= $(patasubst %, $(TMPDIR)/%.trc.c, C_BASE_CLI)
-CC_TRC_LIB= $(patasubst %, $(TMPDIR)/%.trc.cc, CC_BASE_LIB)
-CC_TRC_CLI= $(patasubst %, $(TMPDIR)/%.trc.cc, CC_BASE_CLI)
-
-# two sets of object files, one for the lib, and one for the command line interface progs
-OBJECT_LIB= $(patsubst %, $(TMDIR)/%.o, $(C_BASE_LIB) $(CC_BASE_LIB))
-OBJECT_CLI= $(patsubst %, $(TMDIR)/%.o, $(C_BASE_CLI) $(CC_BASE_CLI))
-
-# executables are made from CLI sources
-EXEC= (patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI))
-
-#otherwise make provides default values for these
-C=
-CC=
-
--include makefile-flags
-
-DEPFILE=$(TMPDIR)/makefile_dep
-
-# a single space literal, for example if you wanted to subsitute commas to
-# spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send
-# multiple separate command arguments to a shell script from one variable value
-blank :=
-space :=$(blank)  $(blank)
-
-all: version deps lib execs
-
-version:
-       @echo makefile version 3.0
-       @echo "PWD: " $(PWD)
-       @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST)
-       @echo "C: " $(C)
-       @echo "CFLAGS: " $(CFLAGS)
-       @echo "CC: " $(CC)
-       @echo "CCFLAGS: " $(CCFLAGS)
-       @echo "LINKFLAGS: " $(LINKFLAGS)
-
-info:
-       @echo "DEPDIR: " $(DEPDIR)
-       @echo "DOCDIR: " $(DOCDIR)
-       @echo "EXECSDIR: " $(EXECSDIR)
-       @echo "INCDIR: " $(INCDIR)
-       @echo "LIBDIR: " $(LIBDIR)
-       @echo "TESTDIR: " $(TESTDIR)
-       @echo "TMPDIR: " $(TMPDIR)
-       @echo "TOOLSDIR: " $(TOOLSDIR)
-       @echo "TRYDIR: " $(TRYDIR)
-       @echo "DEPSFILE: " $(DEPSFILE)
-       @echo "LIBFILE: " $(LIBFILE)
-        @echo "TRC_TRC: " $(TRC_TRC)
-       @echo "C_BASE_LIB: " $(C_BASE_LIB)
-       @echo "C_BASE_CLI: " $(C_BASE_CLI)
-       @echo "CC_BASE_LIB: " $(CC_BASE_LIB)
-       @echo "CC_BASE_CLI: " $(CC_BASE_CLI)
-
-# should be safe to run this in an already setup or partially setup directory
-setup:
-       if [ ! -e $(DEPRDIR) ]; then mkdir $(DEPRDIR); fi
-       if [ ! -e $(DOCDIR) ]; then mkdir $(DOCDIR); fi
-       if [ ! -e $(EXECSDIR) ]; then mkdir $(EXECSDIR); fi
-       if [ ! -e $(INCDIR) ]; then mkdir $(INCDIR); fi
-       if [ ! -e $(LIBDIR) ]; then mkdir $(LIBDIR); fi
-       if [ ! -e $(SRCDIR) ]; then mkdir $(SRCDIR); fi
-       if [ ! -e $(TESTDIR) ]; then mkdir $(TESTDIR); fi
-       if [ ! -e $(TMPDIR) ]; then mkdir $(TMPDIR); fi
-       if [ ! -e $(TRYDIR) ]; then mkdir $(TRYDIR); fi
-
-dep: $(C_TRC_LIB) $(C_TRC_CLI) $(CC_TRC_LIB) $(CC_TRC_CLI)
-       if [ -z "$(CC)" ]; then\
-         if [ -z "$C()" ]; then\
-           echo "No compiler specified";\
-           exit 1;\
-         else\
-           echo "C compiler only deps" ;\
-           $(C) $(CFLAGS) -MM  $(C_TRC_LIB) $(C_TRC_CLI) 1> $(DEPSFILE);\
-           echo "deps for C linking";\
-           for i in $(EXECS) ; do\
-             $(ECHO) >> $(DEPSFILE);\
-             $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\
-             $(ECHO) " $(C) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\
-           done;\
-         fi;\
-       else\
-         $(CC) $(CCFLAGS) -MM  $(CC_TRC_LIB) $(CC_TRC_CLI) 1> $(DEPSFILE);\
-         if [ -z "$C()" ]; then\
-           echo "CC compiler only deps" ;\
-         else\
-           echo "CC and C mixed compile deps" ;\
-           $(C) $(CFLAGS) -MM   $(C_TRC_LIB) $(C_TRC_CLI) 1>> $(DEPSFILE);\
-         fi;\
-         echo "deps for CC linking";\
-         for i in $(EXECS) ; do\
-           $(ECHO) >> $(DEPSFILE);\
-           $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\
-           $(ECHO) "   $(CC) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\
-         done;\
-       fi
-
-lib: 
-       make $(LIBDIR)/$(LIBFILE)
-
-$(LIBDIR)/$(LIBFILE) : $(OBJECTS_LIB)
-       ar rcs $(LIBDIR)/$(LIBFILE) $(OBJECTS_LIB)
-
-exec: $(LIBDIR)/$(LIBFILE)
-       make sub_exec
-
-sub_exec: $(patsubst %,  $(EXECSDIR)/%, $(EXECS))
-
-stage:
-       if [ -f $(LIBDIR)/$(LIBFILE) ]; then cp $(LIBDIR)/$(LIBFILE) $(PROJECT_SUBU)/stage/lib; fi
-       if [ -f $(INCDIR)/$(INCFILE) ]; then cp $(INCDIR)/$(INCFILE) $(PROJECT_SUBU)/stage/include; fi
-       -cp $(EXECSDIR)/* $(PROJECT_SUBU)/stage/bin
-
-clean:
-       for i in $(wildcard *~); do mv $$i $(TMPDIR); done
-       for i in $(wildcard *.lib.o) $(wildcard *.cli.o); do rm $$i; done 
-       for i in $(EXECS); do if [ -e $(EXECSDIR)/$$i ]; then rm $(EXECSDIR)/$$i; fi; done 
-       if [ -f $(LIBDIR)/$(LIBFILE) ]; then rm $(LIBDIR)/$(LIBFILE); fi
-       if [ -f $(DEPSFILE) ]; then rm $(DEPSFILE); fi
-
--include $(DEPSFILE)
-
-# recipes
-#
-%.trc.c : %.lib.c
-       $(TRANCHE) $<
-
-%.trc.c : %.cli.c
-       $(TRANCHE) $<
-
-%.trc.cc : %.lib.cc
-       $(TRANCHE) $<
-
-%.trc.cc : %.cli.cc
-       $(TRANCHE) $<
-
-%.o : %.c
-       $(C) $(CFLAGS) -c $<
-
-%.o : %.cc
-       $(CC) $(CCFLAGS) -c $<
-
diff --git a/tools/src/makeheaders.c b/tools/src/makeheaders.c
deleted file mode 100644 (file)
index b58e787..0000000
+++ /dev/null
@@ -1,3739 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<base href="https://fossil-scm.org/fossil/doc/8cecc544/src/makeheaders.c" />
-<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: ; script-src 'self' 'nonce-e2f4709a3deeafd8212401c84e2a082e1fbd3068470984f2' ; style-src 'self' 'unsafe-inline'" />
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<title>Fossil: File Content</title>
-<link rel="alternate" type="application/rss+xml" title="RSS Feed"  href="/fossil/timeline.rss" />
-<link rel="stylesheet" href="/fossil/style.css?id=9eb7de39" type="text/css"  media="screen" />
-</head>
-<body>
-<div class="header">\r
-  <div class="title"><h1>Fossil</h1>File Content</div>\r
-    <div class="status"><a href='/fossil/login'>Login</a>
-</div>\r
-</div>\r
-<div class="mainmenu">\r
-<a id='hbbtn' href='#'>&#9776;</a><a href='/fossil/doc/trunk/www/index.wiki' class=''>Home</a>
-<a href='/fossil/timeline' class=''>Timeline</a>
-<a href='/fossil/doc/trunk/www/permutedindex.html' class=''>Docs</a>
-<a href='https://fossil-scm.org/forum'>Forum</a><a href='/fossil/uv/download.html' class='desktoponly'>Download</a>
-</div>\r
-<div id='hbdrop'></div>\r
-<form id='f01' method='GET' action='/fossil/file'>
-<input type='hidden' name='udc' value='1'>
-<div class="submenu">
-<a class="label" href="/fossil/artifact/49c76a69">Artifact</a>
-<a class="label" href="/fossil/timeline?n=200&amp;uf=49c76a6973d579ff0b346e5f73182fa72dd797cbb07e8b20612849dc2adef85d">Check-ins Using</a>
-<a class="label" href="/fossil/raw/src/makeheaders.c?name=49c76a6973d579ff0b346e5f73182fa72dd797cbb07e8b20612849dc2adef85d">Download</a>
-<a class="label" href="/fossil/hexdump?name=49c76a6973d579ff0b346e5f73182fa72dd797cbb07e8b20612849dc2adef85d">Hex</a>
-<label class='submenuctrl submenuckbox'><input type='checkbox' name='ln' id='submenuctrl-0' >Line Numbers</label>
-</div>
-<input type="hidden" name="name" value="src/makeheaders.c">
-</form>
-<script src='/fossil/builtin/menu.js?id=6f60cb38'></script>
-<div class="content">
-<h2>Latest version of file 'src/makeheaders.c':</h2>
-<ul>
-<li>File
-<a data-href='/fossil/finfo?name=src/makeheaders.c&m=49c76a6973d579ff' href='/fossil/honeypot'>src/makeheaders.c</a>
-&mdash; part of check-in
-<span class="timelineHistDsp">[8cecc544]</span>
-at
-2018-11-02 15:21:54
-on branch <a data-href='/fossil/timeline?r=trunk' href='/fossil/honeypot'>trunk</a>
-&mdash; Enhance makeheaders so that it is able to deal with static_assert() statements.
-(These do not come up in Fossil itself.  This check-in is in response to use
-of Makeheaders by external projects.)
- (user:
-drh
-size: 100011)
-<a data-href='/fossil/whatis/49c76a6973d579ff' href='/fossil/honeypot'>[more...]</a>
-</ul>
-<hr />
-<blockquote>
-<pre>
-/*
-** 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 &quot;2-Clause License&quot; or &quot;FreeBSD License&quot;.)
-**
-** 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 &quot;as is&quot; 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 &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;ctype.h&gt;
-#include &lt;memory.h&gt;
-#include &lt;sys/stat.h&gt;
-#include &lt;assert.h&gt;
-#include &lt;string.h&gt;
-
-#if defined( __MINGW32__) ||  defined(__DMC__) || defined(_MSC_VER) || defined(__POCC__)
-#  ifndef WIN32
-#    define WIN32
-#  endif
-#else
-# include &lt;unistd.h&gt;
-#endif
-
-/*
-** Macros for debugging.
-*/
-#ifdef DEBUG
-static int debugMask = 0;
-# define debug0(F,M)       if( (F)&amp;debugMask ){ fprintf(stderr,M); }
-# define debug1(F,M,A)     if( (F)&amp;debugMask ){ fprintf(stderr,M,A); }
-# define debug2(F,M,A,B)   if( (F)&amp;debugMask ){ fprintf(stderr,M,A,B); }
-# define debug3(F,M,A,B,C) if( (F)&amp;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&#39;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&#39;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 &quot;forward declaration&quot; is a declaration that an object exists that
-** doesn&#39;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 &quot;Properties&quot; below */
-  Token *pComment;   /* A block comment associated with this declaration */
-  Token tokenCode;   /* Implementation of functions and procedures */
-  Decl *pSameName;   /* Next declaration with the same &quot;zName&quot; */
-  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 &quot;typedef struct Abc Abc;&quot; and the
-** full declaration is &quot;struct Abc { int a; float b; };&quot;.)
-**
-** 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&#39;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 &#39;extern &quot;C&quot;&#39; in a C++ header.
-                                ** Prepend nothing in a C header */
-#define DP_ExternReqd   0x080   /* Prepend &#39;extern &quot;C&quot;&#39; in a C++ header if
-                                ** DP_Cplusplus is not also set. If DP_Cplusplus
-                                ** is set or this is a C header then
-                                ** prepend &#39;extern&#39; */
-
-/*
-** Convenience macros for dealing with declaration properties
-*/
-#define DeclHasProperty(D,P)    (((D)-&gt;flags&amp;(P))==(P))
-#define DeclHasAnyProperty(D,P) (((D)-&gt;flags&amp;(P))!=0)
-#define DeclSetProperty(D,P)    (D)-&gt;flags |= (P)
-#define DeclClearProperty(D,P)  (D)-&gt;flags &amp;= ~(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 &quot;flags&quot; 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    /* &quot;extern&quot; has been seen */
-#define PS_Export        0x001000    /* If between &quot;#if EXPORT_INTERFACE&quot;
-                                     ** and &quot;#endif&quot; */
-#define PS_Export2       0x002000    /* If &quot;EXPORT&quot; seen */
-#define PS_Typedef       0x004000    /* If &quot;typedef&quot; has been seen */
-#define PS_Static        0x008000    /* If &quot;static&quot; has been seen */
-#define PS_Interface     0x010000    /* If within #if INTERFACE..#endif */
-#define PS_Method        0x020000    /* If &quot;::&quot; token has been seen */
-#define PS_Local         0x040000    /* If within #if LOCAL_INTERFACE..#endif */
-#define PS_Local2        0x080000    /* If &quot;LOCAL&quot; seen. */
-#define PS_Public        0x100000    /* If &quot;PUBLIC&quot; seen. */
-#define PS_Protected     0x200000    /* If &quot;PROTECTED&quot; seen. */
-#define PS_Private       0x400000    /* If &quot;PRIVATE&quot; seen. */
-#define PS_PPP           0x700000    /* If any of PUBLIC, PRIVATE, PROTECTED */
-
-/*
-** The following set of flags are ORed into the &quot;flags&quot; 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 &quot;&quot; or &lt;&gt; */
-  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 &quot;#undef INTERFACE&quot; part is a hack to work around a name collision
-** in MSVC 2008.
-*/
-const char zTopLine[] =
-  &quot;/* \aThis file was automatically generated.  Do not edit! */\n&quot;
-  &quot;#undef INTERFACE\n&quot;;
-#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,&quot;Assertion failed on line %d\n&quot;,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,&quot;Out of memory.  Can&#39;t allocate %d bytes.\n&quot;,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,
-        &quot;Out of memory.  Can&#39;t enlarge an allocation to %d bytes\n&quot;,nByte);
-      exit(1);
-    }
-  }
-  return p;
-}
-static char *StrDup(const char *zSrc, int nByte){
-  char *zDest;
-  if( nByte&lt;=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)==&#39;_&#39; || isalnum(X))
-
-/*
-** Routines for dealing with unbounded strings.
-*/
-static void StringInit(String *pStr){
-  pStr-&gt;nAlloc = 0;
-  pStr-&gt;nUsed = 0;
-  pStr-&gt;zText = 0;
-}
-static void StringReset(String *pStr){
-  SafeFree(pStr-&gt;zText);
-  StringInit(pStr);
-}
-static void StringAppend(String *pStr, const char *zText, int nByte){
-  if( nByte&lt;=0 ){
-    nByte = strlen(zText);
-  }
-  if( pStr-&gt;nUsed + nByte &gt;= pStr-&gt;nAlloc ){
-    if( pStr-&gt;nAlloc==0 ){
-      pStr-&gt;nAlloc = nByte + 100;
-      pStr-&gt;zText = SafeMalloc( pStr-&gt;nAlloc );
-    }else{
-      pStr-&gt;nAlloc = pStr-&gt;nAlloc*2 + nByte;
-      pStr-&gt;zText = SafeRealloc(pStr-&gt;zText, pStr-&gt;nAlloc);
-    }
-  }
-  strncpy(&amp;pStr-&gt;zText[pStr-&gt;nUsed],zText,nByte);
-  pStr-&gt;nUsed += nByte;
-  pStr-&gt;zText[pStr-&gt;nUsed] = 0;
-}
-#define StringGet(S) ((S)-&gt;zText?(S)-&gt;zText:&quot;&quot;)
-
-/*
-** 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&lt;=0 ){
-    n = strlen(z);
-  }
-  while( n-- ){
-    h = h ^ (h&lt;&lt;5) ^ *z++;
-  }
-  return h &amp; 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&lt;=0 ){
-    len = strlen(zName);
-  }
-  h = Hash(zName,len) % DECL_HASH_SIZE;
-  p = apTable[h];
-  while( p &amp;&amp; (strncmp(p-&gt;zName,zName,len)!=0 || p-&gt;zName[len]!=0) ){
-    p = p-&gt;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-&gt;zName,0) % DECL_HASH_SIZE;
-  pOther = apTable[h];
-  while( pOther &amp;&amp; strcmp(pDecl-&gt;zName,pOther-&gt;zName)!=0 ){
-    pOther = pOther-&gt;pSameHash;
-  }
-  if( pOther ){
-    pDecl-&gt;pSameName = pOther-&gt;pSameName;
-    pOther-&gt;pSameName = pDecl;
-  }else{
-    pDecl-&gt;pSameName = 0;
-    pDecl-&gt;pSameHash = apTable[h];
-    apTable[h] = pDecl;
-  }
-  pDecl-&gt;pNext = 0;
-  if( pDeclFirst==0 ){
-    pDeclFirst = pDeclLast = pDecl;
-  }else{
-    pDeclLast-&gt;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-&gt;pNext){
-    if( pIf-&gt;zCondition==0 || *pIf-&gt;zCondition==0 ) continue;
-    if( !hasIf ){
-      hasIf = 1;
-      StringInit(&amp;str);
-    }else{
-      StringAppend(&amp;str,&quot; &amp;&amp; &quot;,4);
-    }
-    StringAppend(&amp;str,pIf-&gt;zCondition,0);
-  }
-  if( hasIf ){
-    zResult = StrDup(StringGet(&amp;str),0);
-    StringReset(&amp;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-&gt;zName = (char*)&amp;pDecl[1];
-  sprintf(pDecl-&gt;zName,&quot;%.*s&quot;,nName,zName);
-  pDecl-&gt;zFile = zFilename;
-  pDecl-&gt;pInclude = includeList;
-  pDecl-&gt;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&lt;=0 ){
-    nId = strlen(zId);
-  }
-  h = Hash(zId,nId) % IDENT_HASH_SIZE;
-  for(pId = pTable-&gt;apTable[h]; pId; pId=pId-&gt;pCollide){
-    if( strncmp(zId,pId-&gt;zName,nId)==0 &amp;&amp; pId-&gt;zName[nId]==0 ){
-      /* printf(&quot;Already in table: %.*s\n&quot;,nId,zId); */
-      return 0;
-    }
-  }
-  pId = SafeMalloc( sizeof(Ident) + nId + 1 );
-  pId-&gt;zName = (char*)&amp;pId[1];
-  sprintf(pId-&gt;zName,&quot;%.*s&quot;,nId,zId);
-  pId-&gt;pNext = pTable-&gt;pList;
-  pTable-&gt;pList = pId;
-  pId-&gt;pCollide = pTable-&gt;apTable[h];
-  pTable-&gt;apTable[h] = pId;
-  /* printf(&quot;Add to table: %.*s\n&quot;,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&lt;=0 ){
-    nId = strlen(zId);
-  }
-  h = Hash(zId,nId) % IDENT_HASH_SIZE;
-  for(pId = pTable-&gt;apTable[h]; pId; pId=pId-&gt;pCollide){
-    if( strncmp(zId,pId-&gt;zName,nId)==0 &amp;&amp; pId-&gt;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-&gt;pList; pId; pId = pNext){
-    pNext = pId-&gt;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-&gt;pList; pId; pId = pId-&gt;pNext){
-    fprintf(pOut,&quot;%s\n&quot;,pId-&gt;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,&amp;sStat)!=0
-#ifndef WIN32
-    || !S_ISREG(sStat.st_mode)
-#endif
-  ){
-    return 0;
-  }
-  pIn = fopen(zFilename,&quot;r&quot;);
-  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,&quot;w&quot;);
-  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. &quot;..&quot; or &#39;.&#39; */
-#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 &quot;low-level token&quot; 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 &quot;..&quot; or &#39;..&#39; */
-  int nErr = 0;    /* Number of errors seen */
-
-  z = pIn-&gt;z;
-  i = pIn-&gt;i;
-  pToken-&gt;nLine = pIn-&gt;nLine;
-  pToken-&gt;zText = &amp;z[i];
-  switch( z[i] ){
-    case 0:
-      pToken-&gt;eType = TT_EOF;
-      pToken-&gt;nText = 0;
-      break;
-
-    case &#39;#&#39;:
-      if( i==0 || z[i-1]==&#39;\n&#39; || (i&gt;1 &amp;&amp; z[i-1]==&#39;\r&#39; &amp;&amp; z[i-2]==&#39;\n&#39;)){
-        /* We found a preprocessor statement */
-        pToken-&gt;eType = TT_Preprocessor;
-        i++;
-        while( z[i]!=0 &amp;&amp; z[i]!=&#39;\n&#39; ){
-          if( z[i]==&#39;\\&#39; ){
-            i++;
-            if( z[i]==&#39;\n&#39; ) pIn-&gt;nLine++;
-          }
-          i++;
-        }
-        pToken-&gt;nText = i - pIn-&gt;i;
-      }else{
-        /* Just an operator */
-        pToken-&gt;eType = TT_Other;
-        pToken-&gt;nText = 1;
-      }
-      break;
-
-    case &#39; &#39;:
-    case &#39;\t&#39;:
-    case &#39;\r&#39;:
-    case &#39;\f&#39;:
-    case &#39;\n&#39;:
-      while( isspace(z[i]) ){
-        if( z[i]==&#39;\n&#39; ) pIn-&gt;nLine++;
-        i++;
-      }
-      pToken-&gt;eType = TT_Space;
-      pToken-&gt;nText = i - pIn-&gt;i;
-      break;
-
-    case &#39;\\&#39;:
-      pToken-&gt;nText = 2;
-      pToken-&gt;eType = TT_Other;
-      if( z[i+1]==&#39;\n&#39; ){
-        pIn-&gt;nLine++;
-        pToken-&gt;eType = TT_Space;
-      }else if( z[i+1]==0 ){
-        pToken-&gt;nText = 1;
-      }
-      break;
-
-    case &#39;\&#39;&#39;:
-    case &#39;\&quot;&#39;:
-      cStart = z[i];
-      startLine = pIn-&gt;nLine;
-      do{
-        i++;
-        c = z[i];
-        if( c==&#39;\n&#39; ){
-          if( !nlisc ){
-            fprintf(stderr,
-              &quot;%s:%d: (warning) Newline in string or character literal.\n&quot;,
-              zFilename, pIn-&gt;nLine);
-            nlisc = 1;
-          }
-          pIn-&gt;nLine++;
-        }
-        if( c==&#39;\\&#39; ){
-          i++;
-          c = z[i];
-          if( c==&#39;\n&#39; ){
-            pIn-&gt;nLine++;
-          }
-        }else if( c==cStart ){
-          i++;
-          c = 0;
-        }else if( c==0 ){
-          fprintf(stderr, &quot;%s:%d: Unterminated string or character literal.\n&quot;,
-             zFilename, startLine);
-          nErr++;
-        }
-      }while( c );
-      pToken-&gt;eType = TT_String;
-      pToken-&gt;nText = i - pIn-&gt;i;
-      break;
-
-    case &#39;/&#39;:
-      if( z[i+1]==&#39;/&#39; ){
-        /* C++ style comment */
-        while( z[i] &amp;&amp; z[i]!=&#39;\n&#39; ){ i++; }
-        pToken-&gt;eType = TT_Comment;
-        pToken-&gt;nText = i - pIn-&gt;i;
-      }else if( z[i+1]==&#39;*&#39; ){
-        /* C style comment */
-        int isBlockComment = i==0 || z[i-1]==&#39;\n&#39;;
-        i += 2;
-        startLine = pIn-&gt;nLine;
-        while( z[i] &amp;&amp; (z[i]!=&#39;*&#39; || z[i+1]!=&#39;/&#39;) ){
-          if( z[i]==&#39;\n&#39; ){
-            pIn-&gt;nLine++;
-            if( isBlockComment ){
-              if( z[i+1]==&#39;*&#39; || z[i+2]==&#39;*&#39; ){
-                 isBlockComment = 2;
-              }else{
-                 isBlockComment = 0;
-              }
-            }
-          }
-          i++;
-        }
-        if( z[i] ){
-          i += 2;
-        }else{
-          isBlockComment = 0;
-          fprintf(stderr,&quot;%s:%d: Unterminated comment\n&quot;,
-            zFilename, startLine);
-          nErr++;
-        }
-        pToken-&gt;eType = isBlockComment==2 ? TT_BlockComment : TT_Comment;
-        pToken-&gt;nText = i - pIn-&gt;i;
-      }else{
-        /* A divide operator */
-        pToken-&gt;eType = TT_Other;
-        pToken-&gt;nText = 1 + (z[i+1]==&#39;+&#39;);
-      }
-      break;
-
-    case &#39;0&#39;:
-      if( z[i+1]==&#39;x&#39; || z[i+1]==&#39;X&#39; ){
-        /* A hex constant */
-        i += 2;
-        while( isxdigit(z[i]) ){ i++; }
-      }else{
-        /* An octal constant */
-        while( isdigit(z[i]) ){ i++; }
-      }
-      pToken-&gt;eType = TT_Number;
-      pToken-&gt;nText = i - pIn-&gt;i;
-      break;
-
-    case &#39;1&#39;: case &#39;2&#39;: case &#39;3&#39;: case &#39;4&#39;:
-    case &#39;5&#39;: case &#39;6&#39;: case &#39;7&#39;: case &#39;8&#39;: case &#39;9&#39;:
-      while( isdigit(z[i]) ){ i++; }
-      if( (c=z[i])==&#39;.&#39; ){
-         i++;
-         while( isdigit(z[i]) ){ i++; }
-         c = z[i];
-         if( c==&#39;e&#39; || c==&#39;E&#39; ){
-           i++;
-           if( ((c=z[i])==&#39;+&#39; || c==&#39;-&#39;) &amp;&amp; isdigit(z[i+1]) ){ i++; }
-           while( isdigit(z[i]) ){ i++; }
-           c = z[i];
-         }
-         if( c==&#39;f&#39; || c==&#39;F&#39; || c==&#39;l&#39; || c==&#39;L&#39; ){ i++; }
-      }else if( c==&#39;e&#39; || c==&#39;E&#39; ){
-         i++;
-         if( ((c=z[i])==&#39;+&#39; || c==&#39;-&#39;) &amp;&amp; isdigit(z[i+1]) ){ i++; }
-         while( isdigit(z[i]) ){ i++; }
-      }else if( c==&#39;L&#39; || c==&#39;l&#39; ){
-         i++;
-         c = z[i];
-         if( c==&#39;u&#39; || c==&#39;U&#39; ){ i++; }
-      }else if( c==&#39;u&#39; || c==&#39;U&#39; ){
-         i++;
-         c = z[i];
-         if( c==&#39;l&#39; || c==&#39;L&#39; ){ i++; }
-      }
-      pToken-&gt;eType = TT_Number;
-      pToken-&gt;nText = i - pIn-&gt;i;
-      break;
-
-    case &#39;a&#39;: case &#39;b&#39;: case &#39;c&#39;: case &#39;d&#39;: case &#39;e&#39;: case &#39;f&#39;: case &#39;g&#39;:
-    case &#39;h&#39;: case &#39;i&#39;: case &#39;j&#39;: case &#39;k&#39;: case &#39;l&#39;: case &#39;m&#39;: case &#39;n&#39;:
-    case &#39;o&#39;: case &#39;p&#39;: case &#39;q&#39;: case &#39;r&#39;: case &#39;s&#39;: case &#39;t&#39;: case &#39;u&#39;:
-    case &#39;v&#39;: case &#39;w&#39;: case &#39;x&#39;: case &#39;y&#39;: case &#39;z&#39;: case &#39;A&#39;: case &#39;B&#39;:
-    case &#39;C&#39;: case &#39;D&#39;: case &#39;E&#39;: case &#39;F&#39;: case &#39;G&#39;: case &#39;H&#39;: case &#39;I&#39;:
-    case &#39;J&#39;: case &#39;K&#39;: case &#39;L&#39;: case &#39;M&#39;: case &#39;N&#39;: case &#39;O&#39;: case &#39;P&#39;:
-    case &#39;Q&#39;: case &#39;R&#39;: case &#39;S&#39;: case &#39;T&#39;: case &#39;U&#39;: case &#39;V&#39;: case &#39;W&#39;:
-    case &#39;X&#39;: case &#39;Y&#39;: case &#39;Z&#39;: case &#39;_&#39;:
-      while( isalnum(z[i]) || z[i]==&#39;_&#39; ){ i++; };
-      pToken-&gt;eType = TT_Id;
-      pToken-&gt;nText = i - pIn-&gt;i;
-      break;
-
-    case &#39;:&#39;:
-      pToken-&gt;eType = TT_Other;
-      pToken-&gt;nText = 1 + (z[i+1]==&#39;:&#39;);
-      break;
-
-    case &#39;=&#39;:
-    case &#39;&lt;&#39;:
-    case &#39;&gt;&#39;:
-    case &#39;+&#39;:
-    case &#39;-&#39;:
-    case &#39;*&#39;:
-    case &#39;%&#39;:
-    case &#39;^&#39;:
-    case &#39;&amp;&#39;:
-    case &#39;|&#39;:
-      pToken-&gt;eType = TT_Other;
-      pToken-&gt;nText = 1 + (z[i+1]==&#39;=&#39;);
-      break;
-
-    default:
-      pToken-&gt;eType = TT_Other;
-      pToken-&gt;nText = 1;
-      break;
-  }
-  pIn-&gt;i += pToken-&gt;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 &quot;#if 0&quot; and &quot;#endif&quot;.
-**
-** This routine returns the number of errors encountered.  An error
-** is an unterminated token or unmatched &quot;#if 0&quot;.
-**
-** 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-&gt;nLine;
-  while( 1 ){
-    nErr += GetToken(pIn,pToken);
-    /* printf(&quot;%04d: Type=%d nIf=%d [%.*s]\n&quot;,
-       pToken-&gt;nLine,pToken-&gt;eType,nIf,pToken-&gt;nText,
-       pToken-&gt;eType!=TT_Space ? pToken-&gt;zText : &quot;&lt;space&gt;&quot;); */
-    pToken-&gt;pComment = blockComment;
-    switch( pToken-&gt;eType ){
-      case TT_Comment:          /*0123456789 12345678 */
-       if( strncmp(pToken-&gt;zText, &quot;/*MAKEHEADERS-STOP&quot;, 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,&quot;%s:%d: Unterminated \&quot;#if\&quot;\n&quot;,
-             zFilename, startLine);
-          nErr++;
-        }
-        return nErr;
-
-      case TT_Preprocessor:
-        z = &amp;pToken-&gt;zText[1];
-        while( *z==&#39; &#39; || *z==&#39;\t&#39; ) z++;
-        if( sscanf(z,&quot;if %d&quot;,&amp;value)==1 &amp;&amp; value==0 ){
-          nIf++;
-          inZero = 1;
-        }else if( inZero ){
-          if( strncmp(z,&quot;if&quot;,2)==0 ){
-            nIf++;
-          }else if( strncmp(z,&quot;endif&quot;,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-&gt;zText;
-  sIn.i = 1;
-  sIn.nLine = 1;
-  while( go &amp;&amp; sIn.i &lt; pToken-&gt;nText ){
-    GetToken(&amp;sIn,&amp;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-&gt;eType ){
-    case TT_Id:
-      if( pTable!=0 ){
-        IdentTableInsert(pTable,pToken-&gt;zText,pToken-&gt;nText);
-      }
-      return nErr;
-
-    case TT_Preprocessor:
-      if( pTable!=0 ){
-        FindIdentifiersInMacro(pToken,pTable);
-      }
-      return nErr;
-
-    case TT_Other:
-      if( pToken-&gt;zText[0]==&#39;{&#39; ) break;
-      return nErr;
-
-    default:
-      return nErr;
-  }
-
-  iStart = pIn-&gt;i;
-  zStart = pToken-&gt;zText;
-  nLine = pToken-&gt;nLine;
-  nBrace = 1;
-  while( nBrace ){
-    nErr += GetNonspaceToken(pIn,pToken);
-    /* printf(&quot;%04d: nBrace=%d [%.*s]\n&quot;,pToken-&gt;nLine,nBrace,
-       pToken-&gt;nText,pToken-&gt;zText); */
-    switch( pToken-&gt;eType ){
-      case TT_EOF:
-        fprintf(stderr,&quot;%s:%d: Unterminated \&quot;{\&quot;\n&quot;,
-           zFilename, nLine);
-        nErr++;
-        pToken-&gt;eType = TT_Error;
-        return nErr;
-
-      case TT_Id:
-        if( pTable ){
-          IdentTableInsert(pTable,pToken-&gt;zText,pToken-&gt;nText);
-        }
-        break;
-
-      case TT_Preprocessor:
-        if( pTable!=0 ){
-          FindIdentifiersInMacro(pToken,pTable);
-        }
-        break;
-
-      case TT_Other:
-        if( (c = pToken-&gt;zText[0])==&#39;{&#39; ){
-          nBrace++;
-        }else if( c==&#39;}&#39; ){
-          nBrace--;
-        }
-        break;
-
-      default:
-        break;
-    }
-  }
-  pToken-&gt;eType = TT_Braces;
-  pToken-&gt;nText = 1 + pIn-&gt;i - iStart;
-  pToken-&gt;zText = zStart;
-  pToken-&gt;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-&gt;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(&amp;sIn,pNew,pTable);
-    debug3(TOKENIZER, &quot;Token on line %d: [%.*s]\n&quot;,
-       pNew-&gt;nLine, pNew-&gt;nText&lt;50 ? pNew-&gt;nText : 50, pNew-&gt;zText);
-    if( pFirst==0 ){
-      pFirst = pLast = pNew;
-      pNew-&gt;pPrev = 0;
-    }else{
-      pLast-&gt;pNext = pNew;
-      pNew-&gt;pPrev = pLast;
-      pLast = pNew;
-    }
-    if( pNew-&gt;eType==TT_EOF ) break;
-  }
-  if( pLast ) pLast-&gt;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,&quot;Usage: %s filename\n&quot;,*argv);
-    exit(1);
-  }
-  memset(&amp;sTable,0,sizeof(sTable));
-  zFile = ReadFile(argv[1]);
-  if( zFile==0 ){
-    fprintf(stderr,&quot;Can&#39;t read file \&quot;%s\&quot;\n&quot;,argv[1]);
-    exit(1);
-  }
-  pList = TokenizeFile(zFile,&amp;sTable);
-  for(p=pList; p; p=p-&gt;pNext){
-    int j;
-    switch( p-&gt;eType ){
-      case TT_Space:
-        printf(&quot;%4d: Space\n&quot;,p-&gt;nLine);
-        break;
-      case TT_Id:
-        printf(&quot;%4d: Id           %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
-        break;
-      case TT_Preprocessor:
-        printf(&quot;%4d: Preprocessor %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
-        break;
-      case TT_Comment:
-        printf(&quot;%4d: Comment\n&quot;,p-&gt;nLine);
-        break;
-      case TT_BlockComment:
-        printf(&quot;%4d: Block Comment\n&quot;,p-&gt;nLine);
-        break;
-      case TT_Number:
-        printf(&quot;%4d: Number       %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
-        break;
-      case TT_String:
-        printf(&quot;%4d: String       %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
-        break;
-      case TT_Other:
-        printf(&quot;%4d: Other        %.*s\n&quot;,p-&gt;nLine,p-&gt;nText,p-&gt;zText);
-        break;
-      case TT_Braces:
-        for(j=0; j&lt;p-&gt;nText &amp;&amp; j&lt;30 &amp;&amp; p-&gt;zText[j]!=&#39;\n&#39;; j++){}
-        printf(&quot;%4d: Braces       %.*s...}\n&quot;,p-&gt;nLine,j,p-&gt;zText);
-        break;
-      case TT_EOF:
-        printf(&quot;%4d: End of file\n&quot;,p-&gt;nLine);
-        break;
-      default:
-        printf(&quot;%4d: type %d\n&quot;,p-&gt;nLine,p-&gt;eType);
-        break;
-    }
-  }
-  FreeTokenList(pList);
-  SafeFree(zFile);
-  IdentTablePrint(&amp;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-&gt;pNext;
-  while( pFirst!=pLast ){
-    switch( pFirst-&gt;eType ){
-      case TT_Preprocessor:
-        printf(&quot;\n%.*s\n&quot;,pFirst-&gt;nText,pFirst-&gt;zText);
-        needSpace = 0;
-        break;
-
-      case TT_Id:
-      case TT_Number:
-        printf(&quot;%s%.*s&quot;, needSpace ? &quot; &quot; : &quot;&quot;, pFirst-&gt;nText, pFirst-&gt;zText);
-        needSpace = 1;
-        break;
-
-      default:
-        c = pFirst-&gt;zText[0];
-        printf(&quot;%s%.*s&quot;,
-          (needSpace &amp;&amp; (c==&#39;*&#39; || c==&#39;{&#39;)) ? &quot; &quot; : &quot;&quot;,
-          pFirst-&gt;nText, pFirst-&gt;zText);
-        needSpace = pFirst-&gt;zText[0]==&#39;,&#39;;
-        break;
-    }
-    pFirst = pFirst-&gt;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(&amp;str);
-  pLast = pLast-&gt;pNext;
-  while( pFirst!=pLast ){
-    if( pFirst==pSkip ){ iSkip = nSkip; }
-    if( iSkip&gt;0 ){
-      iSkip--;
-      pFirst=pFirst-&gt;pNext;
-      continue;
-    }
-    switch( pFirst-&gt;eType ){
-      case TT_Preprocessor:
-        StringAppend(&amp;str,&quot;\n&quot;,1);
-        StringAppend(&amp;str,pFirst-&gt;zText,pFirst-&gt;nText);
-        StringAppend(&amp;str,&quot;\n&quot;,1);
-        needSpace = 0;
-        break;
-
-      case TT_Id:
-        switch( pFirst-&gt;zText[0] ){
-          case &#39;E&#39;:
-            if( pFirst-&gt;nText==6 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;EXPORT&quot;,6)==0 ){
-              skipOne = 1;
-            }
-            break;
-          case &#39;P&#39;:
-            switch( pFirst-&gt;nText ){
-              case 6:  skipOne = !strncmp(pFirst-&gt;zText,&quot;PUBLIC&quot;, 6);    break;
-              case 7:  skipOne = !strncmp(pFirst-&gt;zText,&quot;PRIVATE&quot;,7);    break;
-              case 9:  skipOne = !strncmp(pFirst-&gt;zText,&quot;PROTECTED&quot;,9);  break;
-              default: break;
-            }
-            break;
-          default:
-            break;
-        }
-        if( skipOne ){
-          pFirst = pFirst-&gt;pNext;
-          continue;
-        }
-        /* Fall thru to the next case */
-      case TT_Number:
-        if( needSpace ){
-          StringAppend(&amp;str,&quot; &quot;,1);
-        }
-        StringAppend(&amp;str,pFirst-&gt;zText,pFirst-&gt;nText);
-        needSpace = 1;
-        break;
-
-      default:
-        c = pFirst-&gt;zText[0];
-        if( needSpace &amp;&amp; (c==&#39;*&#39; || c==&#39;{&#39;) ){
-          StringAppend(&amp;str,&quot; &quot;,1);
-        }
-        StringAppend(&amp;str,pFirst-&gt;zText,pFirst-&gt;nText);
-        /* needSpace = pFirst-&gt;zText[0]==&#39;,&#39;; */
-        needSpace = 0;
-        break;
-    }
-    pFirst = pFirst-&gt;pNext;
-  }
-  if( zTerm &amp;&amp; *zTerm ){
-    StringAppend(&amp;str,zTerm,strlen(zTerm));
-  }
-  zReturn = StrDup(StringGet(&amp;str),0);
-  StringReset(&amp;str);
-  return zReturn;
-}
-
-/*
-** This routine is called when we see one of the keywords &quot;struct&quot;,
-** &quot;enum&quot;, &quot;union&quot; or &quot;class&quot;.  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&#39;t also a variable definition)
-** then set *pReset to &#39;;&#39;.  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-&gt;pNext==0 || pList-&gt;pNext-&gt;eType!=TT_Id ){
-    return 0;
-  }
-  pName = pList-&gt;pNext;
-
-  /* Catch the case of &quot;struct Foo;&quot; and skip it. */
-  if( pName-&gt;pNext &amp;&amp; pName-&gt;pNext-&gt;zText[0]==&#39;;&#39; ){
-    *pReset = &#39;;&#39;;
-    return 0;
-  }
-
-  for(pEnd=pName-&gt;pNext; pEnd &amp;&amp; pEnd-&gt;eType!=TT_Braces; pEnd=pEnd-&gt;pNext){
-    switch( pEnd-&gt;zText[0] ){
-      case &#39;(&#39;:
-      case &#39;)&#39;:
-      case &#39;*&#39;:
-      case &#39;[&#39;:
-      case &#39;=&#39;:
-      case &#39;;&#39;:
-        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-&gt;pNext==0 || pEnd-&gt;pNext-&gt;zText[0]==&#39;;&#39; ){
-    *pReset = &#39;;&#39;;
-    need_to_collapse = 0;
-  }else{
-    need_to_collapse = 1;
-  }
-
-  if( proto_static==0 &amp;&amp; (flags &amp; (PS_Local|PS_Export|PS_Interface))==0 ){
-    /* Ignore these objects unless they are explicitly declared as interface,
-    ** or unless the &quot;-local&quot; command line option was specified. */
-    *pReset = &#39;;&#39;;
-    return 0;
-  }
-
-#ifdef DEBUG
-  if( debugMask &amp; PARSER ){
-    printf(&quot;**** Found type: %.*s %.*s...\n&quot;,
-      pList-&gt;nText, pList-&gt;zText, pName-&gt;nText, pName-&gt;zText);
-    PrintTokens(pList,pEnd);
-    printf(&quot;;\n&quot;);
-  }
-#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-&gt;zText ){
-    case &#39;c&#39;:  type = TY_Class;        break;
-    case &#39;s&#39;:  type = TY_Structure;    break;
-    case &#39;e&#39;:  type = TY_Enumeration;  break;
-    case &#39;u&#39;:  type = TY_Union;        break;
-    default:   /* Can&#39;t Happen */      break;
-  }
-  if( type!=TY_Class ){
-    pDecl = 0;
-  }else{
-    pDecl = FindDecl(pName-&gt;zText, pName-&gt;nText);
-    if( pDecl &amp;&amp; (pDecl-&gt;flags &amp; type)!=type ) pDecl = 0;
-  }
-  if( pDecl==0 ){
-    pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
-  }
-  if( (flags &amp; PS_Static) || !(flags &amp; (PS_Interface|PS_Export)) ){
-    DeclSetProperty(pDecl,DP_Local);
-  }
-  DeclSetProperty(pDecl,type);
-
-  /* The object has a full declaration only if it is contained within
-  ** &quot;#if INTERFACE...#endif&quot; or &quot;#if EXPORT_INTERFACE...#endif&quot; or
-  ** &quot;#if LOCAL_INTERFACE...#endif&quot;.  Otherwise, we only give it a
-  ** forward declaration.
-  */
-  if( flags &amp; (PS_Local | PS_Export | PS_Interface)  ){
-    pDecl-&gt;zDecl = TokensToString(pList,pEnd,&quot;;\n&quot;,0,0);
-  }else{
-    pDecl-&gt;zDecl = 0;
-  }
-  pDecl-&gt;pComment = pList-&gt;pComment;
-  StringInit(&amp;str);
-  StringAppend(&amp;str,&quot;typedef &quot;,0);
-  StringAppend(&amp;str,pList-&gt;zText,pList-&gt;nText);
-  StringAppend(&amp;str,&quot; &quot;,0);
-  StringAppend(&amp;str,pName-&gt;zText,pName-&gt;nText);
-  StringAppend(&amp;str,&quot; &quot;,0);
-  StringAppend(&amp;str,pName-&gt;zText,pName-&gt;nText);
-  StringAppend(&amp;str,&quot;;\n&quot;,2);
-  pDecl-&gt;zFwd = StrDup(StringGet(&amp;str),0);
-  StringReset(&amp;str);
-  StringInit(&amp;str);
-  StringAppend(&amp;str,pList-&gt;zText,pList-&gt;nText);
-  StringAppend(&amp;str,&quot; &quot;,0);
-  StringAppend(&amp;str,pName-&gt;zText,pName-&gt;nText);
-  StringAppend(&amp;str,&quot;;\n&quot;,2);
-  pDecl-&gt;zFwdCpp = StrDup(StringGet(&amp;str),0);
-  StringReset(&amp;str);
-  if( flags &amp; PS_Export ){
-    DeclSetProperty(pDecl,DP_Export);
-  }else if( flags &amp; PS_Local ){
-    DeclSetProperty(pDecl,DP_Local);
-  }
-
-  /* Here&#39;s something weird.  ANSI-C doesn&#39;t allow a forward declaration
-  ** of an enumeration.  So we have to build the typedef into the
-  ** definition.
-  */
-  if( pDecl-&gt;zDecl &amp;&amp; DeclHasProperty(pDecl, TY_Enumeration) ){
-    StringInit(&amp;str);
-    StringAppend(&amp;str,pDecl-&gt;zDecl,0);
-    StringAppend(&amp;str,pDecl-&gt;zFwd,0);
-    SafeFree(pDecl-&gt;zDecl);
-    SafeFree(pDecl-&gt;zFwd);
-    pDecl-&gt;zFwd = 0;
-    pDecl-&gt;zDecl = StrDup(StringGet(&amp;str),0);
-    StringReset(&amp;str);
-  }
-
-  if( pName-&gt;pNext-&gt;zText[0]==&#39;:&#39; ){
-    DeclSetProperty(pDecl,DP_Cplusplus);
-  }
-  if( pName-&gt;nText==5 &amp;&amp; strncmp(pName-&gt;zText,&quot;class&quot;,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-&gt;pPrev;
-      pPrev-&gt;pNext = pEnd-&gt;pNext;
-      pEnd-&gt;pNext-&gt;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 &quot;[&quot;, or
-**
-**     2.  The first identifier that is followed by a &quot;(&quot; where the
-**         &quot;(&quot; is followed by another identifier, or
-**
-**     3.  The first identifier followed by &quot;::&quot;, or
-**
-**     4.  If none of the above, then the last identifier.
-**
-**   In all of the above, certain reserved words (like &quot;char&quot;) 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-&gt;pNext;
-  for(p=pFirst; p &amp;&amp; p!=pLast; p=p-&gt;pNext){
-    if( p-&gt;eType==TT_Id ){
-      static IdentTable sReserved;
-      static int isInit = 0;
-      static const char *aWords[] = { &quot;char&quot;, &quot;class&quot;,
-       &quot;const&quot;, &quot;double&quot;, &quot;enum&quot;, &quot;extern&quot;, &quot;EXPORT&quot;, &quot;ET_PROC&quot;,
-       &quot;float&quot;, &quot;int&quot;, &quot;long&quot;,
-       &quot;PRIVATE&quot;, &quot;PROTECTED&quot;, &quot;PUBLIC&quot;,
-       &quot;register&quot;, &quot;static&quot;, &quot;struct&quot;, &quot;sizeof&quot;, &quot;signed&quot;, &quot;typedef&quot;,
-       &quot;union&quot;, &quot;volatile&quot;, &quot;virtual&quot;, &quot;void&quot;, };
-
-      if( !isInit ){
-        int i;
-        for(i=0; i&lt;sizeof(aWords)/sizeof(aWords[0]); i++){
-          IdentTableInsert(&amp;sReserved,aWords[i],0);
-        }
-        isInit = 1;
-      }
-      if( !IdentTableTest(&amp;sReserved,p-&gt;zText,p-&gt;nText) ){
-        pName = p;
-      }
-    }else if( p==pFirst ){
-      continue;
-    }else if( (c=p-&gt;zText[0])==&#39;[&#39; &amp;&amp; pName ){
-      break;
-    }else if( c==&#39;(&#39; &amp;&amp; p-&gt;pNext &amp;&amp; p-&gt;pNext-&gt;eType==TT_Id &amp;&amp; pName ){
-      break;
-    }else if( c==&#39;:&#39; &amp;&amp; p-&gt;zText[1]==&#39;:&#39; &amp;&amp; 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-&gt;pPrev;
-  while( pFirst-&gt;zText[0]==&#39;P&#39; ){
-    int rc = 1;
-    switch( pFirst-&gt;nText ){
-      case 6:  rc = strncmp(pFirst-&gt;zText,&quot;PUBLIC&quot;,6); break;
-      case 7:  rc = strncmp(pFirst-&gt;zText,&quot;PRIVATE&quot;,7); break;
-      case 9:  rc = strncmp(pFirst-&gt;zText,&quot;PROTECTED&quot;,9); break;
-      default:  break;
-    }
-    if( rc ) break;
-    pFirst = pFirst-&gt;pNext;
-  }
-  pClass = FindDeclName(pFirst,pLast);
-  if( pClass==0 ){
-    fprintf(stderr,&quot;%s:%d: Unable to find the class name for this method\n&quot;,
-       zFilename, pFirst-&gt;nLine);
-    return 1;
-  }
-  pDecl = FindDecl(pClass-&gt;zText, pClass-&gt;nText);
-  if( pDecl==0 || (pDecl-&gt;flags &amp; TY_Class)!=TY_Class ){
-    pDecl = CreateDecl(pClass-&gt;zText, pClass-&gt;nText);
-    DeclSetProperty(pDecl, TY_Class);
-  }
-  StringInit(&amp;str);
-  if( pDecl-&gt;zExtra ){
-    StringAppend(&amp;str, pDecl-&gt;zExtra, 0);
-    SafeFree(pDecl-&gt;zExtra);
-    pDecl-&gt;zExtra = 0;
-  }
-  type = flags &amp; PS_PPP;
-  if( pDecl-&gt;extraType!=type ){
-    if( type &amp; PS_Public ){
-      StringAppend(&amp;str, &quot;public:\n&quot;, 0);
-      pDecl-&gt;extraType = PS_Public;
-    }else if( type &amp; PS_Protected ){
-      StringAppend(&amp;str, &quot;protected:\n&quot;, 0);
-      pDecl-&gt;extraType = PS_Protected;
-    }else if( type &amp; PS_Private ){
-      StringAppend(&amp;str, &quot;private:\n&quot;, 0);
-      pDecl-&gt;extraType = PS_Private;
-    }
-  }
-  StringAppend(&amp;str, &quot;  &quot;, 0);
-  zDecl = TokensToString(pFirst, pLast, &quot;;\n&quot;, pClass, 2);
-  StringAppend(&amp;str, zDecl, 0);
-  SafeFree(zDecl);
-  pDecl-&gt;zExtra = StrDup(StringGet(&amp;str), 0);
-  StringReset(&amp;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 &amp; PS_Method ){
-    if( flags &amp; PS_PPP ){
-      return ProcessMethodDef(pFirst, pLast, flags);
-    }else{
-      return 0;
-    }
-  }
-  if( (flags &amp; PS_Static)!=0 &amp;&amp; !proto_static ){
-    return 0;
-  }
-  pCode = pLast;
-  while( pLast &amp;&amp; pLast!=pFirst &amp;&amp; pLast-&gt;zText[0]!=&#39;)&#39; ){
-    pLast = pLast-&gt;pPrev;
-  }
-  if( pLast==0 || pLast==pFirst || pFirst-&gt;pNext==pLast ){
-    fprintf(stderr,&quot;%s:%d: Unrecognized syntax.\n&quot;,
-      zFilename, pFirst-&gt;nLine);
-    return 1;
-  }
-  if( flags &amp; (PS_Interface|PS_Export|PS_Local) ){
-    fprintf(stderr,&quot;%s:%d: Missing \&quot;inline\&quot; on function or procedure.\n&quot;,
-      zFilename, pFirst-&gt;nLine);
-    return 1;
-  }
-  pName = FindDeclName(pFirst,pLast);
-  if( pName==0 ){
-    fprintf(stderr,&quot;%s:%d: Malformed function or procedure definition.\n&quot;,
-      zFilename, pFirst-&gt;nLine);
-    return 1;
-  }
-
-  /*
-  ** At this point we&#39;ve isolated a procedure declaration between pFirst
-  ** and pLast with the name pName.
-  */
-#ifdef DEBUG
-  if( debugMask &amp; PARSER ){
-    printf(&quot;**** Found routine: %.*s on line %d...\n&quot;, pName-&gt;nText,
-       pName-&gt;zText, pFirst-&gt;nLine);
-    PrintTokens(pFirst,pLast);
-    printf(&quot;;\n&quot;);
-  }
-#endif
-  pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
-  pDecl-&gt;pComment = pFirst-&gt;pComment;
-  if( pCode &amp;&amp; pCode-&gt;eType==TT_Braces ){
-    pDecl-&gt;tokenCode = *pCode;
-  }
-  DeclSetProperty(pDecl,TY_Subroutine);
-  pDecl-&gt;zDecl = TokensToString(pFirst,pLast,&quot;;\n&quot;,0,0);
-  if( (flags &amp; (PS_Static|PS_Local2))!=0 ){
-    DeclSetProperty(pDecl,DP_Local);
-  }else if( (flags &amp; (PS_Export2))!=0 ){
-    DeclSetProperty(pDecl,DP_Export);
-  }
-
-  if( flags &amp; DP_Cplusplus ){
-    DeclSetProperty(pDecl,DP_Cplusplus);
-  }else{
-    DeclSetProperty(pDecl,DP_ExternCReqd);
-  }
-
-  return 0;
-}
-
-/*
-** This routine is called whenever we see the &quot;inline&quot; 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-&gt;pNext){
-    if( pEnd-&gt;zText[0]==&#39;{&#39; || pEnd-&gt;zText[0]==&#39;;&#39; ){
-      *pReset = pEnd-&gt;zText[0];
-      break;
-    }
-  }
-  if( pEnd==0 ){
-    *pReset = &#39;;&#39;;
-    fprintf(stderr,&quot;%s:%d: incomplete inline procedure definition\n&quot;,
-      zFilename, pFirst-&gt;nLine);
-    return 1;
-  }
-  pName = FindDeclName(pFirst,pEnd);
-  if( pName==0 ){
-    fprintf(stderr,&quot;%s:%d: malformed inline procedure definition\n&quot;,
-      zFilename, pFirst-&gt;nLine);
-    return 1;
-  }
-
-#ifdef DEBUG
-  if( debugMask &amp; PARSER ){
-    printf(&quot;**** Found inline routine: %.*s on line %d...\n&quot;,
-       pName-&gt;nText, pName-&gt;zText, pFirst-&gt;nLine);
-    PrintTokens(pFirst,pEnd);
-    printf(&quot;\n&quot;);
-  }
-#endif
-  pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
-  pDecl-&gt;pComment = pFirst-&gt;pComment;
-  DeclSetProperty(pDecl,TY_Subroutine);
-  pDecl-&gt;zDecl = TokensToString(pFirst,pEnd,&quot;;\n&quot;,0,0);
-  if( (flags &amp; (PS_Static|PS_Local|PS_Local2)) ){
-    DeclSetProperty(pDecl,DP_Local);
-  }else if( flags &amp; (PS_Export|PS_Export2) ){
-    DeclSetProperty(pDecl,DP_Export);
-  }
-
-  if( flags &amp; 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 &#39;;&#39; or
-** a &#39;=&#39;.  If it is &#39;=&#39;, then assume we have a variable definition.
-**
-** If pEnd is &#39;;&#39;, then the determination is more difficult.  We have
-** to search for an occurrence of an ID followed immediately by &#39;(&#39;.
-** If found, we have a prototype.  Otherwise we are dealing with a
-** variable definition.
-*/
-static int isVariableDef(Token *pFirst, Token *pEnd){
-  if( pEnd &amp;&amp; pEnd-&gt;zText[0]==&#39;=&#39; &amp;&amp;
-    (pEnd-&gt;pPrev-&gt;nText!=8 || strncmp(pEnd-&gt;pPrev-&gt;zText,&quot;operator&quot;,8)!=0)
-  ){
-    return 1;
-  }
-  while( pFirst &amp;&amp; pFirst!=pEnd &amp;&amp; pFirst-&gt;pNext &amp;&amp; pFirst-&gt;pNext!=pEnd ){
-    if( pFirst-&gt;eType==TT_Id &amp;&amp; pFirst-&gt;pNext-&gt;zText[0]==&#39;(&#39; ){
-      return 0;
-    }
-    pFirst = pFirst-&gt;pNext;
-  }
-  return 1;
-}
-
-/*
-** Return TRUE if pFirst is the first token of a static assert.
-*/
-static int isStaticAssert(Token *pFirst){
-  if( (pFirst-&gt;nText==13 &amp;&amp; strncmp(pFirst-&gt;zText, &quot;static_assert&quot;, 13)==0)
-   || (pFirst-&gt;nText==14 &amp;&amp; strncmp(pFirst-&gt;zText, &quot;_Static_assert&quot;, 14)==0)
-  ){
-    return 1;
-  }else{
-    return 0;
-  }
-}
-
-/*
-** This routine is called whenever we encounter a &quot;;&quot; or &quot;=&quot;.  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 &amp; PS_Typedef ){
-    if( (flags &amp; (PS_Export2|PS_Local2))!=0 ){
-      fprintf(stderr,&quot;%s:%d: \&quot;EXPORT\&quot; or \&quot;LOCAL\&quot; ignored before typedef.\n&quot;,
-        zFilename, pFirst-&gt;nLine);
-      nErr++;
-    }
-    if( (flags &amp; (PS_Interface|PS_Export|PS_Local|DP_Cplusplus))==0 ){
-      /* It is illegal to duplicate a typedef in C (but OK in C++).
-      ** So don&#39;t record typedefs that aren&#39;t within a C++ file or
-      ** within #if INTERFACE..#endif */
-      return nErr;
-    }
-    if( (flags &amp; (PS_Interface|PS_Export|PS_Local))==0 &amp;&amp; proto_static==0 ){
-      /* Ignore typedefs that are not with &quot;#if INTERFACE..#endif&quot; unless
-      ** the &quot;-local&quot; command line option is used. */
-      return nErr;
-    }
-    if( (flags &amp; (PS_Interface|PS_Export))==0 ){
-      /* typedefs are always local, unless within #if INTERFACE..#endif */
-      isLocal = 1;
-    }
-  }else if( flags &amp; (PS_Static|PS_Local2) ){
-    if( proto_static==0 &amp;&amp; (flags &amp; PS_Local2)==0 ){
-      /* Don&#39;t record static variables unless the &quot;-local&quot; command line
-      ** option was specified or the &quot;LOCAL&quot; keyword is used. */
-      return nErr;
-    }
-    while( pFirst!=0 &amp;&amp; pFirst-&gt;pNext!=pEnd &amp;&amp;
-       ((pFirst-&gt;nText==6 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;static&quot;,6)==0)
-        || (pFirst-&gt;nText==5 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;LOCAL&quot;,6)==0))
-    ){
-      /* Lose the initial &quot;static&quot; or local from local variables.
-      ** We&#39;ll prepend &quot;extern&quot; later. */
-      pFirst = pFirst-&gt;pNext;
-      isLocal = 1;
-    }
-    if( pFirst==0 || !isLocal ){
-      return nErr;
-    }
-  }else if( flags &amp; PS_Method ){
-    /* Methods are declared by their class.  Don&#39;t declare separately. */
-    return nErr;
-  }else if( isStaticAssert(pFirst) ){
-    return 0;
-  }
-  isVar =  (flags &amp; (PS_Typedef|PS_Method))==0 &amp;&amp; isVariableDef(pFirst,pEnd);
-  if( isVar &amp;&amp; (flags &amp; (PS_Interface|PS_Export|PS_Local))!=0
-  &amp;&amp; (flags &amp; PS_Extern)==0 ){
-    fprintf(stderr,&quot;%s:%d: Can&#39;t define a variable in this context\n&quot;,
-      zFilename, pFirst-&gt;nLine);
-    nErr++;
-  }
-  pName = FindDeclName(pFirst,pEnd-&gt;pPrev);
-  if( pName==0 ){
-    if( pFirst-&gt;nText==4 &amp;&amp; strncmp(pFirst-&gt;zText,&quot;enum&quot;,4)==0 ){
-      /* Ignore completely anonymous enums.  See documentation section 3.8.1. */
-      return nErr;
-    }else{
-      fprintf(stderr,&quot;%s:%d: Can&#39;t find a name for the object declared here.\n&quot;,
-        zFilename, pFirst-&gt;nLine);
-      return nErr+1;
-    }
-  }
-
-#ifdef DEBUG
-  if( debugMask &amp; PARSER ){
-    if( flags &amp; PS_Typedef ){
-      printf(&quot;**** Found typedef %.*s at line %d...\n&quot;,
-        pName-&gt;nText, pName-&gt;zText, pName-&gt;nLine);
-    }else if( isVar ){
-      printf(&quot;**** Found variable %.*s at line %d...\n&quot;,
-        pName-&gt;nText, pName-&gt;zText, pName-&gt;nLine);
-    }else{
-      printf(&quot;**** Found prototype %.*s at line %d...\n&quot;,
-        pName-&gt;nText, pName-&gt;zText, pName-&gt;nLine);
-    }
-    PrintTokens(pFirst,pEnd-&gt;pPrev);
-    printf(&quot;;\n&quot;);
-  }
-#endif
-
-  pDecl = CreateDecl(pName-&gt;zText,pName-&gt;nText);
-  if( (flags &amp; PS_Typedef) ){
-    DeclSetProperty(pDecl, TY_Typedef);
-  }else if( isVar ){
-    DeclSetProperty(pDecl,DP_ExternReqd | TY_Variable);
-    if( !(flags &amp; DP_Cplusplus) ){
-      DeclSetProperty(pDecl,DP_ExternCReqd);
-    }
-  }else{
-    DeclSetProperty(pDecl, TY_Subroutine);
-    if( !(flags &amp; DP_Cplusplus) ){
-      DeclSetProperty(pDecl,DP_ExternCReqd);
-    }
-  }
-  pDecl-&gt;pComment = pFirst-&gt;pComment;
-  pDecl-&gt;zDecl = TokensToString(pFirst,pEnd-&gt;pPrev,&quot;;\n&quot;,0,0);
-  if( isLocal || (flags &amp; (PS_Local|PS_Local2))!=0 ){
-    DeclSetProperty(pDecl,DP_Local);
-  }else if( flags &amp; (PS_Export|PS_Export2) ){
-    DeclSetProperty(pDecl,DP_Export);
-  }
-  if( flags &amp; 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 &quot;define&quot; or &quot;!&quot; */
-  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-&gt;zCondition = (char*)&amp;pIf[1];
-    if( zPrefix ){
-      sprintf(pIf-&gt;zCondition,&quot;%s(%.*s)&quot;,zPrefix,nText,zText);
-    }else{
-      sprintf(pIf-&gt;zCondition,&quot;%.*s&quot;,nText,zText);
-    }
-  }else{
-    pIf-&gt;zCondition = 0;
-  }
-  pIf-&gt;nLine = nLine;
-  pIf-&gt;flags = flags;
-  pIf-&gt;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 &quot;#if INTERFACE&quot; 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 = &amp;pToken-&gt;zText[1];
-  while( isspace(*zCmd) &amp;&amp; *zCmd!=&#39;\n&#39; ){
-    zCmd++;
-  }
-  if( !isalpha(*zCmd) ){
-    return 0;
-  }
-  nCmd = 1;
-  while( isalpha(zCmd[nCmd]) ){
-    nCmd++;
-  }
-
-  if( nCmd==5 &amp;&amp; strncmp(zCmd,&quot;endif&quot;,5)==0 ){
-    /*
-    ** Pop the if stack
-    */
-    pIf = ifStack;
-    if( pIf==0 ){
-      fprintf(stderr,&quot;%s:%d: extra &#39;#endif&#39;.\n&quot;,zFilename,pToken-&gt;nLine);
-      return 1;
-    }
-    ifStack = pIf-&gt;pNext;
-    SafeFree(pIf);
-  }else if( nCmd==6 &amp;&amp; strncmp(zCmd,&quot;define&quot;,6)==0 ){
-    /*
-    ** Record a #define if we are in PS_Interface or PS_Export
-    */
-    Decl *pDecl;
-    if( !(flags &amp; (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
-    zArg = &amp;zCmd[6];
-    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
-      zArg++;
-    }
-    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
-    for(nArg=0; ISALNUM(zArg[nArg]); nArg++){}
-    if( nArg==0 ){ return 0; }
-    pDecl = CreateDecl(zArg,nArg);
-    pDecl-&gt;pComment = pToken-&gt;pComment;
-    DeclSetProperty(pDecl,TY_Macro);
-    pDecl-&gt;zDecl = SafeMalloc( pToken-&gt;nText + 2 );
-    sprintf(pDecl-&gt;zDecl,&quot;%.*s\n&quot;,pToken-&gt;nText,pToken-&gt;zText);
-    if( flags &amp; PS_Export ){
-      DeclSetProperty(pDecl,DP_Export);
-    }else if( flags &amp; PS_Local ){
-      DeclSetProperty(pDecl,DP_Local);
-    }
-  }else if( nCmd==7 &amp;&amp; strncmp(zCmd,&quot;include&quot;,7)==0 ){
-    /*
-    ** Record an #include if we are in PS_Interface or PS_Export
-    */
-    Include *pInclude;
-    char *zIf;
-
-    if( !(flags &amp; (PS_Interface|PS_Export)) ){ return 0; }
-    zArg = &amp;zCmd[7];
-    while( *zArg &amp;&amp; isspace(*zArg) ){ zArg++; }
-    for(nArg=0; !isspace(zArg[nArg]); nArg++){}
-    if( (zArg[0]==&#39;&quot;&#39; &amp;&amp; zArg[nArg-1]!=&#39;&quot;&#39;)
-      ||(zArg[0]==&#39;&lt;&#39; &amp;&amp; zArg[nArg-1]!=&#39;&gt;&#39;)
-    ){
-      fprintf(stderr,&quot;%s:%d: malformed #include statement.\n&quot;,
-        zFilename,pToken-&gt;nLine);
-      return 1;
-    }
-    zIf = GetIfString();
-    if( zIf ){
-      pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 );
-      pInclude-&gt;zFile = (char*)&amp;pInclude[1];
-      pInclude-&gt;zLabel = &amp;pInclude-&gt;zFile[nArg+1];
-      sprintf(pInclude-&gt;zFile,&quot;%.*s&quot;,nArg,zArg);
-      sprintf(pInclude-&gt;zLabel,&quot;%.*s:%s&quot;,nArg,zArg,zIf);
-      pInclude-&gt;zIf = &amp;pInclude-&gt;zLabel[nArg+1];
-      SafeFree(zIf);
-    }else{
-      pInclude = SafeMalloc( sizeof(Include) + nArg + 1 );
-      pInclude-&gt;zFile = (char*)&amp;pInclude[1];
-      sprintf(pInclude-&gt;zFile,&quot;%.*s&quot;,nArg,zArg);
-      pInclude-&gt;zIf = 0;
-      pInclude-&gt;zLabel = pInclude-&gt;zFile;
-    }
-    pInclude-&gt;pNext = includeList;
-    includeList = pInclude;
-  }else if( nCmd==2 &amp;&amp; strncmp(zCmd,&quot;if&quot;,2)==0 ){
-    /*
-    ** Push an #if.  Watch for the special cases of INTERFACE
-    ** and EXPORT_INTERFACE and LOCAL_INTERFACE
-    */
-    zArg = &amp;zCmd[2];
-    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
-      zArg++;
-    }
-    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
-    nArg = pToken-&gt;nText + (int)(pToken-&gt;zText - zArg);
-    if( nArg==9 &amp;&amp; strncmp(zArg,&quot;INTERFACE&quot;,9)==0 ){
-      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Interface);
-    }else if( nArg==16 &amp;&amp; strncmp(zArg,&quot;EXPORT_INTERFACE&quot;,16)==0 ){
-      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Export);
-    }else if( nArg==15 &amp;&amp; strncmp(zArg,&quot;LOCAL_INTERFACE&quot;,15)==0 ){
-      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Local);
-    }else if( nArg==15 &amp;&amp; strncmp(zArg,&quot;MAKEHEADERS_STOPLOCAL_INTERFACE&quot;,15)==0 ){
-      PushIfMacro(0,0,0,pToken-&gt;nLine,PS_Local);
-    }else{
-      PushIfMacro(0,zArg,nArg,pToken-&gt;nLine,0);
-    }
-  }else if( nCmd==5 &amp;&amp; strncmp(zCmd,&quot;ifdef&quot;,5)==0 ){
-    /*
-    ** Push an #ifdef.
-    */
-    zArg = &amp;zCmd[5];
-    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
-      zArg++;
-    }
-    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
-    nArg = pToken-&gt;nText + (int)(pToken-&gt;zText - zArg);
-    PushIfMacro(&quot;defined&quot;,zArg,nArg,pToken-&gt;nLine,0);
-  }else if( nCmd==6 &amp;&amp; strncmp(zCmd,&quot;ifndef&quot;,6)==0 ){
-    /*
-    ** Push an #ifndef.
-    */
-    zArg = &amp;zCmd[6];
-    while( *zArg &amp;&amp; isspace(*zArg) &amp;&amp; *zArg!=&#39;\n&#39; ){
-      zArg++;
-    }
-    if( *zArg==0 || *zArg==&#39;\n&#39; ){ return 0; }
-    nArg = pToken-&gt;nText + (int)(pToken-&gt;zText - zArg);
-    PushIfMacro(&quot;!defined&quot;,zArg,nArg,pToken-&gt;nLine,0);
-  }else if( nCmd==4 &amp;&amp; strncmp(zCmd,&quot;else&quot;,4)==0 ){
-    /*
-    ** Invert the #if on the top of the stack
-    */
-    if( ifStack==0 ){
-      fprintf(stderr,&quot;%s:%d: &#39;#else&#39; without an &#39;#if&#39;\n&quot;,zFilename,
-         pToken-&gt;nLine);
-      return 1;
-    }
-    pIf = ifStack;
-    if( pIf-&gt;zCondition ){
-      ifStack = ifStack-&gt;pNext;
-      PushIfMacro(&quot;!&quot;,pIf-&gt;zCondition,strlen(pIf-&gt;zCondition),pIf-&gt;nLine,0);
-      SafeFree(pIf);
-    }else{
-      pIf-&gt;flags = 0;
-    }
-  }else{
-    /*
-    ** This directive can be safely ignored
-    */
-    return 0;
-  }
-
-  /*
-  ** Recompute the preset flags
-  */
-  *pPresetFlags = 0;
-  for(pIf = ifStack; pIf; pIf=pIf-&gt;pNext){
-    *pPresetFlags |= pIf-&gt;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-&gt;eType ){
-    case TT_EOF:
-      goto end_of_loop;
-
-    case TT_Preprocessor:
-      nErr += ParsePreprocessor(pList,flags,&amp;presetFlags);
-      pStart = 0;
-      presetFlags |= initFlags;
-      flags = presetFlags;
-      break;
-
-    case TT_Other:
-      switch( pList-&gt;zText[0] ){
-      case &#39;;&#39;:
-        nErr += ProcessDecl(pStart,pList,flags);
-        pStart = 0;
-        flags = presetFlags;
-        break;
-
-      case &#39;=&#39;:
-        if( pList-&gt;pPrev-&gt;nText==8
-            &amp;&amp; strncmp(pList-&gt;pPrev-&gt;zText,&quot;operator&quot;,8)==0 ){
-          break;
-        }
-        nErr += ProcessDecl(pStart,pList,flags);
-        pStart = 0;
-        while( pList &amp;&amp; pList-&gt;zText[0]!=&#39;;&#39; ){
-          pList = pList-&gt;pNext;
-        }
-        if( pList==0 ) goto end_of_loop;
-        flags = presetFlags;
-        break;
-
-      case &#39;:&#39;:
-        if( pList-&gt;zText[1]==&#39;:&#39; ){
-          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-&gt;zText[0] ){
-       case &#39;c&#39;:
-         if( pList-&gt;nText==5 &amp;&amp; strncmp(pList-&gt;zText,&quot;class&quot;,5)==0 ){
-           nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
-         }
-         break;
-
-       case &#39;E&#39;:
-         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;EXPORT&quot;,6)==0 ){
-           flags |= PS_Export2;
-           /* pStart = 0; */
-         }
-         break;
-
-       case &#39;e&#39;:
-         if( pList-&gt;nText==4 &amp;&amp; strncmp(pList-&gt;zText,&quot;enum&quot;,4)==0 ){
-           if( pList-&gt;pNext &amp;&amp; pList-&gt;pNext-&gt;eType==TT_Braces ){
-             pList = pList-&gt;pNext;
-           }else{
-             nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
-           }
-         }else if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;extern&quot;,6)==0 ){
-           pList = pList-&gt;pNext;
-           if( pList &amp;&amp; pList-&gt;nText==3 &amp;&amp; strncmp(pList-&gt;zText,&quot;\&quot;C\&quot;&quot;,3)==0 ){
-             pList = pList-&gt;pNext;
-             flags &amp;= ~DP_Cplusplus;
-           }else{
-             flags |= PS_Extern;
-           }
-           pStart = pList;
-         }
-         break;
-
-       case &#39;i&#39;:
-         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;inline&quot;,6)==0
-          &amp;&amp; (flags &amp; PS_Static)==0
-         ){
-           nErr += ProcessInlineProc(pList,flags,&amp;resetFlag);
-         }
-         break;
-
-       case &#39;L&#39;:
-         if( pList-&gt;nText==5 &amp;&amp; strncmp(pList-&gt;zText,&quot;LOCAL&quot;,5)==0 ){
-           flags |= PS_Local2;
-           pStart = pList;
-         }
-         break;
-
-       case &#39;P&#39;:
-         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText, &quot;PUBLIC&quot;,6)==0 ){
-           flags |= PS_Public;
-           pStart = pList;
-         }else if( pList-&gt;nText==7 &amp;&amp; strncmp(pList-&gt;zText, &quot;PRIVATE&quot;,7)==0 ){
-           flags |= PS_Private;
-           pStart = pList;
-         }else if( pList-&gt;nText==9 &amp;&amp; strncmp(pList-&gt;zText,&quot;PROTECTED&quot;,9)==0 ){
-           flags |= PS_Protected;
-           pStart = pList;
-         }
-         break;
-
-       case &#39;s&#39;:
-         if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;struct&quot;,6)==0 ){
-           if( pList-&gt;pNext &amp;&amp; pList-&gt;pNext-&gt;eType==TT_Braces ){
-             pList = pList-&gt;pNext;
-           }else{
-             nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
-           }
-         }else if( pList-&gt;nText==6 &amp;&amp; strncmp(pList-&gt;zText,&quot;static&quot;,6)==0 ){
-           flags |= PS_Static;
-         }
-         break;
-
-       case &#39;t&#39;:
-         if( pList-&gt;nText==7 &amp;&amp; strncmp(pList-&gt;zText,&quot;typedef&quot;,7)==0 ){
-           flags |= PS_Typedef;
-         }
-         break;
-
-       case &#39;u&#39;:
-         if( pList-&gt;nText==5 &amp;&amp; strncmp(pList-&gt;zText,&quot;union&quot;,5)==0 ){
-           if( pList-&gt;pNext &amp;&amp; pList-&gt;pNext-&gt;eType==TT_Braces ){
-             pList = pList-&gt;pNext;
-           }else{
-             nErr += ProcessTypeDecl(pList,flags,&amp;resetFlag);
-           }
-         }
-         break;
-
-       default:
-         break;
-       }
-       if( resetFlag!=0 ){
-         while( pList &amp;&amp; pList-&gt;zText[0]!=resetFlag ){
-           pList = pList-&gt;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-&gt;pNext;
-  }
-  end_of_loop:
-
-  /* Verify that all #ifs have a matching &quot;#endif&quot; */
-  while( ifStack ){
-    Ifmacro *pIf = ifStack;
-    ifStack = pIf-&gt;pNext;
-    fprintf(stderr,&quot;%s:%d: This &#39;#if&#39; has no &#39;#endif&#39;\n&quot;,zFilename,
-      pIf-&gt;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 &quot;}&quot; 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-&gt;zExtra==0 || pDecl-&gt;zDecl==0 ) return;
-  i = strlen(pDecl-&gt;zDecl) - 1;
-  while( i&gt;0 &amp;&amp; pDecl-&gt;zDecl[i]!=&#39;}&#39; ){ i--; }
-  StringInit(&amp;str);
-  StringAppend(&amp;str, pDecl-&gt;zDecl, i);
-  StringAppend(&amp;str, pDecl-&gt;zExtra, 0);
-  StringAppend(&amp;str, &amp;pDecl-&gt;zDecl[i], 0);
-  SafeFree(pDecl-&gt;zDecl);
-  SafeFree(pDecl-&gt;zExtra);
-  pDecl-&gt;zDecl = StrDup(StringGet(&amp;str), 0);
-  StringReset(&amp;str);
-  pDecl-&gt;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&#39;t
-** in the file zFilename so that it won&#39;t be printing in other files.
-*/
-static void ResetDeclFlags(char *zFilename){
-  Decl *pDecl;
-
-  for(pDecl = pDeclFirst; pDecl; pDecl = pDecl-&gt;pNext){
-    DeclClearProperty(pDecl,DP_Forward|DP_Declared);
-    if( DeclHasProperty(pDecl,DP_Local) &amp;&amp; pDecl-&gt;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 &quot;#if NEW&quot; 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-&gt;zIf==0 ) return;
-    StringAppend(pState-&gt;pStr,&quot;#endif\n&quot;,0);
-    pState-&gt;zIf = 0;
-  }else{
-    if( pState-&gt;zIf ){
-      if( strcmp(zIf,pState-&gt;zIf)==0 ) return;
-      StringAppend(pState-&gt;pStr,&quot;#endif\n&quot;,0);
-      pState-&gt;zIf = 0;
-    }
-    ScanText(zIf, pState);
-    if( pState-&gt;zIf!=0 ){
-      StringAppend(pState-&gt;pStr,&quot;#endif\n&quot;,0);
-    }
-    StringAppend(pState-&gt;pStr,&quot;#if &quot;,0);
-    StringAppend(pState-&gt;pStr,zIf,0);
-    StringAppend(pState-&gt;pStr,&quot;\n&quot;,0);
-    pState-&gt;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&#39;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-&gt;pNext ){
-      AddIncludes(pInclude-&gt;pNext,pState);
-    }
-    if( IdentTableInsert(pState-&gt;pTable,pInclude-&gt;zLabel,0) ){
-      ChangeIfContext(pInclude-&gt;zIf,pState);
-      StringAppend(pState-&gt;pStr,&quot;#include &quot;,0);
-      StringAppend(pState-&gt;pStr,pInclude-&gt;zFile,0);
-      StringAppend(pState-&gt;pStr,&quot;\n&quot;,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&#39;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(&quot;BEGIN %s of %s\n&quot;,needFullDecl?&quot;FULL&quot;:&quot;PROTOTYPE&quot;,pDecl-&gt;zName);*/
-  /*
-  ** For any object that has a forward declaration, go ahead and do the
-  ** forward declaration first.
-  */
-  isCpp = (pState-&gt;flags &amp; DP_Cplusplus) != 0;
-  for(p=pDecl; p; p=p-&gt;pSameName){
-    if( p-&gt;zFwd ){
-      if( !DeclHasProperty(p,DP_Forward) ){
-        DeclSetProperty(p,DP_Forward);
-        if( strncmp(p-&gt;zFwd,&quot;typedef&quot;,7)==0 ){
-          if( doneTypedef ) continue;
-          doneTypedef = 1;
-        }
-        ChangeIfContext(p-&gt;zIf,pState);
-        StringAppend(pState-&gt;pStr,isCpp ? p-&gt;zFwdCpp : p-&gt;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-&gt;pSameName){
-    if( !DeclHasProperty(p,flag) ) break;
-  }
-  if( p==0 ){
-    return;
-  }
-
-  /*
-  ** Make sure we have all necessary #includes
-  */
-  for(p=pDecl; p; p=p-&gt;pSameName){
-    AddIncludes(p-&gt;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&#39;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-&gt;pSameName){
-    if( !DeclHasProperty(p,DP_Declared)
-     &amp;&amp; (p-&gt;zFwd==0 || needFullDecl)
-     &amp;&amp; p-&gt;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-&gt;pSameName){
-    if( DeclHasProperty(p,DP_Flag) ){
-      if( p-&gt;zDecl[0]==&#39;#&#39; ){
-        ScanText(&amp;p-&gt;zDecl[1],pState);
-      }else{
-        InsertExtraDecl(p);
-        ScanText(p-&gt;zDecl,pState);
-      }
-    }
-  }
-
-  /*
-  ** Output the declarations.  Do this in two passes.  First
-  ** output everything that isn&#39;t a typedef.  Then go back and
-  ** get the typedefs by the same name.
-  */
-  for(p=pDecl; p; p=p-&gt;pSameName){
-    if( DeclHasProperty(p,DP_Flag) &amp;&amp; !DeclHasProperty(p,TY_Typedef) ){
-      if( DeclHasAnyProperty(p,TY_Enumeration) ){
-        if( doneTypedef ) continue;
-        doneTypedef = 1;
-      }
-      ChangeIfContext(p-&gt;zIf,pState);
-      if( !isCpp &amp;&amp; DeclHasAnyProperty(p,DP_ExternReqd) ){
-        StringAppend(pState-&gt;pStr,&quot;extern &quot;,0);
-      }else if( isCpp &amp;&amp; DeclHasProperty(p,DP_Cplusplus|DP_ExternReqd) ){
-        StringAppend(pState-&gt;pStr,&quot;extern &quot;,0);
-      }else if( isCpp &amp;&amp; DeclHasAnyProperty(p,DP_ExternCReqd|DP_ExternReqd) ){
-        StringAppend(pState-&gt;pStr,&quot;extern \&quot;C\&quot; &quot;,0);
-      }
-      InsertExtraDecl(p);
-      StringAppend(pState-&gt;pStr,p-&gt;zDecl,0);
-      if( !isCpp &amp;&amp; DeclHasProperty(p,DP_Cplusplus) ){
-        fprintf(stderr,
-          &quot;%s: C code ought not reference the C++ object \&quot;%s\&quot;\n&quot;,
-          pState-&gt;zFilename, p-&gt;zName);
-        pState-&gt;nErr++;
-      }
-      DeclClearProperty(p,DP_Flag);
-    }
-  }
-  for(p=pDecl; p &amp;&amp; !doneTypedef; p=p-&gt;pSameName){
-    if( DeclHasProperty(p,DP_Flag) ){
-      /* This has to be a typedef */
-      doneTypedef = 1;
-      ChangeIfContext(p-&gt;zIf,pState);
-      InsertExtraDecl(p);
-      StringAppend(pState-&gt;pStr,p-&gt;zDecl,0);
-    }
-  }
-}
-
-/*
-** This routine scans the input text given, and appends to the
-** string in pState-&gt;pStr the text of any declarations that must
-** occur before the text in zText.
-**
-** If an identifier in zText is immediately followed by &#39;*&#39;, then
-** only forward declarations are needed for that identifier.  If the
-** identifier name is not followed immediately by &#39;*&#39;, 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(&quot;BEGIN SCAN TEXT on %s\n&quot;, zText); */
-
-  sIn.z = zText;
-  sIn.i = 0;
-  sIn.nLine = 1;
-  while( sIn.z[sIn.i]!=0 ){
-    if( nextValid ){
-      sToken = sNext;
-      nextValid = 0;
-    }else{
-      GetNonspaceToken(&amp;sIn,&amp;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&#39;ve found an identifier that has a
-      ** declaration in the database.  Now see if we the full declaration
-      ** or just a forward declaration.
-      */
-      GetNonspaceToken(&amp;sIn,&amp;sNext);
-      if( sNext.zText[0]==&#39;*&#39; ){
-        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(&quot;END SCANTEXT\n&quot;); */
-}
-
-/*
-** 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-&gt;pNext){
-      if( DeclHasProperty(pDecl,DP_Forward)
-       &amp;&amp; !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-&gt;zHdr==0 || *pFile-&gt;zHdr==0 ) return 0;
-  sState.pStr = &amp;outStr;
-  StringInit(&amp;outStr);
-  StringAppend(&amp;outStr,zTopLine,nTopLine);
-  sState.pTable = &amp;includeTable;
-  memset(&amp;includeTable,0,sizeof(includeTable));
-  sState.zIf = 0;
-  sState.nErr = 0;
-  sState.zFilename = pFile-&gt;zSrc;
-  sState.flags = pFile-&gt;flags &amp; DP_Cplusplus;
-  ResetDeclFlags(nolocal_flag ? &quot;no&quot; : pFile-&gt;zSrc);
-  for(pId = pFile-&gt;idTable.pList; pId; pId=pId-&gt;pNext){
-    Decl *pDecl = FindDecl(pId-&gt;zName,0);
-    if( pDecl ){
-      DeclareObject(pDecl,&amp;sState,1);
-    }
-  }
-  CompleteForwardDeclarations(&amp;sState);
-  ChangeIfContext(0,&amp;sState);
-  nErr += sState.nErr;
-  zOldVersion = ReadFile(pFile-&gt;zHdr);
-  zNewVersion = StringGet(&amp;outStr);
-  if( report ) fprintf(report,&quot;%s: &quot;,pFile-&gt;zHdr);
-  if( zOldVersion==0 ){
-    if( report ) fprintf(report,&quot;updated\n&quot;);
-    if( WriteFile(pFile-&gt;zHdr,zNewVersion) ){
-      fprintf(stderr,&quot;%s: Can&#39;t write to file\n&quot;,pFile-&gt;zHdr);
-      nErr++;
-    }
-  }else if( strncmp(zOldVersion,zTopLine,nTopLine)!=0 ){
-    if( report ) fprintf(report,&quot;error!\n&quot;);
-    fprintf(stderr,
-       &quot;%s: Can&#39;t overwrite this file because it wasn&#39;t previously\n&quot;
-       &quot;%*s  generated by &#39;makeheaders&#39;.\n&quot;,
-       pFile-&gt;zHdr, (int)strlen(pFile-&gt;zHdr), &quot;&quot;);
-    nErr++;
-  }else if( strcmp(zOldVersion,zNewVersion)!=0 ){
-    if( report ) fprintf(report,&quot;updated\n&quot;);
-    if( WriteFile(pFile-&gt;zHdr,zNewVersion) ){
-      fprintf(stderr,&quot;%s: Can&#39;t write to file\n&quot;,pFile-&gt;zHdr);
-      nErr++;
-    }
-  }else if( report ){
-    fprintf(report,&quot;unchanged\n&quot;);
-  }
-  SafeFree(zOldVersion);
-  IdentTableReset(&amp;includeTable);
-  StringReset(&amp;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 = &amp;outStr;
-  StringInit(&amp;outStr);
-  /* StringAppend(&amp;outStr,zTopLine,nTopLine); */
-  sState.pTable = &amp;includeTable;
-  memset(&amp;includeTable,0,sizeof(includeTable));
-  sState.zIf = 0;
-  sState.nErr = 0;
-  sState.zFilename = &quot;(all)&quot;;
-  sState.flags = 0;
-  ResetDeclFlags(0);
-  for(pDecl=pDeclFirst; pDecl; pDecl=pDecl-&gt;pNext){
-    if( forExport==0 || DeclHasProperty(pDecl,DP_Export) ){
-      DeclareObject(pDecl,&amp;sState,1);
-    }
-  }
-  ChangeIfContext(0,&amp;sState);
-  printf(&quot;%s&quot;,StringGet(&amp;outStr));
-  IdentTableReset(&amp;includeTable);
-  StringReset(&amp;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&gt;0 &amp;&amp; (z[n-1]==&#39;\n&#39; || z[n-1]==&#39;\r&#39;) ){ n--; }
-  return n;
-}
-
-/*
-** Dump the entire declaration list for debugging purposes
-*/
-static void DumpDeclList(void){
-  Decl *pDecl;
-
-  for(pDecl = pDeclFirst; pDecl; pDecl=pDecl-&gt;pNext){
-    printf(&quot;**** %s from file %s ****\n&quot;,pDecl-&gt;zName,pDecl-&gt;zFile);
-    if( pDecl-&gt;zIf ){
-      printf(&quot;If: [%.*s]\n&quot;,ClipTrailingNewline(pDecl-&gt;zIf),pDecl-&gt;zIf);
-    }
-    if( pDecl-&gt;zFwd ){
-      printf(&quot;Decl: [%.*s]\n&quot;,ClipTrailingNewline(pDecl-&gt;zFwd),pDecl-&gt;zFwd);
-    }
-    if( pDecl-&gt;zDecl ){
-      InsertExtraDecl(pDecl);
-      printf(&quot;Def: [%.*s]\n&quot;,ClipTrailingNewline(pDecl-&gt;zDecl),pDecl-&gt;zDecl);
-    }
-    if( pDecl-&gt;flags ){
-      static struct {
-        int mask;
-        char *desc;
-      } flagSet[] = {
-        { TY_Class,       &quot;class&quot; },
-        { TY_Enumeration, &quot;enum&quot; },
-        { TY_Structure,   &quot;struct&quot; },
-        { TY_Union,       &quot;union&quot; },
-        { TY_Variable,    &quot;variable&quot; },
-        { TY_Subroutine,  &quot;function&quot; },
-        { TY_Typedef,     &quot;typedef&quot; },
-        { TY_Macro,       &quot;macro&quot; },
-        { DP_Export,      &quot;export&quot; },
-        { DP_Local,       &quot;local&quot; },
-        { DP_Cplusplus,   &quot;C++&quot; },
-      };
-      int i;
-      printf(&quot;flags:&quot;);
-      for(i=0; i&lt;sizeof(flagSet)/sizeof(flagSet[0]); i++){
-        if( flagSet[i].mask &amp; pDecl-&gt;flags ){
-          printf(&quot; %s&quot;, flagSet[i].desc);
-        }
-      }
-      printf(&quot;\n&quot;);
-    }
-    if( pDecl-&gt;pInclude ){
-      Include *p;
-      printf(&quot;includes:&quot;);
-      for(p=pDecl-&gt;pInclude; p; p=p-&gt;pNext){
-        printf(&quot; %s&quot;,p-&gt;zFile);
-      }
-      printf(&quot;\n&quot;);
-    }
-  }
-}
-#endif
-
-/*
-** When the &quot;-doc&quot; 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,       &#39;c&#39; },
-    { TY_Enumeration, &#39;e&#39; },
-    { TY_Structure,   &#39;s&#39; },
-    { TY_Union,       &#39;u&#39; },
-    { TY_Variable,    &#39;v&#39; },
-    { TY_Subroutine,  &#39;f&#39; },
-    { TY_Typedef,     &#39;t&#39; },
-    { TY_Macro,       &#39;m&#39; },
-    { DP_Export,      &#39;x&#39; },
-    { DP_Local,       &#39;l&#39; },
-    { DP_Cplusplus,   &#39;+&#39; },
-  };
-
-  for(pDecl = pDeclFirst; pDecl; pDecl=pDecl-&gt;pNext){
-    int i;
-    int nLabel = 0;
-    char *zDecl;
-    char zLabel[50];
-    for(i=0; i&lt;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-&gt;zDecl;
-    if( zDecl==0 ) zDecl = pDecl-&gt;zFwd;
-    printf(&quot;%s %s %s %p %d %d %d %d %d\n&quot;,
-       pDecl-&gt;zName,
-       zLabel,
-       pDecl-&gt;zFile,
-       pDecl-&gt;pComment,
-       pDecl-&gt;pComment ? pDecl-&gt;pComment-&gt;nText+1 : 0,
-       pDecl-&gt;zIf ? (int)strlen(pDecl-&gt;zIf)+1 : 0,
-       zDecl ? (int)strlen(zDecl) : 0,
-       pDecl-&gt;pComment ? pDecl-&gt;pComment-&gt;nLine : 0,
-       pDecl-&gt;tokenCode.nText ? pDecl-&gt;tokenCode.nText+1 : 0
-    );
-    if( pDecl-&gt;pComment ){
-      printf(&quot;%.*s\n&quot;,pDecl-&gt;pComment-&gt;nText, pDecl-&gt;pComment-&gt;zText);
-    }
-    if( pDecl-&gt;zIf ){
-      printf(&quot;%s\n&quot;,pDecl-&gt;zIf);
-    }
-    if( zDecl ){
-      printf(&quot;%s&quot;,zDecl);
-    }
-    if( pDecl-&gt;tokenCode.nText ){
-      printf(&quot;%.*s\n&quot;,pDecl-&gt;tokenCode.nText, pDecl-&gt;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!=&#39;/&#39; || zFile[1]!=&#39;*&#39; ) return;
-  for(i=2; zFile[i] &amp;&amp; (zFile[i-1]!=&#39;/&#39; || zFile[i-2]!=&#39;*&#39;); i++){}
-  if( zFile[i]==0 ) return;
-  printf(&quot;%s M %s %d %d 0 0 0 0\n%.*s\n&quot;,
-    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 &#39;:&#39; or the whole file if no &#39;:&#39; is seen.
-  **
-  ** Except, on windows, ignore any &#39;:&#39; that occurs as the second character
-  ** since it might be part of the drive specifier.  So really, the &quot;:&#39; 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] &amp;&amp; zArg[nSrc]!=&#39;:&#39;; nSrc++){}
-  pFile = SafeMalloc( sizeof(InFile) );
-  memset(pFile,0,sizeof(InFile));
-  pFile-&gt;zSrc = StrDup(zSrc,nSrc);
-
-  /* Figure out if we are dealing with C or C++ code.  Assume any
-  ** file with &quot;.c&quot; or &quot;.h&quot; is C code and all else is C++.
-  */
-  if( nSrc&gt;2 &amp;&amp; zSrc[nSrc-2]==&#39;.&#39; &amp;&amp; (zSrc[nSrc-1]==&#39;c&#39; || zSrc[nSrc-1]==&#39;h&#39;)){
-    pFile-&gt;flags &amp;= ~DP_Cplusplus;
-  }else{
-    pFile-&gt;flags |= DP_Cplusplus;
-  }
-
-  /*
-  ** If a separate header file is specified, use it
-  */
-  if( zSrc[nSrc]==&#39;:&#39; ){
-    int nHdr;
-    char *zHdr;
-    zHdr = &amp;zSrc[nSrc+1];
-    for(nHdr=0; zHdr[nHdr]; nHdr++){}
-    pFile-&gt;zHdr = StrDup(zHdr,nHdr);
-  }
-
-  /* Look for any &#39;c&#39; or &#39;C&#39; in the suffix of the file name and change
-  ** that character to &#39;h&#39; or &#39;H&#39; respectively.  If no &#39;c&#39; or &#39;C&#39; is found,
-  ** then assume we are dealing with a header.
-  */
-  else{
-    int foundC = 0;
-    pFile-&gt;zHdr = StrDup(zSrc,nSrc);
-    for(i = nSrc-1; i&gt;0 &amp;&amp; pFile-&gt;zHdr[i]!=&#39;.&#39;; i--){
-      if( pFile-&gt;zHdr[i]==&#39;c&#39; ){
-        foundC = 1;
-        pFile-&gt;zHdr[i] = &#39;h&#39;;
-      }else if( pFile-&gt;zHdr[i]==&#39;C&#39; ){
-        foundC = 1;
-        pFile-&gt;zHdr[i] = &#39;H&#39;;
-      }
-    }
-    if( !foundC ){
-      SafeFree(pFile-&gt;zHdr);
-      pFile-&gt;zHdr = 0;
-    }
-  }
-
-  /*
-  ** If pFile-&gt;zSrc contains no &#39;c&#39; or &#39;C&#39; in its extension, it
-  ** must be a header file.   In that case, we need to set the
-  ** PS_Interface flag.
-  */
-  pFile-&gt;flags |= PS_Interface;
-  for(i=nSrc-1; i&gt;0 &amp;&amp; zSrc[i]!=&#39;.&#39;; i--){
-    if( zSrc[i]==&#39;c&#39; || zSrc[i]==&#39;C&#39; ){
-      pFile-&gt;flags &amp;= ~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 &quot;-f FILENAME&quot; 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 &quot;FILENAME&quot; argument
-** in the original argument list.
-**
-** This first parameter to this routine is the index of the &quot;-f&quot;
-** 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 &#39;#&#39; 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,&quot;r&quot;);
-  if( in==0 ){
-    fprintf(stderr,&quot;Can&#39;t open input file \&quot;%s\&quot;\n&quot;,zFile);
-    exit(1);
-  }
-  c = &#39; &#39;;
-  while( c!=EOF ){
-    while( c!=EOF &amp;&amp; isspace(c) ){
-      if( c==&#39;\n&#39; ){
-        startOfLine = 1;
-      }
-      c = getc(in);
-      if( startOfLine &amp;&amp; c==&#39;#&#39; ){
-        while( c!=EOF &amp;&amp; c!=&#39;\n&#39; ){
-          c = getc(in);
-        }
-      }
-    }
-    n = 0;
-    while( c!=EOF &amp;&amp; !isspace(c) ){
-      if( n&lt;sizeof(zBuf)-1 ){ zBuf[n++] = c; }
-      startOfLine = 0;
-      c = getc(in);
-    }
-    zBuf[n] = 0;
-    if( n&gt;0 ){
-      nNew++;
-      if( nNew + argc &gt; 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&lt;=index; i++){
-    zNew[i] = argv[i];
-  }
-  for(i=nNew + index + 1; i&lt;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&#39;t
-** locate the file (because, for example, it doesn&#39;t exist), then
-** return 0.
-*/
-static unsigned int ModTime(const char *zFilename){
-  unsigned int mTime = 0;
-  struct stat sStat;
-  if( stat(zFilename,&amp;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,&quot;%s: Illegal argument \&quot;%s\&quot;\n&quot;,argv0,argvN);
-  fprintf(stderr,&quot;Usage: %s [options] filename...\n&quot;
-    &quot;Options:\n&quot;
-    &quot;  -h          Generate a single .h to standard output.\n&quot;
-    &quot;  -H          Like -h, but only output EXPORT declarations.\n&quot;
-    &quot;  -v          (verbose) Write status information to the screen.\n&quot;
-    &quot;  -doc        Generate no header files.  Instead, output information\n&quot;
-    &quot;              that can be used by an automatic program documentation\n&quot;
-    &quot;              and cross-reference generator.\n&quot;
-    &quot;  -local      Generate prototypes for \&quot;static\&quot; functions and\n&quot;
-    &quot;              procedures.\n&quot;
-    &quot;  -f FILE     Read additional command-line arguments from the file named\n&quot;
-    &quot;              \&quot;FILE\&quot;.\n&quot;
-#ifdef DEBUG
-    &quot;  -! MASK     Set the debugging mask to the number \&quot;MASK\&quot;.\n&quot;
-#endif
-    &quot;  --          Treat all subsequent comment-line parameters as filenames,\n&quot;
-    &quot;              even if they begin with \&quot;-\&quot;.\n&quot;,
-    argv0
-  );
-}
-
-/*
-** The following text contains a few simple #defines that we want
-** to be available to every file.
-*/
-static const char zInit[] =
-  &quot;#define INTERFACE 0\n&quot;
-  &quot;#define EXPORT_INTERFACE 0\n&quot;
-  &quot;#define LOCAL_INTERFACE 0\n&quot;
-  &quot;#define EXPORT\n&quot;
-  &quot;#define LOCAL static\n&quot;
-  &quot;#define PUBLIC\n&quot;
-  &quot;#define PRIVATE\n&quot;
-  &quot;#define PROTECTED\n&quot;
-;
-
-#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&lt;argc; i++){
-    if( argv[i][0]==&#39;-&#39; &amp;&amp; !noMoreFlags ){
-      switch( argv[i][1] ){
-        case &#39;h&#39;:   h_flag = 1;   break;
-        case &#39;H&#39;:   H_flag = 1;   break;
-        case &#39;v&#39;:   v_flag = 1;   break;
-        case &#39;d&#39;:   doc_flag = 1; proto_static = 1; break;
-        case &#39;l&#39;:   proto_static = 1; break;
-        case &#39;f&#39;:   AddParameters(i, &amp;argc, &amp;argv); break;
-        case &#39;-&#39;:   noMoreFlags = 1;   break;
-#ifdef DEBUG
-        case &#39;!&#39;:   i++;  debugMask = strtol(argv[i],0,0); break;
-#endif
-        default:    Usage(argv[0],argv[i]); return 1;
-      }
-    }else{
-      pFile = CreateInFile(argv[i],&amp;nErr);
-      if( pFile ){
-        if( pFileList ){
-          pTail-&gt;pNext = pFile;
-          pTail = pFile;
-        }else{
-          pFileList = pTail = pFile;
-        }
-      }
-    }
-  }
-  if( h_flag &amp;&amp; H_flag ){
-    h_flag = 0;
-  }
-  if( v_flag ){
-    report = (h_flag || H_flag) ? stderr : stdout;
-  }else{
-    report = 0;
-  }
-  if( nErr&gt;0 ){
-    return nErr;
-  }
-  for(pFile=pFileList; pFile; pFile=pFile-&gt;pNext){
-    char *zFile;
-
-    zFilename = pFile-&gt;zSrc;
-    if( zFilename==0 ) continue;
-    zFile = ReadFile(zFilename);
-    if( zFile==0 ){
-      fprintf(stderr,&quot;Can&#39;t read input file \&quot;%s\&quot;\n&quot;,zFilename);
-      nErr++;
-      continue;
-    }
-    if( strncmp(zFile,zTopLine,nTopLine)==0 ){
-      pFile-&gt;zSrc = 0;
-    }else{
-      if( report ) fprintf(report,&quot;Reading %s...\n&quot;,zFilename);
-      pList = TokenizeFile(zFile,&amp;pFile-&gt;idTable);
-      if( pList ){
-        nErr += ParseFile(pList,pFile-&gt;flags);
-        FreeTokenList(pList);
-      }else if( zFile[0]==0 ){
-        fprintf(stderr,&quot;Input file \&quot;%s\&quot; is empty.\n&quot;, zFilename);
-        nErr++;
-      }else{
-        fprintf(stderr,&quot;Errors while processing \&quot;%s\&quot;\n&quot;, zFilename);
-        nErr++;
-      }
-    }
-    if( !doc_flag ) SafeFree(zFile);
-    if( doc_flag ) PrintModuleRecord(zFile,zFilename);
-  }
-  if( nErr&gt;0 ){
-    return nErr;
-  }
-#ifdef DEBUG
-  if( debugMask &amp; DECL_DUMP ){
-    DumpDeclList();
-    return nErr;
-  }
-#endif
-  if( doc_flag ){
-    DocumentationDump();
-    return nErr;
-  }
-  zFilename = &quot;--internal--&quot;;
-  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-&gt;pNext){
-      if( pFile-&gt;zSrc==0 ) continue;
-      nErr += MakeHeader(pFile,report,0);
-    }
-  }
-  return nErr;
-}
-#endif
-
-</pre>
-</blockquote>
-</div>
-<div class="footer">\r
-This page was generated in about\r
-0.007s by\r
-Fossil 2.9 [6f60cb3881] 2019-02-27 14:34:30\r
-</div>\r
-<script nonce="e2f4709a3deeafd8212401c84e2a082e1fbd3068470984f2">\r
-/*\r
-** Copyright © 2018 Warren Young\r
-**\r
-** This program is free software; you can redistribute it and/or\r
-** modify it under the terms of the Simplified BSD License (also\r
-** known as the "2-Clause License" or "FreeBSD License".)\r
-**\r
-** This program is distributed in the hope that it will be useful,\r
-** but without any warranty; without even the implied warranty of\r
-** merchantability or fitness for a particular purpose.\r
-**\r
-** Contact: wyoung on the Fossil forum, https://fossil-scm.org/forum/\r
-**\r
-*******************************************************************************\r
-**\r
-** This file contains the JS code specific to the Fossil default skin.\r
-** Currently, the only thing this does is handle clicks on its hamburger\r
-** menu button.\r
-*/\r
-(function() {\r
-  var hbButton = document.getElementById("hbbtn");\r
-  if (!hbButton) return;   // no hamburger button\r
-  if (!document.addEventListener) {\r
-    // Turn the button into a link to the sitemap for incompatible browsers.\r
-    hbButton.href = "/fossil/sitemap";\r
-    return;\r
-  }\r
-  var panel = document.getElementById("hbdrop");\r
-  if (!panel) return;   // site admin might've nuked it\r
-  if (!panel.style) return;  // shouldn't happen, but be sure\r
-  var panelBorder = panel.style.border;\r
-  var panelInitialized = false;   // reset if browser window is resized\r
-  var panelResetBorderTimerID = 0;   // used to cancel post-animation tasks\r
-\r
-  // Disable animation if this browser doesn't support CSS transitions.\r
-  //\r
-  // We need this ugly calling form for old browsers that don't allow\r
-  // panel.style.hasOwnProperty('transition'); catering to old browsers\r
-  // is the whole point here.\r
-  var animate = panel.style.transition !== null && (typeof(panel.style.transition) == "string");\r
-\r
-  // The duration of the animation can be overridden from the default skin\r
-  // header.txt by setting the "data-anim-ms" attribute of the panel.\r
-  var animMS = panel.getAttribute("data-anim-ms");\r
-  if (animMS) {           // not null or empty string, parse it\r
-    animMS = parseInt(animMS);\r
-    if (isNaN(animMS) || animMS == 0)\r
-      animate = false;    // disable animation if non-numeric or zero\r
-    else if (animMS < 0)\r
-      animMS = 400;       // set default animation duration if negative\r
-  }\r
-  else                    // attribute is null or empty string, use default\r
-    animMS = 400;\r
-\r
-  // Calculate panel height despite its being hidden at call time.\r
-  // Based on https://stackoverflow.com/a/29047447/142454\r
-  var panelHeight;  // computed on first panel display\r
-  function calculatePanelHeight() {\r
-\r
-    // Clear the max-height CSS property in case the panel size is recalculated\r
-    // after the browser window was resized.\r
-    panel.style.maxHeight = '';\r
-\r
-    // Get initial panel styles so we can restore them below.\r
-    var es   = window.getComputedStyle(panel),\r
-        edis = es.display,\r
-        epos = es.position,\r
-        evis = es.visibility;\r
-\r
-    // Restyle the panel so we can measure its height while invisible.\r
-    panel.style.visibility = 'hidden';\r
-    panel.style.position   = 'absolute';\r
-    panel.style.display    = 'block';\r
-    panelHeight = panel.offsetHeight + 'px';\r
-\r
-    // Revert styles now that job is done.\r
-    panel.style.display    = edis;\r
-    panel.style.position   = epos;\r
-    panel.style.visibility = evis;\r
-  }\r
-\r
-  // Show the panel by changing the panel height, which kicks off the\r
-  // slide-open/closed transition set up in the XHR onload handler.\r
-  //\r
-  // Schedule the change for a near-future time in case this is the\r
-  // first call, where the div was initially invisible.  If we were\r
-  // to change the panel's visibility and height at the same time\r
-  // instead, that would prevent the browser from seeing the height\r
-  // change as a state transition, so it'd skip the CSS transition:\r
-  //\r
-  // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#JavaScript_examples\r
-  function showPanel() {\r
-    // Cancel the timer to remove the panel border after the closing animation,\r
-    // otherwise double-clicking the hamburger button with the panel opened will\r
-    // remove the borders from the (closed and immediately reopened) panel.\r
-    if (panelResetBorderTimerID) {\r
-      clearTimeout(panelResetBorderTimerID);\r
-      panelResetBorderTimerID = 0;\r
-    }\r
-    if (animate) {\r
-      if (!panelInitialized) {\r
-        panelInitialized = true;\r
-        // Set up a CSS transition to animate the panel open and\r
-        // closed.  Only needs to be done once per page load.\r
-        // Based on https://stackoverflow.com/a/29047447/142454\r
-        calculatePanelHeight();\r
-        panel.style.transition = 'max-height ' + animMS +\r
-            'ms ease-in-out';\r
-        panel.style.overflowY  = 'hidden';\r
-        panel.style.maxHeight  = '0';\r
-      }\r
-      setTimeout(function() {\r
-        panel.style.maxHeight = panelHeight;\r
-        panel.style.border    = panelBorder;\r
-      }, 40);   // 25ms is insufficient with Firefox 62\r
-    }\r
-    panel.style.display = 'block';\r
-    document.addEventListener('keydown',panelKeydown,/* useCapture == */true);\r
-    document.addEventListener('click',panelClick,false);\r
-  }\r
-\r
-  var panelKeydown = function(event) {\r
-    var key = event.which || event.keyCode;\r
-    if (key == 27) {\r
-      event.stopPropagation();   // ignore other keydown handlers\r
-      panelToggle(true);\r
-    }\r
-  };\r
-\r
-  var panelClick = function(event) {\r
-    if (!panel.contains(event.target)) {\r
-      // Call event.preventDefault() to have clicks outside the opened panel\r
-      // just close the panel, and swallow clicks on links or form elements.\r
-      //event.preventDefault();\r
-      panelToggle(true);\r
-    }\r
-  };\r
-\r
-  // Return true if the panel is showing.\r
-  function panelShowing() {\r
-    if (animate) {\r
-      return panel.style.maxHeight == panelHeight;\r
-    }\r
-    else {\r
-      return panel.style.display == 'block';\r
-    }\r
-  }\r
-\r
-  // Check if the specified HTML element has any child elements. Note that plain\r
-  // text nodes, comments, and any spaces (presentational or not) are ignored.\r
-  function hasChildren(element) {\r
-    var childElement = element.firstChild;\r
-    while (childElement) {\r
-      if (childElement.nodeType == 1) // Node.ELEMENT_NODE == 1\r
-        return true;\r
-      childElement = childElement.nextSibling;\r
-    }\r
-    return false;\r
-  }\r
-\r
-  // Reset the state of the panel to uninitialized if the browser window is\r
-  // resized, so the dimensions are recalculated the next time it's opened.\r
-  window.addEventListener('resize',function(event) {\r
-    panelInitialized = false;\r
-  },false);\r
-\r
-  // Click handler for the hamburger button.\r
-  hbButton.addEventListener('click',function(event) {\r
-    // Break the event handler chain, or the handler for document → click\r
-    // (about to be installed) may already be triggered by the current event.\r
-    event.stopPropagation();\r
-    event.preventDefault();  // prevent browser from acting on <a> click\r
-    panelToggle(false);\r
-  },false);\r
-\r
-  function panelToggle(suppressAnimation) {\r
-    if (panelShowing()) {\r
-      document.removeEventListener('keydown',panelKeydown,/* useCapture == */true);\r
-      document.removeEventListener('click',panelClick,false);\r
-      // Transition back to hidden state.\r
-      if (animate) {\r
-        if (suppressAnimation) {\r
-          var transition = panel.style.transition;\r
-          panel.style.transition = '';\r
-          panel.style.maxHeight = '0';\r
-          panel.style.border = 'none';\r
-          setTimeout(function() {\r
-            // Make sure CSS transition won't take effect now, so restore it\r
-            // asynchronously. Outer variable 'transition' still valid here.\r
-            panel.style.transition = transition;\r
-          }, 40);   // 25ms is insufficient with Firefox 62\r
-        }\r
-        else {\r
-          panel.style.maxHeight = '0';\r
-          panelResetBorderTimerID = setTimeout(function() {\r
-            // Browsers show a 1px high border line when maxHeight == 0,\r
-            // our "hidden" state, so hide the borders in that state, too.\r
-            panel.style.border = 'none';\r
-            panelResetBorderTimerID = 0;   // clear ID of completed timer\r
-          }, animMS);\r
-        }\r
-      }\r
-      else {\r
-        panel.style.display = 'none';\r
-      }\r
-    }\r
-    else {\r
-      if (!hasChildren(panel)) {\r
-        // Only get the sitemap once per page load: it isn't likely to\r
-        // change on us.\r
-        var xhr = new XMLHttpRequest();\r
-        xhr.onload = function() {\r
-          var doc = xhr.responseXML;\r
-          if (doc) {\r
-            var sm = doc.querySelector("ul#sitemap");\r
-            if (sm && xhr.status == 200) {\r
-              // Got sitemap.  Insert it into the drop-down panel.\r
-              panel.innerHTML = sm.outerHTML;\r
-              // Display the panel\r
-              showPanel();\r
-            }\r
-          }\r
-          // else, can't parse response as HTML or XML\r
-        }\r
-        xhr.open("GET", "/fossil/sitemap?popup");   // note the TH1 substitution!\r
-        xhr.responseType = "document";\r
-        xhr.send();\r
-      }\r
-      else {\r
-        showPanel();   // just show what we built above\r
-      }\r
-    }\r
-  }\r
-})();\r
-\r
-</script>\r
-<script id='href-data' type='application/json'>{"delay":10,"mouseover":0}</script>
-<script nonce="e2f4709a3deeafd8212401c84e2a082e1fbd3068470984f2">
-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()
-</script>
-</body>
-</html>
diff --git a/tranche/deprecated/0_makefile b/tranche/deprecated/0_makefile
deleted file mode 100644 (file)
index b8c7b9d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# src/0_makefile
-
-SHELL=/bin/bash
-
--include 0_makefile_flags
-
-SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
-MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-SOURCES=$(wildcard *.c)
-HFILES=$(wildcard *.h)
-
-all: version deps lib execs
-
-version:
-       $(MAKE) $@
-       @echo "SUID_TOOL: " $(SUID_TOOL)
-
-deps:
-       makeheaders $(SOURCES) $(HFILES)
-       sed -i '/^ *int *main *(.*)/d' *.h
-       $(MAKE) $@
-
-execs:
-       $(MAKE) $@
-       @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
-       cat $(SUID_TOOL)
-       @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
-       sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
-
-clean:
-       $(MAKE) $@
-       for i in $(HFILES); do rm $$i; done
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/tranche/deprecated/0_makefile-flags b/tranche/deprecated/0_makefile-flags
deleted file mode 100644 (file)
index 0da8b61..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=1_deprecated
-DOCDIR=1_doc
-EXECSDIR=1_execs
-HDIR=1_headers
-LIBDIR=1_lib
-TESTDIR=1_tests
-TMPDIR=1_tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=1_try
-
-
-# compiler and flags
-CC=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-L1_lib -lsubu -lsqlite3
-
-LIBFILE=$(LIBDIR)/libsubu.a
-
diff --git a/tranche/doc/todo.txt b/tranche/doc/todo.txt
deleted file mode 100644 (file)
index 1494e66..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-2019-03-22T13:37:23Z
-1. indentation
-
-   the first non blank line after the #tranche keyword sets the indentation
-   level for the following text.  When echoing to the output file 
-   remove that many leading spaces.
-
-   Hmm,  or allow options among the tranche parameters,  -indent 3 or
-   -indent '  '.
-   
diff --git a/tranche/makefile b/tranche/makefile
deleted file mode 100644 (file)
index 4c20d5e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# tranche/makefile
-
-SHELL=/bin/bash
-
--include makefile-flags
-
-.PHONY: all version deps lib exec
-all: version deps lib exec
-
-lib:
-       $(MAKE) $@
-       cp src/tranche.lib.h include/tranche.h
-
-exec:
-       $(MAKE) $@
-
-%::
-       $(MAKE) $@
-
-
-
-
diff --git a/tranche/makefile-flags b/tranche/makefile-flags
deleted file mode 100644 (file)
index 68f6296..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-MODULE=tranche
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECDIR, INCDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=deprecated
-DOCDIR=doc
-EXECDIR=exec
-INCDIR=include
-LIBDIR=lib
-SRCDIR=src
-TESTDIR=test
-TMPDIR=tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=try
-
-C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -I../stage/include -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-Llib -L../stage/lib/ -lda -ltranche
-
-MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
diff --git a/tranche/src/tranche.cli.c b/tranche/src/tranche.cli.c
deleted file mode 100644 (file)
index 8df4337..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#include <stdio.h>
-#include <unistd.h>
-#include <da.h>
-#include "tranche.lib.h"
-
-int main(int argc, char **argv, char **envp){
-  if(argc != 2){
-    fprintf(stderr, "usage: %s <source-file>\n",argv[0]);
-    return 1;
-  }
-  FILE *file = fopen(argv[1], "r");
-  if(!file){
-    fprintf(stderr,"could not open file %s\n", argv[1]);
-    return 2;
-  }
-  Da targets;
-  da_alloc(&targets, sizeof(int));
-  int fd = STDOUT_FILENO;
-  da_push(&targets, &fd);
-  tranche_send(file, &targets);
-  da_free(&targets);
-  fclose(file);
-  return 0;
-}
diff --git a/tranche/src/tranche.lib.c b/tranche/src/tranche.lib.c
deleted file mode 100644 (file)
index 9b824d3..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-The purpose of this tools is to facilitate putting prototypes (declarations) next
-to implementations (definitions) in a single source file of a C/C++ programs. 
-
-Splits a single source file into multiple files.  Scans through the single
-source file looking for lines of the form:
-
-  #tranche-begin filename ...
-
-With the # as the first non-space character on the line, and only filename
-following the tag. Upon finding such a line, copies all following lines into the
-listed files, until reaching the end marker:
-
-  #tranche-end
-
-A next improvement of this file would be to support variables to be passed in
-for the file names.  As it stands, changing the file name requires editing 
-the source file.
-
-Files are opened for create or append, so opening to the same file will append
-to the end.
-
-*/
-
-#include <da.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-//--------------------------------------------------------------------------------
-// parsing
-
-char newline = '\n';
-char terminator = 0;
-
-char tranche_begin_tag[] = "#tranche";
-size_t tranche_begin_tag_len = 8;
-
-char tranche_end_tag[] = "#tranche-end";
-size_t tranche_end_tag_len = 12;
-
-// given a line
-// returns beginning of file name list
-static char *is_tranche_begin(char *pt){
-  while( *pt && isspace(*pt) ) pt++;
-  if(!*pt) return NULL;
-  if( strncmp(pt, tranche_begin_tag, tranche_begin_tag_len) ) return NULL;
-  return pt + tranche_begin_tag_len;
-}
-
-static char *is_tranche_end(char *pt){
-  while( *pt && isspace(*pt) ) pt++;
-  if(!*pt) return NULL;
-  if( strncmp(pt, tranche_end_tag, tranche_end_tag_len) ) return NULL;
-  return pt + tranche_end_tag_len;
-}
-
-static bool parse_file_list(Da *file_names, char *pt0){
-  char *pt1;
-  while( *pt0 && isspace(*pt0) ) pt0++;
-  pt1 = pt0;
-  while( *pt0 ){
-    while( *pt1 && !isspace(*pt1) ) pt1++;
-    char *file_name = strndup(pt0, pt1 - pt0);
-    da_push(file_names, &file_name);
-    while( *pt1 && isspace(*pt1) ) pt1++;
-    pt0 = pt1;
-  }
-}
-
-
-
-//--------------------------------------------------------------------------------
-// da_map calls
-
-static void tranche_open_fd(void *fnp, void *closure){
-  char *file_name = *(char **)fnp;
-  Da *fdap = (Da *)closure;
-  int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, 0666);
-  if(fd == -1){
-    fprintf(stderr, "Could not open file %s\n", file_name);
-    return;
-  }
-  da_push(fdap, &fd);  
-  return;
-}
-static void tranche_open_fds(Da *fnap, Da *fdap){
-  da_map(fnap, tranche_open_fd, fdap);
-}
-
-static void tranche_close_fd(void *fdp, void *closure){
-  close(*(int *)fdp);
-}
-static void tranche_close_fds(Da *fdap){
-  da_map(fdap, tranche_close_fd, NULL);
-  da_rewind(fdap);
-}
-
-static void tranche_puts(void *fdp, void *string){
-  write(*(int *)fdp, string, strlen(string));
-}
-static void tranche_puts_all(Da *fdap, char *string){
-  da_map(fdap, tranche_puts, string);
-}
-
-
-
-//--------------------------------------------------------------------------------
-// we have a little problem if the user tries to tranche two things to the same file ..
-int tranche_send(FILE *src, Da *arg_fdap){
-  char *pt;
-  Da line;
-  Da file_name_arr;
-  Da fda;
-  da_alloc(&line, sizeof(char));
-  da_alloc(&file_name_arr, sizeof(char *));
-  da_alloc(&fda, sizeof(int));
-
-  while( !feof(src) ){
-    da_fgets(&line, src);
-    if( is_tranche_end(line.base) ) break;
-    pt = is_tranche_begin(line.base);
-    if(pt){ // then this line is the start of a nested tranche block
-      parse_file_list(&file_name_arr, pt);
-      tranche_open_fds(&file_name_arr, &fda);
-      da_free_elements(&file_name_arr);
-      tranche_send(src, &fda);
-      tranche_close_fds(&fda);
-    }else{
-      da_pop(&line, NULL); // pop the terminating zero
-      da_push(&line, &newline);
-      da_push(&line, &terminator);
-      tranche_puts_all(arg_fdap, line.base);
-    }
-    da_rewind(&line);
-  }
-
-  da_free(&line);
-  da_free(&file_name_arr);
-  da_free(&fda);
-  return 0;
-}
diff --git a/tranche/src/tranche.lib.h b/tranche/src/tranche.lib.h
deleted file mode 100644 (file)
index 27990a6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef TRANCHE_LIB_H
-#define TRANCHE_LIB_H
-
-int tranche_send(FILE *src, Da *arg_fds);
-
-
-
-#endif
diff --git a/tranche/test/test1.dat b/tranche/test/test1.dat
deleted file mode 100644 (file)
index b03df3f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#tranche test11.dat test12.dat
-The little red hen said to Mick, no thank you not today sir.
-And then all the barnes animals shouted out in glee.
-No more misery!
-#tranche test13.dat
-apple banana pear
-kiwi
-#tranche-end
-cows
-and cats
-#tranche-end
-
-the between space
-
-#tranche test14.dat
-int float if while
-do
-function
-#tranche-end
-
-#tranche test15.dat
-#tranche-end
\ No newline at end of file
diff --git a/tranche/test/test1.sh b/tranche/test/test1.sh
deleted file mode 100644 (file)
index c1140ca..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash -x
-./tranche test1.dat >test1stdout.dat
-diff test11.dat test11.dat.expected
-diff test12.dat test12.dat.expected
-diff test13.dat test13.dat.expected
-diff test14.dat test14.dat.expected
-diff test15.dat test15.dat.expected
-diff test1stdout.dat test1stdout.dat.expected
-rm test11.dat test12.dat test13.dat test14.dat test15.dat test1stdout.dat
-
diff --git a/tranche/test/test11.dat.expected b/tranche/test/test11.dat.expected
deleted file mode 100644 (file)
index 2c2904a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-The little red hen said to Mick, no thank you not today sir.
-And then all the barnes animals shouted out in glee.
-No more misery!
-cows
-and cats
diff --git a/tranche/test/test12.dat.expected b/tranche/test/test12.dat.expected
deleted file mode 100644 (file)
index 2c2904a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-The little red hen said to Mick, no thank you not today sir.
-And then all the barnes animals shouted out in glee.
-No more misery!
-cows
-and cats
diff --git a/tranche/test/test13.dat.expected b/tranche/test/test13.dat.expected
deleted file mode 100644 (file)
index 81fb20c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-apple banana pear
-kiwi
diff --git a/tranche/test/test14.dat.expected b/tranche/test/test14.dat.expected
deleted file mode 100644 (file)
index 0d8b89b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-int float if while
-do
-function
diff --git a/tranche/test/test15.dat.expected b/tranche/test/test15.dat.expected
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tranche/test/test1stdout.dat.expected b/tranche/test/test1stdout.dat.expected
deleted file mode 100644 (file)
index 4e519ff..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-the between space
-
-
diff --git a/tranche/test/test2.c.expected b/tranche/test/test2.c.expected
deleted file mode 100644 (file)
index a4876a1..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-#include "test2.h"
-
-
-int f(int x){
-  return x;
-}
-
-
diff --git a/tranche/test/test2.h.expected b/tranche/test/test2.h.expected
deleted file mode 100644 (file)
index fdc4d72..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef TEST2_H
-#define TEST2_H
-int f(int x);
-#endif
diff --git a/tranche/test/test2.trc.c b/tranche/test/test2.trc.c
deleted file mode 100644 (file)
index ff7d696..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#tranche test2.c
-
-#tranche test2.h
-#ifndef TEST2_H
-#define TEST2_H
-#tranche-end
-
-#include "test2.h"
-
-#tranche test2.h
-int f(int x);
-#tranche-end
-
-int f(int x){
-  return x;
-}
-
-#tranche test2.h
-#endif
-#tranche-end
-
-#tranche-end
diff --git a/tranche/test/tranche b/tranche/test/tranche
deleted file mode 120000 (symlink)
index acf4a6f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../1_execs/tranche
\ No newline at end of file