From: Thomas Walker Lynch Date: Mon, 1 Apr 2019 11:05:17 +0000 (+0200) Subject: trc support for makefile_cc X-Git-Url: https://git.reasoningtechnology.com/style/rt_dark_doc.css?a=commitdiff_plain;h=c84c1e862c3655529f17d90148e54fcc7f6da580;p=subu trc support for makefile_cc --- diff --git a/makefile b/makefile index c7a88ed..af4d046 100755 --- a/makefile +++ b/makefile @@ -5,7 +5,7 @@ # | grep -v deprecated | grep -v doc | sort -u | sed ':a;N;$!ba;s/\n/ /g' \ #) -MAKEABLE= module/da module/da/test module/tranche +MAKEABLE= module/da module/da/test module/tranche module/dispatch .PHONY: all info clean dist-clean diff --git a/module/da/src/da.lib.c b/module/da/src/da.lib.c index f09412d..18abb99 100644 --- a/module/da/src/da.lib.c +++ b/module/da/src/da.lib.c @@ -10,9 +10,7 @@ Dynamic Array #include //-------------------------------------------------------------------------------- -// 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. +// allocation void da_alloc(Da *dap, size_t element_size){ dap->element_size = element_size; @@ -36,7 +34,6 @@ size_t da_length(Da *dap){ return (dap->end - dap->base)/dap->element_size; } - void da_rebase(Da *dap, char *old_base, void *pta){ char **pt = (char **)pta; size_t offset = *pt - old_base; @@ -58,16 +55,20 @@ char *da_expand(Da *dap){ 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 +// true when end has run off the allocated area bool da_boundq(Da *dap){ return dap->end >= dap->base + dap->size; } +//-------------------------------------------------------------------------------- +// putting/taking items + +char *da_index(Da *dap, size_t i){ + size_t offset = i * dap->element_size; + char *pt = dap->base + offset; + return pt; +} + void da_push(Da *dap, void *element){ if( dap->end >= dap->base + dap->size ) da_expand(dap); memcpy(dap->end, element, dap->element_size); @@ -83,32 +84,12 @@ bool da_pop(Da *dap, void *element){ return flag; } -void da_cat(Da *dap0, Da *dap1){ - if(dap1->base == dap1->end) return; - size_t dap0_size = dap0->end - dap0->base; - size_t dap1_size = dap1->end - dap1->base; // size of the active portion - dap0->end += dap1_size; - while( dap0->end >= dap0->base + dap0->size ) da_expand(dap0); - memcpy(dap0->base + dap0_size, dap1->base, dap1_size); -} - -// If dap0 has had a terminatating zero added, that must be popped off before -// the call. Similarly if a terminating zero is desired, it should be pushed -// after the call. -void da_push_string(Da *dap0, char *string){ - if(!*string) return; - size_t dap0_size = dap0->end - dap0->base; - size_t string_size = strlen(string); - dap0->end += string_size; - while( dap0->end >= dap0->base + dap0->size ) da_expand(dap0); - memcpy(dap0->base + dap0_size, string, string_size); -} - +//-------------------------------------------------------------------------------- +// iteration -char *da_index(Da *dap, size_t i){ - size_t offset = i * dap->element_size; - char *pt = dap->base + offset; - return pt; +// true when pt has run off the end +bool da_endq(Da *dap, void *pt){ + return (char *)pt >= dap->end; } // passed in f(element_pt, arg_pt) @@ -122,41 +103,98 @@ void da_map(Da *dap, void f(void *, void *), void *closure){ } } -// da_lists are sometimes used as resource managers +//-------------------------------------------------------------------------------- +// da being used as a resource manager + + +// elements were malloced, now they will all be freed 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); } +//-------------------------------------------------------------------------------- +// da is an array of integers + +// would like to pass in the printf format to make a general print +// but can't get *pt on the stack for the printf call .. hmmm +void da_ints_print(Da *dap, char *sep){ + char *pt = dap->base; // char * because it points to a byte in the array + if( pt < dap->end ){ + printf("%u", *(int *)pt); + pt += dap->element_size; + while( pt < dap->end ){ + printf("%s%u", sep, *(int *)pt); + pt += dap->element_size; + }}} + + +//-------------------------------------------------------------------------------- +// da is an array of strings + // for the case of an array of strings -void da_strings_puts(Da *dap){ +void da_strings_print(Da *dap, char *sep){ char *pt = dap->base; // char * because it points to a byte in the array - while( pt < dap->end ){ - puts(*(char **)pt); - pt += dap->element_size; + if( pt < dap->end ){ + fputs(*(char **)pt, stdout); + pt += dap->element_size; + while( pt < dap->end ){ + fputs(sep,stdout); + fputs(*(char **)pt,stdout); + pt += dap->element_size; + }}} + +// da is an array of strings, true if the test string is in the array +// might be better to iterate instead of using a map ... +typedef struct { + char *string; + bool found; +} da_strings_exists_closure; +static void string_equal(void *sp, void *closure){ + char *string_element = *(char **)sp; + da_strings_exists_closure *ss = (da_strings_exists_closure *)closure; + if( ss->found ) return; + ss->found = !strcmp(string_element, ss->string); + return; +} +bool da_strings_exists(Da *string_arrp, char *test_string){ + da_strings_exists_closure sec; + sec.string = test_string; + sec.found = false; + da_map(string_arrp, string_equal, &sec); + return sec.found; +} + +void da_strings_set_insert(Da *string_arrp, char *proffered_string, void destruct(void *)){ + if( da_strings_exists( string_arrp, proffered_string)){ // then throw it away, we don't need it + if(destruct)destruct(proffered_string); + return; } + da_push(string_arrp, &proffered_string); } -// would like to pass in the printf format to make a general print -// but can't get *pt on the stack for the printf call .. hmmm -void da_ints_print(Da *dap){ - char *pt = dap->base; - while( pt < dap->end ){ - printf("%u\n", *(int *)pt); - pt += dap->element_size; +// union +void da_strings_set_union(Da *string_arrp, Da *proffered_string_arrp, void destruct(void *)){ + char *pt = proffered_string_arrp->base; + while( pt < proffered_string_arrp->end ){ + da_strings_set_insert(string_arrp, *(char **)pt, destruct); + pt += proffered_string_arrp->element_size; } + return; } +//-------------------------------------------------------------------------------- +// the da itself is a string + // 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 *da_string_input(Da *dap, FILE *file){ char *old_base = dap->base; int c = fgetc(file); while( c != EOF && c != '\n' ){ @@ -167,3 +205,32 @@ char *da_fgets(Da *dap, FILE *file){ da_push(dap, &terminator); return old_base; } + +void da_string_push(Da *dap0, char *string){ + if(!*string) return; + size_t dap0_size = dap0->end - dap0->base; + size_t string_size = strlen(string); + dap0->end += string_size; + while( dap0->end >= dap0->base + dap0->size ) da_expand(dap0); + memcpy(dap0->base + dap0_size, string, string_size); +} + + +//-------------------------------------------------------------------------------- +// list operations + +// If dap0 has had a terminatating zero added, that must be popped off before +// the call. Similarly if a terminating zero is desired, it should be pushed +// after the call. + +// appends contents of dap1 onto dap0 +void da_cat(Da *dap0, Da *dap1){ + if(dap1->base == dap1->end) return; + size_t dap0_size = dap0->end - dap0->base; + size_t dap1_size = dap1->end - dap1->base; // size of the active portion + dap0->end += dap1_size; + while( dap0->end >= dap0->base + dap0->size ) da_expand(dap0); + memcpy(dap0->base + dap0_size, dap1->base, dap1_size); +} + + diff --git a/module/da/src/da.lib.h b/module/da/src/da.lib.h index 3188011..518e72c 100644 --- a/module/da/src/da.lib.h +++ b/module/da/src/da.lib.h @@ -14,25 +14,37 @@ typedef struct 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); bool da_emptyq(Da *dap); size_t da_length(Da *dap); -char *da_expand(Da *dap); void da_rebase(Da *dap, char *old_base, void *pta); -bool da_endq(Da *dap, void *pt); +char *da_expand(Da *dap); bool da_boundq(Da *dap); + +char *da_index(Da *dap, size_t i); void da_push(Da *dap, void *element); bool da_pop(Da *dap, void *element); -void da_cat(Da *dap_base, Da *dap_cat); -void da_push_string(Da *dap0, char *string); -char *da_index(Da *dap, size_t i); + +bool da_endq(Da *dap, void *pt); void da_map(Da *dap, void f(void *, void *), void *closure); + void da_free_elements(Da *dap); -void da_strings_puts(Da *dap); -void da_ints_print(Da *dap); -char *da_fgets(Da *dap, FILE *fd); + +void da_ints_print(Da *dap, char *sep); + +void da_strings_print(Da *dap, char *sep); +bool da_strings_exists(Da *string_arrp, char *test_string); +void da_strings_set_insert(Da *string_arrp, char *proffered_string, void destruct(void *)); +void da_strings_set_union(Da *string_arrp, Da *proffered_string_arrp, void destruct(void *)); + + +char *da_string_input(Da *dap, FILE *file); +void da_string_push(Da *dap0, char *string); + +void da_cat(Da *dap_base, Da *dap_cat); #endif diff --git a/module/da/test/results b/module/da/test/results deleted file mode 100644 index 9e59b33..0000000 --- a/module/da/test/results +++ /dev/null @@ -1 +0,0 @@ -passed all 4 tests diff --git a/module/da/test/src/test_da.lib.c b/module/da/test/src/test_da.lib.c index f16be66..12f06d2 100644 --- a/module/da/test/src/test_da.lib.c +++ b/module/da/test/src/test_da.lib.c @@ -84,19 +84,19 @@ bool test_da_2(){ Da da; da_alloc(&da, sizeof(char)); - da_fgets(&da, file); + da_string_input(&da, file); 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,file); + old_base = da_string_input(&da,file); 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,file); + old_base = da_string_input(&da,file); da_rebase(&da, old_base, &s2); bool f2 = !strcmp(s2, "(setq mode-require-final-newline nil)"); diff --git a/module/da/test/try/passed.transcript b/module/da/test/try/passed.transcript new file mode 100644 index 0000000..d75d376 --- /dev/null +++ b/module/da/test/try/passed.transcript @@ -0,0 +1,5 @@ +2019-03-31T20:08:48Z +morpheus@manorhouse§~/subu_land/subu/module/da/test/exec§ +> ./test_da +passed all 5 tests + diff --git a/module/db/0_makefile b/module/db/0_makefile deleted file mode 100644 index f0708ef..0000000 --- a/module/db/0_makefile +++ /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/module/db/0_makefile-flags b/module/db/0_makefile-flags deleted file mode 100644 index d4df01f..0000000 --- a/module/db/0_makefile-flags +++ /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 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 deleted file mode 100644 index b7f8cbb..0000000 --- a/module/db/1_doc/return-from-transaction.txt +++ /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/module/db/dbprintf.lib.c b/module/db/dbprintf.lib.c deleted file mode 100644 index d9d236b..0000000 --- a/module/db/dbprintf.lib.c +++ /dev/null @@ -1,14 +0,0 @@ - -#include "dbprintf.lib.h" - -#include -#include - -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/db/include/db.h b/module/db/include/db.h new file mode 100644 index 0000000..7563eea --- /dev/null +++ b/module/db/include/db.h @@ -0,0 +1,6 @@ +#ifndef DB_LIB_H +#define DB_LIB_H + +int dbprintf(const char *format, ...); + +#endif diff --git a/module/db/lib/libda.a b/module/db/lib/libda.a new file mode 100644 index 0000000..c6e819f Binary files /dev/null and b/module/db/lib/libda.a differ diff --git a/module/db/lib/libdb.a b/module/db/lib/libdb.a new file mode 100644 index 0000000..bf6ce01 Binary files /dev/null and b/module/db/lib/libdb.a differ diff --git a/module/db/makefile b/module/db/makefile new file mode 100644 index 0000000..167b997 --- /dev/null +++ b/module/db/makefile @@ -0,0 +1,23 @@ +# da/makefile + + +SHELL=/bin/bash +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 + +-include makefile-flags + +.PHONY: all +all: version dep lib exec + +.PHONY: lib +lib: + $(MAKE) $@ + cp src/db.lib.h include/db.h + +%:: + $(MAKE) $@ + + + + diff --git a/module/db/makefile-flags b/module/db/makefile-flags new file mode 100644 index 0000000..f37c595 --- /dev/null +++ b/module/db/makefile-flags @@ -0,0 +1,18 @@ + +MODULE=db + +# 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=-Llib -ldb + + + diff --git a/module/db/src/db.lib.c b/module/db/src/db.lib.c new file mode 100644 index 0000000..8e6fe5d --- /dev/null +++ b/module/db/src/db.lib.c @@ -0,0 +1,14 @@ + +#include "db.lib.h" + +#include +#include + +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/db/src/db.lib.h b/module/db/src/db.lib.h new file mode 100644 index 0000000..7563eea --- /dev/null +++ b/module/db/src/db.lib.h @@ -0,0 +1,6 @@ +#ifndef DB_LIB_H +#define DB_LIB_H + +int dbprintf(const char *format, ...); + +#endif diff --git a/module/dispatch/makefile-flags b/module/dispatch/makefile-flags index 48cadc2..eb127fc 100644 --- a/module/dispatch/makefile-flags +++ b/module/dispatch/makefile-flags @@ -1,4 +1,6 @@ +MODULE=dispatch + # 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 @@ -13,8 +15,9 @@ CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB LINKFLAGS=-L1_lib -lda -MODULE=dispatch +SRCDIR=tmp +TRCDIR=trc -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 +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/dispatch/src/dispatch.lib.c b/module/dispatch/src/dispatch.lib.c deleted file mode 100644 index e34d020..0000000 --- a/module/dispatch/src/dispatch.lib.c +++ /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 -#include - -#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 -#include -#include -#include - -#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/dispatch/trc/dispatch.trc.c b/module/dispatch/trc/dispatch.trc.c new file mode 100644 index 0000000..3b594a7 --- /dev/null +++ b/module/dispatch/trc/dispatch.trc.c @@ -0,0 +1,166 @@ +#tranche dispatch.lib.c + +#tranche dispatch.lib.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 +#include + +#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 +#include +#include +#include + +#tranche dispatch.lib.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 dispatch.lib.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 dispatch.lib.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 dispatch.lib.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 index 3188011..518e72c 100644 --- a/module/share/include/da.h +++ b/module/share/include/da.h @@ -14,25 +14,37 @@ typedef struct 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); bool da_emptyq(Da *dap); size_t da_length(Da *dap); -char *da_expand(Da *dap); void da_rebase(Da *dap, char *old_base, void *pta); -bool da_endq(Da *dap, void *pt); +char *da_expand(Da *dap); bool da_boundq(Da *dap); + +char *da_index(Da *dap, size_t i); void da_push(Da *dap, void *element); bool da_pop(Da *dap, void *element); -void da_cat(Da *dap_base, Da *dap_cat); -void da_push_string(Da *dap0, char *string); -char *da_index(Da *dap, size_t i); + +bool da_endq(Da *dap, void *pt); void da_map(Da *dap, void f(void *, void *), void *closure); + void da_free_elements(Da *dap); -void da_strings_puts(Da *dap); -void da_ints_print(Da *dap); -char *da_fgets(Da *dap, FILE *fd); + +void da_ints_print(Da *dap, char *sep); + +void da_strings_print(Da *dap, char *sep); +bool da_strings_exists(Da *string_arrp, char *test_string); +void da_strings_set_insert(Da *string_arrp, char *proffered_string, void destruct(void *)); +void da_strings_set_union(Da *string_arrp, Da *proffered_string_arrp, void destruct(void *)); + + +char *da_string_input(Da *dap, FILE *file); +void da_string_push(Da *dap0, char *string); + +void da_cat(Da *dap_base, Da *dap_cat); #endif diff --git a/module/share/lib/libda.a b/module/share/lib/libda.a index 595690a..a3da46e 100644 Binary files a/module/share/lib/libda.a and b/module/share/lib/libda.a differ diff --git a/module/tranche/makefile b/module/tranche/makefile index 651e98b..18f8fc7 100644 --- a/module/tranche/makefile +++ b/module/tranche/makefile @@ -17,7 +17,7 @@ exec: $(MAKE) $@ share: - if [ ! -z "$(wildcard $(EXECDIR)/*)" ]; then cp $(EXECDIR)/* $(PROJECT_SUBU)/tool/bin; fi + if [ -d $(EXECDIR) ]; then if [ ! -z "$(wildcard $(EXECDIR)/*)" ]; then cp $(EXECDIR)/* $(PROJECT_SUBU)/tool/bin; fi; fi %:: $(MAKE) $@ diff --git a/module/tranche/makefile-flags b/module/tranche/makefile-flags index bb0340e..cd54223 100644 --- a/module/tranche/makefile-flags +++ b/module/tranche/makefile-flags @@ -6,6 +6,7 @@ ECHO= echo # directories used by this makefile, these could all be set to dot for # the simplest source directory structure +EXECDIR=exec C=gcc CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -ggdb -Werror -DDEBUG -DDEBUGDB diff --git a/module/tranche/src/tranche-make.cli.c b/module/tranche/src/tranche-make.cli.c index 5faf31f..bfe9d9b 100644 --- a/module/tranche/src/tranche-make.cli.c +++ b/module/tranche/src/tranche-make.cli.c @@ -38,31 +38,36 @@ user does not want this behavior, give a value of "." for -sdir. int main(int argc, char **argv, char **envp){ - char *src_file_path = 0; + int err = 0; char *sname = 0; char *tdir = 0; char *mfile_path = 0; - + Da args; // we will queue the non option args here + Da *argsp = &args; // collection of the non-option non-option-value args + da_alloc(argsp, sizeof(char *)); { // argument parse - Da args; // we will queue the non option args here - Da *argsp = &args; - da_alloc(argsp, sizeof(char *)); - - int err_cnt = 0; - char **pt = argv; + char **pt = argv + 1; // skip the command name char *option; char *value; // currently all our tranche options have exactly one value while(*pt){ if( **pt == '-' ){ option = *pt + 1; + + // options that take no values: if(!*option){ fprintf(stderr, "Currently there is no lone '-' option.\n"); - err_cnt++; + err |= TRANCHE_ERR_ARG_PARSE; goto endif; } + if( !strcmp(option, "h") || !strcmp(option, "help") ){ + err |= TRANCHE_ERR_HELP; // this will force the usage message, though it will also return an error + goto endif; + } + + // options that take one value: pt++; if(!*pt || **pt == '-'){ fprintf(stderr, "Missing value for option %s.\n", option); - err_cnt++; + err |= TRANCHE_ERR_ARG_PARSE; if(!*pt) break; // then nothing more to parse goto endif; } @@ -73,6 +78,7 @@ int main(int argc, char **argv, char **envp){ } if( !strcmp(option, "tdir") ){ tdir = value; + path_trim_slashes(tdir); goto endif; } if( !strcmp(option, "sname") ){ @@ -80,72 +86,69 @@ int main(int argc, char **argv, char **envp){ goto endif; } fprintf(stderr, "Unrecognized option %s.", option); - err_cnt++; + err |= TRANCHE_ERR_ARG_PARSE; goto endif; } // else clause da_push(argsp, pt); endif: - pt++; + pt++; } - int args_cnt = da_length(argsp); - if(args_cnt > 1) src_file_path = *(char **)da_index(argsp, 1); - - // arg contracts - if(args_cnt > 2){ - fprintf(stderr, "too many args\n"); - err_cnt++; - } - if(!src_file_path && !sname){ - fprintf(stderr, "must specify at least one of a src_file_path or an sname\n"); - err_cnt++; + if(da_emptyq(argsp) && !sname){ + fprintf(stderr, "Must be given at least one source name argument or an sname option\n"); + err |= TRANCHE_ERR_SNAME; } - if(err_cnt > 0){ - fprintf(stderr, "usage: %s [] [-sname ] [-tdir ] [-mfile ]\n", argv[0]); - return TRANCHE_ERR_ARG_PARSE; + if(err){ + fprintf(stderr, "usage: %s [].. [-sname ] [-tdir ]\n", argv[0]); + return err; } - da_free(argsp); // this only frees the array itself, not the things it points to - }// end of argument parse - FILE *src_file; + // open the output file int mfile_fd; - { //source and mfile open - if(!src_file_path) - src_file = stdin; - else - src_file = fopen(src_file_path, "r"); - + { if(mfile_path) mfile_fd = open(mfile_path, O_WRONLY | O_APPEND | O_CREAT, 0666); else mfile_fd = STDOUT_FILENO; - int err = 0; - if(!src_file){ - fprintf(stderr,"could not open tranche source file %s\n", src_file_path); - err+= TRANCHE_ERR_SRC_OPEN; - } if(mfile_fd == -1){ fprintf(stderr, "Could not open the dep file %s\n", mfile_path); - err+= TRANCHE_ERR_DST_OPEN; + err |= TRANCHE_ERR_DST_OPEN; } - if(err) return err; } - if(sname)src_file_path = sname; - path_trim_slashes(tdir); - tranche_make(src_file, src_file_path, mfile_fd, tdir); + // The arguments are source file paths, but we process each one only once. + Da src_arr; + Da *src_arrp = &src_arr; + da_alloc(src_arrp, sizeof(char *)); + da_strings_set_union(src_arrp, argsp, NULL); // NULL destructor + da_free(argsp); - { // deallocate resources instead of just existing, so as to catch any errors - int err_cnt = 0; - if(src_file != stdin) - if( fclose(src_file) ){perror(NULL); err_cnt++;} - if(mfile_fd != STDOUT_FILENO) - if( close(mfile_fd) == -1 ){perror(NULL); err_cnt++;} - if( err_cnt ) - return TRANCHE_ERR_FCLOSE; - else - return 0; + char *src_file_path; + FILE *src_file; + if(da_emptyq(src_arrp)) + tranche_make(stdin, sname, mfile_fd, tdir); + else{ + char *pt = src_arrp->base; + while( pt < src_arrp->end ){ + src_file_path = *(char **)pt; + src_file = fopen(src_file_path, "r"); + if(!src_file){ + fprintf(stderr,"Could not open source file %s.\n", src_file_path); + err |= TRANCHE_ERR_SRC_OPEN; + }else{ + tranche_make(src_file, src_file_path, mfile_fd, tdir); + if( fclose(src_file) == -1 ){perror(NULL); err |= TRANCHE_ERR_FCLOSE;} + } + pt += src_arrp->element_size; + } + } + da_free(src_arrp); + + if(mfile_fd != STDOUT_FILENO && close(mfile_fd) == -1 ){ + perror(NULL); + err |= TRANCHE_ERR_FCLOSE; } + return err; } diff --git a/module/tranche/src/tranche-target.cli.c b/module/tranche/src/tranche-target.cli.c index b579e88..c216534 100644 --- a/module/tranche/src/tranche-target.cli.c +++ b/module/tranche/src/tranche-target.cli.c @@ -9,6 +9,7 @@ between blank lines being sent and text being sent to stdout. #include #include +#include #include #include "tranche.lib.h" @@ -17,27 +18,94 @@ between blank lines being sent and text being sent to stdout. int main(int argc, char **argv, char **envp){ - if(argc != 2){ - fprintf(stderr, "usage: %s \n",argv[0]); - return ERR_ARGC; - } - char *src_file_name = argv[1]; - - int dep_fd; - FILE *src_file = fopen(src_file_name, "r"); - unsigned int err = 0; - if(!src_file){ - fprintf(stderr,"could not open tranche source file %s\n", src_file_name); - err+= ERR_SRC_OPEN; - } - if(err) return err; + int err = 0; + char *sep = 0; + Da args; // we will queue the non option args here + Da *argsp = &args; // collection of the non-option non-option-value args + da_alloc(argsp, sizeof(char *)); + { // argument parse + char **pt = argv + 1; // skip the command name + char *option; + char *value; // currently all our tranche options have exactly one value + while(*pt){ + if( **pt == '-' ){ + option = *pt + 1; + + // options that take no values: + if(!*option){ + fprintf(stderr, "Currently there is no lone '-' option.\n"); + err |= TRANCHE_ERR_ARG_PARSE; + goto endif; + } + if( !strcmp(option, "h") || !strcmp(option, "help") ){ + err |= TRANCHE_ERR_HELP; // this will force the usage message, though it will also return an error + goto endif; + } + + // options that take one value: + pt++; if(!*pt || **pt == '-'){ + fprintf(stderr, "Missing value for option %s.\n", option); + err |= TRANCHE_ERR_ARG_PARSE; + if(!*pt) break; // then nothing more to parse + goto endif; + } + value = *pt; + if( !strcmp(option, "sep") ){ + sep = value; + goto endif; + } + fprintf(stderr, "Unrecognized option %s.", option); + err |= TRANCHE_ERR_ARG_PARSE; + goto endif; + } + // else clause + da_push(argsp, pt); + endif: + pt++; + } + if(!sep)sep = "\n"; + if(err){ + fprintf(stderr, "usage: %s [].. [-sep ]\n", argv[0]); + return err; + } + }// end of argument parse + + // The arguments are source file paths, but we process each one only once. + Da src_arr; + Da *src_arrp = &src_arr; + da_alloc(src_arrp, sizeof(char *)); + da_strings_set_union(src_arrp, argsp, NULL); // NULL destructor + da_free(argsp); + + // a list of unique targets Da target_arr; Da *target_arrp = &target_arr; da_alloc(target_arrp, sizeof(char *)); - tranche_target(src_file, target_arrp); - da_strings_puts(target_arrp); + + uint err_cnt = 0; + char *src_file_path; + FILE *src_file; + if(da_emptyq(src_arrp)) + tranche_target(stdin, target_arrp); + else{ + char *pt = src_arrp->base; + while( pt < src_arrp->end ){ + src_file_path = *(char **)pt; + src_file = fopen(src_file_path, "r"); + if(!src_file){ + fprintf(stderr,"Could not open source file %s.\n", src_file_path); + err |= TRANCHE_ERR_SRC_OPEN; + }else{ + tranche_target(src_file, target_arrp); + if( fclose(src_file) == -1 ){perror(NULL); err |= TRANCHE_ERR_FCLOSE;} + } + pt += src_arrp->element_size; + } + } + da_free(src_arrp); + da_strings_print(target_arrp, sep); da_free_elements(target_arrp); - fclose(src_file); - return 0; + da_free(target_arrp); + return err; } diff --git a/module/tranche/src/tranche.cli.c b/module/tranche/src/tranche.cli.c index a0fe798..597a191 100644 --- a/module/tranche/src/tranche.cli.c +++ b/module/tranche/src/tranche.cli.c @@ -19,7 +19,6 @@ the tranche output files before running tranche a second time. .. currently tranche_send will probably mess up if the user nests a tranche to the same file as one already open in the containing tranche .. -.. should allow multiple source file args */ #include @@ -29,29 +28,35 @@ the same file as one already open in the containing tranche .. #include "tranche.lib.h" int main(int argc, char **argv, char **envp){ - char *src_file_path = 0; - char *tdir = 0; + int err = 0; + char *tdir = 0; + Da args; // we will queue the non option args here + Da *argsp = &args; // collection of the non-option non-option-value args + da_alloc(argsp, sizeof(char *)); { // argument parse - Da args; // we will queue the non option args here - Da *argsp = &args; - da_alloc(argsp, sizeof(char *)); - - int err_cnt = 0; - char **pt = argv; + char **pt = argv + 1; // skip the command name char *option; char *value; // currently all our tranche options have exactly one value while(*pt){ if( **pt == '-' ){ option = *pt + 1; + + // options that take no values: if(!*option){ fprintf(stderr, "Currently there is no lone '-' option.\n"); - err_cnt++; + err |= TRANCHE_ERR_ARG_PARSE; + goto endif; + } + if( !strcmp(option, "h") || !strcmp(option, "help") ){ + err |= TRANCHE_ERR_HELP; // this will force the usage message, though it will also return an error goto endif; } + + // options that take one value: pt++; if(!*pt || **pt == '-'){ fprintf(stderr, "Missing value for option %s.\n", option); - err_cnt++; + err |= TRANCHE_ERR_ARG_PARSE; if(!*pt) break; // then nothing more to parse goto endif; } @@ -61,7 +66,7 @@ int main(int argc, char **argv, char **envp){ goto endif; } fprintf(stderr, "Unrecognized option %s.", option); - err_cnt++; + err |= TRANCHE_ERR_ARG_PARSE; goto endif; } // else clause @@ -69,46 +74,46 @@ int main(int argc, char **argv, char **envp){ endif: pt++; } - int args_cnt = da_length(argsp); - if(args_cnt > 1) src_file_path = *(char **)da_index(argsp, 1); - - // arg contracts - if(args_cnt > 2){ - fprintf(stderr, "too many arguments\n"); - err_cnt++; - } - if(err_cnt > 0){ - fprintf(stderr, "usage: %s [] [-tdir ]\n", argv[0]); - return TRANCHE_ERR_ARG_PARSE; + if(err){ + fprintf(stderr, "usage: %s [].. [-tdir ]\n", argv[0]); + return err; } - da_free(argsp); // this only frees the array itself, not the things it points to - }// end of argument parse - FILE *src_file; - { //source and mfile open - if(!src_file_path) - src_file = stdin; - else - src_file = fopen(src_file_path, "r"); - - int err = 0; - if(!src_file){ - fprintf(stderr,"could not open tranche source file %s\n", src_file_path); - err+= TRANCHE_ERR_SRC_OPEN; - } - if(err) return err; - } - Da targets; - da_alloc(&targets, sizeof(int)); + Da *target_arrp = &targets; + da_alloc(target_arrp, sizeof(int)); int fd = STDOUT_FILENO; - da_push(&targets, &fd); + da_push(target_arrp, &fd); if(tdir)chdir(tdir); - tranche_send(src_file, &targets); + Da src_arr; + Da *src_arrp = &src_arr; + da_alloc(src_arrp, sizeof(char *)); + da_strings_set_union(src_arrp, argsp, NULL); + da_free(argsp); + + char *src_file_path; + FILE *src_file; + if(da_emptyq(src_arrp)) + tranche_send(stdin, target_arrp); + else{ + char *pt = src_arrp->base; + while( pt < src_arrp->end ){ + src_file_path = *(char **)pt; + src_file = fopen(src_file_path, "r"); + if(!src_file){ + fprintf(stderr,"Could not open source file %s.\n", src_file_path); + err |= TRANCHE_ERR_SRC_OPEN; + }else{ + tranche_send(src_file, target_arrp); + if( fclose(src_file) == -1 ){perror(NULL); err |= TRANCHE_ERR_FCLOSE;} + } + pt += src_arrp->element_size; + } + } - da_free(&targets); - fclose(src_file); - return 0; + da_free(target_arrp); + da_free(src_arrp); + return err; } diff --git a/module/tranche/src/tranche.lib.c b/module/tranche/src/tranche.lib.c index aad290a..412e950 100644 --- a/module/tranche/src/tranche.lib.c +++ b/module/tranche/src/tranche.lib.c @@ -95,7 +95,7 @@ int tranche_send(FILE *src, Da *arg_fdap){ da_alloc(&fda, sizeof(int)); while( !feof(src) ){ - da_fgets(&line, src); + da_string_input(&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 @@ -122,47 +122,6 @@ int tranche_send(FILE *src, Da *arg_fdap){ //-------------------------------------------------------------------------------- // returns a list of unique target file names from a tranche source - -// return true if proffered test string is already in the strings array -typedef struct { - char *string; - bool found; -} string_state; -static void string_equal(void *sp, void *closure){ - char *string_element = *(char **)sp; - string_state *ss = (string_state *)closure; - if( ss->found ) return; - ss->found = !strcmp(string_element, ss->string); - return; -} -static bool exists(Da *string_arrp, char *test_string){ - string_state ss; - ss.string = test_string; - ss.found = false; - da_map(string_arrp, string_equal, &ss); - return ss.found; -} - -// only inserts the string if it is not already in the array -static void insert_if_unique(Da *string_arrp, char *proffered_string){ - if( exists( string_arrp, proffered_string)){ // then throw it away, we don't need it - free(proffered_string); - return; - } - da_push(string_arrp, &proffered_string); -} - -// dissolves proffered array into the existing array -static void combine_one(void *psp, void *closure){ - char *proffered_string = *(char **)psp; - Da *string_arrp = (Da *)closure; - insert_if_unique(string_arrp, proffered_string); -} -static void combine(Da *string_arrp, Da *proffered_string_arrp){ - da_map(proffered_string_arrp, combine_one, string_arrp); - return; -} - // make a list of the unique tranche target files found in src int tranche_target(FILE *src, Da *target_arrp){ char *pt; @@ -171,12 +130,12 @@ int tranche_target(FILE *src, Da *target_arrp){ da_alloc(&line, sizeof(char)); da_alloc(&file_name_arr, sizeof(char *)); while( !feof(src) ){ - da_fgets(&line, src); + da_string_input(&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); - combine(target_arrp, &file_name_arr); // frees strings that are not inserted + da_strings_set_union(target_arrp, &file_name_arr, free); da_rewind(&file_name_arr); tranche_target(src, target_arrp); } @@ -225,16 +184,16 @@ void tranche_make(FILE *src_file, char *src_name, int mfile_fd, char *tdir){ char *pt = tap->base; // char * because it points to a byte in the array while( pt < tap->end ){ if(tdir){ - da_push_string(dlap, tdir); + da_string_push(dlap, tdir); da_push(dlap, &slash); } - da_push_string(dlap, *(char **)pt); + da_string_push(dlap, *(char **)pt); da_push(dlap, &sp); pt += tap->element_size; } da_push(dlap, &colon); da_push(dlap, &sp); - da_push_string(dlap, src_name); + da_string_push(dlap, src_name); da_push(dlap, &newline); write(mfile_fd, dlap->base, dlap->end - dlap->base); da_free_elements(tap); @@ -243,10 +202,10 @@ void tranche_make(FILE *src_file, char *src_name, int mfile_fd, char *tdir){ // output acction line ---------------------------------------- da_rewind(dlap); // reuse the line buffer da_push(dlap, &tab); - da_push_string(dlap, "tranche $<"); + da_string_push(dlap, "tranche $<"); if(tdir){ - da_push_string(dlap, " -tdir "); - da_push_string(dlap, tdir); + da_string_push(dlap, " -tdir "); + da_string_push(dlap, tdir); } da_push(dlap, &newline); da_push(dlap, &newline); diff --git a/module/tranche/src/tranche.lib.h b/module/tranche/src/tranche.lib.h index c847765..d40c074 100644 --- a/module/tranche/src/tranche.lib.h +++ b/module/tranche/src/tranche.lib.h @@ -5,6 +5,8 @@ #define TRANCHE_ERR_SRC_OPEN 2 #define TRANCHE_ERR_DST_OPEN 4 #define TRANCHE_ERR_FCLOSE 8 +#define TRANCHE_ERR_HELP 16 +#define TRANCHE_ERR_SNAME 32 void path_trim_slashes(char *path); int tranche_send(FILE *src, Da *arg_fds); diff --git a/module/tranche/test/try/test2.sh b/module/tranche/test/try/test2.sh index 6ec2626..5959bbc 100644 --- a/module/tranche/test/try/test2.sh +++ b/module/tranche/test/try/test2.sh @@ -3,6 +3,6 @@ diff -q test2.c test2.c.expected diff -q test2.h test2.h.expected diff -q test2stdout.dat test2stdout.dat.expected -rm test2.c test2.h +rm test2.c test2.h test2stdout.dat.expected diff --git a/module/tranche/test/try/test2stdout.dat.expected b/module/tranche/test/try/test2stdout.dat.expected deleted file mode 100644 index 139597f..0000000 --- a/module/tranche/test/try/test2stdout.dat.expected +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/module/tranche/test/try/test5.sh b/module/tranche/test/try/test5.sh new file mode 100644 index 0000000..284d01e --- /dev/null +++ b/module/tranche/test/try/test5.sh @@ -0,0 +1,13 @@ +./tranche test1.dat test2.trc.c + +diff -q test11.dat test11.dat.expected +diff -q test12.dat test12.dat.expected +diff -q test13.dat test13.dat.expected +diff -q test14.dat test14.dat.expected +diff -q test15.dat test15.dat.expected + +diff -q test2.c test2.c.expected +diff -q test2.h test2.h.expected + +rm test11.dat test12.dat test13.dat test14.dat test15.dat +rm test2.c test2.h diff --git a/tool/bin/@System.solv b/tool/bin/@System.solv new file mode 100644 index 0000000..1e89182 Binary files /dev/null and b/tool/bin/@System.solv differ diff --git a/tool/bin/tranche b/tool/bin/tranche index 0682265..5489419 100755 Binary files a/tool/bin/tranche and b/tool/bin/tranche differ diff --git a/tool/bin/tranche-make b/tool/bin/tranche-make index 7c587c2..6ec278f 100755 Binary files a/tool/bin/tranche-make and b/tool/bin/tranche-make differ diff --git a/tool/bin/tranche-target b/tool/bin/tranche-target index 710e4c9..e315a2c 100755 Binary files a/tool/bin/tranche-target and b/tool/bin/tranche-target differ diff --git a/tool/lib/makefile-cc b/tool/lib/makefile-cc index d03d4e1..1265908 100755 --- a/tool/lib/makefile-cc +++ b/tool/lib/makefile-cc @@ -29,6 +29,10 @@ 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)) +# default directory seteup +# For TRC projects define TRDIR (even if it is just '.'), and typically set SRCDIR to tmp +# + DEPRDIR=deprecated DOCDIR=doc EXECDIR=exec @@ -39,8 +43,10 @@ SRCDIR=src TESTDIR=test TMPDIR=tmp TOOLDIR=$(realpath $(PROJECT_SUBU)/tool) +TRCDIR= TRYDIR=try + # a single space literal, for example if you wanted to subsitute commas to # spaces: $(subst $(space),;,$(string)) blank := @@ -60,15 +66,25 @@ DEPFILE=$(TMPDIR)/makefile-cc.deps LIBFILE=$(LIBDIR)/lib$(MODULE).a INCFILE=$(INCDIR)/$(MODULE).h +#-------------------------------------------------------------------------------- +# when local customizations set a TRCDIR, then these are the actual sources + +ifneq ($TRCDIR,) + TRCFILES= $(wildcard $(TRCDIR)/*.trc.c) $(wildcard $(TRCDIR)/*.trc.cc) +else + TRCFILES= +endif + + #-------------------------------------------------------------------------------- # targets .PHONY: all -all: version dep lib exec +all: version .PHONY: version version: - @echo makefile version 4.0 + @echo makefile version 5.0 @echo "PWD: " $(PWD) @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST) @echo "C: " $(C) @@ -87,10 +103,13 @@ info: @echo "TESTDIR: " $(TESTDIR) @echo "TMPDIR: " $(TMPDIR) @echo "TOOLDIR: " $(TOOLDIR) + @echo "TRCDIR: " $(TRCDIR) @echo "TRYDIR: " $(TRYDIR) @echo "DEPFILE: " $(DEPFILE) @echo "LIBFILE: " $(LIBFILE) @echo "INCFILE: " $(INCFILE) + @echo "TRCFILES: " $(TRCFILES) + @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB) @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB) @echo "C_SOURCE_CLI: " $(C_SOURCE_CLI) @echo "CC_SOURCE_LIB: " $(CC_SOURCE_LIB) @@ -104,43 +123,62 @@ info: @echo "EXEC: " $(EXEC) # should be safe to run this in an already setup or partially setup directory +# gee looks like a candidate for a makefile function .. .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 + [ ! -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 $(TRCDIR) ] && mkdir $(TRCDIR) || true + [ ! -e $(TRYDIR) ] && mkdir $(TRYDIR) || true + +# gee this script could be better, particlarly in gathering the targets +# it would be simplified if the tranche commands took multiple source arguments +# if [ -e $(DEPFILE) ]; then rm $(DEPFILE); fi +# if [ ! -z "$(TRCFILES)" ]; then\ +# targets="";\ +# for i in $(TRCFILES); do\ +# tranche-make $$i -tdir $(SRCDIR) -mfile $(DEPFILE);\ +# targets+=$$(tranche-target $$i);\ +# targets+=" ";\ +# done;\ +# echo $$targets;\ +# fi + + .PHONY: dep -dep: - @if [ -z "$(CC)" ]; then\ +dep: + if [ -e $(DEPFILE) ]; then rm $(DEPFILE); fi + if [ ! -z "$(TRCFILES)" ]; then\ + tranche-make $(TRCFILES) -mfile $(DEPFILE);\ + $(MAKE) $(shell tranche-targets $(TRCFILES) -sep " ");\ + fi + 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);\ + $(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\ + 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);\ + $(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);\ + $(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\ diff --git a/tool/lib/makefile-trc b/tool/lib/makefile-trc deleted file mode 100644 index 14b3c4f..0000000 --- a/tool/lib/makefile-trc +++ /dev/null @@ -1,37 +0,0 @@ - -# This makefile is usually called through a local makefile rather than directly. -# The purpose of this makefile is to expand out the tranched C/CC sources, and -# otherwise to fall through to makefile_cc. - -SHELL=/bin/bash - -TRCDIR=trc - -# these are the sources edited by the programmer -TRC_FILE= $(wildcard $(TRCDIR)/*.trc.c) $(wildcard $(TRCDIR)/*.trc.cc) - --include makefile-flags - -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 - -DEPFILE=$(TMPDIR)/makefile-trc.deps - -all: version deps lib execs - -.PHONY: all version deps lib exec -all: version deps lib exec - -lib: - $(MAKE) $@ - -exec: - $(MAKE) $@ - -share: - if [ ! -z "$(wildcard $(EXECDIR)/*)" ]; then cp $(EXECDIR)/* $(PROJECT_SUBU)/tool/bin; fi - -%:: - $(MAKE) $@ - -dep: \ No newline at end of file