# 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
--- /dev/null
+/*
+Scans a tranche file and outputs a dep line suitable for make.
+
+The dep file is opened for append. If the depfile is not present stdout is used.
+
+If the given source file name has a directory prefix, the targets in
+the dep line are given the same prefix.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <da.h>
+#include "tranche.lib.h"
+
+#define ERR_ARGC 1
+#define ERR_SRC_OPEN 2
+#define ERR_DEP_OPEN 4
+
+
+int main(int argc, char **argv, char **envp){
+ if(argc < 2 || argc > 3){
+ fprintf(stderr, "usage: %s <source> [<dep-file>]\n",argv[0]);
+ return ERR_ARGC;
+ }
+ char *src_file_name = argv[1];
+ char *dep_file_name = argv[2];
+
+ int dep_fd;
+ FILE *src_file = fopen(src_file_name, "r");
+ if(argc < 3)
+ dep_fd = 1;
+ else{
+ dep_fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, 0666);
+ }
+ 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(dep_fd == -1){
+ fprintf(stderr, "Could not open the dep file %s\n", dep_file_name);
+ err+= ERR_DEP_OPEN;
+ }
+ if(err) return err;
+
+ tranche_deps(src_file, dep_fd);
+ fclose(file);
+ close(dep_fd);
+ return 0;
+}
--- /dev/null
+/*
+Scans a tranche and lists the named target files.
+
+stdout is not explicitly named. Would be intersting if stdout
+were also listed if anything is sent to stdout. Might distinguish
+between blank lines being sent and text being sent to stdout.
+
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <da.h>
+#include "tranche.lib.h"
+
+#define ERR_ARGC 1
+#define ERR_SRC_OPEN 2
+
+
+int main(int argc, char **argv, char **envp){
+ if(argc != 2){
+ fprintf(stderr, "usage: %s <source>\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;
+
+ Da targets;
+ da_alloc(&targets, sizeof(char *));
+ tranche_targets(src_file, &targets);
+ da_strings_puts(&targets);
+ fclose(src_file);
+ return 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.
+Sends code tranches from a single source file into one or more output files.
+Scans through the single source file looking for lines of the form:
+
+ #tranche-begin filename filename ...
+
+With the # as the first non-space character on the line, with one or more filenames
+following the tag. Upon finding such a line, copies all following lines into the
+listed files, until reaching the end marker:
+
+ #tranche-end
+
+Files are opened for create or append. Typically the user will want to delete
+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 ..
+*/
+
#include <stdio.h>
#include <unistd.h>
#include <da.h>
int main(int argc, char **argv, char **envp){
if(argc != 2){
fprintf(stderr, "usage: %s <source-file>\n",argv[0]);
- return 1;
+ return TRANCHE_ERR_ARGC;
}
FILE *file = fopen(argv[1], "r");
if(!file){
fprintf(stderr,"could not open file %s\n", argv[1]);
- return 2;
+ return TRANCHE_ERR_SRC_OPEN;
}
Da targets;
da_alloc(&targets, sizeof(int));
-/*
-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>
}
}
-
-
//--------------------------------------------------------------------------------
// da_map calls
da_map(fdap, tranche_puts, string);
}
-
-
//--------------------------------------------------------------------------------
-// we have a little problem if the user tries to tranche two things to the same file ..
+// does the work of tranching a source file
+
int tranche_send(FILE *src, Da *arg_fdap){
char *pt;
- Da line;
- Da file_name_arr;
- Da fda;
+ Da line; // buffer holding the characters from a line
+ Da file_name_arr; // an array of file name parameters parsed from a #tranche line
+ Da fda; // open file descriptors corresponding to the file name parameters
da_alloc(&line, sizeof(char));
da_alloc(&file_name_arr, sizeof(char *));
da_alloc(&fda, sizeof(int));
da_free(&fda);
return 0;
}
+
+//--------------------------------------------------------------------------------
+// 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;
+ char *test_string = ss->string;
+ ss->found = !strcmp(string_element, test_string);
+ return;
+}
+static bool exists(Da *strings, char *test_string){
+ string_state ss;
+ ss.string = test_string;
+ ss.found = false;
+ da_map(strings, string_equal, &ss);
+ return ss.found;
+}
+
+// only inserts the string if it is not already in the array
+static void insert_if_unique(Da *strings, char *proffered_string){
+ if( exists( strings, proffered_string)){ // then throw it away, we don't need it
+ free(proffered_string);
+ return;
+ }
+ da_push(strings, proffered_string);
+}
+
+// dissolves proffered array into the existing array
+static void combine_one(void *psp, void *closure){
+ char *proffered_string = (char *)psp;
+ Da *strings = (Da *)closure;
+ insert_if_unique(strings, proffered_string);
+}
+static void combine(Da *strings, Da *proffered_strings){
+ da_map(proffered_strings, combine_one, strings);
+ return;
+}
+
+int tranche_targets(FILE *src, Da *targets){
+ char *pt;
+ Da line; // buffer holding the characters from a line
+ Da file_name_arr;// an array of file name parameters parsed from a #tranche line
+ da_alloc(&line, sizeof(char));
+ da_alloc(&file_name_arr, sizeof(char *));
+ 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);
+ combine(targets, &file_name_arr); // frees strings that are not inserted
+ }
+ da_rewind(&line);
+ }
+ da_free(&line);
+ da_free(&file_name_arr);
+ return 0;
+}
#ifndef TRANCHE_LIB_H
#define TRANCHE_LIB_H
-int tranche_send(FILE *src, Da *arg_fds);
+#define TRANCHE_ERR_ARGC 1
+#define TRANCHE_ERR_SRC_OPEN 2
+#define TRANCHE_ERR_DEP_OPEN 4
+int tranche_send(FILE *src, Da *arg_fds);
+int tranche_targets(FILE *src, Da *targets);
#endif
+# this makefile is usually called from via make from a local makefile
+
+
#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
+#--------------------------------------------------------------------------------
+# defaults
+
# these are the sources edited by the programmer
C_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.c)
C_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.c)
# executables are made from CLI sources
EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI))
-#otherwise make provides default values for these
-C=
-CC=
+DEPRDIR=deprecated
+DOCDIR=doc
+EXECDIR=exec
+INCDIR=include
+LIBDIR=lib
+SHAREDIR=../share
+SRCDIR=src
+TESTDIR=test
+TMPDIR=tmp
+TOOLDIR=$(realpath $(PROJECT_SUBU)/tool)
+TRYDIR=try
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
+# spaces: $(subst $(space),;,$(string))
blank :=
space :=$(blank) $(blank)
+# prevent make from subsittuing its default for CC
+C=
+CC=
+
+#--------------------------------------------------------------------------------
+# local customization
+# user must define things needed by the local makefile, the compiler, and flags
+
+-include makefile-flags
+
+#--------------------------------------------------------------------------------
+# targets
+
.PHONY: all
all: version dep lib 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: share
+share:
+ if [ -f $(LIBFILE) ];then cp $(LIBFILE) $(SHAREDIR)/lib; fi
+ if [ -f $(INCFILE) ];then cp $(INCFILE) $(SHAREDIR)/include; fi
+ if [ $(shell ls -A $(EXECDIR)) ];then cp $(EXECDIR)/* $(SHAREDIR)/bin; fi
.PHONY: clean
clean:
-# We should read the tranche sources and see what files they output, and then
+# Ideally we would 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}
+# usually we have a bunch of source files and one target, here we have one source
+# file, the tranch file, and a bunch of targets.
+
# 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
+TRCDIR=trc
# 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)
+C_TRC_LIB= $(wildcard $(TRCDIR)/*.lib.c)
+C_TRC_CLI= $(wildcard $(TRCDIR)/*.cli.c)
+CC_TRC_LIB= $(wildcard $(TRCDIR)/*.lib.cc)
+CC_TRC_CLI= $(wildcard $(TRCDIR)/*.cli.cc)
#remove the suffix to get base name
C_BASE_LIB= $(sort $(patsubst %.lib.c, %, $(notdir $(C_SOURCE_LIB))))