v08i044: explode -- a LaTeX to source-file extracter

Brandon S. Allbery - comp.sources.misc allbery at uunet.UU.NET
Sun Sep 24 06:59:57 AEST 1989


Posting-number: Volume 8, Issue 44
Submitted-by: davecb at nexus.yorku.ca (David Collier-Brown)
Archive-name: explode

   Well, this is a little program to pull chunks of
source code out of LaTeX files and put them into one or
more output files.
   As the man page says, I did this as a simple tool to
allow better documentation of quite simple programs, ones
that could be explained easily in a fairly sequential
discussion.  Since it hasn't broken on the few machines
I've used it on, I'm contributing it to the net.  I believe
it portable and reliable, but it's whole life has been in
the Berzerkly universe...

--dave

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile RCS README bar.tex explode.1 explode.c foo.tex
#   unexplode
# Wrapped by davecb at yunexus on Mon Sep 18 21:50:59 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(508 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# A somewhat generic makefile, for explode
X#
XCC=/usr/local/gnu/gcc # Try another compiler
XSRCS= explode.c
XOBJS= explode.o 
XCFLAGS= -g
XDESTDIR= /usr/local/bin
XMANDIR= /usr/local/man/man1
X
Xexplode: ${OBJS}
X 	${CC} -o explode ${CFLAGS} ${OBJS}
X
Xinstall:
X	install -s -m 755 explode ${DESTDIR}
X	install -m 755 unexplode ${DESTDIR}
X	cp explode.1 ${MANDIR}/explode.1
X
Xdeinstall:
X	rm -f ${DESTDIR}/explode ${DESTDIR}/unexplode
X	rm -f ${MANDIR}/explode.1
X
Xclean:
X	rm -f explode *.o core a.out
Xlint:
X	lint explode.c
END_OF_FILE
if test 508 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test ! -d 'RCS' ; then
    echo shar: Creating directory \"'RCS'\"
    mkdir 'RCS'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(154 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is new, incomplet and inefficent.
X	1) no state in table
X	2) no error checking
X	3) no line-splitting when directive in mid-line
X	4) underdocumented.
X
END_OF_FILE
if test 154 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'bar.tex' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bar.tex'\"
else
echo shar: Extracting \"'bar.tex'\" \(136 characters\)
sed "s/^X//" >'bar.tex' <<'END_OF_FILE'
X\file{beginning}
X\begin{verbatim}
Xbeginning
X\end{verbatim}
X
X\begin{verbatim}
Xmiddle
X\end{verbatim}
X
X\begin{verbatim}
Xend
X\end{verbatim}
END_OF_FILE
if test 136 -ne `wc -c <'bar.tex'`; then
    echo shar: \"'bar.tex'\" unpacked with wrong size!
fi
# end of 'bar.tex'
fi
if test -f 'explode.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'explode.1'\"
else
echo shar: Extracting \"'explode.1'\" \(1981 characters\)
sed "s/^X//" >'explode.1' <<'END_OF_FILE'
X.TH EXPLODE 1
X.SH NAME
Xexplode \- file exploder (LaTeX source-code extractor)
X.SH SYNOPSIS
X.B explode
X.I pathname[.tex]
X.sp
X.B unexplode
X.I pathname[.tex]
X
X.SH DESCRIPTION
X.I explode
Xtakes source code intertwined with LaTeX and emits
Xjust the code, to however many files as are needed.
X.I unexplode
Xdeletes the files created that way.
X.PP
XThe syntax of the LaTeX file is very simple:
X.I \\file{filename}
Xnames a file to which material will be written.
X.I \\begin{verbatim}
Xstarts the copy to the file, and
X.I \\end{verbatim}
Xends it.
X.PP
XThe verbatim sections can be interleaved with any other
Xlegal LaTeX construct, and multiple verbatims which
Xfollow a single \\file directive will be written to the
Xsame file.
X.PP
XMultiple files can be in use at any one time, and
Xyou can switch between them by inserting a
X\\file line.  
X
X.SH EXAMPLE
XThe following is the simplest plausible explode-file.
X.nf
X.nj
X
X\\file{foo.h}
X ...
X\\begin{verbatim}
Xtypedef void * FOO;
X\\end{verbatim}
X ...
X\\file{foo.c}
X\\begin{verbatim}
X ...
X.nf
X.nj
X
X.SHISTORY
XThis was written one afternoon when it became obvious that pr
Xrewriting my Web subset was going to take a looooong time.
XThis was written instead, to allow simple, multi-file programs
Xto be generated from a single LaTeX source file.
X.PP
XThe program is extremely simple, has no options and probably never will
Xhave.  The problem of multi-input, multi-output LaTeX ->
Xprogramming-language coding is not something that's going to succumb
Xto simple v7 filters.  In the meantime, here's the filter.
X
XNone at present.
X
X.SH SEE ALSO
XLaTeX(1), tangle(1), weave(1), Donald Knuth's Web system.
X
X.SH AUTHORS
X.nf
XDave Collier-Brown (davecb at nexus.yorku.ca).
X.fi
X
X.SH DIAGNOSTICS
X``Too many output files'', if the system runs out of
Xfile descriptors.
X
X.SH BUGS
XThe limit on output files.  An earlier version
Xre-used file descriptors...
X.PP
XThe directives need to be on a line by themselves, as
Xthe whole line gets discarded after the directive
Xis interpreted.
END_OF_FILE
if test 1981 -ne `wc -c <'explode.1'`; then
    echo shar: \"'explode.1'\" unpacked with wrong size!
fi
# end of 'explode.1'
fi
if test -f 'explode.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'explode.c'\"
else
echo shar: Extracting \"'explode.c'\" \(7384 characters\)
sed "s/^X//" >'explode.c' <<'END_OF_FILE'
X/*
X * explode -- an extact function for a latex-flavored tangle.
X */
X#include <stdio.h>
X#include <strings.h>
X
X#define MAXLINE	256
X#define OK	0
Xchar    *ProgName = NULL;
Xtypedef enum {NO=0,FILENAME,BEGIN_VERBATIM,END_VERBATIM} KEY;
X
X void
Xmain(argc,argv) int argc; char *argv[]; {
X	int	rc = 0, /* Return code from explode. */
X	        i;
X	FILE	*fp, *lopen();
X
X	ProgName = argv[0];
X	if (argc < 2 && isatty(0)) {
X		(void) fprintf(stderr,"Usage: %s file[.tex]\n",
X		       ProgName);
X		exit(1);
X	}
X	if (!isatty(0)) {
X		rc = explode(stdin);
X	}
X	else {
X		for (i=1; i < argc; i++) {
X		        /* printf("argv[%d] = '%s'\n",i,argv[i]); */
X			if ((fp= lopen(argv[i],"r",".tex")) == NULL) {
X				(void) fprintf(stderr,
X					"%s: %s \"%s\", ignored.\n",
X					ProgName, "can't open input file",
X					argv[i]);
X				continue;
X			}
X			else {
X				rc = explode(fp);
X				(void) fclose(fp);
X			}
X		}
X	}
X	exit(rc);
X}
X
X/*
X * explode -- the main function, which supervises parsing
X *      and output-file bookkeeping.
X */
X int
Xexplode(fp) FILE *fp; {
X	char	line[MAXLINE],      /* A place to put the line. */
X	        operand[MAXLINE];   /* The keyword's parameter. */
X	FILE    *outFp,             /* Current output file. */
X	        *tFp,               /* Temporary fp. */
X 	        *initialFile(),     /* Initial output file (/dev/null) */
X	        *beginFile(),       /* Start writing to taht file. */
X	        *endFile();         /* Stop writing to it. */
X	int	initiateFile();     /* Associate a name with an fp. */
X
X	KEY	hasKeyWord();
X
X	if ((outFp= initialFile()) == NULL) {
X	          /* Assumed infallible. */
X	          (void) fprintf(stderr,"%s: unable to open \"%s\", %s.\n",
X			ProgName,"/dev/null","aborting");
X		  exit(3);
X	}
X	while (fgets(line,sizeof(line),fp) != NULL) {
X		switch (hasKeyWord(line,operand)) {
X		case NO: /* Just write the line. */
X		       /* printf("body line: %s",line); */
X		       (void) fputs(line,outFp);
X		       break;
X		case FILENAME: /* Collect a new filename to use. */
X		       /* printf("file line: %s, %s",operand,line); */
X		       if ( !initiateFile(operand)) {
X		               (void) fprintf(stderr, 
X			               "%s: can't open output file \"%s\", %s.\n",
X				       ProgName, operand, "aborting");
X			       exit(3);
X		       }
X		       break;
X		case BEGIN_VERBATIM: /* Start writing to named file. */
X		       /* printf("begin line: %s, %s",operand,line); */
X		       if ((tFp= beginFile()) != NULL) {
X			       outFp = tFp;
X		       }
X		       else {
X			       /* It's "\begin{verbatim}" with no current file. */
X			       (void) fputs(line,outFp);
X		       } 
X		       break;
X		case END_VERBATIM: /* Stop writing to that file. */
X		       /* printf("end line %s, %s",operand,line); */
X		       if ((tFp= endFile()) != NULL) {
X			       outFp = tFp;
X		       }
X		       else {
X			       /* It's "\end{verbatim} with no current file". */
X			       (void) fputs(line,outFp);
X		       } 
X		       break;
X		}
X 	}
X	return OK;
X}
X
X/*
X * lopen -- local open, sees if there's a file with an optional suffix.
X */
X FILE *
Xlopen(name,mode,ext) char *name, *mode, *ext; {
X	FILE	*fp, *fopen();
X	char	buffer[MAXLINE],
X	        *strcat(), *strcpy();
X
X	if ((fp= fopen(name,mode)) != NULL) {
X		return fp;
X	}
X	(void) strcat(strcpy(buffer,name),ext);
X	fp = fopen(buffer,mode);
X	return fp;
X}
X
X/*
X * hasKeyWord -- see if the keyword appears in the line,
X *      return either NO, FILENAME, BEGIN_VERBATIM or END_VERBATIM and
X *      a pointer to a null-terminated string containing
X *      the parameter.  Also produces error messages if
X *      the keyword-phrase is misparsed.
X */
X#define strchr(s,c) index(s,c)
X#define streq(s1,s2) (strncmp(s1,s2,strlen(s2))==0)
X KEY
XhasKeyWord(line,operand) char *line; char *operand; {
X        register char *p; /* Pointer to current position in string. */
X        KEY      rc;      /* Result. */
X	char     *skipTo();
X	void     terminate(), unTerminate();
X
X        if ((p= strchr(line,'\\')) == NULL) {
X	        return NO;
X	}
X	else if (streq(p,"\\file{")) {
X	       rc = FILENAME;
X	}
X	else if (streq(line,"\\begin{verbatim}")) {
X	        rc = BEGIN_VERBATIM;
X	}
X	else if (streq(line,"\\end{verbatim}")) {
X	        rc = END_VERBATIM;
X	}
X	else {
X	        return NO;
X	}
X	/* It found one! Stuff "operand" with the parameter value. */
X        p = skipTo(p,'{') + 1;
X	terminate(p,'}');
X	(void) strcpy(operand,p);
X	unTerminate(p,'}');
X	return rc;
X}
X
X/*
X** string utilities 
X*/
X char *
XskipTo(p,c) register char *p; char c; {
X        while (*p && *p != c)
X	        p++;
X	return p;
X      }
X
X void
Xterminate(from,at) char *from, at; {
X        while (*from && *from != at)
X	        from++;
X	if (!*from)
X	        return;
X	*from = '\0';
X	return;
X}
X
X void
XunTerminate(from,with) char *from, with; {
X        while (*from)
X	        from++;
X	*from = with;
X	return;
X}
X
X/*
X * strsave -- allocate enopugh space for a string & its terminating null.
X */
X char *
Xstrsave(s) char *s; {
X        char    *p, *malloc(), *strcpy();
X
X	if ((p= malloc((unsigned)strlen(s)+1)) != NULL) {
X	        return strcpy(p,s);
X	}
X	else {
X	        return NULL;
X	}
X}
X
X/*
X** File -- output-file managment package.
X**      Depends on table package.
X*/
X#define CURRENT "The current file"
Xtypedef struct {
X        char *name;
X	FILE *fp;
X} TABLE;
X
X
X/*
X * initialFile -- create the initial output file (/dev/null).
X */
X FILE *
XinitialFile() {
X        FILE    *fp, *fopen();
X	TABLE   *addToTable();
X
X	if ((fp= fopen("/dev/null","w")) != NULL 
X	   && addToTable("/dev/null",fp) != NULL) {
X	        return fp;
X	}
X	else {
X	        return (FILE *) NULL;
X	}
X}
X
X/*
X * initiateFile -- get a file pointer for the named file & save it.
X */
X int
XinitiateFile(name) char *name; {
X	TABLE   *getFromTable(), *addToTable();
X	FILE    *fp, *fopen();
X
X       	if (getFromTable(name) != NULL) {
X	        return 1;
X	}
X	else if ((fp= fopen(name,"w")) == NULL) {
X	        return 0;
X	}
X	else {
X	        return addToTable(name,fp)? 1: 0;
X	}
X}
X
X/*
X * beginFile --  start writing to that file.
X */
X FILE *
XbeginFile() {
X        TABLE   *t, *getFromTable();
X
X        if ((t= getFromTable(CURRENT)) != NULL) {
X	        return t->fp;
X	}
X	else {
X	        return NULL;
X        }
X}
X
X/*
X * endFile -- stop writing to it.
X */
X FILE *
XendFile() {    
X        TABLE   *getFromTable();
X
X        if (getFromTable(CURRENT) != NULL) {
X	        /* Return the replacement. */
X	        return getFromTable("/dev/null")->fp;
X	}
X	else {
X	        /* Otherwise don't stop using it. */
X	        return (FILE *) NULL;
X	}
X}
X
X
X/*
X * 
X */
X#define NFILES 30
XTABLE   Table[NFILES];
Xstatic int CurrentFile = -1;
X
X TABLE *
XaddToTable(name,fp) char *name; FILE *fp; {
X        static int lastLookedAt = 0;
X	int     i;
X	char    *strsave();
X	TABLE   *t, *getFromTable();
X
X        if ((t= getFromTable(name)) != NULL) {
X	        return (TABLE *) t;
X	}
X	else {
X	        for (i=lastLookedAt; i < NFILES; i++) {
X		        if (Table[i].name == NULL) {
X			        Table[i].name = strsave(name);
X			        Table[i].fp = fp;
X				CurrentFile = i;
X				return &Table[i];
X			}
X		}
X		return (TABLE *) NULL;
X	}
X}
X
X TABLE *
XgetFromTable(name) char *name; {
X        int     i;
X
X	if (streq(name,CURRENT)) {
X		return (CurrentFile == -1)?  (TABLE *) NULL: &Table[CurrentFile];
X	}
X        for (i=0; i < NFILES && Table[i].name != NULL; i++) {
X	        if (streq(Table[i].name,name) != NULL) {
X		        return &Table[i];
X		}
X	}
X        return (TABLE *) NULL;
X}
END_OF_FILE
if test 7384 -ne `wc -c <'explode.c'`; then
    echo shar: \"'explode.c'\" unpacked with wrong size!
fi
# end of 'explode.c'
fi
if test -f 'foo.tex' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'foo.tex'\"
else
echo shar: Extracting \"'foo.tex'\" \(339 characters\)
sed "s/^X//" >'foo.tex' <<'END_OF_FILE'
Xmake explode blow up (run out of file pointers)
X\file{1}
X\file{2}
X\file{3}
X\file{4}
X\file{5}
X\file{6}
X\file{7}
X\file{8}
X\file{9}
X\file{10}
X\file{11}
X\file{12}
X\file{13}
X\file{14}
X\file{15}
X\file{16}
X\file{17}
X\file{18}
X\file{19}
X\file{20}
X\file{21}
X\file{22}
X\file{23}
X\file{24}
X\file{25}
X\file{26}
X\file{27}
X\file{28}
X\file{29}
X\file{30}
END_OF_FILE
if test 339 -ne `wc -c <'foo.tex'`; then
    echo shar: \"'foo.tex'\" unpacked with wrong size!
fi
# end of 'foo.tex'
fi
if test -f 'unexplode' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unexplode'\"
else
echo shar: Extracting \"'unexplode'\" \(341 characters\)
sed "s/^X//" >'unexplode' <<'END_OF_FILE'
X#!/bin/sh
X#
X# unexplode -- delete the files cerated by explode.
X#
Xif [ $# -lt 1 ] ; then
X	echo "unexplode -- delete files created by explode."
X	echo "Usage: unexplode file"
X	exit 1
Xfi
Xfor i in $*; do
X	if [ -f $i ] ; then
X		:
X	else 
X		if [ -f $i.tex ] ; then
X			i=$i.tex
X		fi
X	fi
X	rm -f `grep '\\file{' $i | sed '
X		s/.file{//
X		s/}//'`
Xdone
END_OF_FILE
if test 341 -ne `wc -c <'unexplode'`; then
    echo shar: \"'unexplode'\" unpacked with wrong size!
fi
chmod +x 'unexplode'
# end of 'unexplode'
fi
echo shar: End of shell archive.
exit 0


-- 
David Collier-Brown,  | davecb at yunexus, ...!yunexus!davecb or
72 Abitibi Ave.,      | {toronto area...}lethe!dave 
Willowdale, Ontario,  | Joyce C-B:
CANADA. 416-223-8968  |    He's so smart he's dumb.



More information about the Comp.sources.misc mailing list