diff options
Diffstat (limited to 'web/glasgow/lit2x-0.16')
178 files changed, 56907 insertions, 0 deletions
diff --git a/web/glasgow/lit2x-0.16/README b/web/glasgow/lit2x-0.16/README new file mode 100644 index 0000000000..76d5b0ad20 --- /dev/null +++ b/web/glasgow/lit2x-0.16/README @@ -0,0 +1,16 @@ +This is the root directory for software distributed by the AQUA +project in the Computing Science Dept at Glasgow University. At +present, we have three different distributions, which share some +components. + + ghc the Glasgow Haskell compilation system + nofib the NoFib Haskell benchmarking suite + literate the Glasgow "literate programming" system + +The "literate" stuff is usually distributed *with* other systems, but +not necessarily. Components which are always part of a distribution +(never stand-alone) are "grasp-utils" and "mkworld" (a configuration +system). + +Please consult the {ghc,nofib,literate}/README file to find out how to +proceed. diff --git a/web/glasgow/lit2x-0.16/STARTUP-literate b/web/glasgow/lit2x-0.16/STARTUP-literate new file mode 100644 index 0000000000..63e11e32e6 --- /dev/null +++ b/web/glasgow/lit2x-0.16/STARTUP-literate @@ -0,0 +1,58 @@ +#! /bin/sh +# +# die quickly if anything goes astray... +set -e + +echo '*******************************************************************' +echo '* I hope that you read the relevant documentation and tweaked the *' +echo '* appropriate configuration files _BEFORE_ you started running *' +echo '* this! *' +echo '*******************************************************************' + +echo '' +echo "*** We don't project-ify or setup-ify this distribution..." +echo '' +PROJECT=none +SETUP=std + +# figure out the absolute pathname of the "top" directory +# (the one which has "mkworld", "nofib", "grasp-utils", etc., as subdirs) +hardtop=`pwd` +hardtop=`echo $hardtop | sed 's|^/tmp_mnt||' | sed 's|^/export||' | sed 's|^/grasp_tmp|/local/grasp_tmp|'` +echo '' +echo "*** I decided the top of your build tree is: $hardtop" + +# make all the Makefiles first + +for i in mkworld grasp-utils literate ; do + ( set -e; \ + cd $i ; \ + echo '' ; \ + echo "*** configuring $i ..." ; \ + make -f Makefile.BOOT BOOT_DEFINES="-P none -S std -DTopDirPwd=$hardtop"; \ + echo '' ; \ + echo "*** making Makefiles in $i ..." ; \ + make Makefiles \ + ) +done + +# now make the dependencies and Real Stuff + +for i in mkworld literate grasp-utils ; do + ( set -e; \ + cd $i ; \ + echo '' ; \ + echo "*** making make dependencies in $i ..." ; \ + make depend ; \ + echo '' ; \ + echo "*** making all in $i ..." ; \ + make all \ + ) +done + +echo '' +echo '*******************************************************************' +echo "* You should be ready to install, test, etc., this system..." +echo "* (Please consult the documentation.)" +echo '*******************************************************************' +exit 0 diff --git a/web/glasgow/lit2x-0.16/grasp-utils/Jmakefile b/web/glasgow/lit2x-0.16/grasp-utils/Jmakefile new file mode 100644 index 0000000000..96625e3d52 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/Jmakefile @@ -0,0 +1,6 @@ +#define IHaveSubdirs + +SUBDIRS = scripts \ + msub \ + etags \ + verbatim diff --git a/web/glasgow/lit2x-0.16/grasp-utils/Makefile.BOOT b/web/glasgow/lit2x-0.16/grasp-utils/Makefile.BOOT new file mode 100644 index 0000000000..16179c7df1 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/Makefile.BOOT @@ -0,0 +1,58 @@ +# hand-hacked Makefile to boot the "make world" process +#--------------------------------------------------------------------- + +# Platform-specific configuration stuff was read from: sun.cf + +SHELL = /bin/sh +PATHSEP = / + +TOP = .. +CURRENT_DIR = ./grasp-utils + +RM=rm -f +MV=mv -f +BOOTSTRAPCFLAGS = + +# Project identification -- name, version, and stuff + +PROJECTNAME = Booting the Make World System +PROJECTVERSION = none +PROJECTLABEL = none +SETUPLABEL = std + +PROJECTCONFIGDIR = + +########################################################################### +# Configuration stuff (jmake, its friends and templates) + +JMKMF = jmkmf_used_only_with_installed_utils +JRESTOREDEPS = $(JMAKESRC)/jrestoredeps +JMAKE = $(JMAKESRC)/jmake +JMAKE_DEFINES = + +JMAKESRC = $(TOP)/mkworld + +JMAKE_CMD = $(NEWTOP)$(JMAKE) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) -DTopDir=$(TOP) -DCurDir=$(CURRENT_DIR) $(BOOT_DEFINES) + +########################################################################### + +Makefile:: $(JMAKE) + +$(JMAKE): + @(cd $(JMAKESRC); if [ -f Makefile ]; then \ + echo "checking $@ in $(JMAKESRC) first..."; $(MAKE) all; else \ + echo "bootstrapping $@ from Makefile.BOOT in $(JMAKESRC) first..."; \ + $(MAKE) -f Makefile.BOOT BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS); fi; \ + echo "okay, continuing in $(CURRENT_DIR)") + +Makefile:: + -@if [ -f Makefile ]; then \ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(JMAKE_CMD) + $(JRESTOREDEPS) + @if cmp -s Makefile Makefile.bak; then $(RM) Makefile.bak ; fi + @chmod 444 Makefile + @echo ==== The new Makefile is for\: ==== + @$(MAKE) whoami diff --git a/web/glasgow/lit2x-0.16/grasp-utils/PATCHLEVEL b/web/glasgow/lit2x-0.16/grasp-utils/PATCHLEVEL new file mode 100644 index 0000000000..9667fc05ed --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/PATCHLEVEL @@ -0,0 +1 @@ +Miscellaneous GRASP-project tools, version 0.16, patchlevel 0 diff --git a/web/glasgow/lit2x-0.16/grasp-utils/README b/web/glasgow/lit2x-0.16/grasp-utils/README new file mode 100644 index 0000000000..a98feebe81 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/README @@ -0,0 +1,48 @@ +This directory tree's worth of stuff are utility bits that are used in +more than one of our GRASP projects. (For the project-specific bits, +try <project>/utils/<blah>.) + +msub/ a utility from Paul DuBois, that lets you substitute + for make variables (e.g., $(CC) ) in any old document. + Given that, with the "make world" configuration + system, Makefiles have loads of useful config info in + them, this is the program used to sneak that info into + other files. + +ugen/ A utility from the LML-compiler distrib to support + poor man's abstract data types for C. Used in the + parser ($(TOP)/parsers/hsp). + +scripts/ little utility scripts + + lndir from X imake stuff (via DuBois); make a shadow tree + of symbolic links + mkdirhier "mkdir a/b/c/d" will do "mkdir a; mkdir a/b; ..." + (assuming none of those dirs exist) + + runstdtest runs a pgm with some flags & some stdin; checks for an + expected exit code, expected stdout, and expected + stderr. (Expect this to change :-) + + newer "newer a b" (obsolete?) exit code 0 if file "a" newer + than "b", or something like that... + + tidycpp, hscpp cpp (C pre-processor) wrappers, the latter for + Haskell, the former obsolete? + + mkdependC script version of C makedepend (from X11R4 via DuBois) + mkdependHS "make depend" (perl) script for Haskell code. + + mkdependLML simon's makedepend1 script (needs work to function here) + (NOT BUILT) + + fastmake a "make" wrapper for compiling Haskell programs; + essentially, strips out the "make depend"ed + dependencies to avoid so much re-checking. + + update_iface a REALLY HORRIBLE hack, for updating the new Haskell + compiler's interface files; covers for deficiencies in + "nhc" (prototype compiler) i/face handling. + + ltx a "latex" wrapper. Re-runs latex/bibtex/makeindex + enough times to "do the right thing." diff --git a/web/glasgow/lit2x-0.16/grasp-utils/etags/Jmakefile b/web/glasgow/lit2x-0.16/grasp-utils/etags/Jmakefile new file mode 100644 index 0000000000..cadc4636d6 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/etags/Jmakefile @@ -0,0 +1,5 @@ +BuildPgmFromOneCFile(etags) + +InstallBinaryTarget(etags,$(INSTBINDIR)) + +CDependTarget( $(SRCS_C) ) diff --git a/web/glasgow/lit2x-0.16/grasp-utils/etags/README b/web/glasgow/lit2x-0.16/grasp-utils/etags/README new file mode 100644 index 0000000000..fb033eabe1 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/etags/README @@ -0,0 +1,2 @@ +This is the "etags" program from the GNU emacs (18.??) distribution. +Kevin Hammond has hacked it slightly to recognise more kinds of files. diff --git a/web/glasgow/lit2x-0.16/grasp-utils/etags/etags.c b/web/glasgow/lit2x-0.16/grasp-utils/etags/etags.c new file mode 100644 index 0000000000..5abb1990a1 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/etags/etags.c @@ -0,0 +1,1757 @@ +/* Tags file maker to go with GNUmacs + Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy a valid copyright notice +"Copyright (C) 1986 Free Software Foundation"; and include +following the copyright notice a verbatim copy of the above disclaimer +of warranty and of this License. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this program (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the terms +of Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + +#include <stdio.h> +#include <ctype.h> + +/* Define the symbol ETAGS to make the program "etags", + which makes emacs-style tag tables by default. + Define CTAGS to make the program "ctags" compatible with the usual one. + Define neither one to get behavior that depends + on the name with which the program is invoked + (but we don't normally compile it that way). */ + +/* On VMS, CTAGS is not useful, so always do ETAGS. */ +#ifdef VMS +#ifndef ETAGS +#define ETAGS +#endif +#endif + +/* Exit codes for success and failure. */ + +#ifdef VMS +#define GOOD (1) +#define BAD (0) +#else +#define GOOD (0) +#define BAD (1) +#endif + +#define reg register +#define logical char + +#define TRUE (1) +#define FALSE (0) + +#define iswhite(arg) (_wht[arg]) /* T if char is white */ +#define begtoken(arg) (_btk[arg]) /* T if char can start token */ +#define intoken(arg) (_itk[arg]) /* T if char can be in token */ +#define endtoken(arg) (_etk[arg]) /* T if char ends tokens */ +#define isgood(arg) (_gd[arg]) /* T if char can be after ')' */ + +#define max(I1,I2) (I1 > I2 ? I1 : I2) + +/* cause token checking for typedef, struct, union, enum to distinguish + keywords from identifier-prefixes (e.g. struct vs struct_tag). */ +#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len)))) + +struct nd_st { /* sorting structure */ + char *name; /* function or type name */ + char *file; /* file name */ + logical f; /* use pattern or line no */ + int lno; /* line number tag is on */ + long cno; /* character number line starts on */ + char *pat; /* search pattern */ + logical been_warned; /* set if noticed dup */ + struct nd_st *left,*right; /* left and right sons */ +}; + +long ftell(); +typedef struct nd_st NODE; + +int number; /* tokens found so far on line starting with # (including #) */ +logical gotone, /* found a func already on line */ + /* boolean "func" (see init) */ + _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177]; + + /* typedefs are recognized using a simple finite automata, + * tydef is its state variable. + */ +typedef enum {none, begin, tag_ok, middle, end } TYST; + +TYST tydef = none; + +char searchar = '/'; /* use /.../ searches */ + +int lineno; /* line number of current line */ +long charno; /* current character number */ +long linecharno; /* character number of start of line */ + +char *curfile, /* current input file name */ + *outfile= 0, /* output file */ + *white = " \f\t\n", /* white chars */ + *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", + /* token ending chars */ + *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$", + /* token starting chars */ + *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789", + /* valid in-token chars */ + *notgd = ",;"; /* non-valid after-function chars */ + +int file_num = 0; /* current file number */ +int aflag = 0; /* -a: append to tags */ +int tflag = 0; /* -t: create tags for typedefs */ +int uflag = 0; /* -u: update tags */ +int wflag = 0; /* -w: suppress warnings */ +int vflag = 0; /* -v: create vgrind style index output */ +int xflag = 0; /* -x: create cxref style output */ +int eflag = 0; /* -e: emacs style output */ + +/* Name this program was invoked with. */ +char *progname; + +FILE *inf, /* ioptr for current input file */ + *outf; /* ioptr for tags file */ + +NODE *head; /* the head of the sorted binary tree */ + +char *savestr(); +char *savenstr (); +char *rindex(); +char *index(); +char *concat (); +void initbuffer (); +long readline (); + +/* A `struct linebuffer' is a structure which holds a line of text. + `readline' reads a line from a stream into a linebuffer + and works regardless of the length of the line. */ + +struct linebuffer + { + long size; + char *buffer; + }; + +struct linebuffer lb, lb1; + +#if 0 /* VMS now provides the `system' function. */ +#ifdef VMS + +#include <descrip.h> + +void +system (buf) + char *buf; +{ + struct dsc$descriptor_s command = + { + strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf + }; + + LIB$SPAWN(&command); +} +#endif /* VMS */ +#endif /* 0 */ + +main(ac,av) + int ac; + char *av[]; +{ + char cmd[100]; + int i; + int fflag = 0; + char *this_file; +#ifdef VMS + char got_err; + + extern char *gfnames(); + extern char *massage_name(); +#endif + + progname = av[0]; + +#ifdef ETAGS + eflag = 1; +#else +#ifdef CTAGS + eflag = 0; +#else + { + char *subname = rindex (progname, '/'); + if (subname++ == NULL) + subname = progname; + eflag = ! strcmp(subname, "ctags"); + } +#endif +#endif + + while (ac > 1 && av[1][0] == '-') + { + for (i=1; av[1][i]; i++) + { + switch(av[1][i]) + { +#ifndef VMS /* These options are useful only with ctags, + and VMS can't input them, so just omit them. */ + case 'B': + searchar='?'; + eflag = 0; + break; + case 'F': + searchar='/'; + eflag = 0; + break; +#endif + case 'a': + aflag++; + break; + case 'e': + eflag++; + break; + case 'f': + if (fflag > 0) + { + fprintf(stderr, + "%s: -f flag may only be given once\n", progname); + goto usage; + } + fflag++, ac--; av++; + if (ac <= 1 || av[1][0] == '\0') + { + fprintf(stderr, + "%s: -f flag must be followed by a filename\n", + progname); + goto usage; + } + outfile = av[1]; + goto end_loop; + case 't': + tflag++; + break; +#ifndef VMS + case 'u': + uflag++; + eflag = 0; + break; +#endif + case 'w': + wflag++; + break; + case 'v': + vflag++; + xflag++; + eflag = 0; + break; + case 'x': + xflag++; + eflag = 0; + break; + default: + goto usage; + } + } + end_loop: ; + ac--; av++; + } + + if (ac <= 1) + { + usage: +#ifdef VMS + fprintf (stderr, "Usage: %s [-aetwvx] [-f outfile] file ...\n", progname); +#else + fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname); +#endif + exit(BAD); + } + + if (outfile == 0) + { + outfile = eflag ? "TAGS" : "tags"; + } + + init(); /* set up boolean "functions" */ + + initbuffer (&lb); + initbuffer (&lb1); + /* + * loop through files finding functions + */ + if (eflag) + { + outf = fopen (outfile, aflag ? "a" : "w"); + if (!outf) + { + fprintf (stderr, "%s: ", progname); + perror (outfile); + exit (BAD); + } + } + + file_num = 1; +#ifdef VMS + for (ac--, av++; + (this_file = gfnames (&ac, &av, &got_err)) != NULL; file_num++) + { + if (got_err) + { + error("Can't find file %s\n", this_file); + ac--, av++; + } + else + { + this_file = massage_name (this_file); +#else + for (; file_num < ac; file_num++) + { + this_file = av[file_num]; + if (1) + { +#endif + find_entries (this_file); + if (eflag) + { + fprintf (outf, "\f\n%s,%d\n", + this_file, total_size_of_entries (head)); + put_entries (head); + free_tree (head); + head = NULL; + } + } + } + + if (eflag) + { + fclose (outf); + exit (GOOD); + } + + if (xflag) + { + put_entries(head); + exit(GOOD); + } + if (uflag) + { + for (i=1; i<ac; i++) + { + sprintf(cmd, + "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS", + outfile, av[i], outfile); + system(cmd); + } + aflag++; + } + outf = fopen(outfile, aflag ? "a" : "w"); + if (outf == NULL) + { + fprintf (stderr, "%s: ", outfile); + perror(outfile); + exit(BAD); + } + put_entries(head); + fclose(outf); +#ifndef VMS + if (uflag) + { + sprintf(cmd, "sort %s -o %s", outfile, outfile); + system(cmd); + } +#endif + exit(GOOD); +} + +/* + * This routine sets up the boolean psuedo-functions which work + * by seting boolean flags dependent upon the corresponding character + * Every char which is NOT in that string is not a white char. Therefore, + * all of the array "_wht" is set to FALSE, and then the elements + * subscripted by the chars in "white" are set to TRUE. Thus "_wht" + * of a char is TRUE if it is the string "white", else FALSE. + */ +init() +{ + + reg char *sp; + reg int i; + + for (i = 0; i < 0177; i++) + { + _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE; + _gd[i] = TRUE; + } + for (sp = white; *sp; sp++) + _wht[*sp] = TRUE; + for (sp = endtk; *sp; sp++) + _etk[*sp] = TRUE; + for (sp = intk; *sp; sp++) + _itk[*sp] = TRUE; + for (sp = begtk; *sp; sp++) + _btk[*sp] = TRUE; + for (sp = notgd; *sp; sp++) + _gd[*sp] = FALSE; + _wht[0] = _wht['\n']; + _etk[0] = _etk['\n']; + _btk[0] = _btk['\n']; + _itk[0] = _itk['\n']; + _gd[0] = _gd['\n']; +} + +/* + * This routine opens the specified file and calls the function + * which finds the function and type definitions. + */ +find_entries (file) + char *file; +{ + char *cp; + + if ((inf=fopen(file,"r")) == NULL) + { + fprintf (stderr, "%s: ", progname); + perror(file); + return; + } + curfile = savestr(file); + cp = rindex(file, '.'); + /* .tex, .aux or .bbl implies LaTeX source code */ + if (cp && (!strcmp (cp + 1, "tex") || !strcmp (cp + 1, "aux") + || !strcmp (cp + 1, "bbl"))) + { + TEX_funcs(inf); + fclose(inf); + return; + } + /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */ + if (cp && (!strcmp (cp + 1, "l") || + !strcmp (cp + 1, "el") || + !strcmp (cp + 1, "lsp") || + !strcmp (cp + 1, "lisp") || + !strcmp (cp + 1, "cl") || + !strcmp (cp + 1, "clisp"))) + { + L_funcs(inf); + fclose(inf); + return; + } + /* .scm or .sm or .scheme implies scheme source code */ + if (cp && (!strcmp (cp + 1, "sm") + || !strcmp (cp + 1, "scm") + || !strcmp (cp + 1, "scheme") + || !strcmp (cp + 1, "t") + || !strcmp (cp + 1, "sch") + || !strcmp (cp + 1, "SM") + || !strcmp (cp + 1, "SCM") + /* The `SCM' or `scm' prefix with a version number */ + || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's') + || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'))) + { + Scheme_funcs(inf); + fclose(inf); + return; + } + /* .M implies Mcode source code */ + if (cp && !strcmp (cp + 1, "M")) + { + Mcode_funcs(inf); + fclose(inf); + return; + } + + /* if not a .c or .h or .y file, try fortran */ + if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y') + && cp[2] == '\0') + { + if (PF_funcs(inf) != 0) + { + fclose(inf); + return; + } + rewind(inf); /* no fortran tags found, try C */ + } + C_entries(); + fclose(inf); +} + +/* Record a tag on the current line. + name is the tag name, + f is nonzero to use a pattern, zero to use line number instead. */ + +pfnote (name, f, linestart, linelen, lno, cno) + char *name; + logical f; /* f == TRUE when function */ + char *linestart; + int linelen; + int lno; + long cno; +{ + register char *fp; + register NODE *np; + char *altname; + char tem[51]; + + if ((np = (NODE *) malloc (sizeof (NODE))) == NULL) + { + fprintf(stderr, "%s: too many entries to sort\n", progname); + put_entries(head); + free_tree(head); + head = NULL; + np = (NODE *) xmalloc(sizeof (NODE)); + } + /* Change name "main" to M<thisfilename>. */ + if (!eflag && !xflag && !strcmp(name, "main")) + { + fp = rindex(curfile, '/'); + if (fp == 0) + fp = curfile; + else + fp++; + altname = concat ("M", fp, ""); + fp = rindex(altname, '.'); + if (fp && fp[2] == 0) + *fp = 0; + name = altname; + } + np->name = savestr(name); + np->file = curfile; + np->f = f; + np->lno = lno; + np->cno = cno; + np->left = np->right = 0; + if (eflag) + { + linestart[linelen] = 0; + } + else if (xflag == 0) + { + sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart); + linestart = tem; + } + np->pat = savestr (linestart); + if (head == NULL) + head = np; + else + add_node(np, head); +} + +free_tree(node) + NODE *node; +{ + while (node) + { + free_tree(node->right); + free(node); + node = node->left; + } +} + +add_node(node, cur_node) + NODE *node,*cur_node; +{ + register int dif; + + dif = strcmp(node->name, cur_node->name); + + /* If this tag name matches an existing one, then + unless -e was given, do not add the node, but maybe print a warning */ + if (!eflag && !dif) + { + if (node->file == cur_node->file) + { + if (!wflag) + { + fprintf(stderr,"%s: Duplicate entry in file %s, line %d: %s\n", + progname, node->file,lineno,node->name); + fprintf(stderr,"Second entry ignored\n"); + } + return; + } + if (!cur_node->been_warned) + if (!wflag) + fprintf(stderr,"%s: Duplicate entry in files %s and %s: %s (Warning only)\n", + progname, node->file, cur_node->file, node->name); + cur_node->been_warned = TRUE; + return; + } + + /* Actually add the node */ + if (dif < 0) + { + if (cur_node->left != NULL) + add_node(node,cur_node->left); + else + cur_node->left = node; + return; + } + if (cur_node->right != NULL) + add_node(node,cur_node->right); + else + cur_node->right = node; +} + +put_entries(node) + reg NODE *node; +{ + reg char *sp; + + if (node == NULL) + return; + + /* Output subentries that precede this one */ + put_entries (node->left); + + /* Output this entry */ + + if (eflag) + { + fprintf (outf, "%s%c%d,%d\n", + node->pat, 0177, node->lno, node->cno); + } + else if (!xflag) + { + fprintf (outf, "%s\t%s\t", + node->name, node->file); + + if (node->f) + { /* a function */ + putc (searchar, outf); + putc ('^', outf); + + for (sp = node->pat; *sp; sp++) + { + if (*sp == '\\' || *sp == searchar) + putc ('\\', outf); + putc (*sp, outf); + } + putc (searchar, outf); + } + else + { /* a typedef; text pattern inadequate */ + fprintf (outf, "%d", node->lno); + } + putc ('\n', outf); + } + else if (vflag) + fprintf (stdout, "%s %s %d\n", + node->name, node->file, (node->lno+63)/64); + else + fprintf (stdout, "%-16s%4d %-16s %s\n", + node->name, node->lno, node->file, node->pat); + + /* Output subentries that follow this one */ + put_entries (node->right); +} + +/* Return total number of characters that put_entries will output for + the nodes in the subtree of the specified node. + Works only if eflag is set, but called only in that case. */ + +total_size_of_entries(node) + reg NODE *node; +{ + reg int total = 0; + reg long num; + + if (node == NULL) + return 0; + + /* Count subentries that precede this one */ + total = total_size_of_entries (node->left); + + /* Count subentries that follow this one */ + total += total_size_of_entries (node->right); + + /* Count this entry */ + + total += strlen (node->pat) + 3; + + num = node->lno; + while (num) + { + total++; + num /= 10; + } + + num = node->cno; + if (!num) total++; + while (num) + { + total++; + num /= 10; + } + return total; +} + +/* + * This routine finds functions and typedefs in C syntax and adds them + * to the list. + */ +#ifdef VMS +long vmslinecharno; +#define VMS_SET_LINECHARNO (vmslinecharno = ftell(inf)) +#else +#define VMS_SET_LINECHARNO +#endif + +#define CNL_SAVE_NUMBER \ +{ \ + VMS_SET_LINECHARNO; \ + linecharno = charno; lineno++; \ + charno += 1 + readline (&lb, inf); \ + lp = lb.buffer; \ +} + +#define CNL \ +{ \ + CNL_SAVE_NUMBER; \ + number = 0; \ +} + +C_entries () +{ + register int c; + register char *token, *tp, *lp; + logical incomm, inquote, inchar, midtoken; + int level; + char tok[BUFSIZ]; + + lineno = 0; + charno = 0; + lp = lb.buffer; + *lp = 0; + + number = 0; + gotone = midtoken = inquote = inchar = incomm = FALSE; + level = 0; + + while (!feof (inf)) + { + c = *lp++; + if (c == 0) + { + CNL; + gotone = FALSE; + } + if (c == '\\') + { + c = *lp++; + if (c == 0) + CNL_SAVE_NUMBER; + c = ' '; + } + else if (incomm) + { + if (c == '*') + { + while ((c = *lp++) == '*') + continue; + if (c == 0) + CNL; + if (c == '/') + incomm = FALSE; + } + } + else if (inquote) + { + /* + * Too dumb to know about \" not being magic, but + * they usually occur in pairs anyway. + */ + if (c == '"') + inquote = FALSE; + continue; + } + else if (inchar) + { + if (c == '\'') + inchar = FALSE; + continue; + } + else switch (c) + { + case '"': + inquote = TRUE; + continue; + case '\'': + inchar = TRUE; + continue; + case '/': + if (*lp == '*') + { + lp++; + incomm = TRUE; + } + continue; + case '#': + if (lp == lb.buffer + 1) + number = 1; + continue; + case '{': + if (tydef == tag_ok) + { + tydef=middle; + } + level++; + continue; + case '}': + if (lp == lb.buffer + 1) + level = 0; /* reset */ + else + level--; + if (!level && tydef==middle) + { + tydef=end; + } + continue; + } + if (!level && !inquote && !incomm && gotone == FALSE) + { + if (midtoken) + { + if (endtoken(c)) + { + int f; + char *buf = lb.buffer; + int endpos = lp - lb.buffer; + char *lp1 = lp; + int line = lineno; + long linestart = linecharno; +#ifdef VMS + long vmslinestart = vmslinecharno; +#endif + int tem = consider_token (&lp1, token, &f, level); + lp = lp1; + if (tem) + { + if (linestart != linecharno) + { +#ifdef VMS + getline (vmslinestart); +#else + getline (linestart); +#endif + strncpy (tok, token + (lb1.buffer - buf), + tp-token+1); + tok[tp-token+1] = 0; + pfnote(tok, f, lb1.buffer, endpos, line, linestart); + } + else + { + strncpy (tok, token, tp-token+1); + tok[tp-token+1] = 0; + pfnote(tok, f, lb.buffer, endpos, line, linestart); + } + gotone = f; /* function */ + } + midtoken = FALSE; + token = lp - 1; + } + else if (intoken(c)) + tp++; + } + else if (begtoken(c)) + { + token = tp = lp - 1; + midtoken = TRUE; + } + } + if (c == ';' && tydef==end) /* clean with typedefs */ + tydef=none; + } +} + +/* + * This routine checks to see if the current token is + * at the start of a function, or corresponds to a typedef + * It updates the input line * so that the '(' will be + * in it when it returns. + */ +consider_token (lpp, token, f, level) + char **lpp, *token; + int *f, level; +{ + reg char *lp = *lpp; + reg char c; + static logical next_token_is_func; + logical firsttok; /* T if have seen first token in ()'s */ + int bad, win; + + *f = 1; /* a function */ + c = lp[-1]; + bad = FALSE; + if (!number) + { /* space is not allowed in macro defs */ + while (iswhite(c)) + { + c = *lp++; + if (c == 0) + { + if (feof (inf)) + break; + CNL; + } + } + } + else + { + /* the following tries to make it so that a #define a b(c) */ + /* doesn't count as a define of b. */ + + number++; + if (number >= 4 || (number==2 && strncmp (token, "define", 6)==0)) + { + /* Force the next symbol to be recognised, even if it is #define a b(c)! */ + if(number == 2) next_token_is_func = 1; + else + gotone = TRUE; + badone: + bad = TRUE; + goto ret; + } + } + /* check for the typedef cases */ + if (tflag && istoken(token, "typedef", 7)) + { + tydef=begin; + goto badone; + } + if (tydef==begin && (istoken(token, "struct", 6) || + istoken(token, "union", 5) || istoken(token, "enum", 4))) + { + tydef=tag_ok; + goto badone; + } + if (tydef==tag_ok) + { + tydef=middle; + goto badone; + } + if (tydef==begin) /* e.g. typedef ->int<- */ + { + tydef=end; + goto badone; + } + if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */ + { + tydef=end; + } + if (tydef==end) + { + *f = 0; + win = 1; + goto ret; + } + /* Detect GNUmacs's function-defining macros. */ + if (!number && !strncmp (token, "DEF", 3)) + + { + next_token_is_func = 1; + goto badone; + } + if (next_token_is_func) + { + next_token_is_func = 0; + win = 1; + goto ret; + } + if (c != '(') + goto badone; + firsttok = FALSE; + while ((c = *lp++) != ')') + { + if (c == 0) + { + if (feof (inf)) + break; + CNL; + } + /* + * This line used to confuse ctags: + * int (*oldhup)(); + * This fixes it. A nonwhite char before the first + * token, other than a / (in case of a comment in there) + * makes this not a declaration. + */ + if (begtoken(c) || c=='/') firsttok++; + else if (!iswhite(c) && !firsttok) goto badone; + } + while (iswhite (c = *lp++)) + { + if (c == 0) + { + if (feof (inf)) + break; + CNL; + } + } + win = isgood (c); +ret: + *lpp = lp - 1; + return !bad && win; +} + +getline (atchar) + long atchar; +{ + long saveftell = ftell (inf); + + fseek (inf, atchar, 0); + readline (&lb1, inf); + fseek (inf, saveftell, 0); +} + +/* Fortran parsing */ + +char *dbp; +int pfcnt; + +PF_funcs(fi) + FILE *fi; +{ + lineno = 0; + charno = 0; + pfcnt = 0; + + while (!feof (fi)) + { + lineno++; + linecharno = charno; + charno += readline (&lb, fi) + 1; + dbp = lb.buffer; + if (*dbp == '%') dbp++ ; /* Ratfor escape to fortran */ + while (isspace(*dbp)) + dbp++; + if (*dbp == 0) + continue; + switch (*dbp |' ') + { + case 'i': + if (tail("integer")) + takeprec(); + break; + case 'r': + if (tail("real")) + takeprec(); + break; + case 'l': + if (tail("logical")) + takeprec(); + break; + case 'c': + if (tail("complex") || tail("character")) + takeprec(); + break; + case 'd': + if (tail("double")) + { + while (isspace(*dbp)) + dbp++; + if (*dbp == 0) + continue; + if (tail("precision")) + break; + continue; + } + break; + } + while (isspace(*dbp)) + dbp++; + if (*dbp == 0) + continue; + switch (*dbp|' ') + { + case 'f': + if (tail("function")) + getit(); + continue; + case 's': + if (tail("subroutine")) + getit(); + continue; + case 'p': + if (tail("program")) + { + getit(); + continue; + } + if (tail("procedure")) + getit(); + continue; + } + } + return (pfcnt); +} + +tail(cp) + char *cp; +{ + register int len = 0; + + while (*cp && (*cp&~' ') == ((*(dbp+len))&~' ')) + cp++, len++; + if (*cp == 0) + { + dbp += len; + return (1); + } + return (0); +} + +takeprec() +{ + while (isspace(*dbp)) + dbp++; + if (*dbp != '*') + return; + dbp++; + while (isspace(*dbp)) + dbp++; + if (!isdigit(*dbp)) + { + --dbp; /* force failure */ + return; + } + do + dbp++; + while (isdigit(*dbp)); +} + +getit() +{ + register char *cp; + char c; + char nambuf[BUFSIZ]; + + while (isspace(*dbp)) + dbp++; + if (*dbp == 0 || !isalpha(*dbp)) + return; + for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++) + continue; + c = cp[0]; + cp[0] = 0; + strcpy(nambuf, dbp); + cp[0] = c; + pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); + pfcnt++; +} + +/* + * lisp tag functions + * just look for (def or (DEF + */ + +L_funcs (fi) + FILE *fi; +{ + lineno = 0; + charno = 0; + pfcnt = 0; + + while (!feof (fi)) + { + lineno++; + linecharno = charno; + charno += readline (&lb, fi) + 1; + dbp = lb.buffer; + if (dbp[0] == '(' && + (dbp[1] == 'D' || dbp[1] == 'd') && + (dbp[2] == 'E' || dbp[2] == 'e') && + (dbp[3] == 'F' || dbp[3] == 'f')) + { + while (!isspace(*dbp)) dbp++; + while (isspace(*dbp)) dbp++; + L_getit(); + } + } +} + +L_getit() +{ + register char *cp; + char c; + char nambuf[BUFSIZ]; + + if (*dbp == 0) return; + for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++) + continue; + c = cp[0]; + cp[0] = 0; + strcpy(nambuf, dbp); + cp[0] = c; + pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); + pfcnt++; +} + +/* + * Scheme tag functions + * look for (def... xyzzy + * look for (def... (xyzzy + * look for (def ... ((...(xyzzy .... + * look for (set! xyzzy + */ + +static get_scheme (); +Scheme_funcs (fi) + FILE *fi; +{ + lineno = 0; + charno = 0; + pfcnt = 0; + + while (!feof (fi)) + { + lineno++; + linecharno = charno; + charno += readline (&lb, fi) + 1; + dbp = lb.buffer; + if (dbp[0] == '(' && + (dbp[1] == 'D' || dbp[1] == 'd') && + (dbp[2] == 'E' || dbp[2] == 'e') && + (dbp[3] == 'F' || dbp[3] == 'f')) + { + while (!isspace(*dbp)) dbp++; + /* Skip over open parens and white space */ + while (*dbp && (isspace(*dbp) || *dbp == '(')) dbp++; + get_scheme (); + } + if (dbp[0] == '(' && + (dbp[1] == 'S' || dbp[1] == 's') && + (dbp[2] == 'E' || dbp[2] == 'e') && + (dbp[3] == 'T' || dbp[3] == 't') && + (dbp[4] == '!' || dbp[4] == '!') && + (isspace(dbp[5]))) + { + while (!isspace(*dbp)) dbp++; + /* Skip over white space */ + while (isspace(*dbp)) dbp++; + get_scheme (); + } + } +} + +static +get_scheme() +{ + register char *cp; + char c; + char nambuf[BUFSIZ]; + + if (*dbp == 0) return; + /* Go till you get to white space or a syntactic break */ + for (cp = dbp+1; *cp && *cp != '(' && *cp != ')' && !isspace(*cp); cp++) + continue; + /* Null terminate the string there. */ + c = cp[0]; + cp[0] = 0; + /* Copy the string */ + strcpy(nambuf, dbp); + /* Unterminate the string */ + cp[0] = c; + /* Announce the change */ + pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); + pfcnt++; +} +static get_mcode (); +Mcode_funcs (fi) + FILE *fi; +{ + lineno = 0; + charno = 0; + pfcnt = 0; + + while (!feof (fi)) + { + lineno++; + linecharno = charno; + charno += readline (&lb, fi) + 1; + dbp = lb.buffer; + + while (*dbp != 0) + { + /* Skip over white space */ + while (isspace(*dbp)) dbp++; + get_mcode(); + } + } +} + +static +get_mcode() +{ + register char *cp; + char c; + char nambuf[BUFSIZ]; + + if (*dbp == 0) return; + /* Go till you get to white space or a syntactic break */ + for (cp = dbp; *cp && *cp != ':' && *cp != ';' && !isspace(*cp); cp++) + continue; + + if(*cp == ':') + { + /* Null terminate the string there. */ + c = cp[0]; + cp[0] = 0; + /* Copy the string */ + strcpy(nambuf, dbp); + /* Unterminate the string */ + cp[0] = c; + /* Announce the change */ + pfnote(nambuf, TRUE, lb.buffer, strlen(lb.buffer), lineno, linecharno); + pfcnt++; + *dbp = 0; + } + if (*cp == ';') + *dbp = 0; + else + dbp = cp; +} + +/* Find tags in TeX and LaTeX input files. */ + +/* TEX_toktab is a table of TeX control sequences that define tags. + Each TEX_tabent records one such control sequence. */ + +struct TEX_tabent +{ + char *name; + int len; +}; + +struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */ + +/* Default set of control sequences to put into TEX_toktab. + The value of environment var TEXTAGS is prepended to this. */ + +static char *TEX_defenv = + ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout"; + +struct TEX_tabent *TEX_decode_env (); + +static char TEX_esc = '\\'; +static char TEX_opgrp = '{'; +static char TEX_clgrp = '}'; + +/* + * TeX/LaTeX scanning loop. + */ + +TEX_funcs (fi) + FILE *fi; +{ + char *lasthit; + + lineno = 0; + charno = 0; + pfcnt = 0; + + /* Select either \ or ! as escape character. */ + TEX_mode (fi); + + /* Initialize token table once from environment. */ + if (!TEX_toktab) + TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv); + + while (!feof (fi)) + { + lineno++; + linecharno = charno; + charno += readline (&lb, fi) + 1; + dbp = lb.buffer; + lasthit = dbp; + + while (!feof (fi)) + { /* Scan each line in file */ + lineno++; + linecharno = charno; + charno += readline (&lb, fi) + 1; + dbp = lb.buffer; + lasthit = dbp; + while (dbp = index (dbp, TEX_esc)) /* Look at each escape in line */ + { + register int i; + + if (! *(++dbp)) + break; + linecharno += dbp - lasthit; + lasthit = dbp; + i = TEX_Token (lasthit); + if (0 <= i) + { + TEX_getit (lasthit, TEX_toktab[i].len); + break; /* We only save a line once */ + } + } + } + } +} + +#define TEX_LESC '\\' +#define TEX_SESC '!' + +/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */ +/* chars accordingly. */ + +TEX_mode (f) + FILE *f; +{ + int c; + + while ((c = getc (f)) != EOF) + if (c == TEX_LESC || c == TEX_SESC) + break; + + if (c == TEX_LESC) + { + TEX_esc = TEX_LESC; + TEX_opgrp = '{'; + TEX_clgrp = '}'; + } + else + { + TEX_esc = TEX_SESC; + TEX_opgrp = '<'; + TEX_clgrp = '>'; + } + rewind (f); +} + +/* Read environment and prepend it to the default string. */ +/* Build token table. */ + +struct TEX_tabent * +TEX_decode_env (evarname, defenv) + char *evarname; + char *defenv; +{ + register char *env, *p; + extern char *savenstr (), *index (); + + struct TEX_tabent *tab; + int size, i; + + /* Append deafult string to environment. */ + env = (char *) getenv (evarname); + if (!env) + env = defenv; + else + env = concat (env, defenv, ""); + + /* Allocate a token table */ + for (size = 1, p=env; p;) + if ((p = index (p, ':')) && *(++p)) + size++; + tab = (struct TEX_tabent *) xmalloc (size * sizeof (struct TEX_tabent)); + + /* Unpack environment string into token table. Be careful about */ + /* zero-length strings (leading ':', "::" and trailing ':') */ + for (i = 0; *env;) + { + p = index (env, ':'); + if (!p) /* End of environment string. */ + p = env + strlen (env); + if (p - env > 0) + { /* Only non-zero strings. */ + tab[i].name = savenstr (env, p - env); + tab[i].len = strlen (tab[i].name); + i++; + } + if (*p) + env = p + 1; + else + { + tab[i].name = NULL; /* Mark end of table. */ + tab[i].len = 0; + break; + } + } + return tab; +} + +/* Record a tag defined by a TeX command of length LEN and starting at NAME. + The name being defined actually starts at (NAME + LEN + 1). + But we seem to include the TeX command in the tag name. */ + +TEX_getit (name, len) + char *name; + int len; +{ + char *p = name + len; + char nambuf[BUFSIZ]; + + if (*name == 0) return; + + /* Let tag name extend to next group close (or end of line) */ + while (*p && *p != TEX_clgrp) + p++; + strncpy (nambuf, name, p - name); + nambuf[p - name] = 0; + + pfnote (nambuf, TRUE, lb.buffer, strlen (lb.buffer), lineno, linecharno); + pfcnt++; +} + +/* If the text at CP matches one of the tag-defining TeX command names, + return the index of that command in TEX_toktab. + Otherwise return -1. */ + +/* Keep the capital `T' in `Token' for dumb truncating compilers + (this distinguishes it from `TEX_toktab' */ +TEX_Token (cp) + char *cp; +{ + int i; + + for (i = 0; TEX_toktab[i].len > 0; i++) + if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0) + return i; + return -1; +} + +/* Initialize a linebuffer for use */ + +void +initbuffer (linebuffer) + struct linebuffer *linebuffer; +{ + linebuffer->size = 200; + linebuffer->buffer = (char *) xmalloc (200); +} + +/* Read a line of text from `stream' into `linebuffer'. + Return the length of the line. */ + +long +readline (linebuffer, stream) + struct linebuffer *linebuffer; + register FILE *stream; +{ + char *buffer = linebuffer->buffer; + register char *p = linebuffer->buffer; + register char *pend = p + linebuffer->size; + + while (1) + { + int c = getc (stream); + if (p == pend) + { + linebuffer->size *= 2; + buffer = (char *) xrealloc (buffer, linebuffer->size); + p += buffer - linebuffer->buffer; + pend = buffer + linebuffer->size; + linebuffer->buffer = buffer; + } + if (c < 0 || c == '\n') + { + *p = 0; + break; + } + *p++ = c; + } + + return p - buffer; +} + +char * +savestr(cp) + char *cp; +{ + return savenstr (cp, strlen (cp)); +} + +char * +savenstr(cp, len) + char *cp; + int len; +{ + register char *dp; + + dp = (char *) xmalloc (len + 1); + strncpy (dp, cp, len); + dp[len] = '\0'; + return dp; +} + +/* + * Return the ptr in sp at which the character c last + * appears; NULL if not found + * + * Identical to v7 rindex, included for portability. + */ + +char * +rindex(sp, c) + register char *sp, c; +{ + register char *r; + + r = NULL; + do + { + if (*sp == c) + r = sp; + } while (*sp++); + return(r); +} + +/* + * Return the ptr in sp at which the character c first + * appears; NULL if not found + * + * Identical to v7 index, included for portability. + */ + +char * +index(sp, c) + register char *sp, c; +{ + do + { + if (*sp == c) + return (sp); + } while (*sp++); + return (NULL); +} + +/* Print error message and exit. */ + +fatal (s1, s2) + char *s1, *s2; +{ + error (s1, s2); + exit (BAD); +} + +/* Print error message. `s1' is printf control string, `s2' is arg for it. */ + +error (s1, s2) + char *s1, *s2; +{ + fprintf (stderr, "%s: ", progname); + fprintf (stderr, s1, s2); + fprintf (stderr, "\n"); +} + +/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + *(result + len1 + len2 + len3) = 0; + + return result; +} + +/* Like malloc but get fatal error if memory is exhausted. */ + +int +xmalloc (size) + int size; +{ + int result = malloc (size); + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/etags/jbw-fixes b/web/glasgow/lit2x-0.16/grasp-utils/etags/jbw-fixes new file mode 100644 index 0000000000..324c0d447e --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/etags/jbw-fixes @@ -0,0 +1,568 @@ +From jbw@bigbird.bu.edu Tue Aug 18 08:07:53 1992 +From: jbw@bigbird.bu.edu (Joe Wells) +Newsgroups: comp.emacs +Subject: Re: How do I include symbols defined with #define in TAGS ? +Date: 16 Aug 92 23:27:25 GMT +Distribution: comp.emacs +Organization: Boston University Computer Science Department +In-reply-to: podi@ESD.3Com.COM's message of 14 Aug 92 17:53:29 GMT + +In article <podi.713814809@chamundi.NSD.3Com.COM> podi@ESD.3Com.COM (Podibanda Kuruppu) writes: + + Keywords: Symbols defined by #defines in TAGS + + I would greatly appreciate it if someone could tell me if I could + include symbols ( defined in .h files with #defines ) in a TAG file. + +Enclosed below is an earlier article with my solution to this. + +-- +Enjoy, + +Joe Wells <jbw@cs.bu.edu> +Member of the League for Programming Freedom --- send e-mail for details + +---------------------------------------------------------------------- +Date: Sat, 4 Apr 92 00:46:52 -0500 +From: jbw@bigbird.bu.edu (Joe Wells) +Message-Id: <9204040546.AA15208@bigbird.bu.edu> +To: bug-gnu-emacs@prep.ai.mit.edu +Subject: numerous bug fixes for etags + +Enclosed is a patch with numerous changes for etags. The following are +the changes and bugs fixed: + +1. Improvement: don't waste time calling strncmp (with "struct", "union", + "enum", "typedef") if the lengths are different. + +2. Bug: pfnote placed a NUL in the line buffer after the tag token which caused + things like `{' or `/*' to be ignored, thus severely screwing up the + parser. Or it did something horrible, I don't remember for sure. + +3. Improvement: record defining occurrences of struct/union/enum tags. + This works even if combined with a typedef definition, for example: + + typedef struct XXX { + ..... + } YYY; + +4. Bug: when a tag token was the last item on the line before the newline + character, garbage would be seen as the token. This is because when a + NUL was seen in the buffer the buffer was replaced with the next line. + +5. Bug: tag tokens immediately followed by a `{' with no intervening space + were not recorded. This was only a problem because of improvement 3 + above. + +6. Bug: a newline in the middle of a comment zeroed the `number' variable. + (Just for good measure I made it not zero `number' in strings even when + the newline is not preceded by `\', in case someone wants to run etags + on illegal code :-) (`number' is used only on lines that begin with + `#'.) + +7. Bug: handling of #define lines was severely broken. I don't actually + remember what etags did with them, but it was really bad. It now + records macro definitions. + +8. Bug: when a tag token was the last item on the line except for + whitespace, etags would replace the contents of the line buffer and + then later do various string comparisons and inspections against + garbage values instead of against the token. Fixing this required + copying the token into a buffer. (This is roughly the same as bug 4 + above, but in a different function.) + +9. Bug: when a tag token was the last item on the line before the newline + (and under various other circumstances), etags would skip over the NUL + in the buffer and skip to the first non-whitespace character in the + buffer. + +10. Improvement (possibly bug fix): parse typedefs even when we aren't + going to print them out. I seem to remember that this fixed some bug, + but I don't remember the specific case that would trigger the bug. + +11. An unfinished attempt to detect and record global variable + definitions. + +The changes are to the 18.57 version of etags, but the only change in +18.58 to the C code handling is to initialize some variables when starting +on a new file, so these changes are orthogonal. + +-- +Enjoy, + +Joe Wells <jbw@cs.bu.edu> + +Member of the League for Programming Freedom --- send e-mail for details + +---------------------------------------------------------------------- +--- etags.c-dist Tue Jan 8 14:08:38 1991 ++++ etags.c Sat Apr 4 00:41:22 1992 +@@ -62,7 +62,10 @@ + + /* cause token checking for typedef, struct, union, enum to distinguish + keywords from identifier-prefixes (e.g. struct vs struct_tag). */ +-#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len)))) ++#define istoken(s, t, len) \ ++ (((len) == (sizeof (t) -1)) && \ ++ ((strncmp(s, t, len)) == 0) && \ ++ (endtoken(*((s)+(len))))) + + struct nd_st { /* sorting structure */ + char *name; /* function or type name */ +@@ -505,6 +508,7 @@ + { + register char *fp; + register NODE *np; ++ char save; + char *altname; + char tem[51]; + +@@ -538,6 +542,7 @@ + np->left = np->right = 0; + if (eflag) + { ++ save = linestart[linelen]; + linestart[linelen] = 0; + } + else if (xflag == 0) +@@ -546,6 +551,7 @@ + linestart = tem; + } + np->pat = savestr (linestart); ++ linestart[linelen] = save; + if (head == NULL) + head = np; + else +@@ -725,6 +731,17 @@ + number = 0; \ + } + ++/* These two are part of a never-finished attempt to record global */ ++/* variable definitions. This is nearly impossible in C without the full */ ++/* power of a C compiler due to C's stupid grammar. */ ++logical infunc; ++int idents_in_decl; ++ ++/* indicates whether the next token (if any) is the tag corresponding to */ ++/* `struct', `union', or `enum' */ ++logical next_token_is_tag; ++ ++ + C_entries () + { + register int c; +@@ -731,6 +748,15 @@ + register char *token, *tp, *lp; + logical incomm, inquote, inchar, midtoken; + int level; ++ ++ /* there are certain things that must be done when the end of line is */ ++ /* encountered, but they must be delayed until after other things are */ ++ /* done. */ ++ logical new_line_flag; ++ ++ /* same as new_line_flag for left braces. */ ++ logical left_brace_flag; ++ + char tok[BUFSIZ]; + + lineno = 0; +@@ -739,17 +765,22 @@ + *lp = 0; + + number = 0; +- gotone = midtoken = inquote = inchar = incomm = FALSE; ++ gotone = midtoken = inquote = inchar = incomm = infunc = FALSE; ++ new_line_flag = FALSE; ++ left_brace_flag = FALSE; + level = 0; ++ idents_in_decl = 0; ++ next_token_is_tag = FALSE; + + while (!feof (inf)) + { + c = *lp++; + if (c == 0) +- { +- CNL; +- gotone = FALSE; +- } ++ new_line_flag = TRUE; ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "E: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ + if (c == '\\') + { + c = *lp++; +@@ -756,15 +787,18 @@ + if (c == 0) + CNL_SAVE_NUMBER; + c = ' '; ++ /* is this correct? I thought escaped newlines disappeared even */ ++ /* before the token breaker got to see things. */ + } + else if (incomm) + { ++ new_line_flag = FALSE; + if (c == '*') + { + while ((c = *lp++) == '*') + continue; + if (c == 0) +- CNL; ++ CNL_SAVE_NUMBER; + if (c == '/') + incomm = FALSE; + } +@@ -771,6 +805,7 @@ + } + else if (inquote) + { ++ new_line_flag = FALSE; + /* + * Too dumb to know about \" not being magic, but + * they usually occur in pairs anyway. +@@ -781,6 +816,7 @@ + } + else if (inchar) + { ++ new_line_flag = FALSE; + if (c == '\'') + inchar = FALSE; + continue; +@@ -809,8 +845,8 @@ + { + tydef=middle; + } +- level++; +- continue; ++ left_brace_flag = TRUE; ++ break; + case '}': + if (lp == lb.buffer + 1) + level = 0; /* reset */ +@@ -820,8 +856,17 @@ + { + tydef=end; + } ++ if (level == 0 && infunc) ++ { ++ idents_in_decl = 0; ++ infunc = FALSE; ++ } + continue; + } ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "D: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ + if (!level && !inquote && !incomm && gotone == FALSE) + { + if (midtoken) +@@ -852,6 +897,11 @@ + tp-token+1); + tok[tp-token+1] = 0; + pfnote(tok, f, lb1.buffer, endpos, line, linestart); ++#ifdef DEBUG ++ fprintf (stderr, ++ "f: %d, infunc %d, tok: %s\nlb1.buffer: %s\n", ++ f, infunc, tok, lb1.buffer); ++#endif /* DEBUG */ + } + else + { +@@ -858,8 +908,15 @@ + strncpy (tok, token, tp-token+1); + tok[tp-token+1] = 0; + pfnote(tok, f, lb.buffer, endpos, line, linestart); ++#ifdef DEBUG ++ fprintf (stderr, ++ "f: %d, infunc %d, tok: %s\nlb.buffer: %s\n", ++ f, infunc, tok, lb.buffer); ++#endif /* DEBUG */ + } + gotone = f; /* function */ ++ if (f) ++ infunc = TRUE; + } + midtoken = FALSE; + token = lp - 1; +@@ -873,8 +930,32 @@ + midtoken = TRUE; + } + } ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "F: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ ++ if (left_brace_flag) ++ { ++ left_brace_flag = FALSE; ++ next_token_is_tag = FALSE; ++ level++; ++ } ++ if (new_line_flag) ++ { ++ new_line_flag = FALSE; ++ number = 0; ++ gotone = FALSE; ++ } ++ if (lp > lb.buffer && lp[-1] == 0) ++ CNL_SAVE_NUMBER; + if (c == ';' && tydef==end) /* clean with typedefs */ + tydef=none; ++ if (c == ';' && level == 0 && !infunc) ++ idents_in_decl = 0; ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "G: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ + } + } + +@@ -891,70 +972,176 @@ + reg char *lp = *lpp; + reg char c; + static logical next_token_is_func; ++ ++ /* indicates that the next token will be a macro defined with #define */ ++ static logical next_token_is_macro; ++ + logical firsttok; /* T if have seen first token in ()'s */ +- int bad, win; ++ int bad = FALSE, win = FALSE; ++ int length = (lp - 1) - token; ++ ++ /* used to keep a copy of the token when we have to fill the line buffer */ ++ /* with the contents of the next line */ ++ static char *tok_buffer = NULL; ++ static long tok_buffer_size = 0; + + *f = 1; /* a function */ + c = lp[-1]; +- bad = FALSE; + if (!number) + { /* space is not allowed in macro defs */ +- while (iswhite(c)) ++ while ((c == 0) || iswhite(c)) + { +- c = *lp++; +- if (c == 0) ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "C: token: %s, c: [%c], lp - token: %d\n", ++ token, c, lp - token); ++#endif /* DEBUG */ ++ while (c == 0) + { + if (feof (inf)) +- break; ++ goto break_while_1; ++ if (token != tok_buffer) ++ { ++ if (length + 1 > tok_buffer_size) ++ if (tok_buffer_size == 0) ++ { ++ tok_buffer_size = length + 1; ++ tok_buffer = (char *) xmalloc (tok_buffer_size); ++ } ++ else ++ { ++ tok_buffer_size = length + 1; ++ tok_buffer = ++ (char *) xrealloc (tok_buffer, tok_buffer_size); ++ } ++ strncpy (tok_buffer, token, length); ++ tok_buffer[length] = '\0'; ++ token = tok_buffer; ++ } + CNL; ++ c = *lp++; + } ++ while ((c != 0) && iswhite(c)) ++ c = *lp++; + } +- /* the following tries to make it so that a #define a b(c) */ +- /* doesn't count as a define of b. */ ++ break_while_1: ++ ; + } + else + { ++ /* the following tries to make it so that a #define a b(c) */ ++ /* doesn't count as a define of b. */ + number++; +- if (number >= 4 || (number==2 && strncmp (token, "define", 6))) +- { +- gotone = TRUE; +- badone: ++#ifdef DEBUG ++ fprintf (stderr, "number: %d, n_t_i_m: %d, token: %s\n", ++ number, next_token_is_macro, token); ++#endif /* DEBUG */ ++ if (number == 2 && strncmp (token, "define", 6) == 0) ++ next_token_is_macro = TRUE; ++ else if (number == 3 && next_token_is_macro) ++ { ++ next_token_is_macro = FALSE; ++ while ((c != 0) && iswhite(c)) ++ { ++#ifdef DEBUG ++ fprintf (stderr, "c: %c, %d\n", c, c); ++#endif /* DEBUG */ ++ c = *lp++; ++ } ++#ifdef DEBUG ++ fprintf (stderr, "c: %c, %d\n", c, c); ++#endif /* DEBUG */ ++ if (c == 0) /* ignore plain "#define FLAG" */ + bad = TRUE; ++ else ++ win = TRUE; ++ /* speed up skipping the rest of this line */ ++ gotone = TRUE; ++ /* never treat a macro as a function, because it doesn't have a */ ++ /* function body, which is what "f" really stands for (now). */ ++ *f = FALSE; + goto ret; + } ++ else ++ /* speed up skipping the rest of this line */ ++ gotone = TRUE; ++ goto badone; + } ++ idents_in_decl ++; ++#ifdef DEBUG ++ fprintf (stderr, ++ "A: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n", ++ idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c, ++ length + 5, token); ++#endif /* DEBUG */ + /* check for the typedef cases */ +- if (tflag && istoken(token, "typedef", 7)) ++ if (istoken (token, "typedef", length)) + { + tydef=begin; + goto badone; + } +- if (tydef==begin && (istoken(token, "struct", 6) || +- istoken(token, "union", 5) || istoken(token, "enum", 4))) +- { ++#ifdef DEBUG ++ fprintf (stderr, "D\n"); ++#endif /* DEBUG */ ++ if (istoken (token, "struct", length) || ++ istoken (token, "union", length) || ++ istoken (token, "enum", length)) ++ { ++ next_token_is_tag = 1; ++#ifdef DEBUG ++ fprintf (stderr, "A: token: %s\n", token); ++#endif /* DEBUG */ ++ if (tydef == begin) + tydef=tag_ok; + goto badone; + } +- if (tydef==tag_ok) ++ else if (next_token_is_tag) + { ++#ifdef DEBUG ++ fprintf (stderr, "B: token: %s, c: [%c]\n", token, c); ++#endif /* DEBUG */ ++ if (tydef==tag_ok) + tydef=middle; +- goto badone; ++ next_token_is_tag = 0; ++ *f = 0; ++ /* only notice when a tag is being defined, not when it is merely */ ++ /* being used. */ ++ if (c == '{') ++ win = TRUE; ++ else ++ bad = TRUE; ++ goto ret; + } ++#ifdef DEBUG ++ fprintf (stderr, "E\n"); ++#endif /* DEBUG */ + if (tydef==begin) /* e.g. typedef ->int<- */ + { + tydef=end; + goto badone; + } ++#ifdef DEBUG ++ fprintf (stderr, "F\n"); ++#endif /* DEBUG */ + if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */ + { + tydef=end; + } ++#ifdef DEBUG ++ fprintf (stderr, "G\n"); ++#endif /* DEBUG */ + if (tydef==end) + { + *f = 0; +- win = 1; ++#ifdef DEBUG ++ fprintf (stderr, "C token: %s\n", token); ++#endif /* DEBUG */ ++ win = tflag; + goto ret; + } ++#ifdef DEBUG ++ fprintf (stderr, "H\n"); ++#endif /* DEBUG */ + /* Detect GNUmacs's function-defining macros. */ + if (!number && !strncmp (token, "DEF", 3)) + +@@ -962,6 +1149,9 @@ + next_token_is_func = 1; + goto badone; + } ++#ifdef DEBUG ++ fprintf (stderr, "I\n"); ++#endif /* DEBUG */ + if (next_token_is_func) + { + next_token_is_func = 0; +@@ -968,9 +1158,15 @@ + win = 1; + goto ret; + } ++#ifdef DEBUG ++ fprintf (stderr, "J\n"); ++#endif /* DEBUG */ + if (c != '(') + goto badone; + firsttok = FALSE; ++#ifdef DEBUG ++ fprintf (stderr, "K\n"); ++#endif /* DEBUG */ + while ((c = *lp++) != ')') + { + if (c == 0) +@@ -999,9 +1195,20 @@ + } + } + win = isgood (c); ++ + ret: ++#ifdef DEBUG ++ fprintf (stderr, ++ "B: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n", ++ idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c, ++ length + 5, token); ++#endif /* DEBUG */ + *lpp = lp - 1; + return !bad && win; ++ ++ badone: ++ bad = TRUE; ++ goto ret; + } + + getline (atchar) +---------------------------------------------------------------------- + diff --git a/web/glasgow/lit2x-0.16/grasp-utils/etags/wells-fixes b/web/glasgow/lit2x-0.16/grasp-utils/etags/wells-fixes new file mode 100644 index 0000000000..242e4e1002 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/etags/wells-fixes @@ -0,0 +1,545 @@ +From jbw@bigbird.bu.edu Sun Apr 5 14:58:19 1992 +From: jbw@bigbird.bu.edu (Joe Wells) +Newsgroups: gnu.emacs.bug +Subject: numerous bug fixes for etags +Date: 3 Apr 92 19:46:52 GMT +Distribution: gnu +Organization: GNUs Not Usenet + +Enclosed is a patch with numerous changes for etags. The following are +the changes and bugs fixed: + +1. Improvement: don't waste time calling strncmp (with "struct", "union", + "enum", "typedef") if the lengths are different. + +2. Bug: pfnote placed a NUL in the line buffer after the tag token which caused + things like `{' or `/*' to be ignored, thus severely screwing up the + parser. Or it did something horrible, I don't remember for sure. + +3. Improvement: record defining occurrences of struct/union/enum tags. + This works even if combined with a typedef definition, for example: + + typedef struct XXX { + ..... + } YYY; + +4. Bug: when a tag token was the last item on the line before the newline + character, garbage would be seen as the token. This is because when a + NUL was seen in the buffer the buffer was replaced with the next line. + +5. Bug: tag tokens immediately followed by a `{' with no intervening space + were not recorded. This was only a problem because of improvement 3 + above. + +6. Bug: a newline in the middle of a comment zeroed the `number' variable. + (Just for good measure I made it not zero `number' in strings even when + the newline is not preceded by `\', in case someone wants to run etags + on illegal code :-) (`number' is used only on lines that begin with + `#'.) + +7. Bug: handling of #define lines was severely broken. I don't actually + remember what etags did with them, but it was really bad. It now + records macro definitions. + +8. Bug: when a tag token was the last item on the line except for + whitespace, etags would replace the contents of the line buffer and + then later do various string comparisons and inspections against + garbage values instead of against the token. Fixing this required + copying the token into a buffer. (This is roughly the same as bug 4 + above, but in a different function.) + +9. Bug: when a tag token was the last item on the line before the newline + (and under various other circumstances), etags would skip over the NUL + in the buffer and skip to the first non-whitespace character in the + buffer. + +10. Improvement (possibly bug fix): parse typedefs even when we aren't + going to print them out. I seem to remember that this fixed some bug, + but I don't remember the specific case that would trigger the bug. + +11. An unfinished attempt to detect and record global variable + definitions. + +The changes are to the 18.57 version of etags, but the only change in +18.58 to the C code handling is to initialize some variables when starting +on a new file, so these changes are orthogonal. + +-- +Enjoy, + +Joe Wells <jbw@cs.bu.edu> + +Member of the League for Programming Freedom --- send e-mail for details + +---------------------------------------------------------------------- +--- etags.c-dist Tue Jan 8 14:08:38 1991 ++++ etags.c Sat Apr 4 00:41:22 1992 +@@ -62,7 +62,10 @@ + + /* cause token checking for typedef, struct, union, enum to distinguish + keywords from identifier-prefixes (e.g. struct vs struct_tag). */ +-#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len)))) ++#define istoken(s, t, len) \ ++ (((len) == (sizeof (t) -1)) && \ ++ ((strncmp(s, t, len)) == 0) && \ ++ (endtoken(*((s)+(len))))) + + struct nd_st { /* sorting structure */ + char *name; /* function or type name */ +@@ -505,6 +508,7 @@ + { + register char *fp; + register NODE *np; ++ char save; + char *altname; + char tem[51]; + +@@ -538,6 +542,7 @@ + np->left = np->right = 0; + if (eflag) + { ++ save = linestart[linelen]; + linestart[linelen] = 0; + } + else if (xflag == 0) +@@ -546,6 +551,7 @@ + linestart = tem; + } + np->pat = savestr (linestart); ++ linestart[linelen] = save; + if (head == NULL) + head = np; + else +@@ -725,6 +731,17 @@ + number = 0; \ + } + ++/* These two are part of a never-finished attempt to record global */ ++/* variable definitions. This is nearly impossible in C without the full */ ++/* power of a C compiler due to C's stupid grammar. */ ++logical infunc; ++int idents_in_decl; ++ ++/* indicates whether the next token (if any) is the tag corresponding to */ ++/* `struct', `union', or `enum' */ ++logical next_token_is_tag; ++ ++ + C_entries () + { + register int c; +@@ -731,6 +748,15 @@ + register char *token, *tp, *lp; + logical incomm, inquote, inchar, midtoken; + int level; ++ ++ /* there are certain things that must be done when the end of line is */ ++ /* encountered, but they must be delayed until after other things are */ ++ /* done. */ ++ logical new_line_flag; ++ ++ /* same as new_line_flag for left braces. */ ++ logical left_brace_flag; ++ + char tok[BUFSIZ]; + + lineno = 0; +@@ -739,17 +765,22 @@ + *lp = 0; + + number = 0; +- gotone = midtoken = inquote = inchar = incomm = FALSE; ++ gotone = midtoken = inquote = inchar = incomm = infunc = FALSE; ++ new_line_flag = FALSE; ++ left_brace_flag = FALSE; + level = 0; ++ idents_in_decl = 0; ++ next_token_is_tag = FALSE; + + while (!feof (inf)) + { + c = *lp++; + if (c == 0) +- { +- CNL; +- gotone = FALSE; +- } ++ new_line_flag = TRUE; ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "E: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ + if (c == '\\') + { + c = *lp++; +@@ -756,15 +787,18 @@ + if (c == 0) + CNL_SAVE_NUMBER; + c = ' '; ++ /* is this correct? I thought escaped newlines disappeared even */ ++ /* before the token breaker got to see things. */ + } + else if (incomm) + { ++ new_line_flag = FALSE; + if (c == '*') + { + while ((c = *lp++) == '*') + continue; + if (c == 0) +- CNL; ++ CNL_SAVE_NUMBER; + if (c == '/') + incomm = FALSE; + } +@@ -771,6 +805,7 @@ + } + else if (inquote) + { ++ new_line_flag = FALSE; + /* + * Too dumb to know about \" not being magic, but + * they usually occur in pairs anyway. +@@ -781,6 +816,7 @@ + } + else if (inchar) + { ++ new_line_flag = FALSE; + if (c == '\'') + inchar = FALSE; + continue; +@@ -809,8 +845,8 @@ + { + tydef=middle; + } +- level++; +- continue; ++ left_brace_flag = TRUE; ++ break; + case '}': + if (lp == lb.buffer + 1) + level = 0; /* reset */ +@@ -820,8 +856,17 @@ + { + tydef=end; + } ++ if (level == 0 && infunc) ++ { ++ idents_in_decl = 0; ++ infunc = FALSE; ++ } + continue; + } ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "D: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ + if (!level && !inquote && !incomm && gotone == FALSE) + { + if (midtoken) +@@ -852,6 +897,11 @@ + tp-token+1); + tok[tp-token+1] = 0; + pfnote(tok, f, lb1.buffer, endpos, line, linestart); ++#ifdef DEBUG ++ fprintf (stderr, ++ "f: %d, infunc %d, tok: %s\nlb1.buffer: %s\n", ++ f, infunc, tok, lb1.buffer); ++#endif /* DEBUG */ + } + else + { +@@ -858,8 +908,15 @@ + strncpy (tok, token, tp-token+1); + tok[tp-token+1] = 0; + pfnote(tok, f, lb.buffer, endpos, line, linestart); ++#ifdef DEBUG ++ fprintf (stderr, ++ "f: %d, infunc %d, tok: %s\nlb.buffer: %s\n", ++ f, infunc, tok, lb.buffer); ++#endif /* DEBUG */ + } + gotone = f; /* function */ ++ if (f) ++ infunc = TRUE; + } + midtoken = FALSE; + token = lp - 1; +@@ -873,8 +930,32 @@ + midtoken = TRUE; + } + } ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "F: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ ++ if (left_brace_flag) ++ { ++ left_brace_flag = FALSE; ++ next_token_is_tag = FALSE; ++ level++; ++ } ++ if (new_line_flag) ++ { ++ new_line_flag = FALSE; ++ number = 0; ++ gotone = FALSE; ++ } ++ if (lp > lb.buffer && lp[-1] == 0) ++ CNL_SAVE_NUMBER; + if (c == ';' && tydef==end) /* clean with typedefs */ + tydef=none; ++ if (c == ';' && level == 0 && !infunc) ++ idents_in_decl = 0; ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "G: c: [%c], lp[-2]: [%c]\n", c, lp[-2]); ++#endif /* DEBUG */ + } + } + +@@ -891,70 +972,176 @@ + reg char *lp = *lpp; + reg char c; + static logical next_token_is_func; ++ ++ /* indicates that the next token will be a macro defined with #define */ ++ static logical next_token_is_macro; ++ + logical firsttok; /* T if have seen first token in ()'s */ +- int bad, win; ++ int bad = FALSE, win = FALSE; ++ int length = (lp - 1) - token; ++ ++ /* used to keep a copy of the token when we have to fill the line buffer */ ++ /* with the contents of the next line */ ++ static char *tok_buffer = NULL; ++ static long tok_buffer_size = 0; + + *f = 1; /* a function */ + c = lp[-1]; +- bad = FALSE; + if (!number) + { /* space is not allowed in macro defs */ +- while (iswhite(c)) ++ while ((c == 0) || iswhite(c)) + { +- c = *lp++; +- if (c == 0) ++#ifdef DEBUG ++ if (next_token_is_tag) ++ fprintf (stderr, "C: token: %s, c: [%c], lp - token: %d\n", ++ token, c, lp - token); ++#endif /* DEBUG */ ++ while (c == 0) + { + if (feof (inf)) +- break; ++ goto break_while_1; ++ if (token != tok_buffer) ++ { ++ if (length + 1 > tok_buffer_size) ++ if (tok_buffer_size == 0) ++ { ++ tok_buffer_size = length + 1; ++ tok_buffer = (char *) xmalloc (tok_buffer_size); ++ } ++ else ++ { ++ tok_buffer_size = length + 1; ++ tok_buffer = ++ (char *) xrealloc (tok_buffer, tok_buffer_size); ++ } ++ strncpy (tok_buffer, token, length); ++ tok_buffer[length] = '\0'; ++ token = tok_buffer; ++ } + CNL; ++ c = *lp++; + } ++ while ((c != 0) && iswhite(c)) ++ c = *lp++; + } +- /* the following tries to make it so that a #define a b(c) */ +- /* doesn't count as a define of b. */ ++ break_while_1: ++ ; + } + else + { ++ /* the following tries to make it so that a #define a b(c) */ ++ /* doesn't count as a define of b. */ + number++; +- if (number >= 4 || (number==2 && strncmp (token, "define", 6))) +- { +- gotone = TRUE; +- badone: ++#ifdef DEBUG ++ fprintf (stderr, "number: %d, n_t_i_m: %d, token: %s\n", ++ number, next_token_is_macro, token); ++#endif /* DEBUG */ ++ if (number == 2 && strncmp (token, "define", 6) == 0) ++ next_token_is_macro = TRUE; ++ else if (number == 3 && next_token_is_macro) ++ { ++ next_token_is_macro = FALSE; ++ while ((c != 0) && iswhite(c)) ++ { ++#ifdef DEBUG ++ fprintf (stderr, "c: %c, %d\n", c, c); ++#endif /* DEBUG */ ++ c = *lp++; ++ } ++#ifdef DEBUG ++ fprintf (stderr, "c: %c, %d\n", c, c); ++#endif /* DEBUG */ ++ if (c == 0) /* ignore plain "#define FLAG" */ + bad = TRUE; ++ else ++ win = TRUE; ++ /* speed up skipping the rest of this line */ ++ gotone = TRUE; ++ /* never treat a macro as a function, because it doesn't have a */ ++ /* function body, which is what "f" really stands for (now). */ ++ *f = FALSE; + goto ret; + } ++ else ++ /* speed up skipping the rest of this line */ ++ gotone = TRUE; ++ goto badone; + } ++ idents_in_decl ++; ++#ifdef DEBUG ++ fprintf (stderr, ++ "A: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n", ++ idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c, ++ length + 5, token); ++#endif /* DEBUG */ + /* check for the typedef cases */ +- if (tflag && istoken(token, "typedef", 7)) ++ if (istoken (token, "typedef", length)) + { + tydef=begin; + goto badone; + } +- if (tydef==begin && (istoken(token, "struct", 6) || +- istoken(token, "union", 5) || istoken(token, "enum", 4))) +- { ++#ifdef DEBUG ++ fprintf (stderr, "D\n"); ++#endif /* DEBUG */ ++ if (istoken (token, "struct", length) || ++ istoken (token, "union", length) || ++ istoken (token, "enum", length)) ++ { ++ next_token_is_tag = 1; ++#ifdef DEBUG ++ fprintf (stderr, "A: token: %s\n", token); ++#endif /* DEBUG */ ++ if (tydef == begin) + tydef=tag_ok; + goto badone; + } +- if (tydef==tag_ok) ++ else if (next_token_is_tag) + { ++#ifdef DEBUG ++ fprintf (stderr, "B: token: %s, c: [%c]\n", token, c); ++#endif /* DEBUG */ ++ if (tydef==tag_ok) + tydef=middle; +- goto badone; ++ next_token_is_tag = 0; ++ *f = 0; ++ /* only notice when a tag is being defined, not when it is merely */ ++ /* being used. */ ++ if (c == '{') ++ win = TRUE; ++ else ++ bad = TRUE; ++ goto ret; + } ++#ifdef DEBUG ++ fprintf (stderr, "E\n"); ++#endif /* DEBUG */ + if (tydef==begin) /* e.g. typedef ->int<- */ + { + tydef=end; + goto badone; + } ++#ifdef DEBUG ++ fprintf (stderr, "F\n"); ++#endif /* DEBUG */ + if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */ + { + tydef=end; + } ++#ifdef DEBUG ++ fprintf (stderr, "G\n"); ++#endif /* DEBUG */ + if (tydef==end) + { + *f = 0; +- win = 1; ++#ifdef DEBUG ++ fprintf (stderr, "C token: %s\n", token); ++#endif /* DEBUG */ ++ win = tflag; + goto ret; + } ++#ifdef DEBUG ++ fprintf (stderr, "H\n"); ++#endif /* DEBUG */ + /* Detect GNUmacs's function-defining macros. */ + if (!number && !strncmp (token, "DEF", 3)) + +@@ -962,6 +1149,9 @@ + next_token_is_func = 1; + goto badone; + } ++#ifdef DEBUG ++ fprintf (stderr, "I\n"); ++#endif /* DEBUG */ + if (next_token_is_func) + { + next_token_is_func = 0; +@@ -968,9 +1158,15 @@ + win = 1; + goto ret; + } ++#ifdef DEBUG ++ fprintf (stderr, "J\n"); ++#endif /* DEBUG */ + if (c != '(') + goto badone; + firsttok = FALSE; ++#ifdef DEBUG ++ fprintf (stderr, "K\n"); ++#endif /* DEBUG */ + while ((c = *lp++) != ')') + { + if (c == 0) +@@ -999,9 +1195,20 @@ + } + } + win = isgood (c); ++ + ret: ++#ifdef DEBUG ++ fprintf (stderr, ++ "B: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n", ++ idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c, ++ length + 5, token); ++#endif /* DEBUG */ + *lpp = lp - 1; + return !bad && win; ++ ++ badone: ++ bad = TRUE; ++ goto ret; + } + + getline (atchar) +---------------------------------------------------------------------- + diff --git a/web/glasgow/lit2x-0.16/grasp-utils/msub/Jmakefile b/web/glasgow/lit2x-0.16/grasp-utils/msub/Jmakefile new file mode 100644 index 0000000000..cc855bd99e --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/msub/Jmakefile @@ -0,0 +1,7 @@ +BuildPgmFromOneCFile(msub) + +InstallBinaryTarget(msub,$(INSTBINDIR)) + +CDependTarget( $(SRCS_C) ) + +RunStdTest(msub001,msub,-f test.makefile testfile -o1 test.stdout) diff --git a/web/glasgow/lit2x-0.16/grasp-utils/msub/msub.c b/web/glasgow/lit2x-0.16/grasp-utils/msub/msub.c new file mode 100644 index 0000000000..dccefa990f --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/msub/msub.c @@ -0,0 +1,520 @@ +/* + msub - Read file(s) and perform substitutions using values of + variables defined in makefile. + + Syntax: msub [-f makefile] [file ...] + + Multiple -f options may be given. + + 27 Mar 1990 Paul DuBois dubois@primate.wisc.edu + + 27 Mar 1990 V1.0. Created. +*/ + +# include <stdio.h> +# include <ctype.h> + + +# define true (1) +# define false (0) + + +extern char *calloc (), *strcpy (); + + +char *NewString(); + + +typedef struct Def Def; + +struct Def +{ + char *var; /* variable name */ + char *val; /* variable value */ + int simple; /* whether value has been expanded */ + Def *nextDef; /* next definition in list */ +}; + + +char *usage = "Usage: msub [ -f makefile ] file"; +char *makefile = NULL; +Def *defList = NULL; /* list of definitions */ +int nDefs = 0; /* number of definitions */ +int changes; + +main (argc, argv) +int argc; +char **argv; +{ +FILE *f; +Def *dp; +int i, pass; + + --argc; + ++argv; + + while (argc > 0 && argv[0][0] == '-') + { + if (strcmp (argv[0], "-f") == 0) + { + if (argc < 2) + panic (usage); + if ((f = fopen (makefile = argv[1], "r")) == NULL) + panic ("Can't open makefile"); + ReadMake (f); + fclose (f); + argc -= 2; + argv += 2; + } + else + panic (usage); /* bad flag */ + } + + if (makefile == NULL) /* no -f options given */ + { + if ((f = fopen ("makefile", "r")) == NULL) + { + if ((f = fopen ("Makefile", "r")) == NULL) + panic ("Can't open makefile"); + } + ReadMake (f); + fclose (f); + } + + EncodeEscapes (); + + /* determine which values need expanding */ + for (dp = defList; dp != NULL; dp = dp->nextDef) + dp->simple = !FindVarRef (dp->val, NULL, NULL, false); + + /* expand values to eliminate embedded var references */ + for (pass = 0; pass < nDefs; pass++) + { + changes = 0; + for (dp = defList; dp != NULL; dp = dp->nextDef) + { + if (!dp->simple) + Expand (dp); + } + if (changes == 0) /* loop while values expand */ + break; + } + + /* sanity check: shouldn't have to make more than nDefs passes */ + if (pass >= nDefs) + panic ("Too many expansion passes. Something's wrong!"); + + DecodeEscapes (); + + /* partain addition: + args of form "foo=bar" are taken to be defs to add in + */ + while (argc > 0 && strchr(argv[0], '=') && isalpha(argv[0][0])) + { + char name[BUFSIZ], *np, *p; + int len; + p = argv[0]; + /* copied from below */ + np = name; + while (isalnum (*p) || *p == '_') + *np++ = *p++; + *np = '\0'; + while (isspace (*p)) /* skip whitespace */ + ++p; + if (*p++ == '=') /* it's a definition */ + { + /* skip leading/trailing whitespace */ + while (isspace (*p)) + ++p; + len = strlen (p); + while (len > 0 && isspace (p[len-1])) + p[--len] = '\0'; + AddDef (name, p, 1); + /* find var refs in value -- NUKED */ + /* FindAllVarRefs (p); */ + /* also NUKED: continue; */ + } + /* end of: copied from below */ + --argc; + ++argv; + } + /* end of partain addition */ + + /* read source file(s) and perform substitutions */ + if (argc == 0) + DoSub (stdin); + else while (argc > 0) + { + if ((f = fopen (*argv, "r")) == NULL) + { + fprintf (stderr, "Can't open \"%s\". ", *argv); + panic ("Quitting."); + } + DoSub (f); + fclose (f); + --argc; + ++argv; + } + + exit (0); +} + + +/* + Read a makefile. +*/ + +ReadMake (f) +FILE *f; +{ +char input[BUFSIZ * 4], name[BUFSIZ], *p, *np; +int i, len; + + while (GetLine (f, input)) /* get line, check whether def'n */ + { + for (p = input; isspace (*p); p++) { /* nop */ } + if (*p == '#' || *p == '\0') /* comment or blank line */ + continue; + if (isalpha (*p)) /* look for var name */ + { + np = name; + while (isalnum (*p) || *p == '_') + *np++ = *p++; + *np = '\0'; + while (isspace (*p)) /* skip whitespace */ + ++p; + if (*p++ == '=') /* it's a definition */ + { + /* skip leading/trailing whitespace */ + while (isspace (*p)) + ++p; + len = strlen (p); + while (len > 0 && isspace (p[len-1])) + p[--len] = '\0'; + AddDef (name, p, 1); + /* find var refs in value */ + FindAllVarRefs (p); + continue; + } + } + /* not a definition; find var refs anywhere in line */ + FindAllVarRefs (input); + } +} + + +/* + Find definition by variable name. +*/ + +Def *FindDefByVar (s) +char *s; +{ +Def *dp; + + for (dp = defList; dp != NULL; dp = dp->nextDef) + { + if (strcmp (dp->var, s) == 0) + return (dp); + } + return (NULL); +} + + +/* + Add a definition. If the name hasn't been seen yet, create a new + definition on the list. If the name has been seen, and replace is + non-zero, replace the current value with the new one. (replace will + be zero if we're just adding a variable which is known by its being + referenced somewhere.) +*/ + +AddDef (name, value, replace) +char *name, *value; +int replace; +{ +Def *dp; + + if ((dp = FindDefByVar (name)) == NULL) + { + if ((dp = (Def *) calloc (1, sizeof (Def))) == NULL) + panic ("AddDef: out of memory"); + dp->var = NewString (name); + dp->val = NewString (value); + dp->simple = 0; /* assume not */ + dp->nextDef = defList; + defList = dp; + ++nDefs; + } + else if (replace) + { + free (dp->val); + dp->val = NewString (value); + } +} + + +/* + Replace instances of '$$' with a single ^A. +*/ + +EncodeEscapes () +{ +Def *dp; +char *p, *q; + + for (dp = defList; dp != NULL; dp = dp->nextDef) + { + for (p = q = dp->val; *p != '\0'; p++, q++) + { + *q = *p; + if (*p == '$' && *(p+1) == '$') + { + *q = '\01'; + p++; + } + } + *q = '\0'; + } +} + + +/* + Replace instances of ^A with a '$'. +*/ + +DecodeEscapes () +{ +Def *dp; +char *p; + + for (dp = defList; dp != NULL; dp = dp->nextDef) + { + for (p = dp->val; *p != '\0'; p++) + { + if (*p == '\01') + *p = '$'; + } + } +} + + +/* + Find variable reference in variable value. begin is set to + the index of the '$' and end is set to the index of the closing + delimiter. (If either is NULL, it is not set.) + + recogEsc is non-zero (true) if '$$' is recognized as an escaped '$' + and skipped. It will be true during initial searching for var refs + and while substituting in source files, false while expanding variable + values. + + $v, ${}, ${1}, ${v), etc. are not accepted as valid and are ignored. +*/ + +FindVarRef (s, beg, end, recogEsc) +char *s; +int *beg, *end, recogEsc; +{ +int i; +char c, delim; + + i = 0; + for (;;) + { + while ((c = s[i]) != '\0') + { + if (c == '$') + { + if ((c = s[i+1]) == '{' || c == '(') + break; + if (recogEsc && c == '$') /* escaped $ */ + ++i; + } + ++i; + } + if (c == '\0') + return (0); /* no reference */ + if (beg != (int *) NULL) + *beg = i; + if (s[++i] == '{') + delim = '}'; + else + delim = ')'; + ++i; + if (!isalpha (s[i])) /* must have at least one char, must */ + continue; /* begin with letter */ + while ((c = s[++i]) != '\0') + { + if (c == delim) /* find matching delim */ + { + if (end != (int *) NULL) + *end = i; + return (1); + } + if (!isalnum (c) && c != '_') + break; + } + } +} + + +FindAllVarRefs (s) +char *s; +{ +char name[BUFSIZ]; +int begin, end; + + while (FindVarRef (s, &begin, &end, true)) + { + /* add with empty value if unknown, */ + /* but don't replace value if known */ + strncpy (name, s + begin + 2, end - begin - 2); + name[end-begin-2] = '\0'; + AddDef (name, "", 0); + s += end + 1; + } +} + + +/* + Pull out a variable reference, skipping leading '$(' or '${' and + trailing ')' or '}'. +*/ + +YankVarRef (dst, src, begin, end) +char *dst, *src; +int begin, end; +{ + strncpy (dst, src + begin + 2, end - begin - 2); + dst[end - begin - 2] = '\0'; +} + + +/* + Look for variable references in a variable value and expand them + when possible. If a variable is referenced but never defined, it + disappears. If a variable is referenced, but its value has not itself + been fully expanded, defer expansion of value until another pass, at + which time the referenced variable might then be expanded. This + prevents infinite expansions on circular references. +*/ + +Expand (dp) +Def *dp; +{ +Def *dp2; +/* partain: made 4 * BUFSIZ +char buf[BUFSIZ]; +*/ +char buf[4 * BUFSIZ]; +int begin, end, vn; + + while (FindVarRef (dp->val, &begin, &end, false)) + { + YankVarRef (buf, dp->val, begin, end); + if ((dp2 = FindDefByVar (buf)) == NULL) + { + fprintf (stderr, "Expand error: can't find %s, ", buf); + panic ("quitting"); + } + if (!dp2->simple) /* can't expand, give up for now */ + break; + dp->val[begin] = '\0'; + sprintf (buf, "%s%s%s", dp->val, dp2->val, &(dp->val)[end+1]); + free (dp->val); + dp->val = NewString (buf); + ++changes; + } + dp->simple = !FindVarRef (dp->val, NULL, NULL, false); +} + + +/* + Read through file, performing substitutions for any variables + known from Makefile. If a variable reference is found that is + for an unknown variable, leave it alone, as it may be a reference + to a real variable in a shell script. +*/ + +DoSub (f) +FILE *f; +{ +Def *dp; +char input[BUFSIZ], var[BUFSIZ], *p; +int begin, end; + + while (fgets (input, sizeof (input), f) != NULL) + { + p = input; + while (FindVarRef (p, &begin, &end, true)) + { + write (1, p, begin); /* write prefix */ + YankVarRef (var, p, begin, end); + /* if var is known from makefile, write */ + /* value, else just echo the reference */ + if ((dp = FindDefByVar (var)) != NULL) + write (1, dp->val, strlen (dp->val)); + else + write (1, p + begin, end - begin + 1); + p += end + 1; + } + write (1, p, strlen (p)); + } +} + + +/* + Get next line from Makefile (combines continuation lines into one). + No overflow checking, oops. +*/ + +GetLine (f, lbuf) +FILE *f; +char *lbuf; +{ +char buf[BUFSIZ]; +int loop = 1, haveLine = 0, len; + + *lbuf = '\0'; + while (loop && fgets (buf, sizeof (buf), f) != NULL) + { + loop = 0; + haveLine = 1; + len = strlen (buf); + if (len > 0 && buf[len-1] == '\n') /* trim newline */ + buf[--len] = '\0'; + if (len > 0 && buf[len-1] == '\\') /* need continuation */ + { + loop = 1; + buf[--len] = ' '; + } + strcat (lbuf, buf); + } + return (haveLine); +} + + +/* + Allocate space for a string, copy the string into it, and return + a pointer to the copy. +*/ + + +char *NewString (s) +char *s; +{ +char *p; + + if ((p = calloc (1, strlen (s) + 1)) == NULL) + panic ("NewString: out of space"); + return (strcpy (p, s)); +} + + +panic (s) +char *s; +{ + fprintf (stderr, "%s\n", s); + exit (1); +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/msub/msub.ms b/web/glasgow/lit2x-0.16/grasp-utils/msub/msub.ms new file mode 100644 index 0000000000..7fe019f509 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/msub/msub.ms @@ -0,0 +1,128 @@ +.SH +Theory of Operation +.LP +.I msub +reads the makefile in the current directory (or the file named after the +.B \-f +flag) and finds all variable definitions and references. +Definitions are lines of the form ``\fIname\fR = \fIvalue\fR''. +References are instances of ``$(\fIvar\fR)'' or ``${\fIvar\fR}'', either in +the value part of definition lines, or any part of dependency or command lines. +Then variable values are examined to eliminate references to other variables +by replacing the referenced variables with their values. +Variables which are referenced but never defined have a value of the empty +string. +.LP +Then +.I msub +reads any files named on the command line (or +.I stdin +if none) and looks for instances of ``$(\fIvar\fR)'' or ``${\fIvar\fR}'', +where +.I var +is known from the makefile, and substitutes the value of +.I var . +.SH +Purpose +.LP +The motivation for +.I msub +is that project configuration information is often contained in makefiles +and it is often desirable to make use of that information. +.I msub +allows files to be produced from templates that contain references +to makefile variables. +In this sense it is similar to the way that the C preprocessor +.I cpp +uses #define statements in header files; the +makefile is the implicit ``header'' file and definition lines are the +``#define'' statements. +.LP +Although it is possible to use +.I cpp +to perform substitutions on templates, a disadvantage of +.I cpp +is that it modifies its source in other ways (eg., lines beginning with +``#'' are special and comments (``/* ... */'') are deleted. +Also, it is necessary to pass a -D flag for every symbol to be substituted. +Similarly, for C programs it can be simpler to use +.I msub +to produce a single configuration header file from a template +than to pass a lot of -D flags to each invocation of +.I cc . +.LP +.I msub +performs no textual modification besides substitution of references +to makefile variables; it leaves everything else alone. +In particular, +references to variables not known from the makefile are left untouched. +This allows +.I msub +to be used to produce shell scripts that use variables of +their own. +.LP +.I msub +is particularly useful in software projects that use +.I imake . +Virtually all configuration information is propagated into makefiles +thus produced, so it is available for propagation into other files using +.I msub . +.SH +Problems +.LP +If +.I msub +is used to produce shell scripts, it is unwise for the script to use names +for its own variables that are the same as those in the makefile. +The problem can be avoided entirely if, for instance, variables in makefiles +are all uppercase and the scripts' own variables are lowercase or mixed case. +.LP +Circular references in makefile variables are not expanded. +If a makefile contains the definitions ``X = ${Y}'' and ``Y = ${X}'', +neither X nor Y will be expanded. +But that is really a problem with the makefile, not +.I msub . +.LP +.I make +recognizes +.B \-f\ \- +to mean the makefile should be read from +.I stdin . +.I msub +does not. +.LP +CC, YACC, etc., have implicit values in +.I make +even if not defined in the makefile. +Not true in +.I msub . +.LP +.I msub +is more restrictive in the variable names that it recognizes and +performs substitutions on. +Names that do not begin with a letter and +that contain any characters besides letters, digits and underscores are +ignored. +This means that variable names such as ``${1}'' are not recognized; +the reason for this is that shell scripts often use such variables and +they should be left untouched. +Also, +``$\fIx\fR'' is legal in +.I make +when +.I x +is a single character, but +.I msub +ignores such references. +.i msub +.LP +.I make +allows variables to be defined on the command line. +.I msub +does not. +.LP +If you try to be tricky with your variable references, e.g., by using +recursive references, you may get burned. +.LP +There is no way to prevent substitution, in a source file, of a reference to +a variable known from the makefile. diff --git a/web/glasgow/lit2x-0.16/grasp-utils/msub/test.makefile b/web/glasgow/lit2x-0.16/grasp-utils/msub/test.makefile new file mode 100644 index 0000000000..b20a2b7868 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/msub/test.makefile @@ -0,0 +1,18 @@ +foo = ${bar} +bar = ${ugh} +ugh = Huh? +space = x +a = ${wildcard x} + +# xyz should be found in next line, given empty value and then the +# value should be replaced later... + +c : ${xyz} + +xyz = abc + + +dollar = $$ +doubledollar = ${dollar}${dollar} + + diff --git a/web/glasgow/lit2x-0.16/grasp-utils/msub/test.stdout b/web/glasgow/lit2x-0.16/grasp-utils/msub/test.stdout new file mode 100644 index 0000000000..506999f3c1 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/msub/test.stdout @@ -0,0 +1,11 @@ +foo = Huh? +bar = Huh? +ugh = Huh? +xy +${wildcard x} + +This (abc) should be abc. + +This should be a single dollar: $ +This should be a double dollar: $$ +So should this: $$ diff --git a/web/glasgow/lit2x-0.16/grasp-utils/msub/testfile b/web/glasgow/lit2x-0.16/grasp-utils/msub/testfile new file mode 100644 index 0000000000..ba3f4ebbf0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/msub/testfile @@ -0,0 +1,11 @@ +foo = ${foo} +bar = ${bar} +ugh = ${ugh} +${space}y +${a} + +This (${xyz}) should be abc. + +This should be a single dollar: ${dollar} +This should be a double dollar: ${dollar}${dollar} +So should this: ${doubledollar} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/perl-4.035-fixes b/web/glasgow/lit2x-0.16/grasp-utils/perl-4.035-fixes new file mode 100644 index 0000000000..e456aa49e8 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/perl-4.035-fixes @@ -0,0 +1,180 @@ +From mjeffery@reed.edu Sun Nov 29 14:07:23 1992 +From: mjeffery@reed.edu (Mark Jefferys) +Newsgroups: comp.lang.perl +Subject: Re: Recursion error in perl 4.035 ? +Date: 28 Nov 92 23:31:14 GMT +Organization: Reed College, Portland, OR + +In article <1f7uvvINN9tp@roundup.crhc.uiuc.edu> parkes@uiuc.edu writes: + +% In cons.c, change the code at or around 1423 from +% +% if (willsave) +% (void)apush(tosave,arg->arg_ptr.arg_str); +% +% to +% +% if (willsave && arg->arg_ptr.arg_str ) +% (void)apush(tosave,arg->arg_ptr.arg_str); + +This is half of my patch to which Larry gave a "Looks OK to me." +It's been a few months, do I'll post it again. + + +Mark + + +Index: cons.c +*** Orig/cons.c Thu Jun 11 22:42:01 1992 +--- cons.c Sun Jun 28 18:31:20 1992 +*************** +*** 1353,1359 **** + + /* in any event, save the iterator */ + +! (void)apush(tosave,cmd->c_short); + } + shouldsave |= tmpsave; + } +--- 1353,1360 ---- + + /* in any event, save the iterator */ + +! if (cmd->c_short) /* Better safe than sorry */ +! (void)apush(tosave,cmd->c_short); + } + shouldsave |= tmpsave; + } +*************** +*** 1420,1426 **** + shouldsave = TRUE; + break; + } +! if (willsave) + (void)apush(tosave,arg->arg_ptr.arg_str); + return shouldsave; + } +--- 1421,1427 ---- + shouldsave = TRUE; + break; + } +! if (willsave && arg->arg_ptr.arg_str) + (void)apush(tosave,arg->arg_ptr.arg_str); + return shouldsave; + } +-- +Mark Jefferys Internet: mjeffery@reed.edu + +From ezk@cs.columbia.edu Fri Dec 4 19:44:03 1992 +From: ezk@cs.columbia.edu (Erez "HWank1" Zadok) +Newsgroups: comp.lang.perl +Subject: REPOST: FIXES to perl/makewhatis (core dump on OW3 man pages) +Date: 3 Dec 92 12:42:05 GMT + +[This is a repost... -Erez] + +I've found three small bugs in the the latest version of perl (4.035), which +I fixed. + +The bugs only appeared when I got Tom Christiansen's man package, and ran +the makewhatis script. Furthermore, it only occurred for one particular set +of manual pages -- SunOS's OpenWindows 3. + +Since it seemed related to DBM, I tried to recompile perl with several +possible combinations of Sun's /bin/cc, gcc (2.2.2), ndbm, gdbm, +- -DDEBUGGING, -traditional (for gcc), Perl's malloc, Sun's malloc, etc. to no +avail. Perl was still dumping core with a segmentation fault. "make test" +was ok. I was running on various Sun 4 machines, running SunOS 4.1.2. + +After debugging I found out that perl was trying to dereference pointers +that were not initialized. + +I fixed this by adding initialization to three declarations in perl.h. The +ones to rsfp and statstab were needed for non-compressed man pages. When I +started using compressed man pages I discovered I had to initialize fdpid as +well. Now everything works fine. Here is the diff file: + +*** array.h.orig Tue Nov 24 02:16:30 1992 +--- array.h Mon Nov 23 14:31:16 1992 +*************** +*** 17,22 **** +--- 17,33 ---- + * + */ + ++ #ifdef NULL ++ #undef NULL ++ #endif ++ #ifndef I286 ++ # define NULL 0 ++ #else ++ # define NULL 0L ++ #endif ++ #define Null(type) ((type)NULL) ++ #define Nullarray Null(ARRAY*) ++ + struct atbl { + STR **ary_array; + STR **ary_alloc; +*** perl.h.orig Tue Nov 24 02:16:10 1992 +--- perl.h Mon Nov 23 14:30:51 1992 +*************** +*** 868,874 **** + + EXT char *hexdigit INIT("0123456789abcdef0123456789ABCDEFx"); + EXT char *origfilename; +! EXT FILE * VOLATILE rsfp; + EXT char buf[1024]; + EXT char *bufptr; + EXT char *oldbufptr; +--- 868,874 ---- + + EXT char *hexdigit INIT("0123456789abcdef0123456789ABCDEFx"); + EXT char *origfilename; +! EXT FILE * VOLATILE rsfp INIT(Nullfp); + EXT char buf[1024]; + EXT char *bufptr; + EXT char *oldbufptr; +*************** +*** 952,958 **** + EXT struct stat statbuf; + EXT struct stat statcache; + EXT STAB *statstab INIT(Nullstab); +! EXT STR *statname; + #ifndef MSDOS + EXT struct tms timesbuf; + #endif +--- 952,958 ---- + EXT struct stat statbuf; + EXT struct stat statcache; + EXT STAB *statstab INIT(Nullstab); +! EXT STR *statname INIT(Nullstr); + #ifndef MSDOS + EXT struct tms timesbuf; + #endif +*************** +*** 1013,1019 **** + EXT ARRAY *lineary; /* lines of script for debugger */ + EXT ARRAY *dbargs; /* args to call listed by caller function */ + +! EXT ARRAY *fdpid; /* keep fd-to-pid mappings for mypopen */ + EXT HASH *pidstatus; /* keep pid-to-status mappings for waitpid */ + + EXT int *di; /* for tmp use in debuggers */ +--- 1013,1019 ---- + EXT ARRAY *lineary; /* lines of script for debugger */ + EXT ARRAY *dbargs; /* args to call listed by caller function */ + +! EXT ARRAY *fdpid INIT(Nullarray); /* keep fd-to-pid mappings for mypopen */ + EXT HASH *pidstatus; /* keep pid-to-status mappings for waitpid */ + + EXT int *di; /* for tmp use in debuggers */ + + +Erez Zadok. +Central Research Facilities. +Columbia University Department of Computer Science. +- --- +"A wank's morning starts one jiffy | Arpa: ezk@cs.columbia.edu + after midnight." | Usenet: ...!rutgers!columbia!cs!ezk + -HebrewWank #1 (US meaning, not UK!) | Bitnet: erzus@cuvmb.BITNET diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/Jmakefile b/web/glasgow/lit2x-0.16/grasp-utils/scripts/Jmakefile new file mode 100644 index 0000000000..22d1ccb32f --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/Jmakefile @@ -0,0 +1,79 @@ +PROGRAMS = lndir \ + mkdirhier \ + runstdtest \ + mkdependC \ + fastmake \ + lmake \ + zap-if-same \ + moan-if-old \ + ltx \ + perltags + +all:: $(PROGRAMS) +/* stuff to have before we get going */ +MsubNeededHere($(PROGRAMS)) + +/* === BUILD STUFF (installation, etc., below) ========== */ + +/* std X11 stuff */ +MsubProgramScriptTarget(BourneShell,mkdirhier,mkdirhier.sh,/*no flags*/,/*no dep*/) + +BuildPgmFromOneCFile(lndir) +#if 0 +MsubProgramScriptTarget(BourneShell,lndir,lndir.sh,/*no flags*/,/*no dep*/) +InstallScriptTarget(lndir, $(INSTSCRIPTDIR)) +#endif + +MsubMakefileDependentProgramScriptTarget(PerlCmd,runstdtest,runstdtest.prl,/*no flags*/,/*Makefile*/) +MsubMakefileDependentProgramScriptTarget(PerlCmd,ltx,ltx.prl,/*no flags*/,/*Makefile*/) +MsubProgramScriptTarget(PerlCmd,fastmake,fastmake.prl,/*no flags*/,/**/) +MsubProgramScriptTarget(PerlCmd,zap-if-same,zap-if-same.prl,/*no flags*/,/**/) +MsubProgramScriptTarget(PerlCmd,moan-if-old,moan-if-old.prl,/*no flags*/,/**/) +MsubProgramScriptTarget(PerlCmd,perltags,perltags.prl,/*no flags*/,/**/) + +MsubProgramScriptTarget(BourneShell,lmake,lmake.sh,/*no flags*/,/*no dep*/) + +/* +mkdependC has to go in "bin" directory, because there may be +machine-dependent ideas of what CC to use, etc. + +ltx, runstdtest: ditto, but only because of TMPDIR +*/ +MsubMakefileDependentProgramScriptTarget(PerlCmd,mkdependC,mkdependC.prl,/*noflags*/,/*Makefile*/) + +#ifdef UseCCMakeDepend +install:: + @echo "install makedepend (in ${CURRENT_DIR}) by hand..." +#endif +/* + lobotomized... install by hand... +#ifdef UseCCMakeDepend +InstallProgramTarget(makedepend,$(BINDIR)) +#endif +*/ + +/* === INSTALLATION ======== */ + +/* the rest of these vary from std/useful to hackish dans le extreme */ + +MakeDirectories(install, $(INSTBINDIR) $(INSTSCRIPTDIR)) +InstallScriptTarget(fastmake, $(INSTSCRIPTDIR)) +InstallScriptTarget(lmake, $(INSTSCRIPTDIR)) +InstallBinaryTarget(lndir, $(INSTBINDIR)) +InstallScriptTarget(ltx, $(INSTBINDIR)) +InstallScriptTarget(mkdependC, $(INSTBINDIR)) +InstallScriptTarget(mkdirhier, $(INSTSCRIPTDIR)) +InstallScriptTarget(perltags, $(INSTSCRIPTDIR)) +InstallScriptTarget(runstdtest, $(INSTBINDIR)) +InstallScriptTarget(zap-if-same, $(INSTSCRIPTDIR)) +InstallScriptTarget(moan-if-old, $(INSTSCRIPTDIR)) + +InstallManPageTarget(lndir,$(INSTCOMMANDIR),$(COMMANSUFFIX)) +InstallManPageTarget(mkdirhier,$(INSTCOMMANDIR),$(COMMANSUFFIX)) + +/* === OTHER STUFF ========= */ + +ExtraStuffToClean($(PROGRAMS)) + +ClearTagsFile() +PerlTagsTarget( *.prl ) /* nothing for the Bourne shell scripts */ diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/fastmake.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/fastmake.prl new file mode 100644 index 0000000000..388b4ed44d --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/fastmake.prl @@ -0,0 +1,126 @@ +#! /usr/local/bin/perl +# +($Pgm = $0) =~ s/.*\/([^\/]+)$/\1/; +$Usage = "\n" . <<EOUSAGE; +Usage: + $Pgm [-? or -help] [-k] [-n] [-v] [-t] dir/module-target(s) + +This script runs `make' to build the requested target, WITHOUT +including the dependencies generated by `mkdependHS' (i.e., all those +derived from import declarations). + +With a -t flag, it also sets the modification time of the resulting +.hi file (one target only, please) to some EARLY date, so that changes +to that interface will not trigger much useless recompilation. + +Typical uses, for module "Bar" in directory "foo": + +(1) You've changed "Bar" and you want to recompile it; you know that + other module interfaces are stable, so you'd rather do without all + of `make''s prognostications: + + $Pgm foo/Bar.s + +(2) You've ADDED a new function to "Bar"; you want to recompile that + module, BUT NOT TRIGGER LOTS OF FURTHER COMPILATION because of the + "changed" interface file: + + $Pgm -t foo/Bar.s + +USE AT YOUR OWN RISK: you can make a big mess with this script! +EOUSAGE + +$Makefile = 'Makefile'; +$Tmpfile = "/tmp/Makefile$$"; +chop($Arch = `/bin/arch`); +$SleazyTouch = '/usr/5bin/touch'; +$DoTouch = 0; +$Verbose = 0; +$MakeFlags = ''; + +sub rm_temp_file { + print STDERR "rm $Tmpfile\n" if $Verbose; + unlink $Tmpfile; + exit(1); +} +$SIG{'INT'} = 'rm_temp_file'; +$SIG{'QUIT'} = 'rm_temp_file'; + +$Target = ''; +$DirMod = ''; # the dir/module-file to make + +# process ARGV +while ($_ = $ARGV[0]) { + shift(@ARGV); + if (/^-\?$/ || /^-help$/) { + print $Usage; + exit 1; + } elsif (/^-v$/) { + $Verbose = 1; + } elsif (/^-t$/) { + $Do_touch = 1; + } elsif (/^-k$/) { + $MakeFlags .= ' -k'; + } elsif (/^-n$/) { + $MakeFlags .= ' -n'; + } elsif (/^-d$/) { + $MakeFlags .= ' -d'; + } elsif (/^-/) { + print STDERR "$Pgm: unknown option: $_\n\n$Usage"; + exit 1; + } elsif (/^([A-Z_]+)=(.+)/) { + $MakeFlags .= " $1=\"$2\""; + + } elsif ($Do_touch) { # the module file + $Target = $_; + if ( /([^\/]+\/[^\/\.]+)\.[a-z]+/ ) { + $DirMod = $1; + } else { + print STDERR "$Pgm: argument not of the form: directory/Module.suffix: $_\n\n$Usage"; + exit 1; + } + } else { # accumulate as "Target"... + $Target .= " $_"; + } +} + +if ($Do_touch && $Target =~ / /) { + print STDERR "$Pgm: too many arguments\n\n$Usage"; + exit 1; +} + +open(INF, "<$Makefile") || die "Can't open $Makefile for input\n"; + +open(OUTF,">$Tmpfile") || die "Can't open $Tmpfile for output\n"; +select(OUTF); + +$_ = <INF>; + +# copy through until ... +while ( $_ && ! /^# DO NOT DELETE: Beginning of Haskell dependencies/ ) { + print $_; + $_ = <INF>; +} + +# now copy through 'til the end, omittin the %.[so] : %.hi dependencies +while ( $_ ) { + print $_ if ! /^\S+ : \S+\.hi$/; + $_ = <INF>; +} + +close(INF); +close(OUTF); + +if ($Arch ne "sun3") { + $Make = 'make JMAKE=jmake LIT2PGM=lit2pgm LIT2LATEX=lit2latex LIT2TEXI=lit2texi MKDEPENDLIT=mkdependlit MAKEINFO=makeinfo POSTMAKEINFO=postmakeinfo'; +} else { + $Make = 'make'; +} +print STDERR "$Make $MakeFlags -f $Tmpfile $Target; rm $Tmpfile\n" if $Verbose; + +system( "$Make $MakeFlags -f $Tmpfile $Target; rm $Tmpfile" ); + +if ($Do_touch) { + print STDERR "$SleazyTouch -m 01010101 $DirMod\.hi\n" if $Verbose; + system( "$SleazyTouch -m 01010101 $DirMod\.hi" ); +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/lmake.sh b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lmake.sh new file mode 100644 index 0000000000..133405cb07 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lmake.sh @@ -0,0 +1,2 @@ +#! /bin/sh +make JMAKE=jmake LIT2PGM=lit2pgm LIT2LATEX=lit2latex LIT2TEXI=lit2texi MKDEPENDLIT=mkdependlit MAKEINFO=makeinfo POSTMAKEINFO=postmakeinfo $* diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.c b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.c new file mode 100644 index 0000000000..d365de6755 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.c @@ -0,0 +1,217 @@ +/* $XConsortium: lndir.c,v 1.5 91/07/21 15:52:11 rws Exp $ */ +/* Create shadow link tree (after X11R4 script of the same name) + Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */ + +/* Copyright 1990, Massachusetts Institute of Technology + + Permission to use, copy, modify, and distribute this program for any purpose + and without fee is hereby granted, provided that this copyright and + permission notice appear on all copies and supporting documentation, that + the name of MIT not be used in advertising or publicity pertaining to + distribution of this program without specific prior permission, and that + notice be given in supporting documentation that copying and distribution is + by permission of MIT. MIT makes no representations about the suitability of + this software for any purpose. It is provided "as is" without expressed or + implied warranty. +*/ + +/* From the original /bin/sh script: + + Used to create a copy of the a directory tree that has links for all + non-directories (except those named RCS or SCCS). If you are + building the distribution on more than one machine, you should use + this script. + + If your master sources are located in /usr/local/src/X and you would like + your link tree to be in /usr/local/src/new-X, do the following: + + % mkdir /usr/local/src/new-X + % cd /usr/local/src/new-X + % lndir ../X +*/ + +/*#include <X11/Xos.h> */ +#include <stdio.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <errno.h> + +#ifndef X_NOT_POSIX +#include <dirent.h> +#else +#ifdef SYSV +#include <dirent.h> +#else +#ifdef USG +#include <dirent.h> +#else +#include <sys/dir.h> +#ifndef dirent +#define dirent direct +#endif +#endif +#endif +#endif + +extern int errno; +int silent; + +void +quit (code, fmt, a1, a2, a3) +char *fmt; +{ + fprintf (stderr, fmt, a1, a2, a3); + putc ('\n', stderr); + exit (code); +} + +void +quiterr (code, s) +char *s; +{ + perror (s); + exit (code); +} + +void +msg (fmt, a1, a2, a3) +char *fmt; +{ + fprintf (stderr, fmt, a1, a2, a3); + putc ('\n', stderr); +} + + +/* Recursively create symbolic links from the current directory to the "from" + directory. Assumes that files described by fs and ts are directories. */ + +dodir (fn, fs, ts, rel) +char *fn; /* name of "from" directory, either absolute or + relative to cwd */ +struct stat *fs, *ts; /* stats for the "from" directory and cwd */ +int rel; /* if true, prepend "../" to fn before using */ +{ + DIR *df; + struct dirent *dp; + char buf[MAXPATHLEN + 1], *p; + char symbuf[MAXPATHLEN + 1]; + struct stat sb, sc; + int n_dirs; + + if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) { + msg ("%s: From and to directories are identical!", fn); + return 1; + } + + if (rel) + strcpy (buf, "../"); + else + buf[0] = '\0'; + strcat (buf, fn); + + if (!(df = opendir (buf))) { + msg ("%s: Cannot opendir", buf); + return 1; + } + + p = buf + strlen (buf); + *p++ = '/'; + n_dirs = fs->st_nlink; + while (dp = readdir (df)) { + strcpy (p, dp->d_name); + + if (n_dirs > 0) { + if (stat (buf, &sb) < 0) { + perror (buf); + continue; + } + + if (sb.st_mode & S_IFDIR) { + /* directory */ + n_dirs--; + if (dp->d_name[0] == '.' && + (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && + dp->d_name[2] == '\0'))) + continue; + if (!strcmp (dp->d_name, "RCS")) + continue; + if (!strcmp (dp->d_name, "SCCS")) + continue; + if (!silent) + printf ("%s:\n", buf); + if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) { + if (mkdir (dp->d_name, 0777) < 0 || + stat (dp->d_name, &sc) < 0) { + perror (dp->d_name); + continue; + } + } + if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) { + msg ("%s: is a link instead of a directory\n", dp->d_name); + continue; + } + if (chdir (dp->d_name) < 0) { + perror (dp->d_name); + continue; + } + dodir (buf, &sb, &sc, (buf[0] != '/')); + if (chdir ("..") < 0) + quiterr (1, ".."); + continue; + } + } + + /* non-directory */ + if (symlink (buf, dp->d_name) < 0) { + int saverrno = errno; + int symlen; + symlen = readlink(dp->d_name, symbuf, sizeof(symbuf) - 1); + errno = saverrno; + if (symlen > 0) + symbuf[symlen] = '\0'; + if (symlen < 0 || strcmp(symbuf, buf)) + perror (dp->d_name); + } + } + + closedir (df); + return 0; +} + + +main (ac, av) +int ac; +char **av; +{ + char *fn, *tn; + struct stat fs, ts; + + silent = 0; + if (ac > 1 && !strcmp(av[1], "-silent")) { + silent = 1; + } + if (ac < silent + 2 || ac > silent + 3) + quit (1, "usage: %s [-silent] fromdir [todir]", av[0]); + + fn = av[silent + 1]; + if (ac == silent + 3) + tn = av[silent + 2]; + else + tn = "."; + + /* to directory */ + if (stat (tn, &ts) < 0) + quiterr (1, tn); + if (!(ts.st_mode & S_IFDIR)) + quit (2, "%s: Not a directory", tn); + if (chdir (tn) < 0) + quiterr (1, tn); + + /* from directory */ + if (stat (fn, &fs) < 0) + quiterr (1, fn); + if (!(fs.st_mode & S_IFDIR)) + quit (2, "%s: Not a directory", fn); + + exit (dodir (fn, &fs, &ts, 0)); +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.man b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.man new file mode 100644 index 0000000000..ae5b4285bd --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.man @@ -0,0 +1,61 @@ +.TH LNDIR 1 "Release 5" "X Version 11" +.SH NAME +lndir \- create a shadow directory of symbolic links to another directory tree +.SH SYNOPSIS +.B lndir +fromdir [todir] +.SH DESCRIPTION +.I Lndir +makes a shadow copy +.I todir +of a directory tree +.I fromdir, +except that the shadow is not +populated with real files but instead with symbolic links pointing at +the real files in the +.I fromdir +directory tree. This is usually useful for maintaining source code for +different machine architectures. You create a shadow directory +containing links to the real source which you will have usually NFS +mounted from a machine of a different architecture, and then recompile +it. The object files will be in the shadow directory, while the +source files in the shadow directory are just symlinks to the real +files. +.PP +This has the advantage that if you update the source, you need not +propagate the change to the other architectures by hand, since all +source in shadow directories are symlinks to the real thing: just cd +to the shadow directory and recompile away. +.PP +The +.I todir +argument is optional and defaults to the current directory. The +.I fromdir +argument may be relative (e.g., ../src) and is relative to +.I todir +(not the current directory). +.PP +.ft B +Note that RCS and SCCS directories are not shadowed. +.ft +.PP +Note that if you add files, you must run +.I lndir +again. Deleting files is a more painful problem; the symlinks will +just point into never never land. +.SH BUGS +.I Patch +gets upset if it cannot change the files. You should never run +.I patch +from a shadow directory anyway. +.PP +You need to use something like +.nf + find todir -type l -print | xargs rm +.fi +to clear out all files before you can relink (if fromdir moved, for instance). +Something like +.nf + find . \\! -type d -print +.fi +will find all files that are not directories. diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.sh b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.sh new file mode 100644 index 0000000000..f09bf7f590 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/lndir.sh @@ -0,0 +1,85 @@ +#! /bin/sh + +# lndir - create shadow link tree +# +# $XConsortium: lndir.sh,v 1.8 91/04/15 17:55:03 rws Exp $ +# +# Used to create a copy of the a directory tree that has links for all +# non- directories (except those named RCS or SCCS). If you are +# building the distribution on more than one machine, you should use +# this script. +# +# If your master sources are located in /usr/local/src/X and you would like +# your link tree to be in /usr/local/src/new-X, do the following: +# +# % mkdir /usr/local/src/new-X +# % cd /usr/local/src/new-X +# % lndir ../X + +USAGE="Usage: $0 fromdir [todir]" + +if [ $# -lt 1 -o $# -gt 2 ] +then + echo "$USAGE" + exit 1 +fi + +DIRFROM=$1 + +if [ $# -eq 2 ]; +then + DIRTO=$2 +else + DIRTO=. +fi + +if [ ! -d $DIRTO ] +then + echo "$0: $DIRTO is not a directory" + echo "$USAGE" + exit 2 +fi + +cd $DIRTO + +if [ ! -d $DIRFROM ] +then + echo "$0: $DIRFROM is not a directory" + echo "$USAGE" + exit 2 +fi + +pwd=`pwd` + +if [ `(cd $DIRFROM; pwd)` = $pwd ] +then + echo "$pwd: FROM and TO are identical!" + exit 1 +fi + +for file in `ls -af $DIRFROM` +do + if [ ! -d $DIRFROM/$file ] + then + ln -s $DIRFROM/$file . + else + if [ $file != RCS -a $file != SCCS -a $file != . -a $file != .. ] + then + echo $file: + mkdir $file + (cd $file + pwd=`pwd` + case "$DIRFROM" in + /*) ;; + *) DIRFROM=../$DIRFROM ;; + esac + if [ `(cd $DIRFROM/$file; pwd)` = $pwd ] + then + echo "$pwd: FROM and TO are identical!" + exit 1 + fi + $0 $DIRFROM/$file + ) + fi + fi +done diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/ltx.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/ltx.prl new file mode 100644 index 0000000000..1bce758270 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/ltx.prl @@ -0,0 +1,215 @@ +$Pgm = $0; $Pgm =~ s/.*\/([^\/]+)$/\1/; +# +# set up signal handler +sub quit_upon_signal { &rm_temp_files_and_exit(); } +$SIG{'INT'} = 'quit_upon_signal'; +$SIG{'QUIT'} = 'quit_upon_signal'; +# +$Verbose = 0; +if ($ARGV[0] eq '-v') { + $Verbose = 1; + shift(@ARGV); +} +# +die "$Pgm: must have exactly one argument\n" if $#ARGV != 0; +# figure out input file and its filename root +if (-f $ARGV[0]) { + $TeX_input = $ARGV[0]; + if ($TeX_input =~ /(.+)\.[^\.\/\n]+$/) { + $TeX_root = $1; + } else { + $TeX_root = $TeX_input; + } +} elsif (-f $ARGV[0].'.tex') { + $TeX_input = $ARGV[0].'.tex'; + $TeX_root = $ARGV[0]; +} else { + die "$Pgm: input file $ARGV[0] doesn't exist\n"; +} + +sub rm_temp_files { + system("rm -f $(TMPDIR)/ltx-*.$$"); +} +sub rm_temp_files_and_exit { + system("rm -f $(TMPDIR)/ltx-*.$$"); + exit(1); +} +$SIG{'INT'} = 'rm_temp_files_and_exit'; +$SIG{'QUIT'} = 'rm_temp_files_and_exit'; + +sub die_gracefully { + local($msg) = @_; + + print STDERR $msg; + &rm_temp_files_and_exit(); +} + +# must read through root file to see if a \bibliography +# is there... +$Bibliography_requested = 0; +open(TEXIF, "<$TeX_input") + || &die_gracefully("$Pgm: Can't read $TeX_input\n"); +while (<TEXIF>) { + $Bibliography_requested = 1 if /^\\bibliography/; +} +close(TEXIF); +&die_gracefully("$Pgm: reading $TeX_input had errors\n") if $? >> 8; + +# run latex first time (?) +&run_latex(); # sets $Says_labels_changed +$Times_run = 1; + +while (&something_more_needed()) { + + print STDERR "labels_changed=$Says_label_changed;bibtex_needed=$BibTeX_run_needed;makeindex_needed=$MakeIndex_run_needed\n" if $Verbose; + + if ($BibTeX_run_needed) { + &run_bibtex(); + } + if ($MakeIndex_run_needed) { + unlink "$TeX_root.ind"; + (system("makeindex $TeX_root.idx") >> 8) + && &die_gracefully("$Pgm: makeindex $TeX_root.idx had errors\n"); + } + + # save (copy) .aux file as .aux-prev file for future ref + # ditto for .idx file + unlink "$TeX_root.aux-prev"; + (system("cp $TeX_root.aux $TeX_root.aux-prev") >> 8) + && &die_gracefully("$Pgm: cp $TeX_root.aux $TeX_root.aux-prev failed\n"); + if (-f "$TeX_root.idx") { + unlink "$TeX_root.idx-prev"; + (system("cp $TeX_root.idx $TeX_root.idx-prev") >> 8) + && &die_gracefully("$Pgm: cp $TeX_root.idx $TeX_root.idx-prev failed\n"); + } + + # run latex again + &run_latex(); # sets $Says_labels_changed + $Times_run++; + + if ($Times_run >= 4) { + print STDERR "*** I don't run LaTeX more than four times;\n"; + print STDERR "*** Something is probably wrong...\n"; + &rm_temp_files_and_exit(); + } +} +&rm_temp_files(); +exit(0); + +sub run_latex { + $Says_labels_changed = 0; + $Multiply_defined_labels = 0; + + select(STDERR); $| = 1; select(STDOUT); # no buffering on STDERR + print STDERR "$Pgm: *** running LaTeX...\n" if $Verbose; + unlink "$TeX_root.dvi"; + + open(LTXPIPE, "latex $TeX_input 2>&1 |") + || &die_gracefully("$Pgm: Can't run latex pipe\n"); + while (<LTXPIPE>) { + $Multiply_defined_labels = 1 if /^LaTeX Warning: Label .* multiply defined/; + $Says_labels_changed = 1 if /^LaTeX Warning: Label\(s\) may have changed/ + && ! $Multiply_defined_labels; + print STDERR $_; + } + close(LTXPIPE); + &die_gracefully("$Pgm: LaTeX run had errors\n") if $? >> 8; + + # sort .idx file, because this helps makeindex + # (can you say `bug'?) + if (-f "$TeX_root.idx") { + print STDERR "$Pgm: *** sorting $TeX_root.idx...\n" if $Verbose; + (system("sort $TeX_root.idx -o $TeX_root.idx") >> 8) + && &die_gracefully("$Pgm: sorting $TeX_root.idx failed\n"); + } + +} + +sub run_bibtex { # ugly because bibtex doesn't return a correct error status + local($bibtex_had_errors) = 0; + + print STDERR "$Pgm: *** running BibTeX...\n" if $Verbose; + unlink "$TeX_root.bbl"; + + $| = 1; # no buffering + open(BIBTXPIPE, "bibtex $TeX_root 2>&1 |") + || &die_gracefully("$Pgm: Can't run bibtex pipe\n"); + while (<BIBTXPIPE>) { + $bibtex_had_errors = 1 if /^\(There.*error message(s)?\)$/; + print STDERR $_; + } + close(BIBTXPIPE); + &die_gracefully("$Pgm: BibTeX run had errors\n") + if $? >> 8 || $bibtex_had_errors; +} + +sub something_more_needed { + # returns 1 or 0 if we need to run LaTeX + # possibly preceded by bibtex and/or makeindex run + + # $Says_labels_changed was set by previous &run_latex... + $BibTeX_run_needed = 0; + $MakeIndex_run_needed = 0; + + if ( ! -f ($TeX_root . '.aux-prev')) { # this was the first run + + print STDERR "$Pgm: *** 'twas first run of LaTeX on $TeX_input\n" if $Verbose; + + # we need makeindex to run if a non-zero-sized .idx file exists + # + $MakeIndex_run_needed = 1 + if -f "$TeX_root.idx" && -s "$TeX_root.idx"; + + # we need bibtex to run if there are \citations in the .aux file + # + &slurp_aux_file('aux'); + $BibTeX_run_needed = 1 + if $Bibliography_requested && + -f "$(TMPDIR)/ltx-aux-cite.$$" && + -s "$(TMPDIR)/ltx-aux-cite.$$"; + + + } else { # ltx had been run before (.aux-prev/.idx-prev files exist) + + # slurp both .aux and .aux-prev files + &slurp_aux_file('aux'); + &slurp_aux_file('aux-prev'); + + local($tmp_pre) = "$(TMPDIR)/ltx"; + + if ((-s "$tmp_pre-.aux-cite.$$") # there are still \cite's in there + && (system("cmp -s $tmp_pre-.aux-cite.$$ $tmp_pre-.aux-prev-cite.$$") >> 8)) { + $BibTeX_run_needed = 1 if $Bibliography_requested; + if ($Verbose) { + system("diff -c1 $tmp_pre-.aux-prev-cite.$$ $tmp_pre-.aux-cite.$$"); + } + } + + if (-f "$TeX_root.idx") { + $MakeIndex_run_needed = + (system("cmp -s $TeX_root.idx $TeX_root.idx-prev") >> 8) ? 1 : 0; + if ($MakeIndex_run_needed && $Verbose) { + system("diff -c1 $TeX_root.idx-prev $TeX_root.idx"); + } + } + } + + $Says_labels_changed || $BibTeX_run_needed || $MakeIndex_run_needed; +} + +sub slurp_aux_file { + local($ext) = @_; + + # copy all citations from slurpfile into $(TMPDIR)/ltx-$ext-cite.$$ + + open(SLURPF,"< $TeX_root.$ext") + || &die_gracefully("$Pgm: Can't open $TeX_root.$ext for reading\n"); + open(CITEF,"> $(TMPDIR)/ltx-$ext-cite.$$") + || &die_gracefully("$Pgm: Can't open $(TMPDIR)/ltx-$ext-cite.$$ for writing\n"); + + while (<SLURPF>) { + print CITEF $_ if /\\citation/; + } + close(CITEF); + close(SLURPF); +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/m5.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/m5.prl new file mode 100644 index 0000000000..f352f64e48 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/m5.prl @@ -0,0 +1,502 @@ +#!/usr/local/bin/perl -- # -*-Perl-*- +############################################################################## +# +# m5 is a poor-man's m4 +# +# written in March of 1991 by Bill Mann; tested with v3.044 of perl +# bill@ksr.com (ksr!bill@uunet.uu.net) +# +# This program may be used or modified for any purpose, but I would +# appreciate it if you would reports bugs and fixes to me, and credit +# yourself with any modifications you make. -bill +# +# I have mailed Larry Wall a fix for the 'perl bug' mentioned in the +# comments below. Once this bug is fixed, removing the 'redundant' +# double-quotes will provide some improvement in speed; the speed-up +# will be application dependent. -bill +# +############################################################################## + +#-- where I got it ----------------------------------------------------------- +#From: Adrian F Clark <alien@sx.ac.uk> +#To: partain +#Subject: Re: Macro-processor in Perl? +#Date: Thu, 25 Jul 91 09:43:05 BST +# +#"Ask and ye shall receive" ... this sounds like just what we both +#want! +# +#..a +# +#Date: Wed, 24 Jul 91 18:09:30 EDT +#From: bill%ksr.com@uk.ac.essex.mailhost +#To: "Adrian F Clark" <alien%sx.ac.uk@uk.ac.essex.mailhost> +#In-Reply-To: alien@essex.ac.uk's message of 24 Jul 91 09:32:13 EDT +#Subject: Re: Macro-processor in Perl? +#Sender: bill%ksr.com%ksr%uunet.uu.net@uk.ac.essex.mailhost +# +#I wrote a m4 clone, with just a couple of features missing, and a +#couple added, because the versions of m4 we had in-house, mostly from +#SUN, were either very old or buggy. +# +#The major missing feature is multiple separate output files. The +#major addition is that eval() now does a full-fledged perl eval, which +#'just happens' to include everything the m4 eval includes, in the same +#syntax. +# +#This program is in daily use, and has been tested by the author, but +#it is only used for a few applications, so problems may still be +#lurking. I'll be happy to answer a few questions, but can't promise +#to spend too much time, and I provide no guarantees. I call it m5 +#just keep it distinct from m4. +#----------------------------------------------------------------------------- + +# Auto identification +#$program_path = $0; +#$program_name = $program_path; +#$program_name =~ s:^.*/::; +#$cmd_line = join(' ', $program_name, @ARGV); +#$rcs_id = '$Id: m5,v 1.1 1991/03/12 19:48:13 bill Exp $ '; +select (STDERR); $| = 1; select (STDOUT); +#print STDERR "$program_path ", '$Revision: 1.1 $ ', "\n"; +#print STDERR $rcs_id, "\n"; + + +#eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';" +# while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV)); +#exit 255 if $die; # process any FOO=bar switches + +%D = ("changecom", "\000changecom", + "changequote", "\000changequote", + "decr", "\000decr", + "define", "\000define", + "defn", "\000defn", + "dnl", "\000dnl", + "dumpdef", "\000dumpdef", + "errprint", "\000errprint", + "eval", "\000eval", + "ifdef", "\000ifdef", + "ifelse", "\000ifelse", + "include", "\000include", + "incr", "\000incr", + "index", "\000index", + "len", "\000len", + "maketemp", "\000maketemp", + "m4exit", "\000m4exit", + "m4wrap", "\000m4wrap", + "popdef", "\000popdef", + "pushdef", "\000pushdef", + "repeat", "\000repeat", + "shift", "\000shift", + "substr", "\000substr", + "syscmd", "\000syscmd", + "undefine", "\000undefine", + "unix", "", + ); + +$ccp = 0; $file = ''; +@inc = ''; +while ($ARGV[0] =~ /^-./) { + $_ = shift(@ARGV); + /^-D(\w+)(=(.*))?$/ && ($D{$1} = (defined($3)? $3 : ''), next); + /^-U(\w+)$/ && (delete $D{$1}, next); + /^-e$/ && (next); # not implemented yet -bill + /^-s$/ && ($ccp = 1, next); + /^-I(.*)$/ && (push(@inc, ($1 || shift(@ARGV)) . '/'), next); + die "unrecognized switch: $_\n"; +} + +# other globals: @args, $ab, $mi, $lq, $rq, $skip +$ab = $mi = 0; # undef would be ok +$m4wrap = ''; + +$lcom = "\#"; +$rcom = "\n"; +&changequote; + +@ARGV || unshift(@ARGV, '-'); + +for (shift(@ARGV)) { # 'feature': each file must end cleanly + print &expand('', &openf($_)); +} +$m4wrap ne '' && print &expand($m4wrap, ''); +exit; + +sub openf { + $ARGV = $_[0]; + $FH = "F" . @FH; + open($FH, $ARGV) || die "Can't open '$ARGV': $@"; + $line = 0; + $ccp && printf ("#line %s \"%s\"\n", 1, $ARGV); + $FH; +} + +# $st states: +# 0: normal text, or reading macro arguments if $pf != 0 +# 1: quoted string +# 2: comment +# 3: starting to read an argument (skipping white space) + +# expand expands its input string, removing one layer of matching quotes; +# it expands defined symbols as long as they are not between quotes. +# whenever it reaches the end of the string it reads a new line and extends +# its input if possible; if it can't it returns errors if in a macro +# argument or in a quoted string. +sub expand { + local($in,$FH) = @_; + local($i,$st,$qn,$pn) = (0,0,0,0); # used recursively + local($ci,$pi,$t); # not used recursively, but declared anyway + + while (1) { # for 'each' character + if ($i == length($in)) { + if ($FH) { + unless ($pn) { # defer output while reading macro arguments + print $in; + $in = ''; + $i = $ci = 0; + } + + if ($t = <$FH>) { + $in .= $t; + $line++; + next; # process next line + } + + close($FH); + + if (@argv) { + $FH = pop(@FH); + $ARGV = pop(@argv); + $line = pop(@line); + $in .= pop(@in); + $ccp && printf ("#line %s \"%s\"\n", $line, $ARGV); + next; + } + } + $st == 1 && die "missing close quote\n"; + $st == 2 && die "missing close comment\n"; + $pn && die "missing close parenthesis\n"; + last; + } + +## substr($in, $i) =~ $skip && ($i += length($&)) == length($in) && next; + substr($in, $i) =~ /^[ \t0-9]+/ && + ($i += length($&)) == length($in) && next; + + if ($st == 1) { # if in a quoted string + if (substr($in, $i, length($rq)) eq $rq) { + if (--$qn) { + $i += length($rq); + } else { + substr($in, $i, length($rq)) = ''; + $st = 0; + } + next; + } + if (substr($in, $i, length($lq)) eq $lq) { + ++$qn; + $i += length($lq); + next; + } + ++$i; + next; + } + elsif ($st == 2) { # if in a comment + if (($i = index($in, $rcom, $i)) == -1) { # extends past eol + $i = length($in); + next; + } + + $i += length($rcom); + if ($pn) { # if in parens + substr($in, $ci, $i-$ci) = ''; + $i = $ci; + $rcom eq "\n" && (substr($in, $i++, 0) = "\n"); + } + $st = 0; + next; + } + elsif ($st == 3) { # if starting an argument + substr($in, $pi, $i-$pi+1) =~ s/^(\s*)(\S)/$2/ && + ($i -= length($1), $st = 0); + } + + if (substr($in, $i, length($lq)) eq $lq && $lq) { + substr($in, $i, length($lq)) = ''; + $st = $qn = 1; + next; + } + + if (substr($in, $i, length($lcom)) eq $lcom && $lcom) { + $i += length($lcom); + $ci = $i; + $st = 2; + next; + } + + if ($pn) { + $t = substr($in, $i, 1); + if ($t eq '(') { + ++$pn; + ++$i; + next; + } + elsif ($t eq ',') { + if ($pn == 1) { + push(@args, substr($in, $pi, $i-$pi)); + $pi = $i+1; + $st = 3; + } + ++$i; + next; + } + elsif ($t eq ')') { + if (--$pn == 0) { + push(@args, substr($in, $pi, $i-$pi)); + ++$i; + &callm; + $pi = pop(@pi); + $pn = pop(@pn); + next; + } + ++$i; + next; + } + } + + substr($in, $i) =~ /^([a-z_]\w*)(\()?/i || (++$i, next); + defined($D{$1}) || ($i += length($1), next); + + push(@ab, $ab); + push(@args, $1); + $ab = $#args; + push(@mi, $mi); + $mi = $i; + $i += length($&); + + if ($2) { + push(@pi, $pi); + push(@pn, $pn); + $pi = $i; + $pn = 1; + $st = 3; + next; + } + + &callm; + } + $in; +} + +sub callm { + + if (($t = $D{$args[$ab]}) =~ s/^\000//) { + $t = &$t; # may recurse here + } else { + $t =~ s/\$(\#|\*|\@|\d)/$1 eq '#' ? $#args-$ab : + $1 eq '*' ? join(',', @args[$ab+1..$#args]) : + $1 eq '@' ? join(',', "elist(@args[$ab+1..$#args])) : + $args[$ab+$1]/ge; + } + + $ccp && + (substr($in, $mi, $i-$mi) =~ tr/\n/\n/) != ($t =~ tr/\n/\n/) && + ($t =~ s/\n$//, + $t .= sprintf("\n#line %s \"%s\"\n", $line, $ARGV)); + substr($in, $mi, $i-$mi) = $t; + + $i = $mi; # rescan + $#args = $ab-1; + $mi = pop(@mi); + $ab = pop(@ab); +} + +sub quotelist { + local(@T); + for (@_) { + push(@T, $lq . $_ . $rq); + } + @T; +} + +sub setskip { + ($skip = "$lcom$rcom$lq$rq(,)") =~ s/(\W)/\\$1/g; + $skip = "^[^a-zA-Z_$skip]+"; +} + +# m5 functions: + +sub changecom { + $lcom = $args[$ab+1]; + $rcom = $args[$ab+2] || "\n"; + &setskip; + ""; +} + +sub changequote { + $lq = $args[$ab+1]; + $rq = $args[$ab+2] || $lq; + if ($#args <= $ab) { # if no arguments at all + $lq = "\`"; + $rq = "\'"; + } + &setskip; + ""; +} + +sub decr { + $t = $args[$ab+1] - 1; + "$t"; # quotes required for perl bug +} + +sub define { + $args[$ab+1] =~ /^[a-z_]\w*$/i || die "bad macro name: '$args[$ab+1]'\n"; + $D{$args[$ab+1]} = $args[$ab+2]; + ""; +} + +sub defn { + $t = ''; + for (@args[$ab+1..$#args]) { + $t .= $lq . $D{$_} . $rq; + } + $t; +} + +sub dnl { + substr($in, $i) =~ s/[^\n]*\n?//; + ""; +} + +sub dumpdef { + for (sort(keys %D)) { + if (($t = $D{$_}) =~ s/^\000//) { + printf STDERR ("%s:\t<%s>\n", $_, $t); + } else { + printf STDERR ("%s:\t%s%s%s\n", $_, $lq, $t, $rq); + } + } + ""; +} + +sub errprint { + print STDERR $args[$ab+1], "\n"; + ""; +} + +sub eval { + local($r) = int($args[$ab+2]); + package m5; + $main't = eval $main'args[$main'ab+1]; #']; + package main; + $@ && die "eval($args[$ab+1]) failed: $@\n"; + if ($r > 1 && $t =~ s/^(-)?(\d+)$//) { # if a radix is specified + local($d) = $2; + do { + $t = ('0'..'9','A'..'Z')[$d % $r] . $t; + $d = int($d / $r); + } while $d; + + $d = $args[$ab+3] - length($t); + $d > 0 && ($t = ('0' x $d) . $t); + $t = $1 . $t; + } + "$t"; # quotes required for perl bug +} + +sub ifdef { + defined($D{$args[$ab+1]}) ? $args[$ab+2] : $args[$ab+3]; +} + +sub ifelse { + for ($t = $ab+1; $t < $#args; $t += 3) { + $args[$t] eq $args[$t+1] && return "$args[$t+2]"; + } + return "$args[$t]"; # quotes required for perl bug +} + +sub include { + for (@inc) { # search -I list + $t = "$_$args[$ab+1]"; + if (-f $t) { + push(@FH, $FH); + push(@argv, $ARGV); + push(@line, $line); + push(@in, substr($in, $i)); + substr($in, $i) = ''; + &openf($t); + return ""; + } + } + die "Can't find include file $args[$ab+1]"; +} + +sub incr { + $t = $args[$ab+1] + 1; + "$t"; # quotes required for perl bug +} + +sub index { + $t = index($args[$ab+1], $args[$ab+2]); + "$t"; # quotes required for perl bug +} + +sub len { + $t = length($args[$ab+1]); + "$t"; # quotes required for perl bug +} + +sub maketemp { + ($t = $args[$ab+1]) =~ s/X{1,6}$/a$$/; # via experiments + "$t"; # quotes required for perl bug +} + +sub m4exit { + exit($args[$ab+1]); +} + +sub m4wrap { + $m4wrap = $args[$ab+1]; + ""; +} + +sub popdef { + eval "\$D{$args[$ab+1]} = pop(@M5'$args[$ab+1])"; + ""; +} + +sub pushdef { + eval "push(@M5'$args[$ab+1], \$D{$args[$ab+1]})"; + $D{$args[$ab+1]} = $args[$ab+2]; + ""; +} + +sub repeat { # repeat(#, expr); evals expr # times; $0 = 0..#-1 + local($t); + for ($args[$ab] = 0; $args[$ab] < $args[$ab+1]; $args[$ab]++) { + $t .= &expand($args[$ab+2], ''); + } + $t; +} + +sub shift { + join(',', "elist(@args[$ab+2..$#args])); +} + +sub substr { + $t = substr($args[$ab+1], $args[$ab+2], $args[$ab+3] || 1000000000); + "$t"; # quotes required for perl bug +} + +sub syscmd { + $m5'sysval = system($args[$ab+1]); #' this is wrong, but close + ""; +} + +sub undefine { + delete $D{$args[$ab+1]}; + ""; +} + +- ---------------------- end ---------------------- + diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdependC.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdependC.prl new file mode 100644 index 0000000000..edffc6b7ba --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdependC.prl @@ -0,0 +1,186 @@ +# *** MSUB does some substitutions here *** +# *** grep for $( *** +# +# tries to work like mkdependC +# +# ToDo: strip out all the .h junk +# +($Pgm = $0) =~ s/.*\/([^\/]+)$/\1/; +$Usage = "usage: $Pgm: not done yet\n"; + +$Status = 0; # just used for exit() status +$Verbose = ''; +$Dashdashes_seen = 0; + +$Begin_magic_str = "# DO NOT DELETE: Beginning of C dependencies\n"; +$End_magic_str = "# DO NOT DELETE: End of C dependencies\n"; +$Obj_suffix = '.o'; +@Defines = (); +$Include_dirs = ''; +$Col_width = 78; # ignored +$Makefile = ''; +@Src_files = (); + +&mangle_command_line_args(); + +if ( ! $Makefile && -f 'makefile' ) { + $Makefile = 'makefile'; +} elsif ( ! $Makefile && -f 'Makefile') { + $Makefile = 'Makefile'; +} else { + die "$Pgm: no makefile or Makefile found\n"; +} + +@Depend_lines = (); +%Depend_seen = (); + +print STDERR "CPP defines=@Defines\n" if $Verbose; +print STDERR "Include_dirs=$Include_dirs\n" if $Verbose; + +foreach $sf (@Src_files) { + # just like lit-inputter + # except it puts each file through CPP and + # a de-commenter (not implemented); + # builds up @Depend_lines + print STDERR "Here we go for source file: $sf\n" if $Verbose; + ($of = $sf) =~ s/\.(c|hc)$/$Obj_suffix/; + + &slurp_file($sf, 'fh00'); +} + +# OK, mangle the Makefile +unlink("$Makefile.bak"); +rename($Makefile,"$Makefile.bak"); +# now copy Makefile.bak into Makefile, rm'ing old dependencies +# and adding the new +open(OMKF,"< $Makefile.bak") || die "$Pgm: can't open $Makefile.bak: $!\n"; +open(NMKF,"> $Makefile") || die "$Pgm: can't open $Makefile: $!\n"; +select(NMKF); +$_ = <OMKF>; +while ($_ && $_ ne $Begin_magic_str) { # copy through, 'til Begin_magic_str + print $_; + $_ = <OMKF>; +} +while ($_ && $_ ne $End_magic_str) { # delete 'til End_magic_str + $_ = <OMKF>; +} +# insert dependencies +print $Begin_magic_str; +print @Depend_lines; +print $End_magic_str; +while (<OMKF>) { # copy the rest through + print $_; +} +close(NMKF); +close(OMKF); +chmod 0444, 'Makefile'; +exit 0; + +sub mangle_command_line_args { + while($_ = $ARGV[0]) { + shift(@ARGV); + + if ( /^--$/ ) { + $Dashdashes_seen++; + + } elsif ( /^-D(.*)/ ) { # recognized wherever they occur + push(@Defines, $_); + } elsif ( /^-I/ ) { + $Include_dirs .= " $_"; + + } elsif ($Dashdashes_seen != 1) { # not between -- ... -- + if ( /^-v$/ ) { + $Verbose = '-v'; + } elsif ( /^-f/ ) { + $Makefile = &grab_arg_arg($_); + } elsif ( /^-o/ ) { + $Obj_suffix = &grab_arg_arg($_); + } elsif ( /^-bs/ ) { + $Begin_magic_str = &grab_arg_arg($_) . "\n"; + } elsif ( /^-es/ ) { + $End_magic_str = &grab_arg_arg($_) . "\n"; + } elsif ( /^-w/ ) { + $Width = &grab_arg_arg($_); + } elsif ( /^-/ ) { + print STDERR "$Pgm: unknown option ignored: $_\n"; + } else { + push(@Src_files, $_); + } + + } elsif ($Dashdashes_seen == 1) { # where we ignore unknown options + push(@Src_files,$_) if ! /^-/; + } + } +} + +sub grab_arg_arg { + local($option) = @_; + local($rest_of_arg); + + ($rest_of_arg = $option) =~ s/^-.//; + + if ($rest_of_arg) { + return($rest_of_arg); + } elsif ($#ARGV >= 0) { + local($temp) = $ARGV[0]; shift(@ARGV); + return($temp); + } else { + die "$Pgm: no argument following $option option\n"; + } +} + +sub slurp_file { # follows an example in the `open' item in perl man page + local($fname,$fhandle) = @_; + local($depend); # tmp + $fhandle++; # a string increment + + $fname = &tidy_dir_names($fname); + + unless (open($fhandle, "$(CPP) $Include_dirs @Defines $fname |")) { + die "$Pgm: Can't open $fname: $!\n"; + } + line: while (<$fhandle>) { + next line if ! /^#/; + next line if /^#(ident|pragma)/; + chop; # rm trailing newline + + $_ = &tidy_dir_names($_); + + # strip junk off the front and back + $_ =~ s/^#\s+\d+\s+//; + $_ =~ s/[ 0-9]*$//; + + # a little bit of ad-hoc fiddling now: + # don't bother w/ dependencies on /usr/include stuff + # don't bother if it looks like a GCC built-in hdr file + # don't bother with "literate" .h files (.lh); we'll just + # depend on the de-litified versions (which have better info) + # don't let a file depend on itself + next line if /^\/usr\/include/; + next line if /\/gcc-lib\/[^\/\n]+\/[\.0-9]+\/include\//; + next line if /\.lh$/; + next line if $_ eq $fname; + + print STDERR "$fname :: $_\n" if $Verbose; + + # ToDo: some sanity checks that we still have something reasonable? + + $depend = "$of : $_\n"; + next line if $Depend_seen{$depend}; # already seen this one... + + # OK, it's a new one. + push (@Depend_lines, $depend); + $Depend_seen{$depend} = 1; + } + close($fhandle); +} + +sub tidy_dir_names { # rm various pernicious dir-name combinations... + local($str) = @_; + + $str =~ s|/[^/.][^/]*/\.\.||g; # nuke: /<dir>/.. + $str =~ s|/\.[^.][^/]*/\.\.||g; # nuke: /./.. (and others) + $str =~ s|"||g; + $str =~ s| \./| |; + $str; +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdirhier.man b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdirhier.man new file mode 100644 index 0000000000..999fa12822 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdirhier.man @@ -0,0 +1,15 @@ +.TH MKDIRHIER 1 "Release 4" "X Version 11" +.SH NAME +mkdirhier \- makes a directory hierarchy +.SH SYNOPSIS +.B mkdirhier +directory ... +.SH DESCRIPTION +The +.I mkdirhier +command creates the specified directories. Unlike +.I mkdir +if any of the parent directories of the specified directory +do not exist, it creates them as well. +.SH "SEE ALSO" +mkdir(1) diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdirhier.sh b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdirhier.sh new file mode 100644 index 0000000000..739535e118 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkdirhier.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# +# create a heirarchy of directories +# + +for f in $*; do + parts=`echo $f | sed 's,\(.\)/\(.\),\1 \2,g' | sed 's,/$,,'`; + path=""; + for p in $parts; do + if [ x"$path" = x ]; then + dir=$p; + else + dir=$path/$p; + fi; + if [ ! -d $dir ]; then + echo mkdir $dir; + mkdir $dir; + chmod a+rx $dir; + fi; + path=$dir; + done; +done + diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkshadowfile.sh b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkshadowfile.sh new file mode 100644 index 0000000000..a00ede08e0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/mkshadowfile.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# +# create a heirarchy of directories (mkdir that makes everything) +# + +USAGE="Usage: $0 master-src-dir-root shadow-src-dir-root filename-from-master-root" + +for f in $*; do + parts=`echo $f | sed 's,\(.\)/\(.\),\1 \2,g' | sed 's,/$,,'`; + path=""; + for p in $parts; do + if [ x"$path" = x ]; then + dir=$p; + else + dir=$path/$p; + fi; + if [ ! -d $dir ]; then + echo mkdir $dir; + mkdir $dir; + chmod a+rx $dir; + fi; + path=$dir; + done; +done +exit 0 diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/moan-if-old.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/moan-if-old.prl new file mode 100644 index 0000000000..9b7c0b98bc --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/moan-if-old.prl @@ -0,0 +1,49 @@ +# "moan" if files in this directory tree appear to be out-of-date +# with respect to a given "master directory". +# +# a utility to use with link trees! +# +# usage: +# % moan-if-old /src/ghc-master-copy + +$Verbose = 1; +$Usage = "usage: moan-if-old master-dir\n"; + +if ($#ARGV != 0) { + die $Usage; +} else { + $Master_dir = $ARGV[0]; + die "no such dir: $Master_dir\n$Usage" if ! -d $Master_dir; +} + +open(F,"find . -type f -print |") || die "Cannot open find ($!)"; +while (<F>) { + chop; + + if (! -f "$Master_dir/$_" && ! &junk_file($_) ) { + print STDERR "$_ : not in master directory\n"; + + } elsif (-f "$Master_dir/$_") { + + $f1 = "$Master_dir/$_"; + $f2 = $_; + + @m_dope = stat($f1); + @s_dope = stat($f2); + if ($m_dope[9] > $s_dope[9]) { # those are modification times... + print STDERR "$f1 ($m_dope[9]) > $f2 ($s_dope[9])\n" if $Verbose; + print STDERR "$_ : older\n"; + } + } +} +close(F); + +sub junk_file { + local($_) = @_; + + if ( /~$/ || /\.bak$/ || /-(PREV|OLD|SAVE|NEW)$/ ) { + return(1); + } else { + return(0); + } +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/perltags.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/perltags.prl new file mode 100644 index 0000000000..d7bf6129cb --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/perltags.prl @@ -0,0 +1,69 @@ +# perl tags, in perl. +# @(#)ptags 1.2 4/11/91, no copyright. Bugfixes to lm@eng.sun.com. + +#In the hack-of-the-hour catagory, a tags file generator for perl. Differences +#from ctags: +# +# 1) Puts a tag in for the filename +# 2) Puts in multiple tags for the same symbol (I have a hacked version +# of vi that groks this). + +# tag file <vi expresion to find it> +# catch /u/lm/tmp/eintr.c /^catch() {}$/ + +if ($#ARGV == -1) { + unshift(@ARGV, "-"); +} +open(STDOUT, ">> TAGS") || die "can't create TAGS"; # partain: NB: APPEND +while ($_ = shift) { + next unless -f $_; + print STDERR "$_\n" if $v; + do file($_); +} +exit; + +sub file +{ + local($name) = $_[0]; + + open(F, $name) || return; + $entries = ''; + $lcnt = 1; + $ccnt = 0; + + while (<F>) { + # skip the word sub in comments + next unless /^[^#]*\bsub\b/; + # skip the word sub in a string (one line only, I'm lazy) + next if /"[^"]*sub/; +# print "$name: $. $_" if $d; + # demand that "sub" is first on the line (partain) + # (the initial > is for some literate perl scripts...) + next if ! /^>?\s*sub\s+/; + chop; + # rm comments + s/#.*$//; + # and here's the entry... + $entries .= "$_\x7f$lcnt,$ccnt\n"; + $lcnt++; + $ccnt += length($_); + } + # print tag for filename + print "\f\n$name,",length($entries),"\n"; + print $entries; +} + +###I've always used this. Don't recall whom I got it from... +## +##--tom +## +###!/usr/local/bin/perl +#open(OUTPUT, "| sort >> TAGS"); +#while (<>) { +# if (/\bsub\s+(\w+')?(\S+)/) { +# $func = $2; +# chop; +# s,[\\\[\]/.*],\\$&,g; +# print OUTPUT "$func\t", $ARGV, "\t/^$_\$/\n"; +# } +#} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/runstdtest.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/runstdtest.prl new file mode 100644 index 0000000000..48e6cc28a8 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/runstdtest.prl @@ -0,0 +1,184 @@ +#! /usr/local/bin/perl +# +# Given: +# * a program to run (1st arg) +# * some "command-line opts" ( -O<opt1> -O<opt2> ... ) +# [default: anything on the cmd line this script doesn't recognise ] +# the first opt not starting w/ "-" is taken to be an input +# file and (if it exists) is grepped for "what's going on here" +# comments (^--!!!). +# * a file to feed to stdin ( -i<file> ) [default: /dev/null ] +# * a "time" command to use (-t <cmd>). +# +# * alternatively, a "-script <script>" argument says: run the +# named Bourne-shell script to do the test. It's passed the +# pgm-to-run as the one-and-only arg. +# +# Run the program with those options and that input, and check: +# if we get... +# +# * an expected exit status ( -x <val> ) [ default 0 ] +# * expected output on stdout ( -o1 <file> ) [ default /dev/null ] +# * expected output on stderr ( -o2 <file> ) [ default /dev/null ] +# +# (if the expected-output files' names end in .Z, then +# they are uncompressed before doing the comparison) +# +# (This is supposed to be a "prettier" replacement for runstdtest.) +# +($Pgm = $0) =~ s|.*/||; +$Verbose = 0; +$Status = 0; +@PgmArgs = (); +$PgmExitStatus = 0; +$PgmStdinFile = '/dev/null'; +$PgmStdoutFile = '/dev/null'; +$PgmStderrFile = '/dev/null'; +$AltScript = ''; +$TimeCmd = ''; + +die "$Pgm: program to run not given as first argument\n" if $#ARGV < 0; +$ToRun = $ARGV[0]; shift(@ARGV); +# avoid picking up same-named thing from somewhere else on $PATH... +$ToRun = "./$ToRun" if $ToRun !~ /^\//; + +arg: while ($_ = $ARGV[0]) { + shift(@ARGV); + + /^-v$/ && do { $Verbose = 1; next arg; }; + /^-O(.*)/ && do { push(@PgmArgs, &grab_arg_arg('-O',$1)); next arg; }; + /^-i(.*)/ && do { $PgmStdinFile = &grab_arg_arg('-i',$1); + $Status++, + print STDERR "$Pgm: bogus -i input file: $PgmStdinFile\n" + if ! -f $PgmStdinFile; + next arg; }; + /^-x(.*)/ && do { $PgmExitStatus = &grab_arg_arg('-x',$1); + $Status++ , + print STDERR "$Pgm: bogus -x expected exit status: $PgmExitStatus\n" + if $PgmExitStatus !~ /^\d+$/; + next arg; }; + /^-o1(.*)/ && do { $PgmStdoutFile = &grab_arg_arg('-o1',$1); + $Status++ , + print STDERR "$Pgm: bogus -o1 expected-output file: $PgmStdoutFile\n" + if ! -f $PgmStdoutFile; + next arg; }; + /^-o2(.*)/ && do { $PgmStderrFile = &grab_arg_arg('-o2',$1); + $Status++, + print STDERR "$Pgm: bogus -o2 expected-stderr file: $PgmStderrFile\n" + if ! -f $PgmStderrFile; + next arg; }; + /^-script(.*)/ && do { $AltScript = &grab_arg_arg('-script',$1); + next arg; }; + /^-t(.*)/ && do { $TimeCmd = &grab_arg_arg('-t', $1); next arg; }; + + # anything else is taken to be a pgm arg + push(@PgmArgs, $_); +} +exit 1 if $Status; + +# tidy up the pgm args: +# (1) look for the "first input file" +# and grep it for "interesting" comments (--!!! ) +# (2) quote any args w/ whitespace in them. +$grep_done = 0; +foreach $a ( @PgmArgs ) { + if (! $grep_done && $a !~ /^-/ && -f $a) { + print `egrep "^--!!!" $a`; + $grep_done = 1; + } + if ($a =~ /\s/ || $a =~ /'/) { + $a =~ s/'/\\'/g; # backslash the quotes; + $a = "\"$a\""; # quote the arg + } +} + +if ($AltScript ne '') { + local($to_do); + $to_do = `cat $AltScript`; + # glue in pgm to run... + $* = 1; + $to_do =~ s/^\$1 /$ToRun /; + &run_something($to_do); + exit 0; +# exec "$AltScript $ToRun"; +# print STDERR "Failed to exec!!! $AltScript $ToRun\n"; +# exit 1; +} + +# OK, so we're gonna do the normal thing... + +$Script = <<EOSCRIPT; +#! /bin/sh +myexit=0 +diffsShown=0 +$TimeCmd /bin/sh -c \'$ToRun @PgmArgs < $PgmStdinFile 1> $(TMPDIR)/runtest$$.1 2> $(TMPDIR)/runtest$$.2\' +progexit=\$? +if [ \$progexit -ne $PgmExitStatus ]; then + echo $ToRun @PgmArgs \\< $PgmStdinFile + echo expected exit status $PgmExitStatus not seen \\; got \$progexit + myexit=1 +else + if cmp -s $PgmStdoutFile $(TMPDIR)/runtest$$.1 ; then + echo -n "" # no-op + else + echo $ToRun @PgmArgs \\< $PgmStdinFile + echo expected stdout not matched by reality + diff -c1 $PgmStdoutFile $(TMPDIR)/runtest$$.1 + myexit=1 + diffsShown=1 + fi +fi +if cmp -s $PgmStderrFile $(TMPDIR)/runtest$$.2 ; then + echo -n "" # no-op +else + echo $ToRun @PgmArgs \\< $PgmStdinFile + echo expected stderr not matched by reality + diff -c1 $PgmStderrFile $(TMPDIR)/runtest$$.2 + myexit=1 + diffsShown=1 +fi +$(RM) core $(TMPDIR)/runtest$$.1 $(TMPDIR)/runtest$$.2 +exit \$myexit +EOSCRIPT + +&run_something($Script); +# print $Script if $Verbose; +# open(SH, "| /bin/sh") || die "Can't open shell pipe\n"; +# print SH $Script; +# close(SH); + +exit 0; + +sub grab_arg_arg { + local($option, $rest_of_arg) = @_; + + if ($rest_of_arg) { + return($rest_of_arg); + } elsif ($#ARGV >= 0) { + local($temp) = $ARGV[0]; shift(@ARGV); + return($temp); + } else { + print STDERR "$Pgm: no argument following $option option\n"; + $Status++; + } +} + +sub run_something { + local($str_to_do) = @_; + + print STDERR "$str_to_do\n" if $Verbose; + + local($return_val) = 0; + system($str_to_do); + $return_val = $?; + + if ($return_val != 0) { +#ToDo: this return-value mangling is wrong +# local($die_msg) = "$Pgm: execution of the $tidy_name had trouble"; +# $die_msg .= " (program not found)" if $return_val == 255; +# $die_msg .= " ($!)" if $Verbose && $! != 0; +# $die_msg .= "\n"; + + exit (($return_val == 0) ? 0 : 1); + } +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/scripts/zap-if-same.prl b/web/glasgow/lit2x-0.16/grasp-utils/scripts/zap-if-same.prl new file mode 100644 index 0000000000..1bdb69ca99 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/scripts/zap-if-same.prl @@ -0,0 +1,50 @@ +# "zap" files in a directory tree if they're the same as somewhere else +# +# zap normally means "rm", but "-s" means to put a symlink in place instead. +# +# usage: +# # delete all files in this dir that are same as in master copy... +# % zap-if-same /src/ghc-master-copy +# # use lndir to put in mere links... +# % lndir /src/ghc-master-copy +# +# a similar effect can be had with just... +# % zap-if-same -s /src/ghc-master-copy + +$Usage = "usage: zap-if-same [-s] master-dir\n"; + +$Action = 'rm'; + +if ($#ARGV >= 0 && $ARGV[0] eq '-s') { + $Action = 'link'; + shift; +} + +if ($#ARGV != 0) { + die $Usage; +} else { + $Master_dir = $ARGV[0]; + die "no such dir: $Master_dir\n$Usage" if ! -d $Master_dir; +} + +open(F,"find . -type f -print |") || die "Cannot open find ($!)"; +while (<F>) { + chop; + + if ( -f "$Master_dir/$_" && &same_contents($_) ) { # ToDo: & not same file? + print STDERR "$_ ...\n"; + unlink $_; + if ($Action eq 'link') { + symlink("$Master_dir/$_", $_); + } + } +} +close(F); + +sub same_contents { + local($f) = @_; + + local($return_val) = 0; + $return_val = system("cmp -s $Master_dir/$f $f") >> 8; + ($return_val == 0) ? 1 : 0; +} diff --git a/web/glasgow/lit2x-0.16/grasp-utils/verbatim/Jmakefile b/web/glasgow/lit2x-0.16/grasp-utils/verbatim/Jmakefile new file mode 100644 index 0000000000..3a2b000b98 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/verbatim/Jmakefile @@ -0,0 +1,4 @@ +BuildPgmFromCFiles(verbatim,verbatim.o,-ll,) +InstallBinaryTarget(verbatim,$(INSTBINDIR)) + +CDependTarget( $(SRCS_C) ) diff --git a/web/glasgow/lit2x-0.16/grasp-utils/verbatim/verbatim.c b/web/glasgow/lit2x-0.16/grasp-utils/verbatim/verbatim.c new file mode 100644 index 0000000000..9d82abe2d9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/verbatim/verbatim.c @@ -0,0 +1,533 @@ +# include "stdio.h" +# define U(x) x +# define NLSTATE yyprevious=YYNEWLINE +# define BEGIN yybgin = yysvec + 1 + +# define INITIAL 0 +# define YYLERR yysvec +# define YYSTATE (yyestate-yysvec-1) +# define YYOPTIM 1 +# define YYLMAX BUFSIZ +# define output(c) putc(c,yyout) +# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar) +# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;} +# define yymore() (yymorfg=1) +# define ECHO fprintf(yyout, "%s",yytext) +# define REJECT { nstr = yyreject(); goto yyfussy;} +int yyleng; extern char yytext[]; +int yymorfg; +extern char *yysptr, yysbuf[]; +int yytchar; +FILE *yyin = {stdin}, *yyout = {stdout}; +extern int yylineno; +struct yysvf { + struct yywork *yystoff; + struct yysvf *yyother; + int *yystops;}; +struct yysvf *yyestate; +extern struct yysvf yysvec[], *yybgin; + /* This Lex script acts as a filter to pre-process Latex files. + It surrounds groups of lines beginning with a ">" sign, and + preceded and followed by a blank line, with \begin{verbatim} + and \end{verbatim}. The ">" may be preceded by a digit or digit + range (eg 4>, 2-5>, 3->); in this case the digits are removed. + They are meant to be used for filtering out versions. + It takes words surrounded with @ signs (thus @letrec@) and makes them + come out in typewriter font, regardless of the current mode. + */ +# define NORM 2 +# define VERB 4 +# define MIRANDA 6 +# define VERBATIM 8 +# define VERBATIMSIM 10 +#define PUSH states[top++] = +#define POP BEGIN states[--top] +# define YYNEWLINE 10 +yylex(){ +int nstr; extern int yyprevious; + int states[256]; + int top; + BEGIN NORM; + top = 0; +while((nstr = yylook()) >= 0) +yyfussy: switch(nstr){ +case 0: +if(yywrap()) return(0); break; +case 1: + { printf ("@"); } +break; +case 2: + { printf ("\\mbox{\\tt "); PUSH NORM; BEGIN VERB; } +break; +case 3: + { printf ("}"); POP; } +break; +case 4: + { printf ("}\\\\{}\n\\mbox{\\tt "); } +break; +case 5: + { printf ("\\ "); } +break; +case 6: + { printf ("@"); } +break; +case 7: + { printf ("{\\char'43}"); } +break; +case 8: + { printf ("{\\char'44}"); } +break; +case 9: + { printf ("{\\char'45}"); } +break; +case 10: + { printf ("{\\char'46}"); } +break; +case 11: + { printf ("{\\char'176}"); } +break; +case 12: + { printf ("{\\char'137}"); } +break; +case 13: + { printf ("{\\char'136}"); } +break; +case 14: + { printf ("{\\char'134}"); } +break; +case 15: + { printf ("{\\char'173}"); } +break; +case 16: + { printf ("{\\char'175}"); } +break; +case 17: + { printf( "\\begin{verbatim}\n" ); + PUSH NORM; BEGIN VERBATIMSIM; } +break; +case 18: +{ printf( "\\end{verbatim}\n" ); POP; } +break; +case 19: +{ printf( "\\begin{verbatim}" ); + PUSH NORM; BEGIN VERBATIM; } +break; +case 20: +{ printf( "\\end{verbatim}" ); POP; } +break; +case 21: +{ printf ("\\begin{verbatim}\n>" ); + PUSH NORM; BEGIN MIRANDA; } +break; +case 22: +{ printf( "\n>" ); } +break; +case 23: + { printf ("\\end{verbatim}\n"); POP; } +break; +case -1: +break; +default: +fprintf(yyout,"bad switch yylook %d",nstr); +} return(0); } +/* end of yylex */ +int yyvstop[] = { +0, + +2, +0, + +2, +0, + +4, +0, + +5, +0, + +7, +0, + +8, +0, + +9, +0, + +10, +0, + +3, +0, + +14, +0, + +13, +0, + +12, +0, + +15, +0, + +16, +0, + +11, +0, + +23, +0, + +1, +0, + +21, +0, + +17, +0, + +6, +0, + +22, +0, + +18, +0, + +20, +0, + +19, +0, +0}; +# define YYTYPE char +struct yywork { YYTYPE verify, advance; } yycrank[] = { +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +4,15, 5,17, 7,30, 8,31, +33,43, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 16,38, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 5,18, +0,0, 0,0, 5,19, 5,20, +5,21, 5,22, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +36,45, 40,46, 0,0, 45,45, +45,45, 45,45, 45,45, 45,45, +45,45, 45,45, 45,45, 45,45, +45,45, 0,0, 0,0, 0,0, +0,0, 3,13, 4,16, 5,23, +12,33, 13,34, 15,36, 15,36, +15,36, 15,36, 15,36, 15,36, +15,36, 15,36, 15,36, 15,36, +16,34, 23,39, 0,0, 0,0, +15,37, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 3,14, 4,14, 5,24, +9,32, 5,25, 5,26, 0,0, +0,0, 14,35, 30,40, 30,40, +30,40, 30,40, 30,40, 30,40, +30,40, 30,40, 30,40, 30,40, +32,42, 35,44, 42,47, 44,48, +30,41, 47,49, 48,50, 53,55, +56,58, 57,59, 59,61, 60,62, +50,52, 62,64, 5,27, 63,65, +5,28, 5,29, 46,46, 46,46, +46,46, 46,46, 46,46, 46,46, +46,46, 46,46, 46,46, 46,46, +49,51, 51,53, 52,54, 54,56, +55,57, 58,60, 61,63, 64,66, +65,67, 66,68, 67,69, 68,70, +70,71, 0,0, 0,0, 0,0, +0,0}; +struct yysvf yysvec[] = { +0, 0, 0, +yycrank+0, 0, 0, +yycrank+0, 0, 0, +yycrank+1, 0, 0, +yycrank+2, 0, 0, +yycrank+3, 0, 0, +yycrank+0, yysvec+5, 0, +yycrank+4, 0, 0, +yycrank+5, 0, 0, +yycrank+4, 0, 0, +yycrank+0, yysvec+9, 0, +yycrank+0, 0, 0, +yycrank+4, 0, 0, +yycrank+5, 0, yyvstop+1, +yycrank+3, 0, 0, +yycrank+22, 0, 0, +yycrank+16, 0, yyvstop+3, +yycrank+0, 0, yyvstop+5, +yycrank+0, 0, yyvstop+7, +yycrank+0, 0, yyvstop+9, +yycrank+0, 0, yyvstop+11, +yycrank+0, 0, yyvstop+13, +yycrank+0, 0, yyvstop+15, +yycrank+17, 0, yyvstop+17, +yycrank+0, 0, yyvstop+19, +yycrank+0, 0, yyvstop+21, +yycrank+0, 0, yyvstop+23, +yycrank+0, 0, yyvstop+25, +yycrank+0, 0, yyvstop+27, +yycrank+0, 0, yyvstop+29, +yycrank+54, 0, 0, +yycrank+0, yysvec+30, yyvstop+31, +yycrank+11, 0, 0, +yycrank+6, 0, 0, +yycrank+0, 0, yyvstop+33, +yycrank+12, 0, 0, +yycrank+3, yysvec+15, 0, +yycrank+0, 0, yyvstop+35, +yycrank+0, 0, yyvstop+37, +yycrank+0, 0, yyvstop+39, +yycrank+4, yysvec+30, 0, +yycrank+0, 0, yyvstop+41, +yycrank+4, 0, 0, +yycrank+0, 0, yyvstop+43, +yycrank+12, 0, 0, +yycrank+3, yysvec+15, 0, +yycrank+82, yysvec+30, 0, +yycrank+17, 0, 0, +yycrank+13, 0, 0, +yycrank+17, 0, 0, +yycrank+14, 0, 0, +yycrank+23, 0, 0, +yycrank+19, 0, 0, +yycrank+18, 0, 0, +yycrank+25, 0, 0, +yycrank+30, 0, 0, +yycrank+19, 0, 0, +yycrank+23, 0, 0, +yycrank+31, 0, 0, +yycrank+25, 0, 0, +yycrank+25, 0, 0, +yycrank+30, 0, 0, +yycrank+28, 0, 0, +yycrank+22, 0, 0, +yycrank+31, 0, 0, +yycrank+39, 0, 0, +yycrank+44, 0, 0, +yycrank+25, 0, 0, +yycrank+42, 0, 0, +yycrank+0, 0, yyvstop+45, +yycrank+27, 0, 0, +yycrank+0, 0, yyvstop+47, +0, 0, 0}; +struct yywork *yytop = yycrank+152; +struct yysvf *yybgin = yysvec+1; +char yymatch[] = { +00 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' , +'0' ,'0' ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +0}; +char yyextra[] = { +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0}; +#ifndef lint +static char ncform_sccsid[] = "@(#)ncform 1.6 88/02/08 SMI"; /* from S5R2 1.2 */ +#endif + +int yylineno =1; +# define YYU(x) x +# define NLSTATE yyprevious=YYNEWLINE +char yytext[YYLMAX]; +struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp; +char yysbuf[YYLMAX]; +char *yysptr = yysbuf; +int *yyfnd; +extern struct yysvf *yyestate; +int yyprevious = YYNEWLINE; +yylook(){ + register struct yysvf *yystate, **lsp; + register struct yywork *yyt; + struct yysvf *yyz; + int yych, yyfirst; + struct yywork *yyr; +# ifdef LEXDEBUG + int debug; +# endif + char *yylastch; + /* start off machines */ +# ifdef LEXDEBUG + debug = 0; +# endif + yyfirst=1; + if (!yymorfg) + yylastch = yytext; + else { + yymorfg=0; + yylastch = yytext+yyleng; + } + for(;;){ + lsp = yylstate; + yyestate = yystate = yybgin; + if (yyprevious==YYNEWLINE) yystate++; + for (;;){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1); +# endif + yyt = yystate->yystoff; + if(yyt == yycrank && !yyfirst){ /* may not be any transitions */ + yyz = yystate->yyother; + if(yyz == 0)break; + if(yyz->yystoff == yycrank)break; + } + *yylastch++ = yych = input(); + yyfirst=0; + tryagain: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"char "); + allprint(yych); + putchar('\n'); + } +# endif + yyr = yyt; + if ( (int)yyt > (int)yycrank){ + yyt = yyr + yych; + if (yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } +# ifdef YYOPTIM + else if((int)yyt < (int)yycrank) { /* r < yycrank */ + yyt = yyr = yycrank+(yycrank-yyt); +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"compressed state\n"); +# endif + yyt = yyt + yych; + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + yyt = yyr + YYU(yymatch[yych]); +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"try fall back character "); + allprint(YYU(yymatch[yych])); + putchar('\n'); + } +# endif + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transition */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } + if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1); +# endif + goto tryagain; + } +# endif + else + {unput(*--yylastch);break;} + contin: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"state %d char ",yystate-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + ; + } +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + while (lsp-- > yylstate){ + *yylastch-- = 0; + if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){ + yyolsp = lsp; + if(yyextra[*yyfnd]){ /* must backup */ + while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){ + lsp--; + unput(*yylastch--); + } + } + yyprevious = YYU(*yylastch); + yylsp = lsp; + yyleng = yylastch-yytext+1; + yytext[yyleng] = 0; +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"\nmatch "); + sprint(yytext); + fprintf(yyout," action %d\n",*yyfnd); + } +# endif + return(*yyfnd++); + } + unput(*yylastch); + } + if (yytext[0] == 0 /* && feof(yyin) */) + { + yysptr=yysbuf; + return(0); + } + yyprevious = yytext[0] = input(); + if (yyprevious>0) + output(yyprevious); + yylastch=yytext; +# ifdef LEXDEBUG + if(debug)putchar('\n'); +# endif + } + } +yyback(p, m) + int *p; +{ +if (p==0) return(0); +while (*p) + { + if (*p++ == m) + return(1); + } +return(0); +} + /* the following are only used in the lex library */ +yyinput(){ + return(input()); + } +yyoutput(c) + int c; { + output(c); + } +yyunput(c) + int c; { + unput(c); + } diff --git a/web/glasgow/lit2x-0.16/grasp-utils/verbatim/verbatim.lex b/web/glasgow/lit2x-0.16/grasp-utils/verbatim/verbatim.lex new file mode 100644 index 0000000000..0263a26620 --- /dev/null +++ b/web/glasgow/lit2x-0.16/grasp-utils/verbatim/verbatim.lex @@ -0,0 +1,57 @@ + + /* This Lex script acts as a filter to pre-process Latex files. + + It surrounds groups of lines beginning with a ">" sign, and + preceded and followed by a blank line, with \begin{verbatim} + and \end{verbatim}. The ">" may be preceded by a digit or digit + range (eg 4>, 2-5>, 3->); in this case the digits are removed. + They are meant to be used for filtering out versions. + + It takes words surrounded with @ signs (thus @letrec@) and makes them + come out in typewriter font, regardless of the current mode. + */ + +%START NORM VERB MIRANDA VERBATIM VERBATIMSIM +sp [ \t]* +nl {sp}\n{sp} +miranda ([0-9]+(\-([0-9]+)?)?)?> +%{ +#define PUSH states[top++] = +#define POP BEGIN states[--top] +%} +%% + int states[256]; + int top; + BEGIN NORM; + top = 0; +<NORM>@@ { printf ("@"); } +<NORM>@ { printf ("\\mbox{\\tt "); PUSH NORM; BEGIN VERB; } +<VERB>@ { printf ("}"); POP; } +<VERB>\n { printf ("}\\\\{}\n\\mbox{\\tt "); } +<VERB>" " { printf ("\\ "); } +<VERB>@@ { printf ("@"); } +<VERB>\# { printf ("{\\char'43}"); } +<VERB>\$ { printf ("{\\char'44}"); } +<VERB>\% { printf ("{\\char'45}"); } +<VERB>\& { printf ("{\\char'46}"); } +<VERB>\~ { printf ("{\\char'176}"); } +<VERB>\_ { printf ("{\\char'137}"); } +<VERB>\^ { printf ("{\\char'136}"); } +<VERB>\\ { printf ("{\\char'134}"); } +<VERB>\{ { printf ("{\\char'173}"); } +<VERB>\} { printf ("{\\char'175}"); } + +<NORM>^@\n { printf( "\\begin{verbatim}\n" ); + PUSH NORM; BEGIN VERBATIMSIM; } +<VERBATIMSIM>^@\n { printf( "\\end{verbatim}\n" ); POP; } + +<NORM>\\"begin{verbatim}" { printf( "\\begin{verbatim}" ); + PUSH NORM; BEGIN VERBATIM; } +<VERBATIM>\\"end{verbatim}" { printf( "\\end{verbatim}" ); POP; } + +<NORM>^\n{miranda} { printf ("\\begin{verbatim}\n>" ); + PUSH NORM; BEGIN MIRANDA; } +<MIRANDA>\n{miranda} { printf( "\n>" ); } +<MIRANDA>^\n { printf ("\\end{verbatim}\n"); POP; } + + diff --git a/web/glasgow/lit2x-0.16/literate/Jmakefile b/web/glasgow/lit2x-0.16/literate/Jmakefile new file mode 100644 index 0000000000..09f11b31f3 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/Jmakefile @@ -0,0 +1,131 @@ +#define IHaveSubdirs + +#if IncludeTestDirsInBuild == YES +#define __lit_tests_dir tests +#else +#define __lit_tests_dir /* nothing */ +#endif + +SUBDIRS = __lit_tests_dir \ + info-utils \ + doc + + +LitSuffixRule(.lprl,.prl) +LitSuffixRule(.llex,.lex) + +/* stuff to have before we get going */ +MsubNeededHere(lit2stuff lit-inputter) + +/* _must_ use special lit2pgm to re-build the lit2pgm source here */ +LIT2PGM = ./lit2pgm.BOOT -Alit2pgm + +LIT2PGM_OPTS = -q /* so we go fast; not really necessary (ToDo) */ + +/* BUILDING STUFF ================================================= */ +/****** the driver script "lit2stuff" *******/ + +/* has host-platform type wired in, so in BIN, not SCRIPT, dir */ + +/* slam INSTLIBDIR_LITERATE, INSTDATADIR_LITERATE, TMPDIR from Makefile into lit2stuff */ +MsubMakefileDependentProgramScriptTarget(PerlCmd,lit2stuff,lit2stuff.prl,/*no flags*/,/*Makefile*/) +/****** the names by which "lit2stuff" may be invoked */ +LinkTarget(lit2pgm,lit2stuff) +LinkTarget(lit2texi,lit2stuff) +LinkTarget(lit2latex,lit2stuff) +LinkTarget(mkdependlit,lit2stuff) +LinkTarget(lit2changelog,lit2stuff) +LinkTarget(lit2text,lit2stuff) + +/* and the mangled source... */ +LitDocRootTargetWithNamedOutput(lit2stuff,lprl,lit2stuff-standalone) + +/****** all the support code that is slurped in or fired up by "lit2stuff" +******/ + +/* these two (lit-deatify & lit-inputter) are executables: */ +lit-deatify.c : lit-deatify.lex /* a flex program ... */ + $(RM) lit-deatify.c + flex -t lit-deatify.lex > lit-deatify.c + +BuildPgmFromCFiles(lit-deatify,lit-deatify.o,,) + +MsubProgramScriptTarget(PerlCmd,lit-inputter,lit-inputter.prl,/*no flags*/,/**/) + +/* LaTeX macros to support the enterprise; + * not kept in the TeX directories because we want to + * know where it is so we can be sure to \input the right version +*/ +LITDATASTUFF = lit-2changes.prl \ + lit-2depend.prl \ + lit-2doc-c.prl \ + lit-2doc-hs.prl \ + lit-2doc-jm.prl \ + lit-2doc-lex.prl \ + lit-2doc-none.prl \ + lit-2doc-prl.prl \ + lit-2doc.prl \ + lit-2latex-c.prl \ + lit-2latex-hs.prl \ + lit-2latex-jm.prl \ + lit-2latex-lex.prl \ + lit-2latex-none.prl \ + lit-2latex-prl.prl \ + lit-2latex.prl \ + lit-2pgm-c.prl \ + lit-2pgm-hs.prl \ + lit-2pgm-jm.prl \ + lit-2pgm-lex.prl \ + lit-2pgm-none.prl \ + lit-2pgm-prl.prl \ + lit-2pgm.prl \ + lit-2texi-c.prl \ + lit-2texi-hs.prl \ + lit-2texi-jm.prl \ + lit-2texi-lex.prl \ + lit-2texi-none.prl \ + lit-2texi-prl.prl \ + lit-2texi.prl \ + lit-2text.prl \ + lit-globals.prl \ + lit-link-globals.prl \ + lit-linker.prl \ + lit-reader.prl + +AllTarget($(LITDATASTUFF)) + +litdatastuff : $(LITDATASTUFF) + +/* all the rest of the things are built with the default .lprl->.prl rule */ + +/* INSTALLING STUFF =============================================== */ + +INSTDATADIR_LITERATE = $(INSTDATADIR)/literate +INSTLIBDIR_LITERATE = $(INSTDATADIR_LITERATE)/$(HOSTPLATFORM) + +MakeDirectories(install, $(INSTBINDIR) $(INSTLIBDIR_LITERATE) $(INSTDATADIR_LITERATE)) + +InstallMsubbedScriptTarget(PerlCmd,lit2stuff,lit2stuff.prl,$(INSTBINDIR)) +InstallLinkTarget(lit2pgm,lit2stuff,$(INSTBINDIR)) +InstallLinkTarget(lit2texi,lit2stuff,$(INSTBINDIR)) +InstallLinkTarget(lit2latex,lit2stuff,$(INSTBINDIR)) +InstallLinkTarget(mkdependlit,lit2stuff,$(INSTBINDIR)) +InstallLinkTarget(lit2changelog,lit2stuff,$(INSTBINDIR)) +InstallLinkTarget(lit2text,lit2stuff,$(INSTBINDIR)) + +InstallBinaryTarget(lit-deatify, $(INSTLIBDIR_LITERATE)) +InstallScriptTarget(lit-inputter, $(INSTLIBDIR_LITERATE)) + +InstallDataTarget(lit-style.tex, $(INSTDATADIR_LITERATE)) +InstallTarget(litdatastuff) +InstallMultNonExecTargets(litdatastuff, $(LITDATASTUFF), $(INSTDATADIR_LITERATE)) + +/* OTHER STUFF ==================================================== */ +ExtraStuffToClean( lit2stuff.prl li-inputter.prl $(LITDATASTUFF) ) + +ClearTagsFile() +LITDATA_LPRLS = $(LITDATASTUFF:.prl=.lprl) +PerlTagsTarget( lit2stuff.lprl lit-inputter.lprl $(LITDATA_LPRLS) ) +EtagsNeededHere(tags) /* need this to do "make tags" */ +CTagsTarget( lit-deatify.lex ) +/* LaTeX style file ? */ diff --git a/web/glasgow/lit2x-0.16/literate/MAIL.ireland b/web/glasgow/lit2x-0.16/literate/MAIL.ireland new file mode 100644 index 0000000000..d9e94e8bbb --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/MAIL.ireland @@ -0,0 +1,76 @@ +From E.Ireland@massey.ac.nz Wed Aug 21 01:56:20 1991 +X-VM-Attributes: [nil nil nil nil t] +Status: RO +Via: uk.ac.nsf; Wed, 21 Aug 91 01:56:14 BST +Received: from vax.nsfnet-relay.ac.uk by sun2.nsfnet-relay.ac.uk + with SMTP inbound id <26022-5@sun2.nsfnet-relay.ac.uk>; + Wed, 21 Aug 1991 01:54:16 +0100 +Received: from [130.123.1.7] by vax.NSFnet-Relay.AC.UK via NSFnet with SMTP + id aa23150; 21 Aug 91 1:39 BST +Received: from sis-a by cc-server4.massey.ac.nz (5.64+IDA-1.3.1) id AA15464; + Wed, 21 Aug 91 12:48:43 +1200 +Received: from sis-c.sis by sis-a (4.1/SMI-4.0) id AA00751; + Wed, 21 Aug 91 12:48:26 NZS +Message-Id: <9108210048.AA00751@sis-a> +Received: by sis-c.sis (4.1/SMI-4.1) id AA13550; Wed, 21 Aug 91 12:48:20 NZS +In-Reply-To: Will Partain's message of Sat, 6 Jul 91 04:21:31 BST <16225.9107060321@dcs.glasgow.ac.uk> +From: E.Ireland@massey.ac.nz +To: partain, simonpj +Subject: Literate Haskell: +Date: Wed, 21 Aug 91 12:48:26 NZS + +Will and/or Simon, + +I have all the literate Haskell stuff up and running here, but I can't see how +to do a few of the things that I thought I would be able to. If I put code in +code or pseudocode environments, it is typeset flush with the left margin. I +would like + +\begin{code} +f x y = x + y +\end{code} + +to typeset as + + > f x y = x + y + +and would like + +\begin{pseudocode} +f x y = x + y +\end{pseudocode} + +to typeset as + + f x y = x + y + +After a section title or code environment, the second and subsequent following +paragraphs should have the first line indented, but this is not happening. I +don't remember having to specify anything to LaTeX in the past to get this +behaviour, but I am not a LaTeX hacker, and neither is any member of our +support staff. How can I fix this? + +Ideally, I would like the code and pseudocode environments to be indented by +the same amount as the indentation for the first line of a `subsequent' +paragraph. Thus I would like things to appear much as they do in the recent +S.P.E. article on Lambda Lifting by Simon and David Lester, but with a smaller +amount of indentation for code environments. + +In summary, my questions are: + +(1) How do I get the first line indentation for `subsequent' paragraphs? + +(2) How do I get the same amount of indentation for code environments? + +(3) How do I get the '>'s for code environments (but not for pseudocode + environments)? + +I would appreciate a prompt reply: I am hoping to complete a paper which has a +3 Sept. deadline. + + Thanks in advance, +_______________________________________________________________________________ + +E.Ireland@massey.ac.nz Evan Ireland, Department of Computer Science, + +64-6-3569099 x8541 Massey University, Palmerston North, New Zealand. + diff --git a/web/glasgow/lit2x-0.16/literate/Makefile.BOOT b/web/glasgow/lit2x-0.16/literate/Makefile.BOOT new file mode 100644 index 0000000000..95ed4970f1 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/Makefile.BOOT @@ -0,0 +1,58 @@ +# hand-hacked Makefile to boot the "make world" process +#--------------------------------------------------------------------- + +# Platform-specific configuration stuff was read from: sun.cf + +SHELL = /bin/sh +PATHSEP = / + +TOP = .. +CURRENT_DIR = ./literate + +RM=rm -f +MV=mv -f +BOOTSTRAPCFLAGS = + +# Project identification -- name, version, and stuff + +PROJECTNAME = Booting the Make World System +PROJECTVERSION = none +PROJECTLABEL = none +SETUPLABEL = std + +PROJECTCONFIGDIR = + +########################################################################### +# Configuration stuff (jmake, its friends and templates) + +JMKMF = jmkmf_used_only_with_installed_utils +JRESTOREDEPS = $(JMAKESRC)/jrestoredeps +JMAKE = $(JMAKESRC)/jmake +JMAKE_DEFINES = + +JMAKESRC = $(TOP)/mkworld + +JMAKE_CMD = $(NEWTOP)$(JMAKE) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) -DTopDir=$(TOP) -DCurDir=$(CURRENT_DIR) $(BOOT_DEFINES) + +########################################################################### + +Makefile:: $(JMAKE) + +$(JMAKE): + @(cd $(JMAKESRC); if [ -f Makefile ]; then \ + echo "checking $@ in $(JMAKESRC) first..."; $(MAKE) all; else \ + echo "bootstrapping $@ from Makefile.BOOT in $(JMAKESRC) first..."; \ + $(MAKE) -f Makefile.BOOT BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS); fi; \ + echo "okay, continuing in $(CURRENT_DIR)") + +Makefile:: + -@if [ -f Makefile ]; then \ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(JMAKE_CMD) + $(JRESTOREDEPS) + @if cmp -s Makefile Makefile.bak; then $(RM) Makefile.bak ; fi + @chmod 444 Makefile + @echo ==== The new Makefile is for\: ==== + @$(MAKE) whoami diff --git a/web/glasgow/lit2x-0.16/literate/PATCHLEVEL b/web/glasgow/lit2x-0.16/literate/PATCHLEVEL new file mode 100644 index 0000000000..be1dad6619 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/PATCHLEVEL @@ -0,0 +1 @@ +Glasgow literate programming system, version 0.16, patchlevel 0 diff --git a/web/glasgow/lit2x-0.16/literate/PROJECTS b/web/glasgow/lit2x-0.16/literate/PROJECTS new file mode 100644 index 0000000000..014d8ec650 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/PROJECTS @@ -0,0 +1,64 @@ +SIMPLE \defines with parameters +\begin\end grammar +better tabulars (changes) +\owner -- how/where does one such decl apply? +don't xref uses that are def'd nearby +tgrind/tags +do postmakeinfo + +de-Birdizing for >#(if|elsif|else|endif) + +codethings def'd more than once +Haskell same-named codethings from diff namespaces + +\title as \section0 ? + +for large docs, could use +\reset{indexing,xref}tables to be heaved in periodically. + +chg onlyinfo, onlylatex semantics to go straight-through. + +onlystandalone, etc.: carry both through, decide on linking + +how does CPP interact w/ haskell? + +independent code writing / code printing styles. + +xtex option? + +\begin...\end{invisiblecode} + +(info) be able to jump to all places where a function is used + +postmakeinfo -- colons in nodenames + +index the right things + +pagebreaks for code in LaTeX + +verbatim in verbatim (cf verbatim.sty) + +math mode + +and what's this with @'s in codeformat (if the latter exists?!) + +multiple indexes -- we need these! (e.g., code for subsystems of a +larger system don't want to share an index): + \index[string]{index-entry-as-usual} % default is "main" index + \printindex[string] % default is "main" index +also + \setcurrentindex{string} % to change default + \setcurrentcodeindex{string} % where code-ish index-entries go +Implementation: I'd pre-pend the string to the entry-as-usual +("string<uniquifier>!"), let LaTeX/makeinfo do the work, then +post-process to make the separate indexes. + +Got a bug with: + + Used only once (ToDo: check ?): + <- spaces here + >newTyVar :: NFSap TyVar + +ditto for \tr{\Haskell}... (defined things) + +if lit2pgm fails, nuke the output file (so make will re-try). diff --git a/web/glasgow/lit2x-0.16/literate/README b/web/glasgow/lit2x-0.16/literate/README new file mode 100644 index 0000000000..34b9f5af8e --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/README @@ -0,0 +1,38 @@ +This directory (and its subdirectories) contains version 0.16 of the +Glasgow literate programming system. This stuff is usually -- but not +always -- distributed as part of a larger system (e.g., the Glasgow +Haskell compiler). + +The version numbers for this system tend to track those for Glasgow +Haskell, even if virtually nothing has changed herein. As this system +is pretty stable, this "version" really has nothing new to offer if +you have a version 0.06 or 0.09. + +The subdirectory "doc" contains the user's guide (notably, the files +literate.dvi [TeX-produced DVI format] and literate.info [equivalent +in GNU Info format]. + +If you are building/installing this stuff as a separate system, please +consult the relevant section of the user's guide, near the end +(source: literate/doc/install.lit). If this stuff "came with" another +system (e.g., GHC or NoFib), simply follow the directions for +building/installing *that* system. + +Once this system is built, if you would like to see its source in +"literate" form (not overly recommended :-), try: + + % cd <here> + % make depend # may be omitted if you've already done it + % make lit2stuff.dvi + # or... + % make lit2stuff.info + +The subdirectory "info-utils" contains hacked versions of the GNU +Info-related utilities, "info" and "makeinfo". See the README file +there. + +Comments about and suggestions for this system would be most welcome. +You may send them directly to me. + +Will Partain +partain@dcs.glasgow.ac.uk diff --git a/web/glasgow/lit2x-0.16/literate/TeX-Mathematica-note b/web/glasgow/lit2x-0.16/literate/TeX-Mathematica-note new file mode 100644 index 0000000000..b597a81ea9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/TeX-Mathematica-note @@ -0,0 +1,34 @@ +From dan@chem.bu.edu Sat Apr 27 15:20:35 1991 +From: dan@chem.bu.edu (Dan Dill) +Newsgroups: sci.math.symbolic,comp.text.tex +Subject: New version of TeX/Mathematica available +Date: 26 Apr 91 19:30:49 GMT +Followup-To: sci.math.symbolic +Organization: Boston University Chemistry Department + +A new version (1.3) of TeX/Mathematica is available by anonymous ftp from +chem.bu.edu (128.197.30.18) in directory /pub/tex-mathematica. + +TeX/Mathematica is a set of tools that provide facilities of Mathematica +Notebooks in a UNIX environment, under GNU Emacs. They permit interaction +between a text and a Mathematica buffer and, if desired, the use of +TeX/LaTeX to annotate Mathematica-based explorations and programs. Inclusion +of Mathematica-generated graphics in TeX/LaTeX documents printed using +PostScript is supported. + +The major new feature is that calculations in a document can automatically be +encapsulated in Mathematica packages. This means that the document can serve +both as the description of the package and the source for the package code +itself, in the spirit of Knuth's WEB system of structured documentation. + +With these tools one can interactively develop and refine teaching and +research documents. The interactive nature of the tools encourages +Mathematica-based exploration as a natural part of the writing process. + +I'd welcome your comments. + +Thanks + +Dan Dill +dan@chem.bu.edu + diff --git a/web/glasgow/lit2x-0.16/literate/a-cpp-ish-thing-from-the-net b/web/glasgow/lit2x-0.16/literate/a-cpp-ish-thing-from-the-net new file mode 100644 index 0000000000..41b38e9d5a --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/a-cpp-ish-thing-from-the-net @@ -0,0 +1,257 @@ +From aks@anywhere.ucsb.edu Fri May 3 10:51:57 1991 +From: aks@anywhere.ucsb.edu (Alan Stebbens) +Newsgroups: comp.lang.perl +Subject: Program to list (and comprehend) nested includes +Summary: Program to list nested `cpp' includes +Keywords: Program lists nested #includes +Date: 1 May 91 23:57:43 GMT +Organization: CCSE, Univ. of CA, Santa Barbara + +When trying to port software to the IBM RS3000 running AIX 3.1, it +often occurs that I have to isolate a missing or malformed rerenced to +some "standard" macro or define. Also, there are many include files in +the /usr/include hierarchy which are ultimately recursive by +re-invoking, for example, /usr/include/standards.h. It becomes very +difficult to understand the dependencies of these include files when +such recursion occurs is several places or is very deep. + +The following program, "includes", is my "quick 'n dirty" solution to +this problem: it will list, and optionally indent and line-number, the +standard `cpp' include directives. + +Oh yeah, a caveat: I had originally intended the program to be able to +dynamically interpret #define's and #undef's, but never followed up +with the code to do the job. Thus, the internal documentation and +"usage:" show a -D and -U option usage, but don't really do anything +with it. Perhaps, some other time, I'll make it work as intended. Or, +someone else will. + +Enjoy. + +Alan Stebbens <aks@hub.ucsb.edu> (805) 893-3221 + Center for Computational Sciences and Engineering (CCSE) + University of California, Santa Barbara (UCSB) + 3111 Engineering I, Santa Barbara, CA 93106 + +============================= cut here =================================== +#!/bin/perl +# includes [[-[vincu]...] [-Idir] [-Dname] [-Uname]]... files +# +# Given a list of files, determine the #include dependency list +# given '-c', use CPP to determine the _dynamic_ dependency list, +# otherwise, the static include file dependency list is produced. +# +# If the `-D' or `-U' options are given, `-c' is assumed. +# +# +$IndentStr = ' ' x 4; +@IncludeDirs = ('.'); +@Defines = (); +$Verbose = 0; +$Pathnames = 0; +$LineNums = 0; +$Indent = 0; +$SortUniq = 0; +&Usage unless $#ARGV >= $[; +while ($_ = shift) { # scan arguments + if (!/^-/) { + unshift(@ARGV,$_); + last; + } + while (s/^-(.)/-/) { + $Compile++ if $1 eq 'c'; + $Indent++ if $1 eq 'i'; + $LineNums++ if $1 eq 'n'; + $Pathnames++ if $1 eq 'p'; + $SortUniq++ if $1 eq 's'; + $Verbose++ if $1 eq 'v'; + if ($1 =~ /[IDU]/) { + $opt = $1; + s/^-(.*)/-$opt$1/; # put option back in + push(@IncludeDirs,$_) if $opt eq 'I'; + push(@Defines,$_) if $opt =~ /DU/; + last; + } + &Usage unless $1 =~ /[cinpsv]/; + } +} +&Usage if $SortUniq && ($LineNums || $Indent); +$Compile++ if $#Defines >= $[; # any defines? compile it +$Pathnames = $LineNums = $Indent = 1 if $Verbose; +@Files = @ARGV; +while ($File = shift(@Files)) { + printf "%s:\n",$File; + if ($SortUniq) { + select(STDOUT); $| = 1; + open(SORT,"|sort -u +1 -2") || die "Can't open pipe to `sort -u' filter because $!\n"; + select(SORT); $| = 1; + } + &ShowIncludes($File,0); + if ($SortUniq) { + close(SORT); + select(STDOUT); + } +} +exit; + +%Included = (); +sub ShowIncludes { + local($name,$level) = @_; + local(*FILE); + local($_,$.); + local($pathname,$lq,$incname,$rq); + local($indent) = $Indent ? $IndentStr x $level : ''; + + if (open(FILE,$name)) { + $Included{$name}++; + while (<FILE>) { + next unless /^#include/; + chop; + if (/^#include\s*(")([^"]*)(")/ || + /^#include\s*(<)([^>]*)(>)/) { + ($lq,$incname,$rq) = ($1,$2,$3); + print $indent; + printf "%3d:",$. if $LineNums; + printf "#include %s%s%s",$lq,$incname,$rq; + if ($file = &FindFile($incname,($lq eq '"'))) { + printf "\t(%s)",$file if $Pathnames; + print "\n"; + &ShowIncludes($file,$level+1) unless $Included{$file}; + } else { + printf ": can't find $incname\n"; + } + } else { + print ": bad syntax.\n"; + } + } + close FILE; + } else { + print ": can't open $name because $!\n"; + } +} + +sub FindFile { + local($file,$localflag) = @_; + local($path); + if ($localflag) { + foreach $dir (@IncludeDirs) { + ($path = $dir . '/' . $file) =~ s/^-I//; + return $path if -f $path; + } + } + foreach $dir ('/usr/local/include', '/usr/include') { + return $path if -f ($path = $dir . '/' . $file); + } + ''; +} + +sub Usage { + select(STDERR); + print STDERR <<"EOF"; +usage: includes [-cinspv] [-Ipath]... [-[D|U]name]... files +Prints the '#include' statements referenced by the named files, automatically +following nested #includes; statically recursive #includes are detected. + -c Compile (interpret) #ifdef's and expressions + -i Indent nested #includes + -n Print the line numbers of the #include statements + -p Print the absolute path names for each include file + -s Run the #includes through a `sort -u' filter + -v Verbose mode; implies `-inp' options + -Ipath Add `path' to the include search path. + -Dname Define `name'; implies the `-c' option. + -Uname Undefine `name'; implies the `-c' option. +Sorting is mutually exclusive with indents and line numbering. +EOF + exit 1; +} + +============================= cut here =================================== +-- + +Alan Stebbens + +From aks@anywhere.ucsb.edu Fri May 3 10:52:08 1991 +From: aks@anywhere.ucsb.edu (Alan Stebbens) +Newsgroups: comp.lang.perl +Subject: Program to check for balanced #{if|else|endif}s +Summary: List, with optional line numbers and indention, `cpp' conditionals +Keywords: CPP #ifdef #else #endif listing +Date: 1 May 91 23:47:36 GMT +Organization: CCSE, Univ. of CA, Santa Barbara + +The following is a perl program to list, with optional indentions +and line numbers, the `cpp' conditionals: #ifdef, #elif, #else, #endif. +I wrote this because I was unsuccessfully trying to find a missing +#ifdef in some newly patched software. + +Enjoy. + +Alan Stebbens <aks@hub.ucsb.edu> (805) 893-3221 + Center for Computational Sciences and Engineering (CCSE) + University of California, Santa Barbara (UCSB) + 3111 Engineering I, Santa Barbara, CA 93106 + +============================= cut here =================================== +#!/bin/perl +# ifdefs [-n] [-i INDENT] [-l] +require 'getopts.pl'; + +&Getopts('i:nl') || die "Usage: ifdefs [-i indent] [-l] [-n] [files...]\n"; + +$INDENT = $opt_i ? $opt_i : 3; +$indent = 0; +@block = (); +@state = (0); +# States: 0 - nothing; 1 = #if ; 2 = #elsif ; 3 = #else +select(STDOUT); $| = 1; +while (<>) { + if (/^#\s*(if|ifn?def|elif|elsif|elseif|else|endif)/) { + $key = $1; + s/[ \t]+/ /g; + $nextindent = $indent; + if ($key eq 'if' || $key =~ /ifn?def/) { + $state[$indent] = 1; + $block[$indent] = "$key $."; + $state[++$nextindent] = 0; + } elsif ($key eq 'elseif' || $key eq 'elsif' || $key eq 'elif') { + $indent--; + &Error if !$indent || $state[$indent] < 1 || $state[$indent] > 2; + $block[$indent] = "$key $."; + $state[$indent] = 2; + } elsif ($key eq 'else') { + &Error if !$indent; + $indent--; + &Error if $state[$indent] < 1 || $state[$indent] > 2; + $state[$indent] = 3; + $block[$indent] = "$key $."; + } elsif ($key eq 'endif') { + &Error if !$indent || $state[$indent]; + $indent--; + &Error if !$state[$indent]; + $state[$indent] = 0; + $block[$indent] = ''; + $nextindent--; + } + } else { + next unless $opt_l; + } + printf "%4d:",$. if $opt_n; + printf "%s%s",(' 'x($indent * $INDENT)),$_; + $indent = $nextindent; +} + +sub Error { + if (!$indent) { + printf "ERROR: Unmatched \#%s:\n%4d: %s",$key,$.,$_; + } else { + printf "ERROR: Out of place \#%s:\n%4d: %s",$key,$.,$_; + ($keyw,$keyl) = split(' ',$block[$indent]); + printf "Previous \#%s at line %d not terminated\n",$keyw,+$keyl; + } + next; +} +============================= cut here =================================== +-- + +Alan Stebbens + diff --git a/web/glasgow/lit2x-0.16/literate/code-bug.tex b/web/glasgow/lit2x-0.16/literate/code-bug.tex new file mode 100644 index 0000000000..7007b2b8ee --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/code-bug.tex @@ -0,0 +1,50 @@ +\documentstyle[11pt,code]{article} +\begin{document} + +\section{Section 1} + +Here is a non-first paragraph of code. + +\begin{code} +f x y = x +g x y = x +f1 x y = x +g1 x y = x\end{code} + +Here is the same thing with some index entries immediately following. + +\begin{code} +f x y = x +g x y = x +f1 x y = x +g1 x y = x\end{code} +\index{foo}% +\index{bar}% +\index{baz} + +{\em The bug is the overly-big space above this line.} + +\section{Section 2} + +Now we do the same thing, but with `quotation' (another `list' +environment), not `code'. + +\begin{quotation} +f x y = x +g x y = x +f1 x y = x +g1 x y = x\end{quotation} + +Here is the same thing with some index entries immediately following. + +\begin{quotation} +f x y = x +g x y = x +f1 x y = x +g1 x y = x\end{quotation} +\index{foo}% +\index{bar}% +\index{baz} + +And some final text for this section. +\end{document} diff --git a/web/glasgow/lit2x-0.16/literate/doc/Jmakefile b/web/glasgow/lit2x-0.16/literate/doc/Jmakefile new file mode 100644 index 0000000000..aeb058e04a --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/Jmakefile @@ -0,0 +1,8 @@ +LitStuffNeededHere(docs depend) +InfoStuffNeededHere(docs) + +LitSuffixRule(.lit,) + +LitDocRootTarget(literate,lit) + +InstallInfoFileTarget(literate,literate,$(INSTINFODIR)) diff --git a/web/glasgow/lit2x-0.16/literate/doc/REM.comments b/web/glasgow/lit2x-0.16/literate/doc/REM.comments new file mode 100644 index 0000000000..bab856a835 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/REM.comments @@ -0,0 +1,239 @@ +From REM@suwatson.stanford.edu Mon Jul 8 09:29:34 1991 +X-VM-Attributes: [nil nil nil nil t] +Status: RO +Via: uk.ac.nsf; Mon, 8 Jul 91 09:29:08 BST +Received: from vax.nsfnet-relay.ac.uk by sun2.nsfnet-relay.ac.uk + with SMTP inbound id <5497-0@sun2.nsfnet-relay.ac.uk>; + Sun, 7 Jul 1991 16:34:38 +0100 +Received: from [36.21.0.12] by vax.NSFnet-Relay.AC.UK via NSFnet with SMTP + id aa03596; 7 Jul 91 16:16 BST +Received: from SUWATSON.stanford.edu + by SUWATSON.stanford.edu (IBM VM SMTP R1.2.2MX) with BSMTP id 6616; + Sun, 07 Jul 91 08:30:53 PDT +From: REM@SUWATSON.stanford.edu +Sender: REM@suwatson.stanford.edu +To: partain +Subject: Glasgow literate programming (documentation -- long) +Date: Sun, 07 Jul 91 08:30:50 PDT + +(Hi. I'm currently months behind in reading PARA archives, but now trying +to catch up. Currently I'm reading postings from 1991.Apr ...) + +<<Date: Tue, 23 Apr 91 13:59:41 BST -- Programs are just documents for +people to read and enjoy which happen to have machine-manipulable code +"buried" in them.>> + +Hmmm, interesting concept. So you just write as if you were submitting an +article to COMM ACM with embedded program snippets, except (1) there's +automatic machinery to extract the snippets, and (2) all the snippets +together in your article just happen to be one complete program when put +together! + +<<... depending on whether that language is "supported" or not.>> +I hope you support LISP. + +<<programs/documents divided into sections, subsections within sections, +subsubsections...>> + +Whether this is a good idea or not is a major question. If you have one +person organizing the file and others just add to pieces, and if it's +small enough that others can find the appropriate place easily, this +might work. This assumes everyone can agree on the organization. But a +non-heirarchial representation, nodes with links but no strict heirarchy, +or even pure tagged-node representation, is usually necessary when more +than one person can contribute new nodes asynchronously and without +agreeing upon a heirarchy that the new nodes can neatly fit into. The +best model may be to simply have each section tagged with keywords, and +have tools for searching for the desired section by keywords, and let +anyone try to make a heirarchial index of the whole document for their +personal use if they feel they can but watch them give up in frustration +as they have more and more trouble fitting new nodes into their old +heirarchy. + +<<Hierarchy is a very powerful structuring tool, but its utility for +wading around a large sea of code is not apparent.>> + +Yes. That's the other problem with a heirarchy. Even if you can neatly +organize everything into topics subtopics etc., can you find things +easily by traversing that heirarchy, or do you really need keywords after +all just so you can quickly find a given node by name (keyword) instead +of by location (topic subtopic etc.). + +<<Say you're writing a Haskell compiler ...>> +As in Eddie Haskell on Leave It To Beaver?? + +<<You could make copies of files, edit them, etc., but that's tacky,>> + +not to mention impossible to maintain, and a royal pain even if you can. +You really want HyperText, any segment of text can be located in multiple +places simultaneously and all edits immediately propagate, because really +each occurance of the piece of text is via pointer to one master copy. +But making HyperText work in the first place, then arranging for +incremental backups and rollbacks etc. is really hard. I wonder if the +Xanadu folks have found real solutions for these major problems, or are +just winging it (sweeping the dirt under the rug and hoping nobody will +notice)? + +<<As it stands, this system lets you put "\begin{onlystandalone}" and +"\end{onlystandalone}" around pieces of your files that only apply in the +"do this as a standalone document" case; similarly, +"\begin{onlypartofdoc}" and "\end{onlypartofdoc}" for stuff that only +applies in the "the glorious whole" case.>> + +UUGGGGLLLLEEEEEEEE! You've re-invented conditional assembly, a common +feature of machine-language assemblers for at least 20 years. Even +CommonLisp has it, but I avoid it since it can so easily get out of hand. +But as things stands, if you don't have HyperText, then conditional +assembly is probably the only game in town for having multiple versions +of a document simultaneously available in the same file. + +One problem, you can't have the different versions put the sections in a +different sequence, unless you use the most hated feature ever invented, +CONDITIONAL-ASSEMBLY GOTO, present in IBM 360 assemblers I believe. But +what the heck, if you want your document to look like a BASIC program, +it's your priviledge. + +Hmmm, about assembly macros? IBM 360 assembler has them too, and they are +a bit cleaner than GOTOs. Each section you might want to put in various +places, you define as a macro at the top of the file, then simply call it +where you want that body of text to appear in the virtual document that +exists under any of the presentation modes. Unfortunately that means if +you look at the raw source file, the top of the file has all these random +sections, instead of any sort of introduction, because macros have to be +defined before used. There are various hacks to avoid this problem... + +<<We don't have a "\define" command that let's you define new macros in +terms of old ones.>> +Awwww, shucks. + +<<Some programming languages have a narrow-minded idea about what order +the pieces of a program must be presented (e.g., COBOL: identification +division, then file division, then data division>> + +I did, sort of. I knew the divisions but not what order they were +supposed to be in, but I knew they had to be in the right order and I'd +look in the manual or at a sample program if I ever needed that info. +(Last time I touched COBOL was 1974, but I respect it for having some +good ideas not present in any other language I've ever seen, +particularily single declaration of relationship between variables in +records in memory and columns of data in file, even if braindamaged by +fixed-width mentality. I wish that single-declaration method of defining +I/O syntaxes existed in other languages that allowed variable-length +fields. printf and scanf are a poor attempt.) + +<<Within non-code parts of documents, code snippets may be included +between `at' signs; e.g., "@f x y = y@">> + +I don't like that. What if your code contains an atsign to indicate +indirect addressing through a pointer variable? Do you double the atsign, +or put a backslant before it? + +A better way is an invention I made when writing POX (Prototype Overlay +Xerographics) at SU-AI (Sail.Stanford.Edu under the domain system), +namely having a whole class of available parenthesizing (grouping) +characters, some symmetric like '' and "" and @@ and // and \\ and some +balanced like () and {} and [] and <> and /* */. You can use any pair +from either class to avoid stepping on the same character within the +embedded text. Furthermore you can nest any of the balanced ones (you +can't nest the symmetric ones for obvious reasons). + +In POX, stuff inside a single level of generic-parentheses was treated as +a body of whatever (macro definition etc.) but was further interpreted, +whereas inside a second level of balanced generic-parentheses was +super-quoted, but for your application of quoting code segments from +within text this distinction may be moot, but I mentionned it to make my +presentation of my invention complete. + +(I had a further idea of allowing interchangeability between +generic-parentheses and BEGIN-END pairs which can be named. For very long +quoted passages, finding the matching ( and ) can be very painful, +whereas if you say BEGIN "Comments on sex" and later say END "Comments on +sex" but you don't have your parentheses or BEGIN-END pairs matched, the +compiler will notice the problem and help you diagnose it. So you +normally use parentheses for short passages where you can eyeball the +matching or EMACS etc. can flash the cursor back and forth to help you, +but you use named BEGIN-END pairs over large blocks where you need +additional help. But I never had time to program this BEGIN-END extension +to parenthesization. P.s. the original labeled BEGIN and END is from +SAIL, a variant of ALGOL 60 developed at SU-AI, the Stanford University +Artificial Intelligence Lab; P.S., from those 5 initial letters, drop the +U to get SAIL, drop the L to get SU-AI.) + +<<"\tr{<text>}" command; the only restriction on "<text>" is that braces +must be balanced.>> + +They should use the POX convention. If you use \tr{<text>} then of course +the braces must be balanced in <text>, but if you want to quote text that +has unbalanced braces you use some other nesting pair such as \tr[<text>] +or \tr/*<text>*/} etc. to avoid stepping on some unbalanced character. Of +course if you want to quote the ASCII character set, but omit all the +right-sides of each nesting pair, you are up a creek, since no matter +what nesting pair you use on the outside you get an inbalance from the +<text>, but c'est la vie. + +<<No graphics, pictures, or sound.>> +Someday maybe we'll all be using the NBS standard for representing +structured multimedia text, then you'll be able to include sound etc. :-) + +<<it's *your problem* to make sure that you don't get nodename clashes.>> + +If somebody proposes a new nodename, your system should tell him if it is +already in use, and also tell which similar nodenames (say varying by at +most two characters replaced or inserted or deleted) are also in use, to +help him find a name that not only isn't in use but isn't so close to +something in use as to encourage typos to collide with another name. + +<<Having one index for a pretty-big program is a dubious proposition; you +get a *huge* index.>> + +I prefer one big index so I can find what I want instantly even if I +don't know a priori its syntactic class (the Common Lisp book has this +single-index feature) rather than having to first find the correct index +before I can find what I want. Perhaps you should do like Macintosh menus +sort of. In your case, you select a mode and an index term. It shows you +the vicinity of that index term in the full index, but all words not in +the correct mode are dimmed (grayed). So you can still see the words from +the other parts of the index, but you can easily skip over them as you +eyeball the index. (If you use this idea, please give me credit. I +invented it as I was replying to your posting tonight, or is it morning +already, I see sunlight behind the window curtains, sigh, up too late.) + +<<The main thing that is a pain about the current sectioning (see section +*Note Sectioning::) is making up unique node names all the time.>> + +I agree. Nobody should be REQUIRED to do that in the course of entering +new text (I hate having to remember to press RETURN every 70 or so +characters too, which is why I use miniWRITER all the time for entering +text, because it has automatic word wrap). There should be a single +keystroke that generates a new label with some obvious machine-look such +as LISP's GENSYM feature that makes G0001 G0002 G0003 etc. It should of +course skip over any that already exist. Later you should be able in +reviewing the document to notice one of these and decide you'd like to +change it to a more meaningful label, get help finding one that doesn't +step on existing ones or get too close (see earlier), and upon finding +one ask the program to automatically change the definition and all +references to this label. If you want to do a massive cleanup some day, +there should be a command to search to find the next such +machine-generated label. + +<<* recording-who-to-blame:: \owner{<name>}.>> + +Hmmm, sounds like an audit trail, very important in any commercial +venture when more than one person can modify the file. You absolutely +have to an audit trail of who made what changes or one worker can +sabotage the project and blame it on the other and nobody can prove +anything. + +No, I see you mean something different, sigh. Well, if somebody can mark +a section as being his, and the program respects that claim (as in gold +mining) and won't anyone else modify that section, only attach proposed +changes to it, but the author must approve those proposals before the +section can be destructively changed, that would be a good method of +audit control. You'd need a way that one person can "give" a section to +another, and that person can accept or refuse the gift, all +program-mediated. + +<<[Para: CHOPPED OFF HERE -- another 60K or so to go]>> +Gosh darn. How can I get the rest of it so I can nitpick it?? + + diff --git a/web/glasgow/lit2x-0.16/literate/doc/april91.lit b/web/glasgow/lit2x-0.16/literate/doc/april91.lit new file mode 100644 index 0000000000..0fa0bea742 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/april91.lit @@ -0,0 +1,572 @@ +\section[april91-proposals]{APRIL91 PROPOSALS} + +%************************************************************************ +%* * +\subsection[april91-new-ideas]{New ideas} +%* * +%************************************************************************ + +These ideas have piled up over the past six months. NONE OF THEM ARE +IMPLEMENTED. And some are TINY little things (and some are BIG). + +JULY91: I have fleshed out the \sectionref{literate-para-mode} and +\sectionref{lit2lit} comments, as these directions piqued the interest +of some fellow GRASPers. + +%************************************************************************ +%* * +\subsubsection[delatexify-commands]{Make the commands look less like \LaTeX{}} +%* * +%************************************************************************ + +The biggest practical problem that has arisen among the (few) users of +the literate programming stuff is that they think they're writing +\LaTeX{} files and are surprised/disappointed when \LaTeX{} fails to +grok their files. We have been too successful in making the notation +``\LaTeX{}-like!'' + +One way to make the notation less \LaTeX{}-like while maintaining the +notation's familiarity is to switch to mixed-case names, used in a +consistent manner; for example: +\begin{verbatim} +CURRENTLY WOULD BECOME ... +\documentstyle \documentStyle +\printindex \printIndex +\begin{flushleft} \begin{flushLeft} +\end{verbatim} +Command/environment names that are one word (e.g., +\tr{\begin{enumerate}}) would be unchanged. + +Alternatively, we could make the literate-system case-insensitive +where command names are concerned and merely make it our {\em +convention} to use mixed-case names. + +%************************************************************************ +%* * +\subsubsection[multiple-indexes]{Multiple indexes} +%* * +%************************************************************************ + +Having one index for a pretty-big program is a dubious proposition; +you get a {\em huge} index. I think you need multiple indexes---in +the case of a compiler, you might then have a separate index for: +parser, typechecker, syntactic desugarer, optimiser, etc. + +Let's assume you index all the pieces of a compiler (as above) as +self-contained units. PROBLEM: it is the uses of functions, etc., +that {\em cross} such boundaries that you would MOST like to have your +attention drawn to. + +That problem aside, I think this is the basic solution: +\begin{description} +\item[\pl{\defineindex{<index-tag-string>}}:] +Says that \pl{<index-tag-string>} is ``legal'' hereafter. +Requiring/encouraging these \tr{\defineindex} will help to catch typos. + +\item[\pl{\index[<index-tag-string>]{<entry>}}:] +The \tr{\index} command has an optional \pl{<index-tag-string>} with +which this \pl{<entry>} should be tagged. The default tag +string is \tr{main} (unless reset with \tr{\setindex...}; below). + +\item[\pl{\printindex[<index-tag-strings>]}:] +Print an index here, made up from all the entries that have one of the +\pl{<index-tag-strings>}. The default tag string is (same +caveats...) \tr{main}. + +\item[\pl{\setcurrentindex{<index-tag-string>}}:] +Set the default tag string for \tr{\index} commands in text. +\end{description} + +I think you could use the mechanism above to come close to Texinfo's +idea about multiple indexes. + +%************************************************************************ +%* * +\subsubsection[better-Haskell-indexing]{Better \Haskell{} indexing} +%* * +%************************************************************************ + +(The idea probably carries over to other languages.) Stick the whole +literate-program \Haskell{} source into an ``interesting-thing +finder'' (call it \tr{htags} :-), getting back (source-location, +index-entry) pairs. Then the only trick is to tack each index-entry +onto the code block nearest to the reported source-location. + +%************************************************************************ +%* * +\subsubsection[revised-sectioning]{Revisions to the sectioning commands} +%* * +%************************************************************************ + +The main thing that is a pain about the current sectioning (see +\sectionref{Sectioning}) is making up unique node names all the time. +I propose the following ``system'' for the optional arg to +\tr{\section<n>}; shown by example: +\begin{description} +\item[\pl{\section{<title>}}:] +(As currently.) A default node name, made from the section number. +No \tr{\label} created. + +\item[\pl{\section[]{<title>}}:] +No node name, no node, no \tr{\label}. Not recommended :-) + +\item[\pl{\section[<the-usual>]{<title>}}:] +(As currently.) Arguably, the stuff to let you specific next/prev/up +explicitly should be dropped (to partly de-Info-ise the notation). + +\item[\pl{\section["]{<title>}}:] +(The new one.) The node name should be the same as the \pl{<title>} +(``ditto''). No \tr{\label} would be generated. Some massaging would +be required to remove nodename-hostile characters from the title +(e.g., colons). +\end{description} + +%************************************************************************ +%* * +\subsubsection[BNF-grammars]{A ``BNF grammar'' environment} +%* * +%************************************************************************ + +This would work like the \tr{verbatim} program used with the +\Haskell{} report; you could say: +\begin{verbatim} +\begin{grammar} +exp -> aexp + | exp aexp + | exp_1 op exp_2 + | @-@ aexp + | @\@ apat_1 ... apat_n [gd] @->@ exp + | @if@ exp_1 @then@ exp_2 @else@ exp_3 + | exp @where@ @{@ decls @}@ + | @case@ exp @of@ @{@ alts @}@ + | exp @::@ [context @=>@] atype +\end{grammar} +\end{verbatim} +and respectable BNF-looking stuff would appear in your output. Index +entries for the definitions of nonterminals would be generated; +possibly a \tr{[noindex]} option to suppress that. + +I'd also like to do something for inference rules, but I'm fairly +baffled about what that might be. (They can be mightily complicated, +and it's not clear that a plain-ASCII form is possible.) + +%************************************************************************ +%* * +\subsubsection[pseudo-C-preprocessor]{Fake ``C pre-processing''} +%* * +%************************************************************************ + +Change things so that literate documents are first put through a +``fake C pre-processor'' (this section assumes you know what a C +pre-processor does). Notes: +\begin{enumerate} +\item +The relevant commands would start with \tr{##} (to avoid confusion w/ +the real thing); hence, \tr{##if}, \tr{##endif}, \tr{##define}, +\tr{##include}, etc. + +\item +(Very important.) This pseudo-C-preprocessor does NOTHING inside: +\begin{itemize} +\item +Code environments (and the Bird-track equivalent). +\item +Verbatim environments. +\item +\tr{\tr} and \tr{\pl} commands (and any friends they may have). +\item +\tr{rawlatex} environments (next section). +\end{itemize} + +\item +All of the current dubious \tr{only<this-or-that>} environments and so +on would go away; what you currently write as: +\begin{verbatim} + \begin{onlystandalone} + \documentstyle[11pt,literate]{article} + \begin{document} + \title{Glasgow Literate Programming\\ User's Guide} + \date{April 1991} + \maketitle + \begin{onlylatex} + \tableofcontents + \end{onlylatex} + \clearpage + \end{onlystandalone} +\end{verbatim} +would be re-written as: +\begin{verbatim} + ##if defined(STANDALONE) + \documentstyle[11pt,literate]{article} + \begin{document} + \title{Glasgow Literate Programming\\ User's Guide} + \date{April 1991} + \maketitle + ##if defined(MK_LATEX) + \tableofcontents + ##endif /* MK_LATEX */ + \clearpage + ##endif /* STANDALONE */ +\end{verbatim} + +\item +\tr{##include} would take the place of the current bogosity +\tr{\inputnow}. + +\item +\tr{##define} would take over from the current emasculated +\tr{\define} and would emphasise the point that this literate notation +is a fixed notation, lacking general macros. + +\item +Running this or that program would pre-\pl{##define} certain symbols +(e.g., \pl{MK_LATEX}), but I don't know exactly which just yet. + +\item +Using \pl{##defines} and \pl{##ifdef}'ing easily generalises the +``standalone/partofdoc'' dichotomy (which badly needs generalising). +\end{enumerate} + +%************************************************************************ +%* * +\subsubsection[invisible-code]{Invisible code} +%* * +%************************************************************************ + +I am wondering if we shouldn't have a code environment of the form: +\begin{verbatim} +\begin{invisiblecode} +main (int argc, char **argv) +{ + printf("Hello, Seaworld!\n"); +} +\end{invisiblecode} +\end{verbatim} +for code that {\em should} be extracted (\tr{lit2pgm}) but that {\em +should not} be displayed in \tr{lit2latex/lit2texi} documents. +This would probably be used when you want to include most, but not all, +of a program's code---in a paper for publication, for example. + +My only fear is that it is too easily subject to abuse. + +Perhaps the C-pre-processing stuff is a better idea... +(\sectionref{pseudo-C-preprocessor}). + +%************************************************************************ +%* * +\subsubsection[text-in-code]{Plain text in your code} +%* * +%************************************************************************ + +In Knuth's WEB, you can refer to code-things in the text parts of the +document/program {\em and} to text-things in your code. (As I recall, +putting \tr{|} around text switches it to +whatever-you're-not-doing-now (code or text)). + +We have the first (the \tr{@...@} shorthand to refer to code things +while in text), but not the second: what's in a code environment is +code just like you would see in an illiterate program in the same +language. + +I guess the right solution is to have specially-marked comments +(again, language-dependent) that say, ``Don't treat this as just a +comment in this programming language, but extract it and +mangle/massage it as if it were literate-document text.'' + +A pain to implement. Not worth it? + +%************************************************************************ +%* * +\subsubsection[diff-fonts-in-text]{Using many ``fonts'' in text} +%* * +%************************************************************************ + +I find the \tr{\tr} (``typewriter font'') and \tr{\pl} (``plain +font'') commands quite useful. (Yes, I know they go against the +intensional markup principle (\sectionref{ASCII-declarative-markup}), +but they are {\em so} convenient...) + +I'm inclined to make up notations for italics, small caps, and bold +(and their ASCII-only ``equivalents'') and then try to systematize +their use. Hmmm.... + +I've found the Texinfo attempt to have a command for every different +kind of thing you might want to talk about in a document to be too +much and also unsatisfying. + +%************************************************************************ +%* * +\subsubsection[code-in-text-formatting]{Formatting code-ish things in text} +%* * +%************************************************************************ + +Right now, the \tr{@...@} shortcut notation means: Format this and +automagically index it as for the code parts of the document. + +Strictly speaking then, I think the \tr{@...@} notation should only be +used to refer to things that {\em actually exist} in the code parts of +the document, and {\em not} for code snippets, fragments, and other +things mentioned along the way. + +For this latter task, perhaps a \tr{\code[<language>]{<text>}} command +is in order. This says: format this \pl{<text>} as for +\pl{<language>}, but don't index it or pretend that it actually has +anything to do with the real code in the program. + +%************************************************************************ +%* * +\subsubsection[interface-with-papers]{Interface with plain \LaTeX{} papers} +%* * +%************************************************************************ + +At least in our setting, it is likely we've written one or more papers +about some interesting part of the literate program we're writing. +The paper is likely to be: +\begin{itemize} +\item +relatively polished (so you'd like to re-use that effort); +\item +either a decent introduction to some part of the program, or a +succinct synopsis of some part; +\item +in straight \LaTeX{}, but using features quite beyond our literate +markup, and including figures, etc.; +\item +not to be changed in any way. +\end{itemize} + +At the least, I'd like to be able to include the paper in toto, and +have pointers into it (refs to its labels). + +More/better ideas welcome. + +%************************************************************************ +%* * +\subsubsection[literate-para-mode]{A literate Para mode} +%* * +%************************************************************************ + +[See also \sectionref{lit2lit}.] + +The sad fact is that, at the moment, these literate programs/documents +are typed in as just plain files and manipulated as such. They are +only processed into LaTeX/Info documents after the fact (and only +occasionally). + +Para mode is a GNU emacs mode that (roughly...) lets you both edit +Texinfo files {\em and} jump around in them like Info files, based on +the node structure. Either edit-as-normal or navigate-as-Info. + +I think there are possibilities for doing the same thing with these +literate documents/programs. Then you'd get the benefits of +navigation, following indexery, etc., {\em as you create the files}. + +One major problem (?): the literate sectioning makes it quite easy to +navigate {\em within} a file, but, for it to be worth it, you'd like +the ``literate Para mode'' (in navigation mode) to be able to carry +you to the right place when you, e.g., want to go ``up'' from the +first \tr{\section} in a file. + +Implementation: my first cut would be: run something over all the +literate files in a program to collect ``Para-useful'' information; +save this somewhere---this is the moral equivalent of a TAGS file. +Then the navigation commands, etc., would use the pseudo-TAGS info to +do their thing. Because the info would get out of date as you hack on +your program, you'd re-make the pseudo-TAGS stuff whenever you stepped +out for coffee, lunch, or sleep. + +%************************************************************************ +%* * +\subsubsection[lit2lit]{A \tr{lit2lit} program (to help implement a Para system)} +%* * +%************************************************************************ + +[This might be a better way to implement a literate Para ...] Have a +program that takes a set of \tr{.lit} files, munges them to do all the +usual cross-referencing, etc., etc., and then writes out {\em versions +of the original files} with all the linking info, etc., etc., inserted +as {\em comments}. Call the program \tr{lit2lit}... + +If you took the \tr{lit2lit} output and re-ran it through one of the +other programs, e.g., \tr{lit2latex}, it would produce {\em exactly} +the same output. + +The purpose of the information stored in comments would be to provide an +Emacs mode (or something) enough information to help you jump around +in a large program or generally do useful stuff. + +For example, it might insert links and things for something like Bob +Weiner's Hyperbole system. + +I'm thinking that \tr{lit2lit} would be re-run over a system's sources +every night by \tr{cron(1)}. + +%************************************************************************ +%* * +\subsubsection[xtex-options]{Generating \LaTeX{} documents especially for \tr{xtex}} +%* * +%************************************************************************ + +\tr{Xtex} is a (free) DVI previewer with some hypertext-ish features; +in particular, if you click on a reference to a label, then it takes +you to the page where that label is defined. By generating a +``\LaTeX{}'' document with all the linking info explicit (in the form +of labels and references to them), \tr{xtex} would do almost all the +jumping-around stuff that \tr{info} and \tr{xinfo} do for you. {\em +And you don't lose the font information.} + +%************************************************************************ +%* * +\subsubsection[free-text-index]{A free-text ``index''} +%* * +%************************************************************************ + +OK, even with all the automagical indexing, cross-referencing, etc., +occasions will arise when you say, ``Help! I need to look absolutely +everywhere for \pl{<foo>}!'' (Like you do with grep/tags, but +preferably nicer---all the tricks of the free-text indexing trade.) + +It would be great to have a ``free text index'' button or pseudo-node +(an Info ``node'' that, when you jump to it, puts you in a +free-text-search mode. Of course, the free-text-search should be able +to plunk you down in the Info node you finally select). + +I really don't want to implement this myself :-) + +%************************************************************************ +%* * +\subsubsection[magic-Info-nodes]{Other ``magic'' Info nodes...} +%* * +%************************************************************************ + +The ``free text index'' magic Info node makes me wish for {\em other} +nodes-that-do-weird-things when you jump to them... You jump to it +and... it starts up a PostScript previewer and shows me a picture... +or sound... or my text editor so I can send a gripe to the maintainer +of \pl{foo}... and so on. + +%************************************************************************ +%* * +\subsubsection[revised-pgm-options]{Revise the way options are fed to \tr{lit2*} programs} +%* * +%************************************************************************ + +Using getopt(3)-style one-letter options is getting messy---there are +too many of them. Perhaps time for something more complicated... + +%************************************************************************ +%* * +\subsubsection[mixing-Bird-code-and-other]{Mixing code in ``Bird tracks'' with other code} +%* * +%************************************************************************ + +When you put something in a code environment, e.g., +\begin{verbatim} +\begin{code} +main _ = [ AppendChan stdout "Hi, Mom!\n" ] +\end{code} +\end{verbatim} +there is no doubt about what should be considered the ``first +column''. On the other hand, if you see a ``Bird track'' equivalent: +\begin{verbatim} +> main _ = [ AppendChan stdout "Hi, Mom!\n" ] +\end{verbatim} +obviously the initial \tr{>} should be stripped, but what about the +space following? This matters if the code is to be put through, e.g., +a C pre-processor, which looks for \pl{#}'s in column~1. + +The solution I lean to is to have an option that says how much whitespace +should be stripped off the front of Bird-track style code lines. + +%************************************************************************ +%* * +\subsubsection[code-reading-and-printing]{Decouple code reading and printing styles} +%* * +%************************************************************************ + +Code may come in either in code environments or in Bird-tracks. At +present, it is printed in the same style as it came. This should +remain the default. + +However, it would be nice to be able to say (with options), ``OK, +print {\em all} the code as if it were in Bird-track form'' (or vice +versa). This allows uniform presentation, while preserving +programmers' preference for typing in one style rather than the other. + +%************************************************************************ +%* * +\subsection[april91-old-ideas]{Old ideas that still haven't gone anywhere} +%* * +%************************************************************************ + +These are ideas that have been around for a long time, HAVE NOT BEEN +IMPLEMENTED, and no-one seems to have minded much. + +%************************************************************************ +%* * +\subsubsection[recording-who-to-blame]{\pl{\owner{<name>}}} +%* * +%************************************************************************ +\index{owner@\owner} +(Not \tr{lit2pgm}.) Give the ``name'' that should be listed as the +``owner'' of a section. If no \tr{\owner} command has been seen, then +the owner of the source file in which the first piece of text in the +section was found is used. + +[I haven't really decided how this should work.] + +%************************************************************************ +%* * +\subsubsection[test-burying]{Burying test cases in your document} +%* * +%************************************************************************ + +The idea is that you can say: +\begin{verbatim} +\begin{test}{foo} +<Weird stuff in here> +\end{test} +\end{verbatim} +For this test \tr{foo}, the \tr{<weird stuff in here>} would somehow +say how to run the test, what should be fed to standard input (etc.), +and what results to expect on standard output, standard error, and +perhaps certain output files. + +The idea is to put the (simple?) test cases right next to the code that +will be exercised. + +The problem is: tests can do pretty arbitrary things, and I don't see +any neat way to encode that fact. Simply bunging full-blown shell +scripts into the middle of your literate program hardly seems the +solution. Hmmm..... + +If we had them: test environments don't nest. + +See ????? (ToDo) for a note on using hidden comments to highlight test +information. + + +%************************************************************************ +%* * +\subsubsection[recording-changes]{Recording changes to your documents} +%* * +%************************************************************************ + +Vaguely like the test case stuff, you might say: +\begin{verbatim} +\begin{change} +<who> & <when> & <tag> & <description of first change> \\ +<who> & <when> & <tag> & <description of second change> \\ +... and so on ... +\end{change} +\end{verbatim} +This is intended to be like the ChangeLog stuff supported in Emacs +(\tr{C-x 4 a}). It really only makes sense to use it after software +is no longer undergoing cataclysmic change (after it is released +perhaps?). + +Anyway, the idea is to record your change notes right next to where +you make them. [The program(s) to extract these notes and to collate +them in the manner of your choice are not written yet.] + +These change environments don't nest. diff --git a/web/glasgow/lit2x-0.16/literate/doc/caveats.lit b/web/glasgow/lit2x-0.16/literate/doc/caveats.lit new file mode 100644 index 0000000000..bb96edd629 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/caveats.lit @@ -0,0 +1,45 @@ +\section[Caveats]{Caveats: bugs and foibles} + +As mentioned in \sectionref{clunky-implementation}, the initial +implementation of this literate-programming system is delicate at +best. + +\begin{enumerate} +\item +Environment-commands should be on lines of their own, and preferably +start in column~1; the latter is especially important for verbatim +environments. + +\item +The line numbers reported with errors stand a fair chance of being +wrong or even laughably irrelevant. \LaTeX{} doesn't report errors in +terms of their original source anyway at all... (urgh) + +\item +\tr{\Define}-itions (incl.~the built-in ones for \Haskell{}, +\LaTeX{}, etc.) are expanded inside \tr{\tr} and friends. + +\item +You can get confused \tr{\items} (in enumerations, etc.) if you have: +\begin{verbatim} +\item[... stuff here... ] ...................... ] + right bracket on the same line -------------------^ +\end{verbatim} +The solution (and it's better style anyway) is to put \tr{\items} on +lines of their own. This is a vestige of the implementation... + +\item +Don't put \tr{\index} commands inside footnotes. There are probably +some other related restrictions... (ToDo) + +\item +Tabs in code will be expanded to spaces. This matters only if you +have tabs in string constants, or some such (which you shouldn't, +because it's hard for the reader of your code to see what you've done; +use \tr{\t} or the equivalent). + +\item +If you use the cross-referencing (\tr{-D}, I think), you have the +annoying feature of cross-referencing to things very near by, even on +the same page. I don't know how to stop this. +\end{enumerate} diff --git a/web/glasgow/lit2x-0.16/literate/doc/habits.lit b/web/glasgow/lit2x-0.16/literate/doc/habits.lit new file mode 100644 index 0000000000..597708b8a0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/habits.lit @@ -0,0 +1,34 @@ +\section[Habits]{A checklist of good literate habits} + +[Suggestions welcome. Haven't worked on this in a while.] + +\begin{itemize} +\item +Express your ideas in a way amenable to plain ASCII representation, as +well as that of full-blown \TeX{} typesetting. For example, serious +\TeX{} math-mode stuff is not really on (even if you can get it past +\tr{lit2latex}). If you find this constraint a big problem, you may +well be using the wrong tool for the job. + +\item +If you test your document first as an Info file (i.e., use +\tr{lit2texi} to process it), once that is right then it is very +likely that the \LaTeX{} side of things (using \tr{lit2latex}) will +come out right as well. The reverse is not true. + +\item +Follow the convention that the sectioning in every file begins with a +\tr{\section}. For details on how to do sectioning, please see +\sectionref{How_to_section}. + +\item +Arrange your document so that your Info nodes come out no more than +two screenfuls' long. Very long nodes obviate the whole point of Info +documents. + +\item +It's hard to make up good sets of Info node names. First, they must +be unique! Second, it's best if the uniqueness is in the first few +characters, so that nodename completion may be used to most advantage. + +\end{itemize} diff --git a/web/glasgow/lit2x-0.16/literate/doc/highlights.lit b/web/glasgow/lit2x-0.16/literate/doc/highlights.lit new file mode 100644 index 0000000000..5a7f9b3d5c --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/highlights.lit @@ -0,0 +1,354 @@ +\section[Highlights]{Literate programming, Glasgow style} + +Literate programming is a style that tries to maximise humans' +understanding of programs by full-scale use the tools of the +description trade (typesetting, indexing, etc.) to say what a program +does and how it works. The power of literate programming is in the +synergy between writing code and documentation in a unified +framework. + +So, for example, in Knuth's original WEB +system [ToDo: add reference(s)] ``code'' and ``text'' may be +intermingled as much as you like, the pieces of ``code'' may appear in +any order (even though it's only glorified Pascal), and quite +substantial cross-referencing and indexing (not to mention +\TeX{}-based typesetting) is built in. Programs are just documents +for people to read and enjoy which happen to have +machine-manipulable code ``buried'' in them. + +% An essential feature of a literate program is that the +% compilable/executable program and the document describing that program +% come from {\em the same source}. A most desirable feature of a +% literate-programming system is that the painful-by-hand parts of +% documents, such as indexing and cross-referencing, are provided +% automatically.\footnote{This characterization of literate programming +% follows Van Wyk's column in CACM, May 1990.} +% +% This system for literate programming meets the criteria above. The +% first \sectiontype{Highlights} lists some of its features; the second +% \sectiontype{notation-tut} describes the \LaTeX{}-looking markup +% language and document structure; the third +% \sectiontype{Programs} says how to run these programs for literate +% programming. + +\subsection[Glasgow-objectives]{Objectives of our Glasgow system} + +With our Glasgow system, your ``program'' is a \LaTeX{}-like document, with +the compilable/executable code marked off by a \tr{\begin{code}} +... \tr{\end{code}} pair (or equivalent shortcut notation). From +there, your ``program'' may be (a)~compiled/interpreted [by extracting +the embedded code and feeding it to a ``normal'' compiler/interpreter]; +(b)~turned into a beautiful typeset document to be smeared onto dead +trees, or (c)~turned into an on-line viewable/jump-aroundable +document. + +Here are the specific (distinctive?) objectives of the Glasgow system. + +\subsubsection[on-line-form]{Programs/documents in an on-line form} + +The people-oriented documents produced by literate-programming systems +are usually on paper (this system provides those, too). For working +programmers, their good properties are largely overshadowed by one +fact: paper documents go stale quickly. Also, large programs turn +into not-so-navigable large piles of dead trees. Surely we can do +better! + +Note our emphasis on presenting work-in-progress, as opposed to a +system that emphasises the presentation of the final perfect +programming gem. + +Our goal is that these on-line documents should be the medium of +choice for programmers' daily reference. (APRIL91: See the note about +``literate Para mode'' in \sectionref{literate-para-mode}.) + +Our choice for an on-line format is the GNU Info format, a primitive +ASCII-only sort-of hypertext system. The main reason for this choice +is to let the GNU people do as much of our programming for us as +possible! The program \tr{info} can display Info files on just about +any kind of terminal; \tr{xinfo} works with the X~Window System; the +ubiquitous GNU~Emacs has an ever-improving Info mode. + +\subsubsection[medium-scale]{Programming on a medium scale} + +We aren't really interested in programming-in-the-small (one person, a +few hundred lines of code), and we don't know about programming in the +large (hundreds of programmers, millions of lines of code); our target +audience is five-person projects working on programs the size of, say, +a \Haskell{} compiler :-) + +\subsubsection[language-independence]{Programming language independence} + +The system may be used for literate programming with any programming +language. However, the quality of the indexing, typesetting, etc., +support will vary, depending on whether that language is ``supported'' +or not. Fortunately, the current implementation, while clunky (see +\sectionref{clunky-implementation}, makes it easy to add better +support for a given programming language. + +See \sectionref{reordering-unemphasis} for a related comment about +code re-ordering. + +\subsubsection[code-verissimilitude]{Program code written exactly as in illiterate programs} + +You put executable/compilable code into your literate programs by +inserting it in a \tr{\begin{code}/\end{code}} environment (or the +``Bird-track'' equivalent); for example: +\begin{verbatim} +\begin{code} +main _ = [ AppendChan stdout "Hello, world!\n" ] +\end{code} +\end{verbatim} +The principle is: you can write code inside a +\tr{\begin{code}/\end{code}} environment {\em exactly} as you would in +an illiterate program in the same language. + +This brings up a dichotomy that pervades literate programs: everything +in the program is either {\em code}\index{code (vs text)} (stuff in a +code environment, or equivalent) or {\em text}\index{text (vs code)} +(everything else). + +\subsubsection[ASCII-declarative-markup]{Use of ASCII-based files, ``declarative'' markup} + +ASCII-based files (as opposed to some weird binary ``internal +format''): so you can read the files directly and e-mail them to your +friends. + +Insisting on ASCII files means some kind of markup commands buried +in the text. + +We want the markup to be ``declarative,'' that is, to say ``what you +want'' rather than ``how to produce what you want.'' Section +numbering, generation of a table of contents, much indexing work, +cross referencing, creating of the Info ``node'' structure, etc., +etc., is done automagically. + +Our starting-point choice for a ``declarative'' markup notation was +\LaTeX{}, because that's what we know (and so do a lot of other +people). You could make the case that GNU's Texinfo format would've +been better, esp.~given some of our other objectives. Or: you could +argue that we should've chosen a completely different notation, +because some people look at our literate files and think they {\em +are} \LaTeX{}, which they are not. + +The most important parts of our \LaTeX{}-like notation are introduced +in \sectionref{notation-tut}, and the whole mess is exhaustively +described in \sectionref{Command_reference}. + +\subsubsection[hierarchical-structure]{Use of hierarchical structure} + +That is: programs/documents divided into sections, subsections within +sections, subsubsections... + +Hierarchy is a very powerful structuring tool, but its utility for +wading around a large sea of code is not apparent. APRIL91: See the +comments about a ``literate Para mode'' in +\sectionref{literate-para-mode}. + +See also \sectionref{sectioning-large-documents}. + +\subsubsection[separate-compilation]{``Separate compilation'' for large programs/documents} + +This really follows from the size of project we're trying to support; +it's just {\em too slow} to have to slurp in the {\em whole} program +text and do anything... (It's pretty slow as it is :-) + +Separate compilation of the embedded code: Use the normal mechanisms +of your programming language. For example, if you have a literate C +file, \tr{foo.lc}, then you would extract the code into \tr{foo.c} +(command: \tr{lit2pgm foo.lc}) and compile as normal (\tr{gcc -c foo.c}). + +``Separate compilation'' of the (\LaTeX{} and (Tex)info) +document-generating tasks: this is harder and quite a lot of work {\em +has} to be done at ``link time''. What happens: the initial +``separate compilations'' of all the individual files in a +program/document (e.g., \tr{lit2texi -c foo.lc} or +\tr{lit2latex -c foo.lc}) produce intermediate files (\tr{*.itxi} and +\tr{*.itex} files, respectively). These are then consulted when +a ``link'' is done (e.g., \tr{lit2latex root.lit}, where \tr{root.lit} +\tr{\inputs} the other files). + +(It's complicated: use Makefiles!) + +\subsubsection[one-file-many-purposes]{Using one file in several ways} + +Say you're writing a \Haskell{} compiler :-), which includes the +source code for a typechecker. On the one hand, you want this to be +included in ``the book'' (document) that is the whole compiler. +However, you may also want to have a ``typechecker document'' that is +itself self-contained (if only because the ``book'' is so big). Going +further: perhaps one module of your typechecker is so amazing that you +want to publish it as a paper. + +You could make copies of files, edit them, etc., but that's tacky, and +against a most deeply-held principle of literate programming: that you are +looking at {\em the} source code for the program being described. + +As it stands, this system lets you put \tr{\begin{onlystandalone}} and +\tr{\end{onlystandalone}} around pieces of your files that only apply +in the ``do this as a standalone document'' case; similarly, +\tr{\begin{onlypartofdoc}} and \tr{\end{onlypartofdoc}} for stuff that +only applies in the ``the glorious whole'' case. + +APRIL91: I am fairly convinced I got this {\em wrong} and believe that +this stuff would be much better handled with a pseudo-``C +pre-preprocessor'' (one that does not look inside code blocks [see +deeply-held principle above; \sectionref{code-verissimilitude}]); see +\sectionref{pseudo-C-preprocessor}. + +\subsection[Glasgow-NON-objectives]{NON-Objectives of our system} + +\subsubsection[not-reinvent-LaTeX]{Not to reinvent \LaTeX{} (or any other extensible notation)} + +Just as with Texinfo, our markup notation has a {\em fixed} set of +commands. We don't have a \tr{\define} command that let's you define +new macros in terms of old ones. This is for simplicity, I suppose. + +APRIL91: see the note about fake ``C pre-processing'' in +\sectionref{pseudo-C-preprocessor}. + +\subsubsection[reordering-unemphasis]{An un-emphasis on code-reordering} + +Some programming languages have a narrow-minded idea about what order +the pieces of a program must be presented (e.g., COBOL: identification +division, then file division, then data division [how many of you knew +this :-]), and some literate-programming systems provide lots of +machinery to get around this orderly intransigence. + +We write in \Haskell{}, which is relatively open-minded about the +order in which functions, etc., are presented. Re-splicing together +code from dispersed program fragments doesn't buy you much---and we +think the same is true for most modern or semi-modern programming +languages. Therefore, this system has only primitive support for +reordering code. + +\subsection[Other-Glasgow-features]{Other features of our Glasgow system} + +\subsubsection[sectioning-large-documents]{Sectioning support for large documents} + +The main thing we've done here is {\em change} the sectioning commands +(vs \LaTeX{}) so it's easy to re-arrange chunks of the hierarchy. +Also, a default Info ``node'' structure is worked out, based on the +sectioning information. (Veteran Texinfo hackers will appreciate the +joys of not typing error-prone \tr{@menu}s.) + +Sectioning in an individual file should {\em always} begins at +\tr{\section}; such files should then glued together in a ``root +file'' with \tr{\input} commands interspersed with \tr{\upsection} and +\tr{\downsection} commands. \tr{lit2latex}/\tr{lit2texi} combine your +files, putting appropriate real-\LaTeX{}/Texinfo sectioning commands +(\tr{\part}, \tr{\chapter}, etc.) in the right places. + +A side-effect of diverging from \LaTeX{} sectioning is that we can +support deeper nesting of sectioning commands. + +It's also neat to be able to change your mind about whether you want +to start with (\LaTeX{}-speak...) parts, chapters, sections, or +whatever... + +Please see \sectionref{Sectioning} for further details about this +whole mess. + +\subsubsection[automatic-indexing]{Automatic indexing of your code} + +An attempt is made to index all the ``interesting things'' in the code +parts of your program. The success of this enterprise depends on the +degree to which the language you are using is supported. + +In a paper manifestation, you'll get nice neat indexes, like we're +used to. In an on-line +manifestation, you would like to use the information to ``point and +jump'' (our Info-based implementation does this, perhaps clumsily). + +APRIL91: See \sectionref{multiple-indexes} for latest thoughts about +indexing. Also, I've put some comment about free-text retrieval in +\sectionref{free-text-index}. + +\subsubsection[manual-indexing]{Indexing by hand} + +Indexing your text (vs your code) is not automatic. You do it by hand +with \tr{\index{<stuff>}} commands. The format of the \tr{\index} +commands is a simplified (?) form of \tr{makeindex} commands. +\Sectionref{Indexing} gives the details. + +\subsubsection[automatic-cross-referencing]{Automatic cross-referencing of your code} + +Your code may also be automatically cross-referenced; again, it's +based on finding ``interesting things'' in your code; furthermore, it +depends on distinguishing between ``definitions'' and ``uses'', +because the main purpose of cross-referencing is to let you move quickly +from a ``use'' (e.g., of a function) to its ``definition''. + +APRIL91: Sometimes you would really like to be able to go from a +definition to all of its uses. Perhaps this should be an option. + +Cross-referencing is automatically OFF when producing \LaTeX{} +documents (we found it mainly cluttered) and ON when producing Info +files (which lets you jump to the definitions through a node's menu). + +\subsubsection[shortcut-notations]{Shortcut notations} + +Within non-code parts of documents, code snippets may be included +between `at' signs; e.g., \tr{@f x y = y@}---appropriate formatting, +indexing, etc., will be done. + +APRIL91 COMMENT: I need to clarify the proper use of these \tr{@}s. I +also need to figure what to do when \tr{@}s are not the right thing! +(I think Texinfo has an over-proliferation of commands for marking off +this and that in the text.) See \sectionref{code-in-text-formatting}. + +For the ordinary text to be shown in a typewriter font (much used in +user's guides, for example), you may use the \tr{\tr{<text>}} command; +the only restriction on \tr{<text>} is that braces must be balanced. +The same trick for ``plain'' (roman) font is \tr{\pl{<text>}}. +[APRIL91: See \sectionref{diff-fonts-in-text} for further thoughts +about fonts in your text.] + +APRIL91: See also: \sectionref{BNF-grammars}. + +\subsubsection[TeX-to-ASCII]{The great ``\LaTeX{} to ASCII'' problem solved!} + +(Well, not quite...) A literate program looks an awful lot like a +\LaTeX{} document. If you convert the program to an Info file, then +run the \tr{info2ascii} script [which I haven't written yet :-] over +it, you'll have a quite-reasonable all-ASCII nicely-formatted version +of your \LaTeX{}-ish input. + +\subsection[Glasgow-NON-features]{Shortcomings of our system} + +\subsubsection[texinfo-limits]{Limits because of the Texinfo intermediate representation} + +We produce our on-line viewable GNU Info files by going through their +Texinfo format. If something cannot be represented easily in Texinfo +(which doesn't do things not easily representable in character-only +ASCII), it ain't in our system. This leads to the following {\em very +notable} shortcomings: +\begin{enumerate} +\item +No graphics, pictures, or sound. +\item +No fancy mathematical stuff of the sort \TeX{}/\LaTeX{} is so good at. +Note: we would like to provide enough {\em basic} mathematical stuff +so you aren't hamstrung by this restriction. +\end{enumerate} + +\subsubsection[clumsy-node-namespace]{Node namespace is not ``neat''} + +For all practical purposes, it's {\em your problem} to make sure that +you don't get nodename clashes. This is really uncool. + +APRIL91: Some ideas for partial alleviation of making-up-nodenames +weariness, see \sectionref{revised-sectioning}. + +Barring that, a good discipline for making up unique nodenames would +be helpful (I haven't found one yet). + +\subsubsection[clunky-implementation]{A clunky implementation} + +The principle has been: do as little work as possible. (What do you +expect from the proponents of lazy functional programming?) + +The implementation is the Perl Script From Hell, with a supporting +cast of the Flex Program From Hell, and a whole bunch of exceedingly +useful programs written by other people, mainly the GNU +Info/Texinfo-related programs and \tr{tgrind} (by Van Jacobsen). [We +can pass along the source to all of these programs.] diff --git a/web/glasgow/lit2x-0.16/literate/doc/install.lit b/web/glasgow/lit2x-0.16/literate/doc/install.lit new file mode 100644 index 0000000000..8f4f9e1827 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/install.lit @@ -0,0 +1,96 @@ +\section[lit-install]{Standalone installation of Glasgow literate programming} + +NOT DONE PROPERLY YET. + +Here are some short notes; they should work on a Sun4: +\begin{enumerate} +\item +If you don't have \tr{perl}, go get it. + +\item +If you don't have \tr{makeindex} (normally with the TeX distribution) +and/or \tr{tgrind}, go get them, if you wish. You can easily get by +without them, especially \tr{tgrind}. + +\item +Customise for your local configuration, by creating a suitable +\tr{mkworld/site.jm} file. We supply a \tr{site.dist} file that you +can copy and work from. + +Setting \tr{PerlCmd} correctly is {\em vital}. + +All the Haskell-compiler stuff isn't important for the +literate-programming system. + +Setting \tr{TgrindHelperCmd} is important if you're going to try the +tgrind-ing stuff. + +Setting the things for installation (near the end) is {\em vital}. +You will almost certainly need to set \tr{InstRootDir}, and perhaps +some others. If you don't set anything, the literate-programming +system will be installed (on a Sun4) in... + +\begin{tabular}{ll} +/usr/local/bin/sun4 & things for the user to invoke (lit2mumble) \\ +/usr/local/lib/literate/sun4 & machine-specific support stuff \\ +/usr/local/lib/literate & machine-independent support stuff \\ +\end{tabular} + +\item +OK, you should be ready to go! From the top of the distribution... +\begin{verbatim} +% cd lit2xxx-X.YY +% ./STARTUP-literate >& startup.log +\end{verbatim} +Everything should proceed to an obviously-successful conclusion (check +the log to see...). + +\item +Test the system enough to see that it's not totally broken. +Invoke \tr{lit2pgm}, \tr{lit2latex}, or \tr{lit2texi} directly from +the \tr{literate/} directory, on some small test file of your choice, +even something as simple as...: +\begin{verbatim} +\section[test]{Test section} +This is a small test. +\end{verbatim} +Then try, perhaps: +\begin{verbatim} +% literate/lit2latex -v -c test.lit +\end{verbatim} + +\item +If things seem basically happy, you can safely install the system. +\begin{verbatim} +% cd literate +% make -n install # trial run, just to see if it looks "right" +% make install # for real! +\end{verbatim} + +\item +To make the documentation (some pre-built stuff is in the distrib): +\begin{verbatim} +% cd literate +% make literate.dvi # or ... +% make literate.info # or ... +% make docs # to do both +\end{verbatim} + +In the unlikely event you wanted to install it, continue with: +\begin{verbatim} +% make install-docs +\end{verbatim} + +\item +You can now either delete the source or just clean up: +\begin{verbatim} +% make clean +\end{verbatim} + +\item +Save a copy of your configuration file \tr{mkworld/site.jm} for next +time. +\end{enumerate} + +If you have problems, please report them to me, +partain\@dcs.glasgow.ac.uk. diff --git a/web/glasgow/lit2x-0.16/literate/doc/lang_ref.lit b/web/glasgow/lit2x-0.16/literate/doc/lang_ref.lit new file mode 100644 index 0000000000..16652af006 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/lang_ref.lit @@ -0,0 +1,472 @@ +\section[Command_reference]{\LaTeX{}-like markup commands: reference} + +This \sectiontype{Command_reference} assumes you are familiar with the +tutorial-ish material in \sectionref{notation-tut}. It also assumes +some familiarity with \LaTeX{}, in that I may say say, ``It works as +in \LaTeX{}''. + +The lists below catalog the environments\index{environment} +(\tr{\begin{...}/\end{...}} things) and commands\index{command} +(backslashed \tr{\things}) of our Glasgow literate-programming notation. +[For this clunky implementation, the \tr{\begin{...}} and \tr{\end{...}} +delimiters should be on lines by themselves, beginning in the leftmost +column.] + +Occasional mention is made of the main programs used to process +literate files: \tr{lit2pgm}, which extracts the code from a file; +\tr{lit2latex}, which creates real \LaTeX{} source from a file; and +\tr{lit2texi}, which creates Texinfo source from a file (from which +Info files can be made with \tr{makeinfo}). + +Little things first: +\begin{itemize} +\item +In text, you should use the \TeX{} style of double quotes: +\tr{``foo''}. +\item +In text, backslashed magic characters, e.g., \tr{\& \_ \# \$}, will +produce the self-same de-backslashed magic characters in the output. +\item +Accents on characters (e.g., \tr{\'e}) are fine; they are tossed from +Info files. +\item +You may safely use the italic correction \tr{\/}. +\item +At least the font-fiddling declarations \tr{\sc} and \tr{\tt} will +work; they are heartily unrecommended. +APRIL91: see the comments in \sectionref{diff-fonts-in-text}. +Also, make them commands, not declarations? +\end{itemize} + +Commands and environments (in alphabetical order): + +% I want to split these somehow so that info menus help one jump around + +\subsection*[\appendix]{\pl{\appendix}} +\index{appendix@\appendix} +Section numbering after this command is for appendices. +(Has no effect on Info files. ToDo: it probably should.) + +\subsection*[\author]{\pl{\author{<text>}}} +\index{author@\author} +Please see under \tr{\maketitle}. + +\subsection*[center_environment]{\pl{center} environment} +\index{center environment} +As for \LaTeX{}. [APRIL91: Not implemented (and not sure how to do it +easily on the Texinfo side), but I need to do something because Simon +keeps using it.] + +\subsection*[\centerline]{\pl{\centerline{<text>}}} +\index{centerline@\centerline} +As for \LaTeX{}. + +\subsection*[\caption]{\pl{\caption{<text>}}} +\index{caption@\caption} +As for \LaTeX{}; likely to be unsatisfactory for Info files because the +latter doesn't do figures. + +\subsection*[\clearpage-etc]{\pl{\clearpage} and \pl{\cleardoublepage}} +\index{clearpage@\clearpage} +\index{cleardoublepage@\cleardoublepage} +As in \LaTeX{}; no effect on Info files. + +\subsection*[code_environment]{\pl{code} environment} +\index{code environment} +% could use some indexing here ??? +See \sectionref{code-in-doc}. Also, don't forget the \tr{pseudocode} +environment. + +You cannot nest other environments inside code environments. + +\subsection*[comment_environment]{\pl{comment} environment} +\index{comment environment} +Text in a \tr{comment} environment will be output (perhaps with +extra indentation, smaller font, etc.) if a \tr{\suppresscomments} +command hasn't yet been encountered. [NB: \tr{\suppresscomments} +doesn't work with \tr{lit2texi}.] + +A comment environment cannot include another comment environment. + +\subsection*[\date]{\pl{\date{<text>}}} +\index{date@\date} +As for \LaTeX{}; please see under \tr{\maketitle} for exact details. + +\subsection*[\define]{\pl{\define{<command>}{<replacement>}}} +\index{define@\define} +Ultra-simple macro substitution, NOT LIKE \LaTeX{}. The text for +\tr{<command>} will be replaced with \tr{<replacement>}; no nesting, +no funny characters, nothing fancy. +Don't \tr{\define} the same \tr{<command>} twice, for +example. Intended for customising documents; please see the note +under \tr{\input}. + +Defaults are provided for \tr{\Haskell}, \tr{\LaTeX}, \tr{\TeX} and +\tr{\ldots}. More defaults on request. + +APRIL91: see \sectionref{pseudo-C-preprocessor} for what I would +REALLY like to do about ``defining''. + +\subsection*[description_environment]{\pl{description} environment} +\index{description environment} +As in \LaTeX{}. + +\subsection*[display_environment]{\pl{display} environment} +\index{display environment} +Similar to \tr{verbatim} (line-breaks are obeyed) but formatted in the +prevailing font (not necessarily typewriter). There is a +\tr{flushdisplay} environment as well. + +You can't nest one display environment inside another. + +\subsection*[\documentstyle]{\pl{\documentstyle[<style-options>]{<doc-type>}}} +\index{documentstyle@\documentstyle} +You do not have to the \tr{literate} \LaTeX{} style option; e.g., +\tr{\documentstyle[literate]{report}}, but it is probably a good idea +so people don't think you're writing real \LaTeX{}. + +\tr{\documentstyle} has two magical actions: (1)~the type of +document (report, article, etc.) determines the default value +for \tr{\rootsectiontype}, and (2)~it indicates that a standalone +document is being generated (not just a part of one). [APRIL91: bear +in mind that this standalone business is in jeopardy.] + +\subsection*[\em]{\pl{{\em <text>}}} +\index{em@\em} +The \pl{\em} (emphasize) declaration works just as in \LaTeX{}. + +APRIL91: make it a command, not a declaration, i.e., \pl{\em{<text>}}? + +\subsection*[enumerate_environment]{\pl{enumerate} environment} +\index{enumerate environment} +As in \LaTeX{}. + +\subsection*[figure_environment]{\pl{figure} environment} +\index{figure environment} +Goes straight through for \LaTeX{}; ignored for Info files, meaning that +whatever is inside won't ``float.'' (Remember: we don't really do +figures; see \sectionref{texinfo-limits}.) + +\subsection*[flushdisplay_environment]{\pl{flushdisplay} environment} +\index{flushdisplay environment} +Same as the \tr{display} environment, except it is not indented +relative to the left margin. + +You can't nest one flushdisplay environment inside another. + +\subsection*[flushverbatim_environment]{\pl{flushverbatim} environment} +\index{flushverbatim environment} +Same as the \tr{verbatim} environment except that text is not indented +relative to the left margin. + +You can't nest other environments inside a flushverbatim environment; +see the note in \sectionref{verbatim_environment}. + +\subsection*[\footnote]{\pl{\footnote{<text>}}} +\index{footnote@\footnote} +Footnotes work! NB: with \tr{makeinfo}, you may choose one of two +ways of doing footnotes in an Info file. By default, they will be at +the bottom of the node (style BN), as opposed to in a node of their +own (style MN). [ToDo: update the makeinfo info] + +\subsection*[\heading]{\pl{\heading{<title>}}} +\index{heading@\heading} +A pseudo-sectioning command that formats \tr{title} as if it were a +section heading (no numbering or any of that rot), but it doesn't put +anything in the table of contents, no Info node, no anything weird. + +\subsection*[\index]{\pl{\index{<entry>}}} +\index{index@\index} +Roughly as for \LaTeX{} with \tr{makeindex}. Don't try anything too +weird: for example, \tr{\index{<mumble>}} inside a footnote doesn't +work. Warning: full-blown \tr{makeindex}-style indexing has been +``simplified'': please see \sectionref{Indexing} for the full gory +(but wonderful!) details. + +\subsection*[\input]{\pl{\input{<filename>}}} +\index{input@\input} +Be sure these are on lines by themselves and start in column 1. The +argument should be the full filename---no implied suffix. Files will +be searched for along the \tr{LITINPUTS} path, specified by an +environment variable of the same name. The default path includes only +your current working directory. + +\tr{\input}s are only followed at link time; if that's not what you +want, either give the appropriate command-line flag (\tr{-n}) or use +\tr{\inputnow}. + +APRIL91: see \sectionref{pseudo-C-preprocessor} for some thoughts +about how inputting may be changed. + +\subsection*[\inputnow]{\pl{\inputnow{<filename>}}} +\index{inputnow@\inputnow} +These are \tr{\input}s that are followed always, no matter what. +Otherwise, they are the same. + +APRIL91: \tr{\inputnow} may go away at any second. + +\subsection*[\insertribbon]{\pl{\insertribbon{<ribbon-name>}}} +\index{insertribbon@\insertribbon} +Used to insert the text of one code-ribbon into another; see +\sectionref{code-in-doc}. Must share a line with nothing +but whitespace. Not recommended. + +ToDo: needs to be made to work {\em outside} of code environments, +rather than inside them. + +DOES NOT WORK WITH \tr{lit2pgm -q}! (which is what we often use.) + +\subsection*[itemize_environment]{\pl{itemize} environment} +\index{itemize environment} +As in \LaTeX{}. British spelling (``itemise'') also accepted. + +\subsection*[\label]{\pl{\label}} +\index{label@\label} +Free-standing \tr{\label}s [supposedly] work as expected in \LaTeX{}; +in Info files, a +\tr{\label} is taken as just another name for the node the \tr{\label} +is in. Determining which node it's in doesn't take account of +\tr{\input}s---it's the one it ``appears'' to be in---which may not be +what you want. You {\em really should} use node-names as labels +(see \sectionref{Node_specifications})... + +Labels (and, therefore, nodenames) shouldn't have weird characters in +them. Such labels (nodenames) will be studiously ignored. + +\subsection*[\listoffigures-etc]{\pl{\listoffigures} and \pl{\listoftables}} +\index{listoffigures@\listoffigures}\index{listoftables@\listoftables} +As for \LaTeX{}; has no effect on Info files, which don't do +lists of figures or tables. + +\subsection*[\makeindex]{\pl{\makeindex}} +\index{makeindex@\makeindex} +Not necessary even for \LaTeX{}---one is inserted automagically just +before \tr{\begin{document}}; has no effect on \tr{lit2texi}. + +\subsection*[\maketitle]{\pl{\maketitle}} +\index{maketitle@\maketitle} +Will work as in \LaTeX{} for simple cases, using values provided +by \tr{\author{<author-stuff>}}, \tr{\title{<title-stuff>}}, and +\tr{\date{<date-stuff>}}. The \tr{\\} line-breaker works. You +die if you try anything weird. + +For better or worse, if you use the \tr{-g} option (to ``grab'' a +subtree of text for printing), then it {\em does} matter if the +\tr{\maketitle} is in the pre-amble (before +\tr{\begin{document}}) or not. Please see \sectionref{Programs-and-options} +for the sorry details. + +\subsection*[menu_environment]{\pl{menu} environment} +\index{menu environment} +In producing an Info file, text in a \tr{menu} environment is +copied verbatim to create an Info menu. You must provide something +that Texinfo can grok. This whole mess +might be used in +conjunction with \tr{\suppressmenu} [if \tr{\suppressmenu} were +implemented yet]. + +APRIL91: this should probably be nuked if the rawtexinfo environment +comes online. + +\subsection*[\menuentry]{\pl{\menuentry{<tag>}{<description>}}} +\index{menuentry@\menuentry} +Requests that an extra menu entry be put at the {\em beginning} of +this section's menu. + +\subsection*[\node]{\pl{\node{<node-spec>}}} +\index{node@\node} +(Ignored for \LaTeX{}.) Makes an extra node in the Texinfo file; the +\tr{<node-spec>} is copied straight through to the output, so it's +your problem to include something sensible. + +APRIL91: nuked if rawtexinfo environment comes in? + +\subsection*[\pounds]{\pl{\pounds<something-like-a-number>}} +\index{pounds@\pounds} +The \pl{\pounds} must be followed by: zero or more whitespace +characters, a digit or a question mark, zero or more +digits/question-marks/commas/full-stops/the-letters-K-or-M, and a +digit/question-mark/the-letter-K-or-M. The Ks or Ms may be in +lower-case. The mind boggles. + +\subsection*[onlyinfo_environment]{\pl{onlyinfo} environment} +\index{onlyinfo environment} +Only the Texinfo/Info extraction program(s) pay attention to stuff +inside. Don't put code in here! + +APRIL91: this stuff is in jeopardy of disappearing. + +\subsection*[onlylatex_environment]{\pl{onlylatex} environment} +\index{onlylatex environment} +Only the \LaTeX{} extraction program(s) pay attention to stuff +inside. Don't put code in here! + +APRIL91: this stuff is in jeopardy of disappearing. + +\subsection*[onlypartofdoc_environment]{\pl{onlypartofdoc} environment} +\index{onlypartofdoc environment} +The extraction programs pay attention to stuff inside only if they +believe this is just a piece of a document (i.e., ``separate +compilation'' is going on). As always, don't put code in here! See +the \tr{\standaloneornot} command for a shortcut. + +% need an xref to how to separate-compile ... + +APRIL91: this stuff is in jeopardy of disappearing. + +\subsection*[onlystandalone_environment]{\pl{onlystandalone} environment} +\index{onlystandalone environment} +The extraction programs pay attention to stuff inside only if they +believe that a standalone document is in the works (i.e., a +\tr{\documentstyle} command has been seen or the \tr{-S} flag +given). As always, don't put +code in here! See the \tr{\standaloneornot} command for a shortcut. + +% need an xref to how to separate-compile ... + +APRIL91: this stuff is in jeopardy of disappearing. + +\subsection*[\pageref]{\pl{\pageref{<label-or-node-name>}}} +\index{pageref@\pageref} +In making \LaTeX{} documents, works as usual. In making Info +files, treated as a \tr{\ref} (there is no concept of ``page'' in +an Info document). + +\subsection*[\pl]{\pl{\pl}} +\index{pl@\pl} +Plain text, set in a roman font; equivalent to \tr{\mbox{\rm #1}}, except +that the argument can include any old printable ASCII characters, including +properly-nested braces (escaping them is irrelevant). If you want to +do something weird, do it another way. Note that linebreaks within +the \tr{\pl} are prevented. + +The equivalent typewriter thing is \tr{\tr}. + +APRIL91: see possible changes in \sectionref{diff-fonts-in-text}. + +\subsection*[\printindex]{\pl{\printindex}} +\index{printindex@\printindex} +Should be just before \tr{\end{document}}. +In Info mode, generates a node `Index' at the same sectioning depth as +your top-level sectioning commands. + +APRIL91: see possible changes in \sectionref{multiple-indexes}. + +\subsection*[pseudocode_environment]{\pl{pseudocode} environment} +\index{pseudocode environment} +Format the same way as in a \tr{code} environment, but the enclosed +stuff is not subject to extraction by \tr{lit2pgm}. + +Other environments do not nest inside a pseudocode environment. + +\subsection*[quotation_environment]{\pl{quotation} environment} +\index{quotation environment} +As in \LaTeX{}. + +\subsection*[rawlatex_environment]{\pl{rawlatex} environment} +\index{rawlatex environment} +If lit2latexing, copies the body of the environment straight through. +Otherwise, discard it. + +One trick you may need: because of the feeble implementation, the +system may still try to ``follow'' an \tr{\input} inside a rawlatex +environment (which it shouldn't). The solution is to ``hide'' the +\tr{\input} so it isn't first on a line: +\begin{verbatim} +\begin{rawlatex} +\begin{figure} +{}\input{weird-fig.ps} +\caption{Weird Figure} +\end{figure} +\end{rawlatex} +\end{verbatim} + +\subsection*[\ref]{\pl{\ref{<label-or-node-name>}}} +\index{ref@\ref} +As for \LaTeX{}. + +\subsection*[\rootsectiontype]{\pl{\rootsectiontype{<real-sectioning-command>}}} +\index{rootsectiontype@\rootsectiontype} +Please see \sectionref{Sectioning}. + +\subsection*[\sectiontype]{\pl{\sectiontype{<nodename>}}} +\index{sectiontype@\sectiontype} +Please see \sectionref{sectiontype-and-ref}. + +\subsection*[\sectionref]{\pl{\sectionref{<nodename>}}} +\index{sectionref@\sectionref} +Please see \sectionref{sectiontype-and-ref}. + +\subsection*[\standaloneornot]{\pl{\standaloneornot{<ifso>}{<ifnot>}}} +\index{standaloneornot@\standaloneornot} +If doing standalone-document processing (i.e., a \tr{\documentstyle} +seen or \tr{-S} flag given), use text \tr{<ifso>}; otherwise, use text +\tr{<ifnot>}. Keep this on one line {\em by itself}, OK?; for longer +things, use the \tr{onlystandalone} and \tr{onlypartofdoc} environments. + +APRIL91: this stuff is in SEVERE jeopardy of being nuked; see +\sectionref{pseudo-C-preprocessor}. + +\subsection*[\suppresscomments]{\pl{\suppresscomments}} +\index{suppresscomments@\suppresscomments} +Best put in the preamble of your overall document (i.e., before +\tr{\begin{document}}). Causes text in all subsequent \tr{comment} +environments to be ignored. NB: only works in producing \LaTeX{} +documents. (ToDo: fix this) + +%\item[\suppressmenu] +%\index{\suppressmenu} +%Put one in a section if you don't want a menu to be +%automagically generated for that section. See about the +%\tr{menu} environment above. [Not yet implemented.] + +\subsection*[table_environment]{\pl{table} environment} +\index{table environment} +Goes straight through for \LaTeX{}; ignored for Info files, meaning that +whatever is inside won't ``float.'' + +\subsection*[\tableofcontents]{\pl{\tableofcontents}} +\index{tableofcontents@\tableofcontents} +As for \LaTeX{}; adds extra stuff to the top-level menu in an Info file. + +\subsection*[tabular_environment]{\pl{tabular} environment} +\index{tabular environment} +Same format as \LaTeX{}, but anything magical beyond \tr{&}, +\tr{\\}, and \tr{\hline} will probably get you in trouble. + +Other environments don't nest inside a tabular environment. + +\subsection*[\title]{\pl{\title{<text>}}} +\index{title@\title} +Please see under \tr{\maketitle}. + +\subsection*[\tr]{\pl{\tr}} +\index{tr@\tr} +Set in typewriter font; equivalent to \tr{\mbox{\tt #1}}, except +that the argument can include any old printable ASCII characters, including +properly-nested braces (escaping them is irrelevant). If you want to +do something weird, do it another way. Note that linebreaks within +the \tr{\tr} are prevented. + +The equivalent non-typewriter thing is \tr{\pl}. + +APRIL91: see \sectionref{diff-fonts-in-text} for further comment on +this stuff. + +\subsection*[verbatim_environment]{\pl{verbatim} environment} +\index{verbatim environment} +As in \LaTeX{}---line-breaks are obeyed and everything is in typewriter +font. See also: the \tr{flushverbatim} and \tr{display} environments. + +You can't nest other environments inside verbatim environments. A +trick (hack) you can use to put a verbatim environment inside another +is to indent the inner one by one space, as in: +\begin{verbatim} + \begin{verbatim} + ... + \begin{verbatim} + ... + \end{verbatim} + ... + \end{verbatim} +\end{verbatim} diff --git a/web/glasgow/lit2x-0.16/literate/doc/lang_specific.lit b/web/glasgow/lit2x-0.16/literate/doc/lang_specific.lit new file mode 100644 index 0000000000..2f0c7a625a --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/lang_specific.lit @@ -0,0 +1,50 @@ +\section[Language_specific]{Language-specific processing} + +This \sectiontype{Language_specific} describes the processing of code +in documents that is done in a language-specific way. This is mainly +to do with indexing, typesetting, and similar matters. + +First, however, we give the default rules used when the programming +language used is unsupported or unknown. + +%------------------------------------------------------------------- +\subsection[Default_rules]{Rules for unknown or unsupported languages} + +[Not finished yet.] + +No hidden comments or explicit index entries in code. + +%------------------------------------------------------------------- +\subsection[Haskell_rules]{Language-specific rules for \Haskell{}} + +[This section is not finished yet.] + +An explicit code index entry comment is of the form: +\tr{--idx::<whatever>}, on a line of its own. + +A hidden comment is of the form: \tr{--hide::<whatever>}, on a line +of its own. + +%------------------------------------------------------------------- +\subsection[Perl_rules]{Language-specific rules for \tr{perl}} + +[This section is not finished yet.] + +An explicit code index entry comment is of the form: +\tr{#idx::<whatever>}, on a line of its own. + +A hidden comment is of the form: \tr{#hide::<whatever>}, on a line of +its own. + +%------------------------------------------------------------------- +\subsection[C_rules]{Language-specific rules for \tr{C}} + +[This section is not finished yet.] + +%------------------------------------------------------------------- +\subsection[Fortran_rules]{Language-specific rules for \tr{FORTRAN}} + +[This section is not finished yet.] + +The FORTRAN-specific support was provided by Adriaan Joubert +(adriaan\@dcs.qmw.ac.uk). diff --git a/web/glasgow/lit2x-0.16/literate/doc/lang_tut.lit b/web/glasgow/lit2x-0.16/literate/doc/lang_tut.lit new file mode 100644 index 0000000000..446a91c61d --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/lang_tut.lit @@ -0,0 +1,658 @@ +\section[notation-tut]{A \LaTeX{}-like document markup language (tutorial-ish)} +\index{latex-like markup language@LaTeX-like markup language} + +Here is a simple silly literate \Haskell{} program: + +\begin{verbatim} +\documentstyle[literate]{report} +\rootsectiontype{\part} +\begin{document} +Here is my \Haskell{} program to send a message to my friends: +\begin{code} +main _ = [ AppendChan stdout (message ++ " to " ++ my_friends) ] +\end{code} + +\section[message]{The Message} +\begin{code} +message = "Hello" +\end{code} +\subsection{Comments about the message and its implementation} +\begin{enumerate} +\item +The message is given as a top-level pattern binding. +\item +The @message@ binding does not violate the monomorphic restriction; +its type is \tr{[Char]}, which is not overloaded. +\end{enumerate} + +\section[friends]{My friends} + +\begin{code} +my_friends = ( \ y -> "Bob and Joe" ) 3 +\end{code} + +\printindex +\end{document} +\end{verbatim} + +Here are some things to see in this example (don't worry if it doesn't +make sense first time): +\begin{itemize} +\item +The compilable program (the parts between \tr{\begin{code}}s and +\tr{\end{code}}s) is simply contained in marked-off parts of your +document, and the code therein is completely ordinary (no special +programming notation). + +Such {\em code}\index{code (vs text)} is one ``kind of stuff'' in your +literate program; {\em text}\index{text (vs code)} is the other. +\item +The overall document is arranged hierarchically (\tr{\section}, +\tr{\subsection}, etc.) and looks an awful lot like a \LaTeX{} +document. +\item +There is quite a bit about {\em what} makes up your document +(sections, code, enumerated lists) and very little about {\em how} +your document should be formatted (e.g., ``skip 2 lines''). This is +``declarative'' markup. +\item +Your program code will be indexed automatically; the \tr{\printindex} +command is how you say where you want the index included. +\item +You can refer to things-in-your-code in the text parts of your +document, by enclosing the reference in \tr{@}'s, as in +\tr{@message@}. The reference will be suitably indexed. +\item +The sectioning commands (e.g., \tr{\section}) are odd (if you are +used to \LaTeX{}). Most important, a sectioning command gives a {\em +relative} position in the hierarchy; this means that commands like +\tr{\rootsectiontype} can be used to adjust the absolute sectioning in +the final document. In this example, the topmost section would be a +\LaTeX{} \tr{\chapter} by default, but it's been changed to be a \tr{\part}. +\item +More not-\LaTeX{} trivia: the optional argument to \tr{\section} +serves both as a label name (for \tr{\ref}, etc.) and as a node name +for GNU Info files. +\end{itemize} + +The following sections describe the more interesting parts of our +\LaTeX{}-like notation, illustrated in the example above. (Before +that is a micro-tutorial on \LaTeX{} conventions, in +\sectionref{micro-latex}.) +\begin{itemize} +\item +As the example above showed, the sectioning commands diverge quite +significantly from \LaTeX{}. \Sectionref{Sectioning} gives the full +details about sectioning. +\item +The example shows how program code is included in a document in the +simplest way: just begin \tr{\begin{code}} and \tr{\end{code}} around it. +\Sectionref{code-in-doc} describes the more involved uses of this +feature. +\item +\Sectionref{Cross_references} and \Sectionref{Indexing} describe how +to take full advantage of the cross-referencing and indexing +facilities in your literate programs. +\item +\Sectionref{Examples} is supposed to include several complete examples +of literate programs but IT IS NOT FINISHED YET. +\end{itemize} + +Remember: \Sectionref{Command_reference} is (supposed to be) a +complete reference document about the \LaTeX{}-like commands you may +safely use. + +\subsection[micro-latex]{A micro-tutorial on our \LaTeX{}-like conventions} + +\LaTeX{} is a document preparation system (described in a book of +almost that name, by Leslie Lamport), and its notation is the basis of +that used in this literate programming system. +Unsurprisingly, one thing you can do with your literate programs is +turn them into real \LaTeX{} documents (for typesetting), using the +program \tr{lit2latex}. + +A few things to know about our literate-programming markup notation: +\begin{itemize} +\item +Backslash (\tr{\}) is the starts-a-command character. Therefore, +\tr{\item} and \tr{\/} are commands, but \tr{dog} and \tr{(+)} are +just plain text. +\item +{\em Mandatory} arguments to a command are given inside curly braces. So, +we would use \tr{\foo{bar}} to pass one argument to the command +\tr{\foo}; we would use \tr{\bar{hey1}{hey2}} to pass two arguments to +the command \tr{\bar}. +\item +{\em Optional} arguments to a command are given in square brackets and +come before mandatory arguments. So, for example, +\tr{\help[everyone]{lunch}} passes one optional and one mandatory +argument to the command \tr{\help}. +\item +\tr{\foo} is a {\em command} called ``foo'', while \tr{\begin{foo}} +\pl{<text in-between>} \tr{\end{foo}} is an {\em environment} called +``foo'' with \pl{<text in-between>} being inside that environment. +\item +The above isn't everything you need to know. +\end{itemize} + +\subsection[Sectioning]{Sectioning commands} +\index{sectioning} + +[APRIL91: After you read this, you may want to see some proposed +changes in \sectionref{revised-sectioning}.] + +\subsubsection[section<n>]{The \tr{\section<n>} command} + +There is really just one sectioning command: +\begin{verbatim} +\section<n>[Info-node-name]{Section heading} +\end{verbatim} +where \tr{<n>} is a positive integer, the sectioning depth. For example, you +might have: +\begin{verbatim} +\documentstyle[literate]{book} +\rootsectiontype{\chapter} +\begin{document} +\section1[Node-1]{The top} + +\section2[Node-2]{The next level} +\section3[Node-3]{The bottom level} +\section3[Node-4]{More on the bottom level} + +\section2[Node-5]{Second part of the middle level} +\section3[Node-6]{Bottom level, next section} +\section3[Node-7]{Last section on bottom level} +\end{document} +\end{verbatim} +As a convenience, the following synonyms are supported: +\begin{verbatim} +\section \section1 +\subsection \section2 +\subsubsection \section3 +\subsubsubsection \section4 +\end{verbatim} + +Saying \tr{\rootsectiontype{\chapter}} causes \tr{\section1}, +\tr{\section2}, and \tr{\section3} to be translated into the \LaTeX{}/Texinfo +commands \tr{\chapter}, \tr{\section}, and \tr{\subsection}, +respectively. This system supports deeper section nesting than +\LaTeX{} (12 levels vs.~7). + +If you want a section heading but don't want anything to appear in the +table of contents, put a \tr{*} after the command name (just like +\LaTeX{}); for example: +\begin{verbatim} +\subsection*[\pageref]{\pl{\pageref{<label-or-node-name>}}} +\end{verbatim} + +If you want something that looks like a section heading but really +isn't (no table-of-contents entry, no Info node), you probably want +the \tr{\heading{<title>}} command. + +[Support your local creaky implementation: +you must put sectioning commands on lines of their own.] + +In making an Info file, the hierarchy of \tr{\section<n>} +commands will be turned into a corresponding hierarchy of Info nodes. +With \tr{info}, +you navigate along one level of the hierarchy with \tr{Next}- and +\tr{Prev}-node links; you move up the hierarchy with \tr{Up}-node +links; and you move down the hierarchy (e.g., from a \tr{\section<n>} +to its \tr{\section<n+1>}s) by choosing from an +(automatically-generated) Info menu. + +\subsubsection[How_to_section]{How to use \tr{\section<n>}} + +The presumption is that {\em every file in a literate document will begin its +sectioning with a \tr{\section}} (equivalently, \tr{\section1}) and +further sectioning will reflect a reasonable hierarchical structure +{\em within} the file. You usually know this when you are typing in a +particular file. + +What you often do {\em not} know is how the file fits into the larger +document, and it is most annoying (as happens sometimes with \LaTeX{}) +to have to rename all \tr{\chapter}s to \tr{\section}s, or some such. +The information on how things go together is usually in a ``root +file,'' which sticks things together with \tr{\input}, +\tr{\downsection} and \tr{\upsection}; this example is typical: +\begin{verbatim} + \section[Desugar_match]{@match@: compiling out pattern-matching} + \downsection + % each of the following files would start with a \section + \input{Match.lhs} + \input{DeTwiddle.lhs} + \input{MatchCon.lhs} + \input{MatchLit.lhs} + \upsection +\end{verbatim} + +The \tr{\upsection}s and \tr{\downsection}s determine what actual +\LaTeX{}/Texinfo sectioning command is generated for a particular +\tr{\section<n>} command. Unfortunately, the desired \LaTeX{}/Texinfo +sectioning command for the {\em top} section in your hierarchy depends +on the kind of document you are producing. For example, should it be +a \tr{\part} or a \tr{\chapter}? The solution here is to let you +choose, with the +\tr{\rootsectiontype{\foo}}\index{rootsectiontype@\rootsectiontype} +command. It says that \tr{\section1}s at the ``top level'' should be +typeset as \LaTeX{}/Texinfo \tr{\foo}'s. The defaults based on the +\tr{\documentstyle} should usually be adequate: +\begin{verbatim} +\documentstyle \rootsectiontype + +article \section +report \chapter +book \chapter +\end{verbatim} +For a report, a useful variant might be \tr{\rootsectiontype{\part}}. + +\subsubsection[sectiontype-and-ref]{The \tr{\sectiontype} and \tr{\sectionref} commands} + +Another annoying thing with \LaTeX{} sectioning is to type +\tr{Section~\ref{foo}} only to have \tr{foo} turn out to be a ``chapter'' +(not a ``section''). In this system, you can type +\tr{\sectiontype{Node-name}}\index{sectiontype@\sectiontype} and the type of the +sectioning command at node \tr{Node-name} (e.g., ``chapter,'' +``section'') will be inserted [any unit below sections will be called +``section'']. To have the inserted text be +capitalised, use \tr{\Sectiontype{Node-name}}. + +For the common idiom, +\tr{\sectiontype{Node-name}~\ref{Node-name}}, you may use +\tr{\sectionref{Node-name}}\index{sectionref@\sectionref} +(similarly for \tr{\Sectionref}).\index{sectionref@\Sectionref} +[I use this all the time. --WDP] + +\subsubsection[Node_specifications]{GNU Info node specifications with \tr{\section<n>}} +\index{node specification} + +[APRIL91: Don't overlook the new ideas in +\sectionref{revised-sectioning}.] + +When making an on-line Info document from a literate program, the text +between two sectioning commands is turned into an Info node. +Moreover, the sectioning commands are used to determine how the nodes +should be linked together---almost always in the hierarchical structure +implied by the sectioning. However, you can tweak the process as much +as you wish (almost no-one ever wishes...). + +Each \tr{\section<n>} command may have an optional ``node specification'', +with which you may specify the name of the Info node and how it should +be linked to other nodes. For common practice, I +recommend giving a (unique) node name and enjoying the default links; +for example: +\begin{verbatim} +\section[Foo-Sem]{Foo Semantics} +\end{verbatim} +Besides serving as the node name, \tr{Foo-Sem} will also be a \LaTeX{} +\tr{\label} and may be \tr{\ref}'d or \tr{\pageref}'d: for example, +you could say, ``The semantics are given in +section\pl{~\ref{Foo_Sem}}''. (This is more likely to work than +introducing a \tr{\label} of your own and \tr{\ref}'ing that.) + +%\begin{comment} +%I've considered making an unadorned \tr{\section{Foo Semantics}} mean the +%same thing as \tr{\section[Foo Semantics]{Foo Semantics}}, but I suspect +%something bad would eventually happen. +%\end{comment} + +Node names must not contain commas (and other unpleasant characters I +don't want to think about) and spaces are probably asking for trouble. + +The next example shows the {\em general} form for a node +specification, in which you want to specify all of a node's +links by hand:\footnote{Ignore the rest of this +\sectiontype{Node_specifications} unless you enjoy pain---it presumes +some familiarity with Texinfo/Info +specifics; see \tr{info info} and/or \tr{info texinfo}.} +\begin{verbatim} +\section1[This-Node,Next-Node,Prev-Node,Up-Node]{Bar Semantics} +\end{verbatim} + +A \tr{?} may be given for any of the four node-names; then the default is +used: +\begin{enumerate} +\item +The default node-name is the section number. +\item +The default +next-node is the one associated with the next same-level sectioning +command (i.e., the next \tr{\section<n>} command if this is a +\tr{\section<n>} command. +\item +Analogously for the default +previous-node\ldots{} +\item +The default up-node is the last-seen +next-level-up sectioning command, e.g., if at a \tr{\section<n>}, then the +last \tr{\section<n-1>} command seen. +\end{enumerate} +Any text before the first +\tr{\section} command goes in node \tr{Top}, which has node +specification ``\tr{Top,,,(dir)}''. + +The recommended form \tr{\section[Foo-Sem]{Foo Semantics}} is +just short for \tr{\section1[Foo-Sem,?,?,?]{Foo Semantics}}. + +Additional Info nodes that are unrelated to sectioning commands may be +added with the \tr{\node} command. [Note: not well tested.] + +% To prevent a node being generated for a sectioning command, give the +% node specification \tr{NO-NODE}, as in \tr{\section[NO-NODE]{Foo}}. + +If you want a \LaTeX{}-style sectioning command (e.g., to +specify a table-of-contents entry), use \tr{onlyinfo} and \tr{onlylatex} +environments. + +\subsection[code-in-doc]{Including program code in your document} + +Central to literate programming is having program code in your +document that can be directly extracted and compiled/executed. + +\subsubsection[usual-code-in-doc]{The usual ways to put code in a documents} + +The most straightforward way to do this is to put all the code in a +file in one or more \tr{\begin{code}} ... \tr{\end{code}} +environments---the code can then be extracted (in the order it appears +in the text) and fed to your favourite compiler/interpreter/whatever. + +An equivalent notation preferred by some is ``Bird tracks'', so-called +because it started with Richard Bird (and because Cordy calls them +that); lines starting with a \tr{>} are extracted; for example: +\begin{verbatim} +>main _ = [AppendChan stdout "hello, world\n"] +\end{verbatim} +is equivalent to: +\begin{verbatim} +\begin{code} +main _ = [AppendChan stdout "hello, world\n"] +\end{code} +\end{verbatim} +A block of Bird-tracked code lines must have a blank line before and +after (not having one usually indicates a typo). + +\begin{comment} +ToDo: Simon wants to know how code looks in (a)~a \LaTeX{}'d document and +(b)~an Info'd document. +\end{comment} + +\subsubsection[ribbons-details]{Code ribbons: the fancy stuff} + +Both of the above are shorthand notation for messier stuff going on +underneath... Strictly speaking, the code in a particular document is +made up of one or more +{\em ribbons}\index{ribbons, code}\index{code ribbons} of code. For +example, +\begin{verbatim} +A common thing to say to the world is ``Hello, world!'' +\begin{code}[hello-goodbye] +void HELLO() { printf("HELLO, WORLD!\n"); } +\end{code} + +However, you might want to be less exuberant: +\begin{code}[wimp] +void hello() { printf("hello, world!\n"); } +\end{code} + +And perhaps you are trying to tune out, not tune in. +\begin{code}[hello-goodbye] +void goodbye() { printf("Good-bye, cruel world...\n"); } +\end{code} +\end{verbatim} + +As always, code to be extracted goes inside a +\tr{\begin{code}}...\tr{\end{code}}; the {\em optional} argument after +\tr{\begin{code}} is the name of the code-ribbon to which the +program-text belongs. The example above has two ribbons, +\tr{hello-goodbye} and +\tr{wimp}. You can extract any code-ribbon(s) you wish [see +\tr{lit2pgm}'s -r option]; the disjoint +pieces of a particular ribbon (e.g., \tr{hello-goodbye} above) are +catenated together in the order seen. + +Usually, this ribbon-business is just a bother, so there is the good +ol' default ribbon, \tr{main}. For example, the +way-you-normally-write-things: +\begin{verbatim} +\begin{code} +void adieu() { printf("Adieu, cruel world...\n"); } +\end{code} +\end{verbatim} +is actually short for: +\begin{verbatim} +\begin{code}[main] +void adieu() { printf("Adieu, cruel world...\n"); } +\end{code} +\end{verbatim} + +Unsurprisingly, \tr{main} is the default code-ribbon when one is in +the ribbon-extraction business. Similarly, code included +with \tr{>} signs in the leftmost column (``Bird tracks'') is just +tacked onto the \tr{main} ribbon, too: +\begin{verbatim} +>void +>adieu() +>{ printf("Adieu, cruel world...\n"); } +\end{verbatim} + +\subsubsection[reordering-with-insertribbon]{Code reordering with \tr{\insertribbon}} + +If you are feeling particularly notorious, one piece of code may be +appended to several ribbons (a comma-separated list of ribbon names, +please---spaces are significant except for beside the commas): +\begin{verbatim} +\begin{code}[ribbon1, ribbon2, ribbon3] +void adieu() { printf("Bon soir, cru\\'el world...\n"); } +\end{code} +\end{verbatim} + +To get the effect of WEB-like parameterless macros, one ribbon +may use \tr{\insertribbon} to include a copy of another one, as in: +\begin{verbatim} +\begin{code} +void adieu() + \insertribbon{message} +\end{code} + +\begin{code}[message] +{ printf("Adieu, cruel world...\n"); } +\end{code} +\end{verbatim} + +ToDo: CHANGE \tr{\insertribbon} SO IT'S OUTSIDE OF code ENVIRONMENT. + +I don't recommend \tr{\insertribbon}. You can make a terrible mess +with it. I haven't tested it for months. + +\subsubsection[pseudocode]{Stuff that looks like code but isn't} + +If you want to include alternate versions of code (for illustrative +purposes, presumably), to be typeset as code but {\em not} subject to +extraction by \tr{lit2pgm}, put the extra versions in \tr{pseudocode} +environments. + +\subsubsection[magic-things-in-code]{Magic things you can put in your code} + +Generally speaking, you enter your program code inside a +\tr{code} environment {\em exactly} as you would +otherwise (the principle discussed in +\sectionref{code-verissimilitude}), and it will appear in your +documents as shown (nicely typeset, we hope). There are two magic +things that you can put in your code that do not appear in your +document (directly): +\begin{description} +\item[Index entries:] +\index{code index entries, extra}\index{index entries, extra ones in code} +Code is automagically indexed, but you may wish additional index +entries of your own choosing. + +\item[Hidden comments:] +\index{hidden comments}\index{comments, hidden} +You will sometimes want comments in your actual code that you do not +want printed. An example: you might want to record next to each code +block the names of the the test files used to exercise it. This is +{\em really boring} information to all but the most dedicated reader. +\end{description} + +In both cases, the information {\em could} be provided outside the +code environment (i.e., without any special construct), but it could +quite easily get lost (code blocks can be big, even if they shouldn't +be :-). + +In all cases, these annotations are in a form recognised as a comment +by the compiler/whatever for that language. Please see +\sectionref{Language_specific} for the exact form used for the +language you are interested in. A \Haskell{} example of both magic +bits might be: +\begin{verbatim} +\begin{code} +main _ = [AppendChan stdout "Hello, world...?\n"] +--idx:: world, state of +--hide:: use testfile093.hs +\end{code} +\end{verbatim} + +[APRIL91: Yell if you really dislike (or like) these two forms of +``magic things in code''.] + +\subsection[Cross_references]{Cross-referencing} + +For cross-referencing, the normal thing is to use node-names on +sectioning commands as labels, and to \tr{\ref{<label>}} and +\tr{\pageref{<label>}} them, as is the \LaTeX{} custom. +\tr{\pageref}s are discouraged, as there is no concept of page numbers +in Info files. + +Similarly, if you heave in a \tr{\label{<some text>}}, the Info side +of things will assume that \tr{<some text>} is just another label for +the current node [NOT IMPLEMENTED (ToDo)]. + +APRIL91: Cross-referencing is normally used to help you move from a +{\em use} of a code-thing to its {\em definition}. There should +probably be an option to let you get cross-referencing that will also +let you move from a definition to all of its uses. + +\subsection[Indexing]{Indexing} + +[APRIL91: changes are envisaged; see \sectionref{multiple-indexes}.] + +Indexing is assumed to work with the program +\tr{makeindex}\index{makeindex}, so you should put a +a \tr{\printindex}\index{printindex@\printindex} command where you want the +index to appear (almost always just before \tr{\end{document}}). +(A \LaTeX{} \tr{\makeindex}\index{makeindex@\makeindex} command is supplied +automagically before \tr{\begin{document}}.) + +Roughly speaking, code portions of your document are {\em automatically} +indexed, and then you index the text portion {\em manually}, with +\tr{\index} commands. + +\tr{\index{<entry text>}} is the basic indexing command and offers a +simplified \tr{makeindex} interface. +\begin{itemize} +\item +If you want just plain simple ``foo'' to appear in the index, use +\tr{\index{foo}}. +\item +If you want subitems in an index entry, separate them with \tr{!}s +[useful]. +\item +If you want separate text for sorting and printing an index entry, put +the two texts in that order, separated by an unescaped \tr{@}. +\item +To put a \tr{!} or \tr{@} in your index entry, escape it with a +backslash \tr{\}. +\item +All other (semi-normal) characters work as is. +\end{itemize} + +I don't encourage trying to have index entries pop out in different +fonts---it doesn't work in plain Info files. You can write devious +\LaTeX{}/\tr{makeindex} code on your own... + +Code-stuff in text (stuff inside \tr{@...@}) is indexed automatically, +just like ``real code''. What actually happens depends on the support +for your programming language---\sectionref{Language_specific} gives +all the language-specific indexing idiosyncracies. The {\em default} +bare-bones mechanism is that whitespace-free code-in-text over three +characters long (e.g., \tr{@typecheck@}) will generate an index entry. +To suppress automatic indexing of a piece of code-in-text, put a +\tr{\noindex}\index{noindex@\noindex} immediately following, as in +\tr{@typecheck@\noindex}. + +As mentioned in \sectionref{magic-things-in-code}, you can add +index entries for your code by inserting specially-formatted comments +(this depends on how well your programming language is supported). +For example, for \Haskell{}, you might use [NB: NOT IMPLEMENTED YET (ToDo?)]: +\begin{verbatim} +f x y z = (y z) x +-- the next line is a comment that will cause an index entry +-- equivalent to: \index{foo-bar-baz} +--#idx::foo-bar-baz +\end{verbatim} + +For a chunk of code, a mini-index pointing to the definitions of the +things it refers to (one possible definition of ``things:'' top-level +functions) will be produced right after the code. (For the Info file, +as part of the menu for that node.) +\begin{comment} +The Info part is done; I'm still thinking about what should be done +for \LaTeX{}. +\end{comment} +[APRIL91: this is one of the things contemplated in +\sectionref{multiple-indexes}.] + +At least some provision has been made for ``stop lists'' for the +automagical indexing (I'm not sure how well it works...). You put +words/strings that are normally picked up by the indexing into a file, +then tell the system this is your ``stop list file'' (\tr{-s} option, +I think), meaning ``Don't index these things---I'm not interested.'' + +\subsection[Examples]{Some complete examples [NOT FINISHED]} + +NOT FINISHED YET. Some day... + +Meanwhile, you will find some reasonable not-over-huge examples in the +\tr{literate/tests} directory in the source. + +\subsubsection[Simple_example]{A simple example} + +\subsubsection[Typical_example]{A typical example} + +\subsubsection[Hairy_example]{A hairy example} + +\subsection[Shortcuts]{Helpful short-cut notations} + +APRIL91: There is discussion about these sorts of things scattered +through the ``new ideas'' in \sectionref{april91-new-ideas}. + +\subsubsection[code-in-text]{Referring to code things in your text} + +In the text part of a literate program, one often wishes to refer to +things in the code (e.g., function names) or have code expressions in +the running text, and so forth. One would like this code-in-text to +be typeset just like the real-code-parts (currently verbatim, but that +could change). To mark off code-in-text, surround it with `at' signs: +as in \tr{@code in text@}; to put an `at' sign in in-line code, you've +got to put in two `ats': \tr{@x @@ (y, z)@}. Line-breaks are prevented +inside ``attified'' code-text. + +Because things inside `at' signs are so often just what you want to be +indexed, the rule is: if the at-signed thing contains no whitespace, +an index entry is generated. (How to prevent indexing and how to do +fancier things about indexing and cross-referencing are given +\sectionref{Indexing}.) + +APRIL91: see comments in \sectionref{text-in-code}. + +\subsubsection[fonts-in-text]{Using different ``fonts'' in your text} + +[APRIL91: Be sure to see \sectionref{diff-fonts-in-text}.] + +The \tr{\tr{<text>}} command sets \tr{<text>} in typewriter font, with +no need for escape characters or anything---provided the braces nest +properly. + +The same trick using a ``plain'' (roman) font is +\tr{\pl{<text>}}, to produce \pl{<text>}. + diff --git a/web/glasgow/lit2x-0.16/literate/doc/lit_mode.lit b/web/glasgow/lit2x-0.16/literate/doc/lit_mode.lit new file mode 100644 index 0000000000..8428bdb20b --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/lit_mode.lit @@ -0,0 +1,3 @@ +\section[Lit-mode]{`lit-mode' for Emacs} + +There will be one sometime. I even know what I want to do\ldots{} diff --git a/web/glasgow/lit2x-0.16/literate/doc/literate.dvi b/web/glasgow/lit2x-0.16/literate/doc/literate.dvi Binary files differnew file mode 100644 index 0000000000..167e3a2553 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/literate.dvi diff --git a/web/glasgow/lit2x-0.16/literate/doc/literate.info b/web/glasgow/lit2x-0.16/literate/doc/literate.info new file mode 100644 index 0000000000..bf24b42031 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/literate.info @@ -0,0 +1,3390 @@ +This is Info file literate.info, produced by Makeinfo-1.47 from the +input file literate.texi. + + +File: literate.info, Node: Top, Up: (dir) + +This guide introduces a suite of programs for literate programming. +They support documentation as a natural part of programming; a +program's organization focusses on understanding by humans. + +If you installing this system as a standalone entity, please see +section *Note lit-install::, near the end. + +This document begins with a few words about literate programming, the +objectives of this system, and the Neat Stuff that this system is +supposed to do for you (i.e., cheap, tasteless self-promotion). See +section *Note Highlights::. + +The real goods come next, most notably: + * an alleged "tutorial" on the LaTeX-like markup language in which + documents/programs are written (section *Note notation-tut::); + + * a "reference manual" about the same markup language; this tends to + be what you consult once you are using the system (section *Note + Command_reference::); + + * the programs/tools to mangle your documents/programs into useful + forms (section *Note Programs-and-options::). There are other +sections, too, in greater-or-less states of usefulness. + +It would be a good idea to understand the rudiments of GNU Info files +before reading much further -- type `info info' at your favourite Unix +prompt. Or you could just ignore all mention of Info files... + +YOUR SUGGESTIONS FOR IMPROVING THIS SYSTEM ARE MOST WELCOME. + +DISCLAIMER: "Literate programming" is not my(WDP)/our area of +expertise. This system has been developed mainly to suit our needs and +has evolved on a grease-the-squeaky-wheel principle. However, we +wouldn't bother to document it if we didn't think there was something +to it! + +APRIL91 PROPOSALS: I am thinking about some changes to the system, NOT +YET IMPLEMENTED. Discussion about most (all?) of them is gathered +together in section *Note april91-proposals::. (You can find all +discussion of proposed changes by grepping for "APRIL91".) + +SEPT92 THOUGHTS: Still haven't really worked on this system. I have +typed a few further thoughts at the obvious place. I have fixed one or +two bugs, and I have incorporated Adriaan Joubert's +(adriaan@dcs.qmw.ac.uk) stuff for "literate Fortran," for which I am +most grateful. (See, it really is easy to extend :-) + +For more information about "real" literate programming, the +bibliography of literate programming in the (approx: ToDo) March 1991 +SIGPLAN Notices may be of use. + +* Menu: + +* Highlights:: Literate programming, Glasgow style. +* notation-tut:: A LaTeX-like document markup language (tutorial-ish). +* Command_reference:: LaTeX-like markup commands: reference. +* Language_specific:: Language-specific processing. +* Habits:: A checklist of good literate habits. +* Caveats:: Caveats: bugs and foibles. +* Programs-and-options:: Programs to process literate documents. +* Info_etc:: Using your processed literate documents. +* april91-proposals:: APRIL91 PROPOSALS. +* sept92-thoughts:: SEPT92 THOUGHTS. +* lit-install:: Standalone installation of Glasgow literate programming. +* Index:: Index. + + +File: literate.info, Node: Highlights, Next: notation-tut, Prev: Top, Up: Top + +Literate programming, Glasgow style +=================================== + +Literate programming is a style that tries to maximise humans' +understanding of programs by full-scale use the tools of the +description trade (typesetting, indexing, etc.) to say what a program +does and how it works. The power of literate programming is in the +synergy between writing code and documentation in a unified framework. + +So, for example, in Knuth's original WEB system [ToDo: add +reference(s)] "code" and "text" may be intermingled as much as you +like, the pieces of "code" may appear in any order (even though it's +only glorified Pascal), and quite substantial cross-referencing and +indexing (not to mention TeX-based typesetting) is built in. Programs +are just documents for people to read and enjoy which happen to have +machine-manipulable code "buried" in them. + +* Menu: + +* Glasgow-objectives:: Objectives of our Glasgow system. +* Glasgow-NON-objectives:: NON-Objectives of our system. +* Other-Glasgow-features:: Other features of our Glasgow system. +* Glasgow-NON-features:: Shortcomings of our system. + + +File: literate.info, Node: Glasgow-objectives, Next: Glasgow-NON-objectives, Prev: Highlights, Up: Highlights + +Objectives of our Glasgow system +-------------------------------- + +With our Glasgow system, your "program" is a LaTeX-like document, with +the compilable/executable code marked off by a `\begin{code}' ... +`\end{code}' pair (or equivalent shortcut notation). From there, your +"program" may be (a) compiled/interpreted [by extracting the embedded +code and feeding it to a "normal" compiler/interpreter]; (b) turned +into a beautiful typeset document to be smeared onto dead trees, or (c) +turned into an on-line viewable/jump-aroundable document. + +Here are the specific (distinctive?) objectives of the Glasgow system. + +* Menu: + +* on-line-form:: Programs/documents in an on-line form. +* medium-scale:: Programming on a medium scale. +* language-independence:: Programming language independence. +* code-verissimilitude:: Program code written exactly as in illiterate programs. +* ASCII-declarative-markup:: Use of ASCII-based files, "declarative" markup. +* hierarchical-structure:: Use of hierarchical structure. +* separate-compilation:: "Separate compilation" for large programs/documents. +* one-file-many-purposes:: Using one file in several ways. + + +File: literate.info, Node: on-line-form, Next: medium-scale, Prev: Glasgow-objectives, Up: Glasgow-objectives + +Programs/documents in an on-line form +..................................... + +The people-oriented documents produced by literate-programming systems +are usually on paper (this system provides those, too). For working +programmers, their good properties are largely overshadowed by one +fact: paper documents go stale quickly. Also, large programs turn into +not-so-navigable large piles of dead trees. Surely we can do better! + +Note our emphasis on presenting work-in-progress, as opposed to a +system that emphasises the presentation of the final perfect +programming gem. + +Our goal is that these on-line documents should be the medium of choice +for programmers' daily reference. (APRIL91: See the note about +"literate Para mode" in section *Note literate-para-mode::.) + +Our choice for an on-line format is the GNU Info format, a primitive +ASCII-only sort-of hypertext system. The main reason for this choice +is to let the GNU people do as much of our programming for us as +possible! The program `info' can display Info files on just about any +kind of terminal; `xinfo' works with the X Window System; the +ubiquitous GNU Emacs has an ever-improving Info mode. + + +File: literate.info, Node: medium-scale, Next: language-independence, Prev: on-line-form, Up: Glasgow-objectives + +Programming on a medium scale +............................. + +We aren't really interested in programming-in-the-small (one person, a +few hundred lines of code), and we don't know about programming in the +large (hundreds of programmers, millions of lines of code); our target +audience is five-person projects working on programs the size of, say, +a Haskell compiler :-) + + +File: literate.info, Node: language-independence, Next: code-verissimilitude, Prev: medium-scale, Up: Glasgow-objectives + +Programming language independence +................................. + +The system may be used for literate programming with any programming +language. However, the quality of the indexing, typesetting, etc., +support will vary, depending on whether that language is "supported" or +not. Fortunately, the current implementation, while clunky (see +section *Note clunky-implementation::, makes it easy to add better +support for a given programming language. + +See section *Note reordering-unemphasis:: for a related comment about +code re-ordering. + + +File: literate.info, Node: code-verissimilitude, Next: ASCII-declarative-markup, Prev: language-independence, Up: Glasgow-objectives + +Program code written exactly as in illiterate programs +...................................................... + +You put executable/compilable code into your literate programs by +inserting it in a `\begin{code}/\end{code}' environment (or the +"Bird-track" equivalent); for example: + \begin{code} + main _ = [ AppendChan stdout "Hello, world!\n" ] + \end{code} +The principle is: you can write code inside a `\begin{code}/\end{code}' +environment *exactly* as you would in an illiterate program in the same +language. + +This brings up a dichotomy that pervades literate programs: everything +in the program is either *code* (stuff in a code environment, or +equivalent) or *text* (everything else). + + +File: literate.info, Node: ASCII-declarative-markup, Next: hierarchical-structure, Prev: code-verissimilitude, Up: Glasgow-objectives + +Use of ASCII-based files, "declarative" markup +.............................................. + +ASCII-based files (as opposed to some weird binary "internal format"): +so you can read the files directly and e-mail them to your friends. + +Insisting on ASCII files means some kind of markup commands buried in +the text. + +We want the markup to be "declarative," that is, to say "what you want" +rather than "how to produce what you want." Section numbering, +generation of a table of contents, much indexing work, cross +referencing, creating of the Info "node" structure, etc., etc., is done +automagically. + +Our starting-point choice for a "declarative" markup notation was +LaTeX, because that's what we know (and so do a lot of other people). +You could make the case that GNU's Texinfo format would've been better, +esp. given some of our other objectives. Or: you could argue that we +should've chosen a completely different notation, because some people +look at our literate files and think they *are* LaTeX, which they are +not. + +The most important parts of our LaTeX-like notation are introduced in +section *Note notation-tut::, and the whole mess is exhaustively +described in section *Note Command_reference::. + + +File: literate.info, Node: hierarchical-structure, Next: separate-compilation, Prev: ASCII-declarative-markup, Up: Glasgow-objectives + +Use of hierarchical structure +............................. + +That is: programs/documents divided into sections, subsections within +sections, subsubsections... + +Hierarchy is a very powerful structuring tool, but its utility for +wading around a large sea of code is not apparent. APRIL91: See the +comments about a "literate Para mode" in section *Note +literate-para-mode::. + +See also section *Note sectioning-large-documents::. + + +File: literate.info, Node: separate-compilation, Next: one-file-many-purposes, Prev: hierarchical-structure, Up: Glasgow-objectives + +"Separate compilation" for large programs/documents +................................................... + +This really follows from the size of project we're trying to support; +it's just *too slow* to have to slurp in the *whole* program text and +do anything... (It's pretty slow as it is :-) + +Separate compilation of the embedded code: Use the normal mechanisms +of your programming language. For example, if you have a literate C +file, `foo.lc', then you would extract the code into `foo.c' (command: +`lit2pgm foo.lc') and compile as normal (`gcc -c foo.c'). + +"Separate compilation" of the (LaTeX and (Tex)info) document-generating +tasks: this is harder and quite a lot of work *has* to be done at "link +time". What happens: the initial "separate compilations" of all the +individual files in a program/document (e.g., `lit2texi -c foo.lc' or +`lit2latex -c foo.lc') produce intermediate files (`*.itxi' and +`*.itex' files, respectively). These are then consulted when a "link" +is done (e.g., `lit2latex root.lit', where `root.lit' `\inputs' the +other files). + +(It's complicated: use Makefiles!) + + +File: literate.info, Node: one-file-many-purposes, Prev: separate-compilation, Up: Glasgow-objectives + +Using one file in several ways +.............................. + +Say you're writing a Haskell compiler :-), which includes the source +code for a typechecker. On the one hand, you want this to be included +in "the book" (document) that is the whole compiler. However, you may +also want to have a "typechecker document" that is itself +self-contained (if only because the "book" is so big). Going further: +perhaps one module of your typechecker is so amazing that you want to +publish it as a paper. + +You could make copies of files, edit them, etc., but that's tacky, and +against a most deeply-held principle of literate programming: that you +are looking at *the* source code for the program being described. + +As it stands, this system lets you put `\begin{onlystandalone}' and +`\end{onlystandalone}' around pieces of your files that only apply in +the "do this as a standalone document" case; similarly, +`\begin{onlypartofdoc}' and `\end{onlypartofdoc}' for stuff that only +applies in the "the glorious whole" case. + +APRIL91: I am fairly convinced I got this *wrong* and believe that this +stuff would be much better handled with a pseudo-"C pre-preprocessor" +(one that does not look inside code blocks [see deeply-held principle +above; section *Note code-verissimilitude::]); see section *Note +pseudo-C-preprocessor::. + + +File: literate.info, Node: Glasgow-NON-objectives, Next: Other-Glasgow-features, Prev: Glasgow-objectives, Up: Highlights + +NON-Objectives of our system +---------------------------- + +* Menu: + +* not-reinvent-LaTeX:: Not to reinvent LaTeX (or any other extensible notation). +* reordering-unemphasis:: An un-emphasis on code-reordering. + + +File: literate.info, Node: not-reinvent-LaTeX, Next: reordering-unemphasis, Prev: Glasgow-NON-objectives, Up: Glasgow-NON-objectives + +Not to reinvent LaTeX (or any other extensible notation) +........................................................ + +Just as with Texinfo, our markup notation has a *fixed* set of +commands. We don't have a `\define' command that let's you define new +macros in terms of old ones. This is for simplicity, I suppose. + +APRIL91: see the note about fake "C pre-processing" in section *Note +pseudo-C-preprocessor::. + + +File: literate.info, Node: reordering-unemphasis, Prev: not-reinvent-LaTeX, Up: Glasgow-NON-objectives + +An un-emphasis on code-reordering +................................. + +Some programming languages have a narrow-minded idea about what order +the pieces of a program must be presented (e.g., COBOL: identification +division, then file division, then data division [how many of you knew +this :-]), and some literate-programming systems provide lots of +machinery to get around this orderly intransigence. + +We write in Haskell, which is relatively open-minded about the order in +which functions, etc., are presented. Re-splicing together code from +dispersed program fragments doesn't buy you much -- and we think the +same is true for most modern or semi-modern programming languages. +Therefore, this system has only primitive support for reordering code. + + +File: literate.info, Node: Other-Glasgow-features, Next: Glasgow-NON-features, Prev: Glasgow-NON-objectives, Up: Highlights + +Other features of our Glasgow system +------------------------------------ + +* Menu: + +* sectioning-large-documents:: Sectioning support for large documents. +* automatic-indexing:: Automatic indexing of your code. +* manual-indexing:: Indexing by hand. +* automatic-cross-referencing:: Automatic cross-referencing of your code. +* shortcut-notations:: Shortcut notations. +* TeX-to-ASCII:: The great "LaTeX to ASCII" problem solved!. + + +File: literate.info, Node: sectioning-large-documents, Next: automatic-indexing, Prev: Other-Glasgow-features, Up: Other-Glasgow-features + +Sectioning support for large documents +...................................... + +The main thing we've done here is *change* the sectioning commands (vs +LaTeX) so it's easy to re-arrange chunks of the hierarchy. Also, a +default Info "node" structure is worked out, based on the sectioning +information. (Veteran Texinfo hackers will appreciate the joys of not +typing error-prone `@menu's.) + +Sectioning in an individual file should *always* begins at `\section'; +such files should then glued together in a "root file" with `\input' +commands interspersed with `\upsection' and `\downsection' commands. +`lit2latex'/`lit2texi' combine your files, putting appropriate +real-LaTeX/Texinfo sectioning commands (`\part', `\chapter', etc.) in +the right places. + +A side-effect of diverging from LaTeX sectioning is that we can support +deeper nesting of sectioning commands. + +It's also neat to be able to change your mind about whether you want to +start with (LaTeX-speak...) parts, chapters, sections, or whatever... + +Please see section *Note Sectioning:: for further details about this +whole mess. + + +File: literate.info, Node: automatic-indexing, Next: manual-indexing, Prev: sectioning-large-documents, Up: Other-Glasgow-features + +Automatic indexing of your code +............................... + +An attempt is made to index all the "interesting things" in the code +parts of your program. The success of this enterprise depends on the +degree to which the language you are using is supported. + +In a paper manifestation, you'll get nice neat indexes, like we're used +to. In an on-line manifestation, you would like to use the information +to "point and jump" (our Info-based implementation does this, perhaps +clumsily). + +APRIL91: See section *Note multiple-indexes:: for latest thoughts about +indexing. Also, I've put some comment about free-text retrieval in +section *Note free-text-index::. + + +File: literate.info, Node: manual-indexing, Next: automatic-cross-referencing, Prev: automatic-indexing, Up: Other-Glasgow-features + +Indexing by hand +................ + +Indexing your text (vs your code) is not automatic. You do it by hand +with `\index{<stuff>}' commands. The format of the `\index' commands +is a simplified (?) form of `makeindex' commands. Section *Note +Indexing:: gives the details. + + +File: literate.info, Node: automatic-cross-referencing, Next: shortcut-notations, Prev: manual-indexing, Up: Other-Glasgow-features + +Automatic cross-referencing of your code +........................................ + +Your code may also be automatically cross-referenced; again, it's based +on finding "interesting things" in your code; furthermore, it depends +on distinguishing between "definitions" and "uses", because the main +purpose of cross-referencing is to let you move quickly from a "use" +(e.g., of a function) to its "definition". + +APRIL91: Sometimes you would really like to be able to go from a +definition to all of its uses. Perhaps this should be an option. + +Cross-referencing is automatically OFF when producing LaTeX documents +(we found it mainly cluttered) and ON when producing Info files (which +lets you jump to the definitions through a node's menu). + + +File: literate.info, Node: shortcut-notations, Next: TeX-to-ASCII, Prev: automatic-cross-referencing, Up: Other-Glasgow-features + +Shortcut notations +.................. + +Within non-code parts of documents, code snippets may be included +between `at' signs; e.g., `@f x y = y@' -- appropriate formatting, +indexing, etc., will be done. + +APRIL91 COMMENT: I need to clarify the proper use of these `@'s. I +also need to figure what to do when `@'s are not the right thing! (I +think Texinfo has an over-proliferation of commands for marking off +this and that in the text.) See section *Note +code-in-text-formatting::. + +For the ordinary text to be shown in a typewriter font (much used in +user's guides, for example), you may use the `\tr{<text>}' command; the +only restriction on `<text>' is that braces must be balanced. The same +trick for "plain" (roman) font is `\pl{<text>}'. [APRIL91: See section +*Note diff-fonts-in-text:: for further thoughts about fonts in your +text.] + +APRIL91: See also: section *Note BNF-grammars::. + + +File: literate.info, Node: TeX-to-ASCII, Prev: shortcut-notations, Up: Other-Glasgow-features + +The great "LaTeX to ASCII" problem solved! +.......................................... + +(Well, not quite...) A literate program looks an awful lot like a +LaTeX document. If you convert the program to an Info file, then run +the `info2ascii' script [which I haven't written yet :-] over it, +you'll have a quite-reasonable all-ASCII nicely-formatted version of +your LaTeX-ish input. + + +File: literate.info, Node: Glasgow-NON-features, Prev: Other-Glasgow-features, Up: Highlights + +Shortcomings of our system +-------------------------- + +* Menu: + +* texinfo-limits:: Limits because of the Texinfo intermediate representation. +* clumsy-node-namespace:: Node namespace is not "neat". +* clunky-implementation:: A clunky implementation. + + +File: literate.info, Node: texinfo-limits, Next: clumsy-node-namespace, Prev: Glasgow-NON-features, Up: Glasgow-NON-features + +Limits because of the Texinfo intermediate representation +......................................................... + +We produce our on-line viewable GNU Info files by going through their +Texinfo format. If something cannot be represented easily in Texinfo +(which doesn't do things not easily representable in character-only +ASCII), it ain't in our system. This leads to the following *very +notable* shortcomings: + 1. No graphics, pictures, or sound. + + 2. No fancy mathematical stuff of the sort TeX/LaTeX is so good at. + Note: we would like to provide enough *basic* mathematical stuff + so you aren't hamstrung by this restriction. + + +File: literate.info, Node: clumsy-node-namespace, Next: clunky-implementation, Prev: texinfo-limits, Up: Glasgow-NON-features + +Node namespace is not "neat" +............................ + +For all practical purposes, it's *your problem* to make sure that you +don't get nodename clashes. This is really uncool. + +APRIL91: Some ideas for partial alleviation of making-up-nodenames +weariness, see section *Note revised-sectioning::. + +Barring that, a good discipline for making up unique nodenames would be +helpful (I haven't found one yet). + + +File: literate.info, Node: clunky-implementation, Prev: clumsy-node-namespace, Up: Glasgow-NON-features + +A clunky implementation +....................... + +The principle has been: do as little work as possible. (What do you +expect from the proponents of lazy functional programming?) + +The implementation is the Perl Script From Hell, with a supporting cast +of the Flex Program From Hell, and a whole bunch of exceedingly useful +programs written by other people, mainly the GNU Info/Texinfo-related +programs and `tgrind' (by Van Jacobsen). [We can pass along the source +to all of these programs.] + + +File: literate.info, Node: notation-tut, Next: Command_reference, Prev: Highlights, Up: Top + +A LaTeX-like document markup language (tutorial-ish) +==================================================== + +Here is a simple silly literate Haskell program: + + \documentstyle[literate]{report} + \rootsectiontype{\part} + \begin{document} + Here is my \Haskell{} program to send a message to my friends: + \begin{code} + main _ = [ AppendChan stdout (message ++ " to " ++ my_friends) ] + \end{code} + + \section[message]{The Message} + \begin{code} + message = "Hello" + \end{code} + \subsection{Comments about the message and its implementation} + \begin{enumerate} + \item + The message is given as a top-level pattern binding. + \item + The @message@ binding does not violate the monomorphic restriction; + its type is \tr{[Char]}, which is not overloaded. + \end{enumerate} + + \section[friends]{My friends} + + \begin{code} + my_friends = ( \ y -> "Bob and Joe" ) 3 + \end{code} + + \printindex + \end{document} + +Here are some things to see in this example (don't worry if it doesn't +make sense first time): + * The compilable program (the parts between `\begin{code}'s and + `\end{code}'s) is simply contained in marked-off parts of your + document, and the code therein is completely ordinary (no special + programming notation). + + Such *code* is one "kind of stuff" in your literate program; + *text* is the other. + + * The overall document is arranged hierarchically (`\section', + `\subsection', etc.) and looks an awful lot like a LaTeX document. + + * There is quite a bit about *what* makes up your document + (sections, code, enumerated lists) and very little about *how* + your document should be formatted (e.g., "skip 2 lines"). This is + "declarative" markup. + + * Your program code will be indexed automatically; the `\printindex' + command is how you say where you want the index included. + + * You can refer to things-in-your-code in the text parts of your + document, by enclosing the reference in `@''s, as in `@message@'. + The reference will be suitably indexed. + + * The sectioning commands (e.g., `\section') are odd (if you are + used to LaTeX). Most important, a sectioning command gives a + *relative* position in the hierarchy; this means that commands like + `\rootsectiontype' can be used to adjust the absolute sectioning in + the final document. In this example, the topmost section would be + a LaTeX `\chapter' by default, but it's been changed to be a + `\part'. + + * More not-LaTeX trivia: the optional argument to `\section' serves + both as a label name (for `\ref', etc.) and as a node name for GNU + Info files. + +The following sections describe the more interesting parts of our +LaTeX-like notation, illustrated in the example above. (Before that is +a micro-tutorial on LaTeX conventions, in section *Note micro-latex::.) + * As the example above showed, the sectioning commands diverge quite + significantly from LaTeX. Section *Note Sectioning:: gives the + full details about sectioning. + + * The example shows how program code is included in a document in the + simplest way: just begin `\begin{code}' and `\end{code}' around it. + Section *Note code-in-doc:: describes the more involved uses of + this feature. + + * Section *Note Cross_references:: and Section *Note Indexing:: + describe how to take full advantage of the cross-referencing and + indexing facilities in your literate programs. + + * Section *Note Examples:: is supposed to include several complete + examples of literate programs but IT IS NOT FINISHED YET. + +Remember: Section *Note Command_reference:: is (supposed to be) a +complete reference document about the LaTeX-like commands you may +safely use. + +* Menu: + +* micro-latex:: A micro-tutorial on our LaTeX-like conventions. +* Sectioning:: Sectioning commands. +* code-in-doc:: Including program code in your document. +* Cross_references:: Cross-referencing. +* Indexing:: Indexing. +* Examples:: Some complete examples [NOT FINISHED]. +* Shortcuts:: Helpful short-cut notations. + + +File: literate.info, Node: micro-latex, Next: Sectioning, Prev: notation-tut, Up: notation-tut + +A micro-tutorial on our LaTeX-like conventions +---------------------------------------------- + +LaTeX is a document preparation system (described in a book of almost +that name, by Leslie Lamport), and its notation is the basis of that +used in this literate programming system. Unsurprisingly, one thing you +can do with your literate programs is turn them into real LaTeX +documents (for typesetting), using the program `lit2latex'. + +A few things to know about our literate-programming markup notation: + * Backslash (`\') is the starts-a-command character. Therefore, + `\item' and `\/' are commands, but `dog' and `(+)' are just plain + text. + + * *Mandatory* arguments to a command are given inside curly braces. + So, we would use `\foo{bar}' to pass one argument to the command + `\foo'; we would use `\bar{hey1}{hey2}' to pass two arguments to + the command `\bar'. + + * *Optional* arguments to a command are given in square brackets and + come before mandatory arguments. So, for example, + `\help[everyone]{lunch}' passes one optional and one mandatory + argument to the command `\help'. + + * `\foo' is a *command* called "foo", while `\begin{foo}' + <text in-between> `\end{foo}' is an *environment* called "foo" + with <text in-between> being inside that environment. + + * The above isn't everything you need to know. + + +File: literate.info, Node: Sectioning, Next: code-in-doc, Prev: micro-latex, Up: notation-tut + +Sectioning commands +------------------- + +[APRIL91: After you read this, you may want to see some proposed +changes in section *Note revised-sectioning::.] + +* Menu: + +* section<n>:: The `\section<n>' command. +* How_to_section:: How to use `\section<n>'. +* sectiontype-and-ref:: The `\sectiontype' and `\sectionref' commands. +* Node_specifications:: GNU Info node specifications with `\section<n>'. + + +File: literate.info, Node: section<n>, Next: How_to_section, Prev: Sectioning, Up: Sectioning + +The `\section<n>' command +......................... + +There is really just one sectioning command: + \section<n>[Info-node-name]{Section heading} +where `<n>' is a positive integer, the sectioning depth. For example, +you might have: + \documentstyle[literate]{book} + \rootsectiontype{\chapter} + \begin{document} + \section1[Node-1]{The top} + + \section2[Node-2]{The next level} + \section3[Node-3]{The bottom level} + \section3[Node-4]{More on the bottom level} + + \section2[Node-5]{Second part of the middle level} + \section3[Node-6]{Bottom level, next section} + \section3[Node-7]{Last section on bottom level} + \end{document} +As a convenience, the following synonyms are supported: + \section \section1 + \subsection \section2 + \subsubsection \section3 + \subsubsubsection \section4 + +Saying `\rootsectiontype{\chapter}' causes `\section1', `\section2', +and `\section3' to be translated into the LaTeX/Texinfo commands +`\chapter', `\section', and `\subsection', respectively. This system +supports deeper section nesting than LaTeX (12 levels vs. 7). + +If you want a section heading but don't want anything to appear in the +table of contents, put a `*' after the command name (just like LaTeX); +for example: + \subsection*[\pageref]{\pl{\pageref{<label-or-node-name>}}} + +If you want something that looks like a section heading but really +isn't (no table-of-contents entry, no Info node), you probably want the +`\heading{<title>}' command. + +[Support your local creaky implementation: you must put sectioning +commands on lines of their own.] + +In making an Info file, the hierarchy of `\section<n>' commands will be +turned into a corresponding hierarchy of Info nodes. With `info', you +navigate along one level of the hierarchy with `Next'- and `Prev'-node +links; you move up the hierarchy with `Up'-node links; and you move +down the hierarchy (e.g., from a `\section<n>' to its `\section<n+1>'s) +by choosing from an (automatically-generated) Info menu. + + +File: literate.info, Node: How_to_section, Next: sectiontype-and-ref, Prev: section<n>, Up: Sectioning + +How to use `\section<n>' +........................ + +The presumption is that *every file in a literate document will begin +its sectioning with a `\section'* (equivalently, `\section1') and +further sectioning will reflect a reasonable hierarchical structure +*within* the file. You usually know this when you are typing in a +particular file. + +What you often do *not* know is how the file fits into the larger +document, and it is most annoying (as happens sometimes with LaTeX) to +have to rename all `\chapter's to `\section's, or some such. The +information on how things go together is usually in a "root file," +which sticks things together with `\input', `\downsection' and +`\upsection'; this example is typical: + \section[Desugar_match]{@match@: compiling out pattern-matching} + \downsection + % each of the following files would start with a \section + \input{Match.lhs} + \input{DeTwiddle.lhs} + \input{MatchCon.lhs} + \input{MatchLit.lhs} + \upsection + +The `\upsection's and `\downsection's determine what actual +LaTeX/Texinfo sectioning command is generated for a particular +`\section<n>' command. Unfortunately, the desired LaTeX/Texinfo +sectioning command for the *top* section in your hierarchy depends on +the kind of document you are producing. For example, should it be a +`\part' or a `\chapter'? The solution here is to let you choose, with +the `\rootsectiontype{\foo}' command. It says that `\section1's at the +"top level" should be typeset as LaTeX/Texinfo `\foo''s. The defaults +based on the `\documentstyle' should usually be adequate: + \documentstyle \rootsectiontype + + article \section + report \chapter + book \chapter +For a report, a useful variant might be `\rootsectiontype{\part}'. + + +File: literate.info, Node: sectiontype-and-ref, Next: Node_specifications, Prev: How_to_section, Up: Sectioning + +The `\sectiontype' and `\sectionref' commands +............................................. + +Another annoying thing with LaTeX sectioning is to type +`Section~\ref{foo}' only to have `foo' turn out to be a "chapter" (not +a "section"). In this system, you can type `\sectiontype{Node-name}' +and the type of the sectioning command at node `Node-name' (e.g., +"chapter," "section") will be inserted [any unit below sections will be +called "section"]. To have the inserted text be capitalised, use +`\Sectiontype{Node-name}'. + +For the common idiom, `\sectiontype{Node-name}~\ref{Node-name}', you +may use `\sectionref{Node-name}' (similarly for `\Sectionref'). [I use +this all the time. --WDP] + + +File: literate.info, Node: Node_specifications, Prev: sectiontype-and-ref, Up: Sectioning + +GNU Info node specifications with `\section<n>' +............................................... + +[APRIL91: Don't overlook the new ideas in section *Note +revised-sectioning::.] + +When making an on-line Info document from a literate program, the text +between two sectioning commands is turned into an Info node. Moreover, +the sectioning commands are used to determine how the nodes should be +linked together -- almost always in the hierarchical structure implied +by the sectioning. However, you can tweak the process as much as you +wish (almost no-one ever wishes...). + +Each `\section<n>' command may have an optional "node specification", +with which you may specify the name of the Info node and how it should +be linked to other nodes. For common practice, I recommend giving a +(unique) node name and enjoying the default links; for example: + \section[Foo-Sem]{Foo Semantics} +Besides serving as the node name, `Foo-Sem' will also be a LaTeX +`\label' and may be `\ref''d or `\pageref''d: for example, you could +say, "The semantics are given in section~\ref{Foo_Sem}". (This is more +likely to work than introducing a `\label' of your own and `\ref''ing +that.) + +Node names must not contain commas (and other unpleasant characters I +don't want to think about) and spaces are probably asking for trouble. + +The next example shows the *general* form for a node specification, in +which you want to specify all of a node's links by hand:(1) + \section1[This-Node,Next-Node,Prev-Node,Up-Node]{Bar Semantics} + +A `?' may be given for any of the four node-names; then the default is +used: + 1. The default node-name is the section number. + + 2. The default next-node is the one associated with the next + same-level sectioning command (i.e., the next `\section<n>' + command if this is a `\section<n>' command. + + 3. Analogously for the default previous-node... + + 4. The default up-node is the last-seen next-level-up sectioning + command, e.g., if at a `\section<n>', then the last + `\section<n-1>' command seen. + Any text before the first `\section' command goes in node `Top', +which has node specification "`Top,,,(dir)'". + +The recommended form `\section[Foo-Sem]{Foo Semantics}' is just short +for `\section1[Foo-Sem,?,?,?]{Foo Semantics}'. + +Additional Info nodes that are unrelated to sectioning commands may be +added with the `\node' command. [Note: not well tested.] + +If you want a LaTeX-style sectioning command (e.g., to specify a +table-of-contents entry), use `onlyinfo' and `onlylatex' environments. + +---------- Footnotes ---------- + +(1) Ignore the rest of this section unless you enjoy pain -- it +presumes some familiarity with Texinfo/Info specifics; see `info info' +and/or `info texinfo'. + + +File: literate.info, Node: code-in-doc, Next: Cross_references, Prev: Sectioning, Up: notation-tut + +Including program code in your document +--------------------------------------- + +Central to literate programming is having program code in your document +that can be directly extracted and compiled/executed. + +* Menu: + +* usual-code-in-doc:: The usual ways to put code in a documents. +* ribbons-details:: Code ribbons: the fancy stuff. +* reordering-with-insertribbon:: Code reordering with `\insertribbon'. +* pseudocode:: Stuff that looks like code but isn't. +* magic-things-in-code:: Magic things you can put in your code. + + +File: literate.info, Node: usual-code-in-doc, Next: ribbons-details, Prev: code-in-doc, Up: code-in-doc + +The usual ways to put code in a documents +......................................... + +The most straightforward way to do this is to put all the code in a +file in one or more `\begin{code}' ... `\end{code}' environments -- the +code can then be extracted (in the order it appears in the text) and +fed to your favourite compiler/interpreter/whatever. + +An equivalent notation preferred by some is "Bird tracks", so-called +because it started with Richard Bird (and because Cordy calls them +that); lines starting with a `>' are extracted; for example: + >main _ = [AppendChan stdout "hello, world\n"] +is equivalent to: + \begin{code} + main _ = [AppendChan stdout "hello, world\n"] + \end{code} +A block of Bird-tracked code lines must have a blank line before and +after (not having one usually indicates a typo). + + COMMENT:---------------------- + + ToDo: Simon wants to know how code looks in (a) a LaTeX'd document + and (b) an Info'd document. ------------------------------ + + +File: literate.info, Node: ribbons-details, Next: reordering-with-insertribbon, Prev: usual-code-in-doc, Up: code-in-doc + +Code ribbons: the fancy stuff +............................. + +Both of the above are shorthand notation for messier stuff going on +underneath... Strictly speaking, the code in a particular document is +made up of one or more *ribbons* of code. For example, + A common thing to say to the world is ``Hello, world!'' + \begin{code}[hello-goodbye] + void HELLO() { printf("HELLO, WORLD!\n"); } + \end{code} + + However, you might want to be less exuberant: + \begin{code}[wimp] + void hello() { printf("hello, world!\n"); } + \end{code} + + And perhaps you are trying to tune out, not tune in. + \begin{code}[hello-goodbye] + void goodbye() { printf("Good-bye, cruel world...\n"); } + \end{code} + +As always, code to be extracted goes inside a +`\begin{code}'...`\end{code}'; the *optional* argument after +`\begin{code}' is the name of the code-ribbon to which the program-text +belongs. The example above has two ribbons, `hello-goodbye' and +`wimp'. You can extract any code-ribbon(s) you wish [see `lit2pgm''s +-r option]; the disjoint pieces of a particular ribbon (e.g., +`hello-goodbye' above) are catenated together in the order seen. + +Usually, this ribbon-business is just a bother, so there is the good +ol' default ribbon, `main'. For example, the +way-you-normally-write-things: + \begin{code} + void adieu() { printf("Adieu, cruel world...\n"); } + \end{code} +is actually short for: + \begin{code}[main] + void adieu() { printf("Adieu, cruel world...\n"); } + \end{code} + +Unsurprisingly, `main' is the default code-ribbon when one is in the +ribbon-extraction business. Similarly, code included with `>' signs in +the leftmost column ("Bird tracks") is just tacked onto the `main' +ribbon, too: + >void + >adieu() + >{ printf("Adieu, cruel world...\n"); } + + +File: literate.info, Node: reordering-with-insertribbon, Next: pseudocode, Prev: ribbons-details, Up: code-in-doc + +Code reordering with `\insertribbon' +.................................... + +If you are feeling particularly notorious, one piece of code may be +appended to several ribbons (a comma-separated list of ribbon names, +please -- spaces are significant except for beside the commas): + \begin{code}[ribbon1, ribbon2, ribbon3] + void adieu() { printf("Bon soir, cru\\'el world...\n"); } + \end{code} + +To get the effect of WEB-like parameterless macros, one ribbon may use +`\insertribbon' to include a copy of another one, as in: + \begin{code} + void adieu() + \insertribbon{message} + \end{code} + + \begin{code}[message] + { printf("Adieu, cruel world...\n"); } + \end{code} + +ToDo: CHANGE `\insertribbon' SO IT'S OUTSIDE OF code ENVIRONMENT. + +I don't recommend `\insertribbon'. You can make a terrible mess with +it. I haven't tested it for months. + + +File: literate.info, Node: pseudocode, Next: magic-things-in-code, Prev: reordering-with-insertribbon, Up: code-in-doc + +Stuff that looks like code but isn't +.................................... + +If you want to include alternate versions of code (for illustrative +purposes, presumably), to be typeset as code but *not* subject to +extraction by `lit2pgm', put the extra versions in `pseudocode' +environments. + + +File: literate.info, Node: magic-things-in-code, Prev: pseudocode, Up: code-in-doc + +Magic things you can put in your code +..................................... + +Generally speaking, you enter your program code inside a `code' +environment *exactly* as you would otherwise (the principle discussed in +section *Note code-verissimilitude::), and it will appear in your +documents as shown (nicely typeset, we hope). There are two magic +things that you can put in your code that do not appear in your +document (directly): +Index entries: + Code is automagically indexed, but you may wish additional index + entries of your own choosing. + +Hidden comments: + You will sometimes want comments in your actual code that you do + not want printed. An example: you might want to record next to + each code block the names of the the test files used to exercise + it. This is *really boring* information to all but the most + dedicated reader. + +In both cases, the information *could* be provided outside the code +environment (i.e., without any special construct), but it could quite +easily get lost (code blocks can be big, even if they shouldn't be :-). + +In all cases, these annotations are in a form recognised as a comment +by the compiler/whatever for that language. Please see section *Note +Language_specific:: for the exact form used for the language you are +interested in. A Haskell example of both magic bits might be: + \begin{code} + main _ = [AppendChan stdout "Hello, world...?\n"] + --idx:: world, state of + --hide:: use testfile093.hs + \end{code} + +[APRIL91: Yell if you really dislike (or like) these two forms of +"magic things in code".] + + +File: literate.info, Node: Cross_references, Next: Indexing, Prev: code-in-doc, Up: notation-tut + +Cross-referencing +----------------- + +For cross-referencing, the normal thing is to use node-names on +sectioning commands as labels, and to `\ref{<label>}' and +`\pageref{<label>}' them, as is the LaTeX custom. `\pageref's are +discouraged, as there is no concept of page numbers in Info files. + +Similarly, if you heave in a `\label{<some text>}', the Info side of +things will assume that `<some text>' is just another label for the +current node [NOT IMPLEMENTED (ToDo)]. + +APRIL91: Cross-referencing is normally used to help you move from a +*use* of a code-thing to its *definition*. There should probably be an +option to let you get cross-referencing that will also let you move +from a definition to all of its uses. + + +File: literate.info, Node: Indexing, Next: Examples, Prev: Cross_references, Up: notation-tut + +Indexing +-------- + +[APRIL91: changes are envisaged; see section *Note multiple-indexes::.] + +Indexing is assumed to work with the program `makeindex', so you should +put a a `\printindex' command where you want the index to appear +(almost always just before `\end{document}'). (A LaTeX `\makeindex' +command is supplied automagically before `\begin{document}'.) + +Roughly speaking, code portions of your document are *automatically* +indexed, and then you index the text portion *manually*, with `\index' +commands. + +`\index{<entry text>}' is the basic indexing command and offers a +simplified `makeindex' interface. + * If you want just plain simple "foo" to appear in the index, use + `\index{foo}'. + + * If you want subitems in an index entry, separate them with `!'s + [useful]. + + * If you want separate text for sorting and printing an index entry, + put the two texts in that order, separated by an unescaped `@'. + + * To put a `!' or `@' in your index entry, escape it with a + backslash `\'. + + * All other (semi-normal) characters work as is. + +I don't encourage trying to have index entries pop out in different +fonts -- it doesn't work in plain Info files. You can write devious +LaTeX/`makeindex' code on your own... + +Code-stuff in text (stuff inside `@...@') is indexed automatically, +just like "real code". What actually happens depends on the support +for your programming language -- section *Note Language_specific:: gives +all the language-specific indexing idiosyncracies. The *default* +bare-bones mechanism is that whitespace-free code-in-text over three +characters long (e.g., `@typecheck@') will generate an index entry. To +suppress automatic indexing of a piece of code-in-text, put a +`\noindex' immediately following, as in `@typecheck@\noindex'. + +As mentioned in section *Note magic-things-in-code::, you can add index +entries for your code by inserting specially-formatted comments (this +depends on how well your programming language is supported). For +example, for Haskell, you might use [NB: NOT IMPLEMENTED YET (ToDo?)]: + f x y z = (y z) x + -- the next line is a comment that will cause an index entry + -- equivalent to: \index{foo-bar-baz} + --#idx::foo-bar-baz + +For a chunk of code, a mini-index pointing to the definitions of the +things it refers to (one possible definition of "things:" top-level +functions) will be produced right after the code. (For the Info file, +as part of the menu for that node.) + COMMENT:---------------------- + + The Info part is done; I'm still thinking about what should be done + for LaTeX. ------------------------------ +[APRIL91: this is one of the things contemplated in section *Note +multiple-indexes::.] + +At least some provision has been made for "stop lists" for the +automagical indexing (I'm not sure how well it works...). You put +words/strings that are normally picked up by the indexing into a file, +then tell the system this is your "stop list file" (`-s' option, I +think), meaning "Don't index these things -- I'm not interested." + + +File: literate.info, Node: Examples, Next: Shortcuts, Prev: Indexing, Up: notation-tut + +Some complete examples [NOT FINISHED] +------------------------------------- + +NOT FINISHED YET. Some day... + +Meanwhile, you will find some reasonable not-over-huge examples in the +`literate/tests' directory in the source. + +* Menu: + +* Simple_example:: A simple example. +* Typical_example:: A typical example. +* Hairy_example:: A hairy example. + + +File: literate.info, Node: Simple_example, Next: Typical_example, Prev: Examples, Up: Examples + +A simple example +................ + + +File: literate.info, Node: Typical_example, Next: Hairy_example, Prev: Simple_example, Up: Examples + +A typical example +................. + + +File: literate.info, Node: Hairy_example, Prev: Typical_example, Up: Examples + +A hairy example +............... + + +File: literate.info, Node: Shortcuts, Prev: Examples, Up: notation-tut + +Helpful short-cut notations +--------------------------- + +APRIL91: There is discussion about these sorts of things scattered +through the "new ideas" in section *Note april91-new-ideas::. + +* Menu: + +* code-in-text:: Referring to code things in your text. +* fonts-in-text:: Using different "fonts" in your text. + + +File: literate.info, Node: code-in-text, Next: fonts-in-text, Prev: Shortcuts, Up: Shortcuts + +Referring to code things in your text +..................................... + +In the text part of a literate program, one often wishes to refer to +things in the code (e.g., function names) or have code expressions in +the running text, and so forth. One would like this code-in-text to be +typeset just like the real-code-parts (currently verbatim, but that +could change). To mark off code-in-text, surround it with `at' signs: +as in `@code in text@'; to put an `at' sign in in-line code, you've got +to put in two `ats': `@x @@ (y, z)@'. Line-breaks are prevented inside +"attified" code-text. + +Because things inside `at' signs are so often just what you want to be +indexed, the rule is: if the at-signed thing contains no whitespace, an +index entry is generated. (How to prevent indexing and how to do +fancier things about indexing and cross-referencing are given section +*Note Indexing::.) + +APRIL91: see comments in section *Note text-in-code::. + + +File: literate.info, Node: fonts-in-text, Prev: code-in-text, Up: Shortcuts + +Using different "fonts" in your text +.................................... + +[APRIL91: Be sure to see section *Note diff-fonts-in-text::.] + +The `\tr{<text>}' command sets `<text>' in typewriter font, with no +need for escape characters or anything -- provided the braces nest +properly. + +The same trick using a "plain" (roman) font is `\pl{<text>}', to +produce <text>. + + +File: literate.info, Node: Command_reference, Next: Language_specific, Prev: notation-tut, Up: Top + +LaTeX-like markup commands: reference +===================================== + +This section assumes you are familiar with the tutorial-ish material in +section *Note notation-tut::. It also assumes some familiarity with +LaTeX, in that I may say say, "It works as in LaTeX". + +The lists below catalog the environments (`\begin{...}/\end{...}' +things) and commands (backslashed `\things') of our Glasgow +literate-programming notation. [For this clunky implementation, the +`\begin{...}' and `\end{...}' delimiters should be on lines by +themselves, beginning in the leftmost column.] + +Occasional mention is made of the main programs used to process +literate files: `lit2pgm', which extracts the code from a file; +`lit2latex', which creates real LaTeX source from a file; and +`lit2texi', which creates Texinfo source from a file (from which Info +files can be made with `makeinfo'). + +Little things first: + * In text, you should use the TeX style of double quotes: ```foo'''. + + * In text, backslashed magic characters, e.g., `\& \_ \# \$', will + produce the self-same de-backslashed magic characters in the + output. + + * Accents on characters (e.g., `\'e') are fine; they are tossed from + Info files. + + * You may safely use the italic correction `\/'. + + * At least the font-fiddling declarations `\sc' and `\tt' will work; + they are heartily unrecommended. APRIL91: see the comments in + section *Note diff-fonts-in-text::. Also, make them commands, not + declarations? + +Commands and environments (in alphabetical order): + +* Menu: + +* \appendix:: \appendix. +* \author:: \author{<text>}. +* center_environment:: center environment. +* \centerline:: \centerline{<text>}. +* \caption:: \caption{<text>}. +* \clearpage-etc:: \clearpage and \cleardoublepage. +* code_environment:: code environment. +* comment_environment:: comment environment. +* \date:: \date{<text>}. +* \define:: \define{<command>}{<replacement>}. +* description_environment:: description environment. +* display_environment:: display environment. +* \documentstyle:: \documentstyle[<style-options>]{<doc-type>}. +* \em:: {\em <text>}. +* enumerate_environment:: enumerate environment. +* figure_environment:: figure environment. +* flushdisplay_environment:: flushdisplay environment. +* flushverbatim_environment:: flushverbatim environment. +* \footnote:: \footnote{<text>}. +* \heading:: \heading{<title>}. +* \index:: \index{<entry>}. +* \input:: \input{<filename>}. +* \inputnow:: \inputnow{<filename>}. +* \insertribbon:: \insertribbon{<ribbon-name>}. +* itemize_environment:: itemize environment. +* \label:: \label. +* \listoffigures-etc:: \listoffigures and \listoftables. +* \makeindex:: \makeindex. +* \maketitle:: \maketitle. +* menu_environment:: menu environment. +* \menuentry:: \menuentry{<tag>}{<description>}. +* \node:: \node{<node-spec>}. +* \pounds:: \pounds<something-like-a-number>. +* onlyinfo_environment:: onlyinfo environment. +* onlylatex_environment:: onlylatex environment. +* onlypartofdoc_environment:: onlypartofdoc environment. +* onlystandalone_environment:: onlystandalone environment. +* \pageref:: \pageref{<label-or-node-name>}. +* \pl:: \pl. +* \printindex:: \printindex. +* pseudocode_environment:: pseudocode environment. +* quotation_environment:: quotation environment. +* rawlatex_environment:: rawlatex environment. +* \ref:: \ref{<label-or-node-name>}. +* \rootsectiontype:: \rootsectiontype{<real-sectioning-command>}. +* \sectiontype:: \sectiontype{<nodename>}. +* \sectionref:: \sectionref{<nodename>}. +* \standaloneornot:: \standaloneornot{<ifso>}{<ifnot>}. +* \suppresscomments:: \suppresscomments. +* table_environment:: table environment. +* \tableofcontents:: \tableofcontents. +* tabular_environment:: tabular environment. +* \title:: \title{<text>}. +* \tr:: \tr. +* verbatim_environment:: verbatim environment. + + +File: literate.info, Node: \appendix, Next: \author, Prev: Command_reference, Up: Command_reference + + \appendix + +Section numbering after this command is for appendices. (Has no effect +on Info files. ToDo: it probably should.) + + +File: literate.info, Node: \author, Next: center_environment, Prev: \appendix, Up: Command_reference + + \author{<text>} + +Please see under `\maketitle'. + + +File: literate.info, Node: center_environment, Next: \centerline, Prev: \author, Up: Command_reference + + center environment + +As for LaTeX. [APRIL91: Not implemented (and not sure how to do it +easily on the Texinfo side), but I need to do something because Simon +keeps using it.] + + +File: literate.info, Node: \centerline, Next: \caption, Prev: center_environment, Up: Command_reference + + \centerline{<text>} + +As for LaTeX. + + +File: literate.info, Node: \caption, Next: \clearpage-etc, Prev: \centerline, Up: Command_reference + + \caption{<text>} + +As for LaTeX; likely to be unsatisfactory for Info files because the +latter doesn't do figures. + + +File: literate.info, Node: \clearpage-etc, Next: code_environment, Prev: \caption, Up: Command_reference + + \clearpage and \cleardoublepage + +As in LaTeX; no effect on Info files. + + +File: literate.info, Node: code_environment, Next: comment_environment, Prev: \clearpage-etc, Up: Command_reference + + code environment + +See section *Note code-in-doc::. Also, don't forget the `pseudocode' +environment. + +You cannot nest other environments inside code environments. + + +File: literate.info, Node: comment_environment, Next: \date, Prev: code_environment, Up: Command_reference + + comment environment + +Text in a `comment' environment will be output (perhaps with extra +indentation, smaller font, etc.) if a `\suppresscomments' command +hasn't yet been encountered. [NB: `\suppresscomments' doesn't work +with `lit2texi'.] + +A comment environment cannot include another comment environment. + + +File: literate.info, Node: \date, Next: \define, Prev: comment_environment, Up: Command_reference + + \date{<text>} + +As for LaTeX; please see under `\maketitle' for exact details. + + +File: literate.info, Node: \define, Next: description_environment, Prev: \date, Up: Command_reference + + \define{<command>}{<replacement>} + +Ultra-simple macro substitution, NOT LIKE LaTeX. The text for +`<command>' will be replaced with `<replacement>'; no nesting, no funny +characters, nothing fancy. Don't `\define' the same `<command>' twice, +for example. Intended for customising documents; please see the note +under `\input'. + +Defaults are provided for `Haskell', `LaTeX', `TeX' and `...'. More +defaults on request. + +APRIL91: see section *Note pseudo-C-preprocessor:: for what I would +REALLY like to do about "defining". + + +File: literate.info, Node: description_environment, Next: display_environment, Prev: \define, Up: Command_reference + + description environment + +As in LaTeX. + + +File: literate.info, Node: display_environment, Next: \documentstyle, Prev: description_environment, Up: Command_reference + + display environment + +Similar to `verbatim' (line-breaks are obeyed) but formatted in the +prevailing font (not necessarily typewriter). There is a +`flushdisplay' environment as well. + +You can't nest one display environment inside another. + + +File: literate.info, Node: \documentstyle, Next: \em, Prev: display_environment, Up: Command_reference + + \documentstyle[<style-options>]{<doc-type>} + +You do not have to the `literate' LaTeX style option; e.g., +`\documentstyle[literate]{report}', but it is probably a good idea so +people don't think you're writing real LaTeX. + +`\documentstyle' has two magical actions: (1) the type of document +(report, article, etc.) determines the default value for +`\rootsectiontype', and (2) it indicates that a standalone document is +being generated (not just a part of one). [APRIL91: bear in mind that +this standalone business is in jeopardy.] + + +File: literate.info, Node: \em, Next: enumerate_environment, Prev: \documentstyle, Up: Command_reference + + {\em <text>} + +The \em (emphasize) declaration works just as in LaTeX. + +APRIL91: make it a command, not a declaration, i.e., \em{<text>}? + + +File: literate.info, Node: enumerate_environment, Next: figure_environment, Prev: \em, Up: Command_reference + + enumerate environment + +As in LaTeX. + + +File: literate.info, Node: figure_environment, Next: flushdisplay_environment, Prev: enumerate_environment, Up: Command_reference + + figure environment + +Goes straight through for LaTeX; ignored for Info files, meaning that +whatever is inside won't "float." (Remember: we don't really do +figures; see section *Note texinfo-limits::.) + + +File: literate.info, Node: flushdisplay_environment, Next: flushverbatim_environment, Prev: figure_environment, Up: Command_reference + + flushdisplay environment + +Same as the `display' environment, except it is not indented relative +to the left margin. + +You can't nest one flushdisplay environment inside another. + + +File: literate.info, Node: flushverbatim_environment, Next: \footnote, Prev: flushdisplay_environment, Up: Command_reference + + flushverbatim environment + +Same as the `verbatim' environment except that text is not indented +relative to the left margin. + +You can't nest other environments inside a flushverbatim environment; +see the note in section *Note verbatim_environment::. + + +File: literate.info, Node: \footnote, Next: \heading, Prev: flushverbatim_environment, Up: Command_reference + + \footnote{<text>} + +Footnotes work! NB: with `makeinfo', you may choose one of two ways of +doing footnotes in an Info file. By default, they will be at the +bottom of the node (style BN), as opposed to in a node of their own +(style MN). [ToDo: update the makeinfo info] + + +File: literate.info, Node: \heading, Next: \index, Prev: \footnote, Up: Command_reference + + \heading{<title>} + +A pseudo-sectioning command that formats `title' as if it were a +section heading (no numbering or any of that rot), but it doesn't put +anything in the table of contents, no Info node, no anything weird. + + +File: literate.info, Node: \index, Next: \input, Prev: \heading, Up: Command_reference + + \index{<entry>} + +Roughly as for LaTeX with `makeindex'. Don't try anything too weird: +for example, `\index{<mumble>}' inside a footnote doesn't work. +Warning: full-blown `makeindex'-style indexing has been "simplified": +please see section *Note Indexing:: for the full gory (but wonderful!) +details. + + +File: literate.info, Node: \input, Next: \inputnow, Prev: \index, Up: Command_reference + + \input{<filename>} + +Be sure these are on lines by themselves and start in column 1. The +argument should be the full filename -- no implied suffix. Files will +be searched for along the `LITINPUTS' path, specified by an environment +variable of the same name. The default path includes only your current +working directory. + +`\input's are only followed at link time; if that's not what you want, +either give the appropriate command-line flag (`-n') or use `\inputnow'. + +APRIL91: see section *Note pseudo-C-preprocessor:: for some thoughts +about how inputting may be changed. + + +File: literate.info, Node: \inputnow, Next: \insertribbon, Prev: \input, Up: Command_reference + + \inputnow{<filename>} + +These are `\input's that are followed always, no matter what. +Otherwise, they are the same. + +APRIL91: `\inputnow' may go away at any second. + + +File: literate.info, Node: \insertribbon, Next: itemize_environment, Prev: \inputnow, Up: Command_reference + + \insertribbon{<ribbon-name>} + +Used to insert the text of one code-ribbon into another; see section +*Note code-in-doc::. Must share a line with nothing but whitespace. +Not recommended. + +ToDo: needs to be made to work *outside* of code environments, rather +than inside them. + +DOES NOT WORK WITH `lit2pgm -q'! (which is what we often use.) + + +File: literate.info, Node: itemize_environment, Next: \label, Prev: \insertribbon, Up: Command_reference + + itemize environment + +As in LaTeX. British spelling ("itemise") also accepted. + + +File: literate.info, Node: \label, Next: \listoffigures-etc, Prev: itemize_environment, Up: Command_reference + + \label + +Free-standing `\label's [supposedly] work as expected in LaTeX; in Info +files, a `\label' is taken as just another name for the node the +`\label' is in. Determining which node it's in doesn't take account of +`\input's -- it's the one it "appears" to be in -- which may not be +what you want. You *really should* use node-names as labels (see +section *Note Node_specifications::)... + +Labels (and, therefore, nodenames) shouldn't have weird characters in +them. Such labels (nodenames) will be studiously ignored. + + +File: literate.info, Node: \listoffigures-etc, Next: \makeindex, Prev: \label, Up: Command_reference + + \listoffigures and \listoftables + +As for LaTeX; has no effect on Info files, which don't do lists of +figures or tables. + + +File: literate.info, Node: \makeindex, Next: \maketitle, Prev: \listoffigures-etc, Up: Command_reference + + \makeindex + +Not necessary even for LaTeX -- one is inserted automagically just +before `\begin{document}'; has no effect on `lit2texi'. + + +File: literate.info, Node: \maketitle, Next: menu_environment, Prev: \makeindex, Up: Command_reference + + \maketitle + +Will work as in LaTeX for simple cases, using values provided by +`\author{<author-stuff>}', `\title{<title-stuff>}', and +`\date{<date-stuff>}'. The `\\' line-breaker works. You die if you +try anything weird. + +For better or worse, if you use the `-g' option (to "grab" a subtree of +text for printing), then it *does* matter if the `\maketitle' is in the +pre-amble (before `\begin{document}') or not. Please see section *Note +Programs-and-options:: for the sorry details. + + +File: literate.info, Node: menu_environment, Next: \menuentry, Prev: \maketitle, Up: Command_reference + + menu environment + +In producing an Info file, text in a `menu' environment is copied +verbatim to create an Info menu. You must provide something that +Texinfo can grok. This whole mess might be used in conjunction with +`\suppressmenu' [if `\suppressmenu' were implemented yet]. + +APRIL91: this should probably be nuked if the rawtexinfo environment +comes online. + + +File: literate.info, Node: \menuentry, Next: \node, Prev: menu_environment, Up: Command_reference + + \menuentry{<tag>}{<description>} + +Requests that an extra menu entry be put at the *beginning* of this +section's menu. + + +File: literate.info, Node: \node, Next: \pounds, Prev: \menuentry, Up: Command_reference + + \node{<node-spec>} + +(Ignored for LaTeX.) Makes an extra node in the Texinfo file; the +`<node-spec>' is copied straight through to the output, so it's your +problem to include something sensible. + +APRIL91: nuked if rawtexinfo environment comes in? + + +File: literate.info, Node: \pounds, Next: onlyinfo_environment, Prev: \node, Up: Command_reference + + \pounds<something-like-a-number> + +The \pounds must be followed by: zero or more whitespace characters, a +digit or a question mark, zero or more +digits/question-marks/commas/full-stops/the-letters-K-or-M, and a +digit/question-mark/the-letter-K-or-M. The Ks or Ms may be in +lower-case. The mind boggles. + + +File: literate.info, Node: onlyinfo_environment, Next: onlylatex_environment, Prev: \pounds, Up: Command_reference + + onlyinfo environment + +Only the Texinfo/Info extraction program(s) pay attention to stuff +inside. Don't put code in here! + +APRIL91: this stuff is in jeopardy of disappearing. + + +File: literate.info, Node: onlylatex_environment, Next: onlypartofdoc_environment, Prev: onlyinfo_environment, Up: Command_reference + + onlylatex environment + +Only the LaTeX extraction program(s) pay attention to stuff inside. +Don't put code in here! + +APRIL91: this stuff is in jeopardy of disappearing. + + +File: literate.info, Node: onlypartofdoc_environment, Next: onlystandalone_environment, Prev: onlylatex_environment, Up: Command_reference + + onlypartofdoc environment + +The extraction programs pay attention to stuff inside only if they +believe this is just a piece of a document (i.e., "separate +compilation" is going on). As always, don't put code in here! See the +`\standaloneornot' command for a shortcut. + +APRIL91: this stuff is in jeopardy of disappearing. + + +File: literate.info, Node: onlystandalone_environment, Next: \pageref, Prev: onlypartofdoc_environment, Up: Command_reference + + onlystandalone environment + +The extraction programs pay attention to stuff inside only if they +believe that a standalone document is in the works (i.e., a +`\documentstyle' command has been seen or the `-S' flag given). As +always, don't put code in here! See the `\standaloneornot' command for +a shortcut. + +APRIL91: this stuff is in jeopardy of disappearing. + + +File: literate.info, Node: \pageref, Next: \pl, Prev: onlystandalone_environment, Up: Command_reference + + \pageref{<label-or-node-name>} + +In making LaTeX documents, works as usual. In making Info files, +treated as a `\ref' (there is no concept of "page" in an Info document). + + +File: literate.info, Node: \pl, Next: \printindex, Prev: \pageref, Up: Command_reference + + \pl + +Plain text, set in a roman font; equivalent to `\mbox{\rm #1}', except +that the argument can include any old printable ASCII characters, +including properly-nested braces (escaping them is irrelevant). If you +want to do something weird, do it another way. Note that linebreaks +within the `\pl' are prevented. + +The equivalent typewriter thing is `\tr'. + +APRIL91: see possible changes in section *Note diff-fonts-in-text::. + + +File: literate.info, Node: \printindex, Next: pseudocode_environment, Prev: \pl, Up: Command_reference + + \printindex + +Should be just before `\end{document}'. In Info mode, generates a node +`Index' at the same sectioning depth as your top-level sectioning +commands. + +APRIL91: see possible changes in section *Note multiple-indexes::. + + +File: literate.info, Node: pseudocode_environment, Next: quotation_environment, Prev: \printindex, Up: Command_reference + + pseudocode environment + +Format the same way as in a `code' environment, but the enclosed stuff +is not subject to extraction by `lit2pgm'. + +Other environments do not nest inside a pseudocode environment. + + +File: literate.info, Node: quotation_environment, Next: rawlatex_environment, Prev: pseudocode_environment, Up: Command_reference + + quotation environment + +As in LaTeX. + + +File: literate.info, Node: rawlatex_environment, Next: \ref, Prev: quotation_environment, Up: Command_reference + + rawlatex environment + +If lit2latexing, copies the body of the environment straight through. +Otherwise, discard it. + +One trick you may need: because of the feeble implementation, the +system may still try to "follow" an `\input' inside a rawlatex +environment (which it shouldn't). The solution is to "hide" the +`\input' so it isn't first on a line: + \begin{rawlatex} + \begin{figure} + {}\input{weird-fig.ps} + \caption{Weird Figure} + \end{figure} + \end{rawlatex} + + +File: literate.info, Node: \ref, Next: \rootsectiontype, Prev: rawlatex_environment, Up: Command_reference + + \ref{<label-or-node-name>} + +As for LaTeX. + + +File: literate.info, Node: \rootsectiontype, Next: \sectiontype, Prev: \ref, Up: Command_reference + + \rootsectiontype{<real-sectioning-command>} + +Please see section *Note Sectioning::. + + +File: literate.info, Node: \sectiontype, Next: \sectionref, Prev: \rootsectiontype, Up: Command_reference + + \sectiontype{<nodename>} + +Please see section *Note sectiontype-and-ref::. + + +File: literate.info, Node: \sectionref, Next: \standaloneornot, Prev: \sectiontype, Up: Command_reference + + \sectionref{<nodename>} + +Please see section *Note sectiontype-and-ref::. + + +File: literate.info, Node: \standaloneornot, Next: \suppresscomments, Prev: \sectionref, Up: Command_reference + + \standaloneornot{<ifso>}{<ifnot>} + +If doing standalone-document processing (i.e., a `\documentstyle' seen +or `-S' flag given), use text `<ifso>'; otherwise, use text `<ifnot>'. +Keep this on one line *by itself*, OK?; for longer things, use the +`onlystandalone' and `onlypartofdoc' environments. + +APRIL91: this stuff is in SEVERE jeopardy of being nuked; see section +*Note pseudo-C-preprocessor::. + + +File: literate.info, Node: \suppresscomments, Next: table_environment, Prev: \standaloneornot, Up: Command_reference + + \suppresscomments + +Best put in the preamble of your overall document (i.e., before +`\begin{document}'). Causes text in all subsequent `comment' +environments to be ignored. NB: only works in producing LaTeX +documents. (ToDo: fix this) + + +File: literate.info, Node: table_environment, Next: \tableofcontents, Prev: \suppresscomments, Up: Command_reference + + table environment + +Goes straight through for LaTeX; ignored for Info files, meaning that +whatever is inside won't "float." + + +File: literate.info, Node: \tableofcontents, Next: tabular_environment, Prev: table_environment, Up: Command_reference + + \tableofcontents + +As for LaTeX; adds extra stuff to the top-level menu in an Info file. + + +File: literate.info, Node: tabular_environment, Next: \title, Prev: \tableofcontents, Up: Command_reference + + tabular environment + +Same format as LaTeX, but anything magical beyond `&', `\\', and +`\hline' will probably get you in trouble. + +Other environments don't nest inside a tabular environment. + + +File: literate.info, Node: \title, Next: \tr, Prev: tabular_environment, Up: Command_reference + + \title{<text>} + +Please see under `\maketitle'. + + +File: literate.info, Node: \tr, Next: verbatim_environment, Prev: \title, Up: Command_reference + + \tr + +Set in typewriter font; equivalent to `\mbox{\tt #1}', except that the +argument can include any old printable ASCII characters, including +properly-nested braces (escaping them is irrelevant). If you want to +do something weird, do it another way. Note that linebreaks within the +`\tr' are prevented. + +The equivalent non-typewriter thing is `\pl'. + +APRIL91: see section *Note diff-fonts-in-text:: for further comment on +this stuff. + + +File: literate.info, Node: verbatim_environment, Prev: \tr, Up: Command_reference + + verbatim environment + +As in LaTeX -- line-breaks are obeyed and everything is in typewriter +font. See also: the `flushverbatim' and `display' environments. + +You can't nest other environments inside verbatim environments. A +trick (hack) you can use to put a verbatim environment inside another +is to indent the inner one by one space, as in: + \begin{verbatim} + ... + \begin{verbatim} + ... + \end{verbatim} + ... + \end{verbatim} + + +File: literate.info, Node: Language_specific, Next: Habits, Prev: Command_reference, Up: Top + +Language-specific processing +============================ + +This section describes the processing of code in documents that is done +in a language-specific way. This is mainly to do with indexing, +typesetting, and similar matters. + +First, however, we give the default rules used when the programming +language used is unsupported or unknown. + +* Menu: + +* Default_rules:: Rules for unknown or unsupported languages. +* Haskell_rules:: Language-specific rules for Haskell. +* Perl_rules:: Language-specific rules for `perl'. +* C_rules:: Language-specific rules for `C'. +* Fortran_rules:: Language-specific rules for `FORTRAN'. + + +File: literate.info, Node: Default_rules, Next: Haskell_rules, Prev: Language_specific, Up: Language_specific + +Rules for unknown or unsupported languages +------------------------------------------ + +[Not finished yet.] + +No hidden comments or explicit index entries in code. + + +File: literate.info, Node: Haskell_rules, Next: Perl_rules, Prev: Default_rules, Up: Language_specific + +Language-specific rules for Haskell +----------------------------------- + +[This section is not finished yet.] + +An explicit code index entry comment is of the form: +`--idx::<whatever>', on a line of its own. + +A hidden comment is of the form: `--hide::<whatever>', on a line of its +own. + + +File: literate.info, Node: Perl_rules, Next: C_rules, Prev: Haskell_rules, Up: Language_specific + +Language-specific rules for `perl' +---------------------------------- + +[This section is not finished yet.] + +An explicit code index entry comment is of the form: +`#idx::<whatever>', on a line of its own. + +A hidden comment is of the form: `#hide::<whatever>', on a line of its +own. + + +File: literate.info, Node: C_rules, Next: Fortran_rules, Prev: Perl_rules, Up: Language_specific + +Language-specific rules for `C' +------------------------------- + +[This section is not finished yet.] + + +File: literate.info, Node: Fortran_rules, Prev: C_rules, Up: Language_specific + +Language-specific rules for `FORTRAN' +------------------------------------- + +[This section is not finished yet.] + +The FORTRAN-specific support was provided by Adriaan Joubert +(adriaan@dcs.qmw.ac.uk). + + +File: literate.info, Node: Habits, Next: Caveats, Prev: Language_specific, Up: Top + +A checklist of good literate habits +=================================== + +[Suggestions welcome. Haven't worked on this in a while.] + + * Express your ideas in a way amenable to plain ASCII + representation, as well as that of full-blown TeX typesetting. + For example, serious TeX math-mode stuff is not really on (even if + you can get it past `lit2latex'). If you find this constraint a + big problem, you may well be using the wrong tool for the job. + + * If you test your document first as an Info file (i.e., use + `lit2texi' to process it), once that is right then it is very + likely that the LaTeX side of things (using `lit2latex') will come + out right as well. The reverse is not true. + + * Follow the convention that the sectioning in every file begins + with a `\section'. For details on how to do sectioning, please see + section *Note How_to_section::. + + * Arrange your document so that your Info nodes come out no more than + two screenfuls' long. Very long nodes obviate the whole point of + Info documents. + + * It's hard to make up good sets of Info node names. First, they + must be unique! Second, it's best if the uniqueness is in the + first few characters, so that nodename completion may be used to + most advantage. + + +File: literate.info, Node: Caveats, Next: Programs-and-options, Prev: Habits, Up: Top + +Caveats: bugs and foibles +========================= + +As mentioned in section *Note clunky-implementation::, the initial +implementation of this literate-programming system is delicate at best. + + 1. Environment-commands should be on lines of their own, and + preferably start in column 1; the latter is especially important + for verbatim environments. + + 2. The line numbers reported with errors stand a fair chance of being + wrong or even laughably irrelevant. LaTeX doesn't report errors in + terms of their original source anyway at all... (urgh) + + 3. `\Define'-itions (incl. the built-in ones for Haskell, LaTeX, + etc.) are expanded inside `\tr' and friends. + + 4. You can get confused `\items' (in enumerations, etc.) if you have: + \item[... stuff here... ] ...................... ] + right bracket on the same line -------------------^ + The solution (and it's better style anyway) is to put `\items' on + lines of their own. This is a vestige of the implementation... + + 5. Don't put `\index' commands inside footnotes. There are probably + some other related restrictions... (ToDo) + + 6. Tabs in code will be expanded to spaces. This matters only if you + have tabs in string constants, or some such (which you shouldn't, + because it's hard for the reader of your code to see what you've + done; use `\t' or the equivalent). + + 7. If you use the cross-referencing (`-D', I think), you have the + annoying feature of cross-referencing to things very near by, even + on the same page. I don't know how to stop this. + + +File: literate.info, Node: Programs-and-options, Next: Info_etc, Prev: Caveats, Up: Top + +Programs to process literate documents +====================================== + +In this incarnation, the programs `lit2pgm', `lit2latex', and +`lit2texi' (to extract program, LaTeX, or GNU Texinfo fodder) are just +three ways of invoking one killer `perl' script, `lit2stuff'. + +[Actually, this same script may be invoked as `mkdependlit', to build a +set of `make' dependencies for a literate document, as `lit2text', to +extract just the non-code text (perhaps for spell-checking), or as +`lit2changelog', which is the (mainly unimplemented) interface to the +changelog-slurping code. I ignore these details herein.] + +APRIL91: there are starting to be enough options that getopt-style +one-letter names aren't enough/too obtuse. Some revision may be in +order there... See section *Note revised-pgm-options::. + +For all three programs, their invocation takes the form +`lit2<whatever> [options] [input-file]'. Usually, output is to a file +determined from the input-file's suffix (e.g., a `.hs' file from a +`.lhs' file); if no input file is provided or life becomes confused, +output is to the standard output. You can control input and output +explicitly with the `-i' and `-o' options. + +Known file suffixes and what they mean: + + .lit a literate-document file with no code in it (e.g., this one) + .lhs literate Haskell source + .lprl literate Perl source + .llex literate Lex source + .lc literate C source + .lh literate C header source + .ltex literate TeX macros + .lf literate FORTRAN + +The suffixes `.itex' and `.itxi' indicate the intermediate files from +"separate compilation" (to LaTeX and Texinfo, respectively) of parts of +a larger document. + +In ordinary life, given a literate C program `foo' in file `foo.lc', +one would hope that the following simple invocations would suffice: + lit2pgm foo.lc + gcc -o foo foo.c + + lit2latex foo.lc + latex foo.tex + + lit2texi foo.lc + makeinfo foo.texi + # (and if you really want to make things right, use the script... + postmakeinfo foo.info + # as well) + +What follows are the options to control these programs (and to +complicate your life [and mine, too]). Not all command-line options +make sense for all three programs; they are so noted. Options may be +glopped together in the best getopt(3) style. + +* Menu: + +* A_option:: -A <pgm-name> option. +* c_option:: -c option. +* d_option:: -d option. +* capital_D_option:: -D option. +* f_option:: -f <nodename-suffix> option. +* g_option:: -g <node-name> option. +* H_option:: -H <dir1>:<dir2> option. +* i_option:: -i <input-file> option. +* capital_I_option:: -I <directories> option. +* capital_L_option:: -L option. +* l_option:: -l <language> option. +* n_option:: -n option. +* capital_N_option:: -N <info-filename> option. +* o_option:: -o <output-file> option. +* capital_O_option:: -O option. +* p_option:: -p <pagebreak-hints> option. +* q_option:: -q option. +* r_option:: -r <ribbons-to-get> option. +* s_option:: -s <stop-list-file> option. +* capital_S_option:: -S option. +* t_option:: -t <typesetting-hints> option. +* v_option:: -v option. +* x_option:: -x <xref-hints> option. + + +File: literate.info, Node: A_option, Next: c_option, Prev: Programs-and-options, Up: Programs-and-options + + -A <pgm-name> option + +(For hackers only.) Assume the program was invoked as `<pgm-name>'. +must be the first option given. Still has to be either `lit2pgm', +`lit2texi', or `lit2latex'. + + +File: literate.info, Node: c_option, Next: d_option, Prev: A_option, Up: Programs-and-options + + -c option + +(Not `lit2pgm'.) Produce Texinfo or LaTeX output (as appropriate) but +don't try to "link" together with other parts of the same document. +Think of the `-c' option to a C compiler... + + +File: literate.info, Node: d_option, Next: capital_D_option, Prev: c_option, Up: Programs-and-options + + -d option + +Print debugging information. I will be monumentally surprised if this +is of any use to you! + + +File: literate.info, Node: capital_D_option, Next: f_option, Prev: d_option, Up: Programs-and-options + + -D option + +(`lit2latex' only.) Print cross-references to code definitions in the +text. + +APRIL91: this option stands some chance of being renamed if the +pseudo-C-preprocessor comes in; see section *Note +pseudo-C-preprocessor::. + + +File: literate.info, Node: f_option, Next: g_option, Prev: capital_D_option, Up: Programs-and-options + + -f <nodename-suffix> option + +(`lit2texi' only.) Append the string `<nodename-suffix>' to every +nodename in a file. This can be useful if you're trying to avoid +nodename clashes between nodes in different parts of a big document +(two of which might, for example, have nodes named "Introduction"). + +APRIL91: A feeble solution; see section *Note clumsy-node-namespace::. + + +File: literate.info, Node: g_option, Next: H_option, Prev: f_option, Up: Programs-and-options + + -g <node-name> option + +(`lit2latex' only.) Grab the sub-tree of text for which node +`<node-name>' is the root. Used when you want to print a whole chapter +or section or something, rather than just one Info node. + +*At this time, this option is only suitable for printing drafts.* + +What is actually done: the output LaTeX-file consists of the pre-amble +(really: everything before the first `\section' command -- not quite +what you want), the subtree you asked for, and `\end{document}'. Your +section will be numbered `1' no matter what. + + +File: literate.info, Node: H_option, Next: i_option, Prev: g_option, Up: Programs-and-options + + -H <dir1>:<dir2> option + +(For hackers only.) Used by villanous people to override the hardwired +directories (`<dir1>' for platform-specific files and `<dir2>' for +platform-independent `perl' libraries) where the literate-programming +system finds its stuff. Also see the `-A' flag. + + +File: literate.info, Node: i_option, Next: capital_I_option, Prev: H_option, Up: Programs-and-options + + -i <input-file> option + +Specify a specific input file. If not specified with `-i', then the +first non-option command-line argument; if no such thing, then standard +input. You may also specify standard input as the "input file" with +`-i -'. + + +File: literate.info, Node: capital_I_option, Next: capital_L_option, Prev: i_option, Up: Programs-and-options + + -I <directories> option + +Add (colon-separated) `<directories>' to the front of the default path +used to follow `\input' commands (just `.' at the moment). Only give +one `-I' option; I cannot promise what will happen if you give more +than one. + +Slight magic: the `.' in the path means: first, look in the directory +where the file doing the `\input''ing is; if not there, look in the +current working directory. (This is usually what you want.) + + +File: literate.info, Node: capital_L_option, Next: l_option, Prev: capital_I_option, Up: Programs-and-options + + -L option + +(`lit2texi' only.) Alternate style of node linking -- puts in more +defaults for "next" and "previous" nodes. If a node doesn't have a +"next" ["previous"] at its level (e.g., it's the last section in a +chapter), then its "next" ["previous"] node will be the physically-next +[-previous] one, regardless of sectioning level. (The default is for +such nodes to have no next [previous] node.) + +[I like the -L node-linking scheme but `makeinfo' issues warnings about +it. APRIL91: newer version of some Info readers achieve the same +effect using additional moving-around-the-tree commands.] + + +File: literate.info, Node: l_option, Next: n_option, Prev: capital_L_option, Up: Programs-and-options + + -l <language> option + +(Not `lit2pgm'.) Assume that any code in the input file is written in +<language> and process accordingly (automatic indexing, etc.). The +<language> is normally intuited from the input-file suffix (e.g., +`.lhs' suggests Haskell code). The `-x', `-p', and `-t' options may be +used to tweak cross-referencing, page-breaking, and typesetting of +code, respectively. + + +File: literate.info, Node: n_option, Next: capital_N_option, Prev: l_option, Up: Programs-and-options + + -n option + +Follow `\input' commands. + + +File: literate.info, Node: capital_N_option, Next: o_option, Prev: n_option, Up: Programs-and-options + + -N <info-filename> option + +(`lit2texi' only.) Arrange for the Info file to be called +`<infofilename>'. By default, for input file `foo.xxx', the Info file +will be called `foo.info'. For a multi-file document, the Info +filename will be derived from the name of the first file encountered. + + +File: literate.info, Node: o_option, Next: capital_O_option, Prev: capital_N_option, Up: Programs-and-options + + -o <output-file> option + +Specify a specific output file. If not specified with `-o', then it's +determined by puzzling over the input file's suffix (see the +`-i <input-file>' option). When in doubt, it reverts to the standard +output. You may also specify standard output as the "output file" with +`-o -'. + +(For hackers only.) If the first character to the `-o' argument is a +`|', then the output is piped through the shell command(s) that +presumably follow. + + +File: literate.info, Node: capital_O_option, Next: p_option, Prev: o_option, Up: Programs-and-options + + -O option + +(`lit2texi' and `lit2latex' only.) At the beginning of each section, +list the owner of the source file from which it was extracted. + +[APRIL91: There is some doubt just how this option would work; see +section *Note recording-who-to-blame::.] + + +File: literate.info, Node: p_option, Next: q_option, Prev: capital_O_option, Up: Programs-and-options + + -p <pagebreak-hints> option + +(`lit2latex' only.) The (language-specific) code for typesetting the +code in the document is passed the <pagebreak-hints> to further control +how it is determined where pagebreaks are allowed. This is because it +is not always obvious where to do pagebreaks in long stretches of code. + +These hints, if any, will be mentioned in the documentation of +language-specific processing (Section *Note Language_specific::). + +[NOT IMPLEMENTED FOR ANY LANGUAGE] + + +File: literate.info, Node: q_option, Next: r_option, Prev: p_option, Up: Programs-and-options + + -q option + +(`lit2pgm' only.) Take quick shortcut. This will work if you are only +using ribbon `main' (i.e., the usual recommended practice). + +Should be much faster than the plain `lit2pgm'. The `-q' option will be +the *default* in the Glorious new Haskell compiler. + + +File: literate.info, Node: r_option, Next: s_option, Prev: q_option, Up: Programs-and-options + + -r <ribbons-to-get> option + +(`lit2pgm' only.) Extract code-ribbons `<ribbons-to-get>' +(comma-separated), instead of the default ribbon, `main'. An artifact +of the implementation is that `-r ''' gets you `main'; use +`-r junkName' to extract nothing. + + +File: literate.info, Node: s_option, Next: capital_S_option, Prev: r_option, Up: Programs-and-options + + -s <stop-list-file> option + +(`lit2texi' and `lit2latex' only.) The file <stop-list-file> provides +extra information for the automatic code-indexing about words that +should *not* be indexed. One hacker's dross is another's gold. + +[I'm not sure this is used for any language yet. ToDo: check] + + +File: literate.info, Node: capital_S_option, Next: t_option, Prev: s_option, Up: Programs-and-options + + -S option + +(Not `lit2pgm'.) Process the input as if it is a standalone document. +It is so processed if a `\documentstyle' command is seen, `-S' option +or not. + +APRIL91: in jeopardy of going away; see section *Note +pseudo-C-preprocessor::. + + +File: literate.info, Node: t_option, Next: v_option, Prev: capital_S_option, Up: Programs-and-options + + -t <typesetting-hints> option + +The (language-specific) routines for typesetting (really: outputting) +the code in the document is passed the <typesetting-hints> to further +control how typesetting is done. + +These (comma-separated) hints, if any, will be mentioned in the +documentation of language-specific processing (Section *Note +Language_specific::). Available hints: +`-t tgrind': + Typeset code blocks by passing them through the `tgrind' program. + +`-t ruled': + Put lines (rules) above and below blocks of code. (The default may + vary with other outputting options.) + +`-t unruled': + Do *not* put lines (rules) above and below blocks of code. + +`-t bird': + Format all code (but not pseudocode) with Bird-tracks in the first + column. By default, only code input with Bird-tracks is so + formatted. + +`-t nobird': + Format all code without Bird-tracks. + + +File: literate.info, Node: v_option, Next: x_option, Prev: t_option, Up: Programs-and-options + + -v option + +Be verbose. This is really a debugging thing, too. + + +File: literate.info, Node: x_option, Prev: v_option, Up: Programs-and-options + + -x <xref-hints> option + +The (language-specific) code for indexing and/or cross-referencing the +code in the document is passed the <xref-hints> to further control how +things are done. + +A general one you can use is `-x noindex', to turn off code indexing. + +These hints, if any, will be mentioned in the documentation of +language-specific processing (Section *Note Language_specific::). + +An example might be using `-l cpp -x extra:make' on the configuration +files for `jmake'. These files have both C pre-processor and `make' +things worthy of indexing/cross-referencing, and these options would +ensure that the code was put through the appropriate routines for both +languages. + + +File: literate.info, Node: Info_etc, Next: april91-proposals, Prev: Programs-and-options, Up: Top + +Using your processed literate documents +======================================= + +This section not written yet. + +It's supposed to be about all the neat ways to use your LaTeX- and +Info-ised programs/documents. + + +File: literate.info, Node: april91-proposals, Next: sept92-thoughts, Prev: Info_etc, Up: Top + +APRIL91 PROPOSALS +================= + +* Menu: + +* april91-new-ideas:: New ideas. +* april91-old-ideas:: Old ideas that still haven't gone anywhere. + + +File: literate.info, Node: april91-new-ideas, Next: april91-old-ideas, Prev: april91-proposals, Up: april91-proposals + +New ideas +--------- + +These ideas have piled up over the past six months. NONE OF THEM ARE +IMPLEMENTED. And some are TINY little things (and some are BIG). + +JULY91: I have fleshed out the section *Note literate-para-mode:: and +section *Note lit2lit:: comments, as these directions piqued the +interest of some fellow GRASPers. + +* Menu: + +* delatexify-commands:: Make the commands look less like LaTeX. +* multiple-indexes:: Multiple indexes. +* better-Haskell-indexing:: Better Haskell indexing. +* revised-sectioning:: Revisions to the sectioning commands. +* BNF-grammars:: A "BNF grammar" environment. +* pseudo-C-preprocessor:: Fake "C pre-processing". +* invisible-code:: Invisible code. +* text-in-code:: Plain text in your code. +* diff-fonts-in-text:: Using many "fonts" in text. +* code-in-text-formatting:: Formatting code-ish things in text. +* interface-with-papers:: Interface with plain LaTeX papers. +* literate-para-mode:: A literate Para mode. +* lit2lit:: A `lit2lit' program (to help implement a Para system). +* xtex-options:: Generating LaTeX documents especially for `xtex'. +* free-text-index:: A free-text "index". +* magic-Info-nodes:: Other "magic" Info nodes.... +* revised-pgm-options:: Revise the way options are fed to `lit2*' programs. +* mixing-Bird-code-and-other:: Mixing code in "Bird tracks" with other code. +* code-reading-and-printing:: Decouple code reading and printing styles. + + +File: literate.info, Node: delatexify-commands, Next: multiple-indexes, Prev: april91-new-ideas, Up: april91-new-ideas + +Make the commands look less like LaTeX +...................................... + +The biggest practical problem that has arisen among the (few) users of +the literate programming stuff is that they think they're writing LaTeX +files and are surprised/disappointed when LaTeX fails to grok their +files. We have been too successful in making the notation "LaTeX-like!" + +One way to make the notation less LaTeX-like while maintaining the +notation's familiarity is to switch to mixed-case names, used in a +consistent manner; for example: + CURRENTLY WOULD BECOME ... + \documentstyle \documentStyle + \printindex \printIndex + \begin{flushleft} \begin{flushLeft} +Command/environment names that are one word (e.g., `\begin{enumerate}') +would be unchanged. + +Alternatively, we could make the literate-system case-insensitive where +command names are concerned and merely make it our *convention* to use +mixed-case names. + + +File: literate.info, Node: multiple-indexes, Next: better-Haskell-indexing, Prev: delatexify-commands, Up: april91-new-ideas + +Multiple indexes +................ + +Having one index for a pretty-big program is a dubious proposition; you +get a *huge* index. I think you need multiple indexes -- in the case +of a compiler, you might then have a separate index for: parser, +typechecker, syntactic desugarer, optimiser, etc. + +Let's assume you index all the pieces of a compiler (as above) as +self-contained units. PROBLEM: it is the uses of functions, etc., that +*cross* such boundaries that you would MOST like to have your attention +drawn to. + +That problem aside, I think this is the basic solution: +\defineindex{<index-tag-string>}: + Says that <index-tag-string> is "legal" hereafter. + Requiring/encouraging these `\defineindex' will help to catch + typos. + +\index[<index-tag-string>]{<entry>}: + The `\index' command has an optional <index-tag-string> with which + this <entry> should be tagged. The default tag string is `main' + (unless reset with `\setindex...'; below). + +\printindex[<index-tag-strings>]: + Print an index here, made up from all the entries that have one of + the <index-tag-strings>. The default tag string is (same + caveats...) `main'. + +\setcurrentindex{<index-tag-string>}: + Set the default tag string for `\index' commands in text. + +I think you could use the mechanism above to come close to Texinfo's +idea about multiple indexes. + + +File: literate.info, Node: better-Haskell-indexing, Next: revised-sectioning, Prev: multiple-indexes, Up: april91-new-ideas + +Better Haskell indexing +....................... + +(The idea probably carries over to other languages.) Stick the whole +literate-program Haskell source into an "interesting-thing finder" +(call it `htags' :-), getting back (source-location, index-entry) +pairs. Then the only trick is to tack each index-entry onto the code +block nearest to the reported source-location. + + +File: literate.info, Node: revised-sectioning, Next: BNF-grammars, Prev: better-Haskell-indexing, Up: april91-new-ideas + +Revisions to the sectioning commands +.................................... + +The main thing that is a pain about the current sectioning (see section +*Note Sectioning::) is making up unique node names all the time. I +propose the following "system" for the optional arg to `\section<n>'; +shown by example: +\section{<title>}: + (As currently.) A default node name, made from the section number. + No `\label' created. + +\section[]{<title>}: + No node name, no node, no `\label'. Not recommended :-) + +\section[<the-usual>]{<title>}: + (As currently.) Arguably, the stuff to let you specific + next/prev/up explicitly should be dropped (to partly de-Info-ise + the notation). + +\section["]{<title>}: + (The new one.) The node name should be the same as the <title> + ("ditto"). No `\label' would be generated. Some massaging would + be required to remove nodename-hostile characters from the title + (e.g., colons). + + +File: literate.info, Node: BNF-grammars, Next: pseudo-C-preprocessor, Prev: revised-sectioning, Up: april91-new-ideas + +A "BNF grammar" environment +........................... + +This would work like the `verbatim' program used with the Haskell +report; you could say: + \begin{grammar} + exp -> aexp + | exp aexp + | exp_1 op exp_2 + | @-@ aexp + | @\@ apat_1 ... apat_n [gd] @->@ exp + | @if@ exp_1 @then@ exp_2 @else@ exp_3 + | exp @where@ @{@ decls @}@ + | @case@ exp @of@ @{@ alts @}@ + | exp @::@ [context @=>@] atype + \end{grammar} +and respectable BNF-looking stuff would appear in your output. Index +entries for the definitions of nonterminals would be generated; +possibly a `[noindex]' option to suppress that. + +I'd also like to do something for inference rules, but I'm fairly +baffled about what that might be. (They can be mightily complicated, +and it's not clear that a plain-ASCII form is possible.) + + +File: literate.info, Node: pseudo-C-preprocessor, Next: invisible-code, Prev: BNF-grammars, Up: april91-new-ideas + +Fake "C pre-processing" +....................... + +Change things so that literate documents are first put through a "fake +C pre-processor" (this section assumes you know what a C pre-processor +does). Notes: + 1. The relevant commands would start with `##' (to avoid confusion w/ + the real thing); hence, `##if', `##endif', `##define', + `##include', etc. + + 2. (Very important.) This pseudo-C-preprocessor does NOTHING inside: + * Code environments (and the Bird-track equivalent). + + * Verbatim environments. + + * `\tr' and `\pl' commands (and any friends they may have). + + * `rawlatex' environments (next section). + + 3. All of the current dubious `only<this-or-that>' environments and so + on would go away; what you currently write as: + \begin{onlystandalone} + \documentstyle[11pt,literate]{article} + \begin{document} + \title{Glasgow Literate Programming\\ User's Guide} + \date{April 1991} + \maketitle + \begin{onlylatex} + \tableofcontents + \end{onlylatex} + \clearpage + \end{onlystandalone} + would be re-written as: + ##if defined(STANDALONE) + \documentstyle[11pt,literate]{article} + \begin{document} + \title{Glasgow Literate Programming\\ User's Guide} + \date{April 1991} + \maketitle + ##if defined(MK_LATEX) + \tableofcontents + ##endif /* MK_LATEX */ + \clearpage + ##endif /* STANDALONE */ + + 4. `##include' would take the place of the current bogosity + `\inputnow'. + + 5. `##define' would take over from the current emasculated `\define' + and would emphasise the point that this literate notation is a + fixed notation, lacking general macros. + + 6. Running this or that program would pre-##define certain symbols + (e.g., MK_LATEX), but I don't know exactly which just yet. + + 7. Using ##defines and ##ifdef'ing easily generalises the + "standalone/partofdoc" dichotomy (which badly needs generalising). + + +File: literate.info, Node: invisible-code, Next: text-in-code, Prev: pseudo-C-preprocessor, Up: april91-new-ideas + +Invisible code +.............. + +I am wondering if we shouldn't have a code environment of the form: + \begin{invisiblecode} + main (int argc, char **argv) + { + printf("Hello, Seaworld!\n"); + } + \end{invisiblecode} +for code that *should* be extracted (`lit2pgm') but that *should not* +be displayed in `lit2latex/lit2texi' documents. This would probably be +used when you want to include most, but not all, of a program's code -- +in a paper for publication, for example. + +My only fear is that it is too easily subject to abuse. + +Perhaps the C-pre-processing stuff is a better idea... (section *Note +pseudo-C-preprocessor::). + + +File: literate.info, Node: text-in-code, Next: diff-fonts-in-text, Prev: invisible-code, Up: april91-new-ideas + +Plain text in your code +....................... + +In Knuth's WEB, you can refer to code-things in the text parts of the +document/program *and* to text-things in your code. (As I recall, +putting `|' around text switches it to whatever-you're-not-doing-now +(code or text)). + +We have the first (the `@...@' shorthand to refer to code things while +in text), but not the second: what's in a code environment is code just +like you would see in an illiterate program in the same language. + +I guess the right solution is to have specially-marked comments (again, +language-dependent) that say, "Don't treat this as just a comment in +this programming language, but extract it and mangle/massage it as if +it were literate-document text." + +A pain to implement. Not worth it? + + +File: literate.info, Node: diff-fonts-in-text, Next: code-in-text-formatting, Prev: text-in-code, Up: april91-new-ideas + +Using many "fonts" in text +.......................... + +I find the `\tr' ("typewriter font") and `\pl' ("plain font") commands +quite useful. (Yes, I know they go against the intensional markup +principle (section *Note ASCII-declarative-markup::), but they are *so* +convenient...) + +I'm inclined to make up notations for italics, small caps, and bold +(and their ASCII-only "equivalents") and then try to systematize their +use. Hmmm.... + +I've found the Texinfo attempt to have a command for every different +kind of thing you might want to talk about in a document to be too much +and also unsatisfying. + + +File: literate.info, Node: code-in-text-formatting, Next: interface-with-papers, Prev: diff-fonts-in-text, Up: april91-new-ideas + +Formatting code-ish things in text +.................................. + +Right now, the `@...@' shortcut notation means: Format this and +automagically index it as for the code parts of the document. + +Strictly speaking then, I think the `@...@' notation should only be +used to refer to things that *actually exist* in the code parts of the +document, and *not* for code snippets, fragments, and other things +mentioned along the way. + +For this latter task, perhaps a `\code[<language>]{<text>}' command is +in order. This says: format this <text> as for <language>, but don't +index it or pretend that it actually has anything to do with the real +code in the program. + + +File: literate.info, Node: interface-with-papers, Next: literate-para-mode, Prev: code-in-text-formatting, Up: april91-new-ideas + +Interface with plain LaTeX papers +................................. + +At least in our setting, it is likely we've written one or more papers +about some interesting part of the literate program we're writing. The +paper is likely to be: + * relatively polished (so you'd like to re-use that effort); + + * either a decent introduction to some part of the program, or a + succinct synopsis of some part; + + * in straight LaTeX, but using features quite beyond our literate + markup, and including figures, etc.; + + * not to be changed in any way. + +At the least, I'd like to be able to include the paper in toto, and +have pointers into it (refs to its labels). + +More/better ideas welcome. + + +File: literate.info, Node: literate-para-mode, Next: lit2lit, Prev: interface-with-papers, Up: april91-new-ideas + +A literate Para mode +.................... + +[See also section *Note lit2lit::.] + +The sad fact is that, at the moment, these literate programs/documents +are typed in as just plain files and manipulated as such. They are +only processed into LaTeX/Info documents after the fact (and only +occasionally). + +Para mode is a GNU emacs mode that (roughly...) lets you both edit +Texinfo files *and* jump around in them like Info files, based on the +node structure. Either edit-as-normal or navigate-as-Info. + +I think there are possibilities for doing the same thing with these +literate documents/programs. Then you'd get the benefits of +navigation, following indexery, etc., *as you create the files*. + +One major problem (?): the literate sectioning makes it quite easy to +navigate *within* a file, but, for it to be worth it, you'd like the +"literate Para mode" (in navigation mode) to be able to carry you to +the right place when you, e.g., want to go "up" from the first +`\section' in a file. + +Implementation: my first cut would be: run something over all the +literate files in a program to collect "Para-useful" information; save +this somewhere -- this is the moral equivalent of a TAGS file. Then the +navigation commands, etc., would use the pseudo-TAGS info to do their +thing. Because the info would get out of date as you hack on your +program, you'd re-make the pseudo-TAGS stuff whenever you stepped out +for coffee, lunch, or sleep. + + +File: literate.info, Node: lit2lit, Next: xtex-options, Prev: literate-para-mode, Up: april91-new-ideas + +A `lit2lit' program (to help implement a Para system) +..................................................... + +[This might be a better way to implement a literate Para ...] Have a +program that takes a set of `.lit' files, munges them to do all the +usual cross-referencing, etc., etc., and then writes out *versions of +the original files* with all the linking info, etc., etc., inserted as +*comments*. Call the program `lit2lit'... + +If you took the `lit2lit' output and re-ran it through one of the other +programs, e.g., `lit2latex', it would produce *exactly* the same output. + +The purpose of the information stored in comments would be to provide an +Emacs mode (or something) enough information to help you jump around in +a large program or generally do useful stuff. + +For example, it might insert links and things for something like Bob +Weiner's Hyperbole system. + +I'm thinking that `lit2lit' would be re-run over a system's sources +every night by `cron(1)'. + + +File: literate.info, Node: xtex-options, Next: free-text-index, Prev: lit2lit, Up: april91-new-ideas + +Generating LaTeX documents especially for `xtex' +................................................ + +`Xtex' is a (free) DVI previewer with some hypertext-ish features; in +particular, if you click on a reference to a label, then it takes you +to the page where that label is defined. By generating a "LaTeX" +document with all the linking info explicit (in the form of labels and +references to them), `xtex' would do almost all the jumping-around +stuff that `info' and `xinfo' do for you. *And you don't lose the font +information.* + + +File: literate.info, Node: free-text-index, Next: magic-Info-nodes, Prev: xtex-options, Up: april91-new-ideas + +A free-text "index" +................... + +OK, even with all the automagical indexing, cross-referencing, etc., +occasions will arise when you say, "Help! I need to look absolutely +everywhere for <foo>!" (Like you do with grep/tags, but preferably +nicer -- all the tricks of the free-text indexing trade.) + +It would be great to have a "free text index" button or pseudo-node (an +Info "node" that, when you jump to it, puts you in a free-text-search +mode. Of course, the free-text-search should be able to plunk you down +in the Info node you finally select). + +I really don't want to implement this myself :-) + + +File: literate.info, Node: magic-Info-nodes, Next: revised-pgm-options, Prev: free-text-index, Up: april91-new-ideas + +Other "magic" Info nodes... +........................... + +The "free text index" magic Info node makes me wish for *other* +nodes-that-do-weird-things when you jump to them... You jump to it +and... it starts up a PostScript previewer and shows me a picture... or +sound... or my text editor so I can send a gripe to the maintainer of +foo... and so on. + + +File: literate.info, Node: revised-pgm-options, Next: mixing-Bird-code-and-other, Prev: magic-Info-nodes, Up: april91-new-ideas + +Revise the way options are fed to `lit2*' programs +.................................................. + +Using getopt(3)-style one-letter options is getting messy -- there are +too many of them. Perhaps time for something more complicated... + + +File: literate.info, Node: mixing-Bird-code-and-other, Next: code-reading-and-printing, Prev: revised-pgm-options, Up: april91-new-ideas + +Mixing code in "Bird tracks" with other code +............................................ + +When you put something in a code environment, e.g., + \begin{code} + main _ = [ AppendChan stdout "Hi, Mom!\n" ] + \end{code} +there is no doubt about what should be considered the "first column". +On the other hand, if you see a "Bird track" equivalent: + > main _ = [ AppendChan stdout "Hi, Mom!\n" ] +obviously the initial `>' should be stripped, but what about the space +following? This matters if the code is to be put through, e.g., a C +pre-processor, which looks for #'s in column 1. + +The solution I lean to is to have an option that says how much +whitespace should be stripped off the front of Bird-track style code +lines. + + +File: literate.info, Node: code-reading-and-printing, Prev: mixing-Bird-code-and-other, Up: april91-new-ideas + +Decouple code reading and printing styles +......................................... + +Code may come in either in code environments or in Bird-tracks. At +present, it is printed in the same style as it came. This should +remain the default. + +However, it would be nice to be able to say (with options), "OK, print +*all* the code as if it were in Bird-track form" (or vice versa). This +allows uniform presentation, while preserving programmers' preference +for typing in one style rather than the other. + + +File: literate.info, Node: april91-old-ideas, Prev: april91-new-ideas, Up: april91-proposals + +Old ideas that still haven't gone anywhere +------------------------------------------ + +These are ideas that have been around for a long time, HAVE NOT BEEN +IMPLEMENTED, and no-one seems to have minded much. + +* Menu: + +* recording-who-to-blame:: \owner{<name>}. +* test-burying:: Burying test cases in your document. +* recording-changes:: Recording changes to your documents. + + +File: literate.info, Node: recording-who-to-blame, Next: test-burying, Prev: april91-old-ideas, Up: april91-old-ideas + +\owner{<name>} +.............. + +(Not `lit2pgm'.) Give the "name" that should be listed as the "owner" +of a section. If no `\owner' command has been seen, then the owner of +the source file in which the first piece of text in the section was +found is used. + +[I haven't really decided how this should work.] + + +File: literate.info, Node: test-burying, Next: recording-changes, Prev: recording-who-to-blame, Up: april91-old-ideas + +Burying test cases in your document +................................... + +The idea is that you can say: + \begin{test}{foo} + <Weird stuff in here> + \end{test} +For this test `foo', the `<weird stuff in here>' would somehow say how +to run the test, what should be fed to standard input (etc.), and what +results to expect on standard output, standard error, and perhaps +certain output files. + +The idea is to put the (simple?) test cases right next to the code that +will be exercised. + +The problem is: tests can do pretty arbitrary things, and I don't see +any neat way to encode that fact. Simply bunging full-blown shell +scripts into the middle of your literate program hardly seems the +solution. Hmmm..... + +If we had them: test environments don't nest. + +See ????? (ToDo) for a note on using hidden comments to highlight test +information. + + +File: literate.info, Node: recording-changes, Prev: test-burying, Up: april91-old-ideas + +Recording changes to your documents +................................... + +Vaguely like the test case stuff, you might say: + \begin{change} + <who> & <when> & <tag> & <description of first change> \\ + <who> & <when> & <tag> & <description of second change> \\ + ... and so on ... + \end{change} +This is intended to be like the ChangeLog stuff supported in Emacs +(`C-x 4 a'). It really only makes sense to use it after software is no +longer undergoing cataclysmic change (after it is released perhaps?). + +Anyway, the idea is to record your change notes right next to where you +make them. [The program(s) to extract these notes and to collate them +in the manner of your choice are not written yet.] + +These change environments don't nest. + + +File: literate.info, Node: sept92-thoughts, Next: lit-install, Prev: april91-proposals, Up: Top + +SEPT92 THOUGHTS +=============== + +These are further ruminations, having had another year to watch how +people do and do not use this system. + +Death to `ribbons' and code re-ordering: + No-one uses it, and it's pretty clunky in this system, both + conceptually and implementationally. + +Suppressable `detail': + Be able to mark sections as `detail', as well as to be able to put + `\begin{detail}/\end{detail}' around arbitrary stuff. Obviously, + you then want to format with/without the details in. + +A minimally-extensible notation? + Texinfo now supports setting and testing of variables, and the + using the values thereof. + +Support "all non-code is raw XXX": + Something like: given a flag `-r latex', then all non-code would be + taken to be pure LaTeX and wouldn't be mangled *at all*. + + Another likely possibility: a `-r verbatim', to support the dubious + `verbatim' script that's popular in some circles. + +Stop automagic indexing of code-in-text: + I'm not sure it's useful. + +Throw out tree-grabbing (`-g <node>' option): + Too hacky, not used, probably inadequate. + + +File: literate.info, Node: lit-install, Next: Index, Prev: sept92-thoughts, Up: Top + +Standalone installation of Glasgow literate programming +======================================================= + +NOT DONE PROPERLY YET. + +Here are some short notes; they should work on a Sun4: + 1. If you don't have `perl', go get it. + + 2. If you don't have `makeindex' (normally with the TeX distribution) + and/or `tgrind', go get them, if you wish. You can easily get by + without them, especially `tgrind'. + + 3. Customise for your local configuration, by creating a suitable + `mkworld/site.jm' file. We supply a `site.dist' file that you can + copy and work from. + + Setting `PerlCmd' correctly is *vital*. + + All the Haskell-compiler stuff isn't important for the + literate-programming system. + + Setting `TgrindHelperCmd' is important if you're going to try the + tgrind-ing stuff. + + Setting the things for installation (near the end) is *vital*. You + will almost certainly need to set `InstRootDir', and perhaps some + others. If you don't set anything, the literate-programming + system will be installed (on a Sun4) in... + + /usr/local/bin/sun4 things for the user to invoke (lit2mumble) + /usr/local/lib/literate/sun4 machine-specific support stuff + /usr/local/lib/literate machine-independent support stuff + + 4. OK, you should be ready to go! From the top of the distribution... + % cd lit2xxx-X.YY + % ./STARTUP-literate >& startup.log + Everything should proceed to an obviously-successful conclusion + (check the log to see...). + + 5. Test the system enough to see that it's not totally broken. Invoke + `lit2pgm', `lit2latex', or `lit2texi' directly from the + `literate/' directory, on some small test file of your choice, + even something as simple as...: + \section[test]{Test section} + This is a small test. + Then try, perhaps: + % literate/lit2latex -v -c test.lit + + 6. If things seem basically happy, you can safely install the system. + % cd literate + % make -n install # trial run, just to see if it looks "right" + % make install # for real! + + 7. To make the documentation (some pre-built stuff is in the distrib): + % cd literate + % make literate.dvi # or ... + % make literate.info # or ... + % make docs # to do both + + In the unlikely event you wanted to install it, continue with: + % make install-docs + + 8. You can now either delete the source or just clean up: + % make clean + + 9. Save a copy of your configuration file `mkworld/site.jm' for next + time. + +If you have problems, please report them to me, +partain@dcs.glasgow.ac.uk. + + +File: literate.info, Node: Index, Prev: lit-install, Up: Top + +Index +===== + +* Menu: + +* -D option: capital_D_option. +* -A <pgm-name> option: A_option. +* \appendix: \appendix. +* \author: \author. +* -c option: c_option. +* \caption: \caption. +* center environment: center_environment. +* \centerline: \centerline. +* \cleardoublepage: \clearpage-etc. +* \clearpage: \clearpage-etc. +* code (vs text): code-verissimilitude. +* code (vs text)_2: notation-tut. +* code environment: code_environment. +* code index entries, extra: magic-things-in-code. +* code ribbons: ribbons-details. +* command: Command_reference. +* comment environment: comment_environment. +* comments, hidden: magic-things-in-code. +* -d option: d_option. +* \date: \date. +* \define: \define. +* description environment: description_environment. +* display environment: display_environment. +* \documentstyle: \documentstyle. +* \em: \em. +* enumerate environment: enumerate_environment. +* environment: Command_reference. +* -f <nodename-suffix> option: f_option. +* figure environment: figure_environment. +* flushdisplay environment: flushdisplay_environment. +* flushverbatim environment: flushverbatim_environment. +* \footnote: \footnote. +* -g <node-name> option: g_option. +* -H <dir1>:<dir2> option: H_option. +* \heading: \heading. +* hidden comments: magic-things-in-code. +* -I <directories> option: capital_I_option. +* -i <input-file> option: i_option. +* index entries, extra ones in code: magic-things-in-code. +* \index: \index. +* \input: \input. +* \inputnow: \inputnow. +* \insertribbon: \insertribbon. +* itemize environment: itemize_environment. +* -L option: capital_L_option. +* -l <language> option: l_option. +* \label: \label. +* LaTeX-like markup language: notation-tut. +* \listoffigures: \listoffigures-etc. +* \listoftables: \listoffigures-etc. +* lit2text: Programs-and-options. +* makeindex: Indexing. +* \makeindex: Indexing. +* \makeindex_2: \makeindex. +* \maketitle: \maketitle. +* menu environment: menu_environment. +* \menuentry: \menuentry. +* mkdependlit: Programs-and-options. +* -N <info-filename> option: capital_N_option. +* -n option: n_option. +* node specification: Node_specifications. +* \node: \node. +* \noindex: Indexing. +* -O option: capital_O_option. +* -o <output-file> option: o_option. +* onlyinfo environment: onlyinfo_environment. +* onlylatex environment: onlylatex_environment. +* onlypartofdoc environment: onlypartofdoc_environment. +* onlystandalone environment: onlystandalone_environment. +* \owner: recording-who-to-blame. +* -p <pagebreak-hints> option: p_option. +* \pageref: \pageref. +* \pl: \pl. +* \pounds: \pounds. +* \printindex: Indexing. +* \printindex_2: \printindex. +* pseudocode environment: pseudocode_environment. +* -q option: q_option. +* quotation environment: quotation_environment. +* -r <ribbons-to-get> option: r_option. +* rawlatex environment: rawlatex_environment. +* \ref: \ref. +* ribbons, code: ribbons-details. +* \rootsectiontype: How_to_section. +* \rootsectiontype_2: \rootsectiontype. +* -S option: capital_S_option. +* -s <stop-list-file> option: s_option. +* sectioning: Sectioning. +* \Sectionref: sectiontype-and-ref. +* \sectionref: \sectionref. +* \sectionref_2: sectiontype-and-ref. +* \sectiontype: \sectiontype. +* \sectiontype_2: sectiontype-and-ref. +* \standaloneornot: \standaloneornot. +* \suppresscomments: \suppresscomments. +* -t <typesetting-hints> option: t_option. +* table environment: table_environment. +* \tableofcontents: \tableofcontents. +* tabular environment: tabular_environment. +* text (vs code): code-verissimilitude. +* text (vs code)_2: notation-tut. +* \title: \title. +* \tr: \tr. +* -v option: v_option. +* verbatim environment: verbatim_environment. +* -x <xref-hints> option: x_option. + + + +Tag Table: +Node: Top96 +Node: Highlights3235 +Node: Glasgow-objectives4426 +Node: on-line-form5734 +Node: medium-scale7013 +Node: language-independence7502 +Node: code-verissimilitude8172 +Node: ASCII-declarative-markup9013 +Node: hierarchical-structure10364 +Node: separate-compilation10933 +Node: one-file-many-purposes12171 +Node: Glasgow-NON-objectives13594 +Node: not-reinvent-LaTeX13939 +Node: reordering-unemphasis14489 +Node: Other-Glasgow-features15348 +Node: sectioning-large-documents15959 +Node: automatic-indexing17191 +Node: manual-indexing17991 +Node: automatic-cross-referencing18401 +Node: shortcut-notations19278 +Node: TeX-to-ASCII20306 +Node: Glasgow-NON-features20788 +Node: texinfo-limits21148 +Node: clumsy-node-namespace21925 +Node: clunky-implementation22467 +Node: notation-tut23069 +Node: micro-latex27347 +Node: Sectioning28813 +Node: section<n>29328 +Node: How_to_section31469 +Node: sectiontype-and-ref33368 +Node: Node_specifications34176 +Node: code-in-doc36990 +Node: usual-code-in-doc37673 +Node: ribbons-details38777 +Node: reordering-with-insertribbon40734 +Node: pseudocode41737 +Node: magic-things-in-code42151 +Node: Cross_references43836 +Node: Indexing44658 +Node: Examples47802 +Node: Simple_example48246 +Node: Typical_example48383 +Node: Hairy_example48527 +Node: Shortcuts48644 +Node: code-in-text49033 +Node: fonts-in-text50082 +Node: Command_reference50530 +Node: \appendix55179 +Node: \author55413 +Node: center_environment55571 +Node: \centerline55858 +Node: \caption56006 +Node: \clearpage-etc56229 +Node: code_environment56414 +Node: comment_environment56702 +Node: \date57125 +Node: \define57310 +Node: description_environment57944 +Node: display_environment58107 +Node: \documentstyle58478 +Node: \em59121 +Node: enumerate_environment59372 +Node: figure_environment59526 +Node: flushdisplay_environment59866 +Node: flushverbatim_environment60186 +Node: \footnote60569 +Node: \heading60958 +Node: \index61279 +Node: \input61677 +Node: \inputnow62348 +Node: \insertribbon62616 +Node: itemize_environment63072 +Node: \label63265 +Node: \listoffigures-etc63905 +Node: \makeindex64135 +Node: \maketitle64384 +Node: menu_environment64981 +Node: \menuentry65456 +Node: \node65681 +Node: \pounds66025 +Node: onlyinfo_environment66437 +Node: onlylatex_environment66736 +Node: onlypartofdoc_environment67047 +Node: onlystandalone_environment67517 +Node: \pageref68012 +Node: \pl68296 +Node: \printindex68822 +Node: pseudocode_environment69162 +Node: quotation_environment69495 +Node: rawlatex_environment69670 +Node: \ref70275 +Node: \rootsectiontype70433 +Node: \sectiontype70625 +Node: \sectionref70814 +Node: \standaloneornot71002 +Node: \suppresscomments71520 +Node: table_environment71882 +Node: \tableofcontents72131 +Node: tabular_environment72347 +Node: \title72654 +Node: \tr72805 +Node: verbatim_environment73347 +Node: Language_specific73903 +Node: Default_rules74638 +Node: Haskell_rules74918 +Node: Perl_rules75313 +Node: C_rules75698 +Node: Fortran_rules75904 +Node: Habits76190 +Node: Caveats77578 +Node: Programs-and-options79262 +Node: A_option82659 +Node: c_option82960 +Node: d_option83257 +Node: capital_D_option83472 +Node: f_option83810 +Node: g_option84290 +Node: H_option84930 +Node: i_option85315 +Node: capital_I_option85668 +Node: capital_L_option86231 +Node: l_option86947 +Node: n_option87442 +Node: capital_N_option87590 +Node: o_option87991 +Node: capital_O_option88570 +Node: p_option88934 +Node: q_option89524 +Node: r_option89894 +Node: s_option90246 +Node: capital_S_option90648 +Node: t_option90998 +Node: v_option91990 +Node: x_option92156 +Node: Info_etc92917 +Node: april91-proposals93232 +Node: april91-new-ideas93480 +Node: delatexify-commands95184 +Node: multiple-indexes96273 +Node: better-Haskell-indexing97769 +Node: revised-sectioning98270 +Node: BNF-grammars99339 +Node: pseudo-C-preprocessor100331 +Node: invisible-code102536 +Node: text-in-code103304 +Node: diff-fonts-in-text104187 +Node: code-in-text-formatting104915 +Node: interface-with-papers105714 +Node: literate-para-mode106544 +Node: lit2lit108098 +Node: xtex-options109171 +Node: free-text-index109809 +Node: magic-Info-nodes110535 +Node: revised-pgm-options111011 +Node: mixing-Bird-code-and-other111387 +Node: code-reading-and-printing112265 +Node: april91-old-ideas112882 +Node: recording-who-to-blame113373 +Node: test-burying113804 +Node: recording-changes114778 +Node: sept92-thoughts115626 +Node: lit-install116843 +Node: Index119654 + +End Tag Table diff --git a/web/glasgow/lit2x-0.16/literate/doc/literate.lit b/web/glasgow/lit2x-0.16/literate/doc/literate.lit new file mode 100644 index 0000000000..d0a98f6410 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/literate.lit @@ -0,0 +1,104 @@ +\begin{onlystandalone} +\documentstyle[11pt,literate]{article} +\begin{document} +\title{Glasgow Literate Programming\\ User's Guide} + +\author{ +The GRASP Team \\ +Contact: Will Partain (partain\@dcs.glasgow.ac.uk) +} +\date{September 1992} +\maketitle +\begin{onlylatex} +\tableofcontents +\end{onlylatex} +\clearpage +\end{onlystandalone} + +This +\standaloneornot{guide}{\sectiontype{Literate_guide}} +introduces a suite of programs for literate programming. +They support documentation as a natural part of programming; +a program's organization focusses on understanding by humans. + +If you installing this system as a standalone entity, please +see~\sectionref{lit-install}, near the end. + +This document begins with a few words about literate programming, the +objectives of this system, and the Neat Stuff that this system is +supposed to do for you (i.e., cheap, tasteless self-promotion). +See~\sectionref{Highlights}. + +The real goods come next, most notably: +\begin{itemize} +\item +an alleged ``tutorial'' on the \LaTeX{}-like markup language in which +documents/programs are written (\sectionref{notation-tut}); +\item +a ``reference manual'' about the same markup language; this tends to +be what you consult once you are using the system +(\sectionref{Command_reference}); +\item +the programs/tools to mangle your documents/programs into useful forms +(\sectionref{Programs-and-options}). +\end{itemize} +There are other sections, too, in greater-or-less states of +usefulness. + +It would be a good idea to understand the rudiments of GNU Info files +before reading much further---type \tr{info info} at your favourite +Unix prompt. Or you could just ignore all mention of Info files... + +YOUR SUGGESTIONS FOR IMPROVING THIS SYSTEM ARE MOST WELCOME. + +DISCLAIMER: ``Literate programming'' is not my(WDP)/our area of +expertise. This system has been developed mainly to suit our needs +and has evolved on a grease-the-squeaky-wheel principle. However, we +wouldn't bother to document it if we didn't think there was something +to it! + +APRIL91 PROPOSALS: I am thinking about some changes to the system, NOT +YET IMPLEMENTED. Discussion about most (all?) of them is gathered +together in \sectionref{april91-proposals}. (You can find all +discussion of proposed changes by grepping for ``APRIL91''.) + +SEPT92 THOUGHTS: Still haven't really worked on this system. I have +typed a few further thoughts at the obvious place. I have fixed one +or two bugs, and I have incorporated Adriaan Joubert's +(adriaan\@dcs.qmw.ac.uk) stuff for ``literate Fortran,'' for which I +am most grateful. (See, it really is easy to extend :-) + +For more information about ``real'' literate programming, the +bibliography of literate programming in the (approx: ToDo) March~1991 +SIGPLAN Notices may be of use. + +% section on who should and shouldn't use this system? +% (now in highlights) +\input{highlights.lit} + +\input{lang_tut.lit} + +\input{lang_ref.lit} + +\input{lang_specific.lit} + +\input{habits.lit} + +\input{caveats.lit} + +\input{programs.lit} + +\input{using.lit} + +\input{april91.lit} + +\input{sept92.lit} + +\input{install.lit} + +%\input{lit_mode.lit} + +\begin{onlystandalone} +\printindex +\end{document} +\end{onlystandalone} diff --git a/web/glasgow/lit2x-0.16/literate/doc/programs.lit b/web/glasgow/lit2x-0.16/literate/doc/programs.lit new file mode 100644 index 0000000000..10ffb283b5 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/programs.lit @@ -0,0 +1,300 @@ +\section[Programs-and-options]{Programs to process literate documents} + +In this incarnation, the programs \tr{lit2pgm}, \tr{lit2latex}, and +\tr{lit2texi} (to extract program, \LaTeX{}, or GNU Texinfo fodder) +are just three ways of invoking one killer \tr{perl} script, +\tr{lit2stuff}. +%\begin{comment} +%A shell script \tr{lit2info}, to run +%\tr{lit2texi} and then \tr{makeinfo} is not yet implemented. A script +%\tr{lit2dvi} to run \tr{lit2latex} and then some sequence of +%\tr{latex} and \tr{makeindex} invocations is also not out of the +%question. +%\end{comment} + +[Actually, this same script may be invoked as +\tr{mkdependlit},\index{mkdependlit} to +build a set of \tr{make} dependencies for a literate document, as +\tr{lit2text}\index{lit2text}, to extract just the non-code text +(perhaps for spell-checking), or as \tr{lit2changelog}, which is the +(mainly unimplemented) interface to the changelog-slurping code. I +ignore these details herein.] + +APRIL91: there are starting to be enough options that getopt-style +one-letter names aren't enough/too obtuse. Some revision may be in +order there... See \sectionref{revised-pgm-options}. + +For all three programs, their invocation takes the form +\tr{lit2<whatever> [options] [input-file]}. +Usually, output is to a file determined from the input-file's suffix +(e.g., a \tr{.hs} file from a \tr{.lhs} file); if no input file is +provided or life becomes confused, output is to the standard output. +You can control input and output explicitly with the \tr{-i} and +\tr{-o} options. + +Known file suffixes and what they mean: + +\begin{tabular}{ll} +.lit & a literate-document file with no code in it (e.g., this one) \\ +.lhs & literate \Haskell{} source \\ +.lprl & literate Perl source \\ +.llex & literate Lex source \\ +.lc & literate C source \\ +.lh & literate C header source \\ +.ltex & literate \TeX{} macros \\ +.lf & literate FORTRAN \\ +\end{tabular} + +The suffixes \tr{.itex} and \tr{.itxi} indicate the intermediate files +from ``separate compilation'' (to \LaTeX{} and Texinfo, respectively) +of parts of a larger document. + +In ordinary life, given a literate C program \tr{foo} in file +\tr{foo.lc}, one would hope that the following simple invocations +would suffice: +\begin{verbatim} +lit2pgm foo.lc +gcc -o foo foo.c + +lit2latex foo.lc +latex foo.tex + +lit2texi foo.lc +makeinfo foo.texi +# (and if you really want to make things right, use the script... +postmakeinfo foo.info +# as well) +\end{verbatim} + +What follows are the options to control these programs (and to +complicate your life [and mine, too]). Not all command-line options +make sense for all three programs; they are so noted. Options may be +glopped together in the best getopt(3) style. + +\subsection*[A_option]{\pl{-A <pgm-name>} option} +\index{a option@-A <pgm-name> option} +(For hackers only.) Assume the program was invoked as \tr{<pgm-name>}. +must be the first option given. Still has to be either \tr{lit2pgm}, +\tr{lit2texi}, or \tr{lit2latex}. + +\subsection*[c_option]{\pl{-c} option} +\index{c option@-c option} +(Not \tr{lit2pgm}.) Produce Texinfo or \LaTeX{} output (as +appropriate) but don't try to ``link'' together with other parts of +the same document. Think of the \tr{-c} option to a C compiler... + +\subsection*[d_option]{\pl{-d} option} +\index{d option@-d option} +Print debugging information. I will be monumentally surprised if this +is of any use to you! + +\subsection*[capital_D_option]{\pl{-D} option} +\index{D option@-D option} +(\tr{lit2latex} only.) Print cross-references to code +definitions in the text. + +APRIL91: this option stands some chance of being renamed if the +pseudo-C-preprocessor comes in; see +\sectionref{pseudo-C-preprocessor}. + +\subsection*[f_option]{\pl{-f <nodename-suffix>} option} +\index{f option@-f <nodename-suffix> option} +(\tr{lit2texi} only.) Append the string \tr{<nodename-suffix>} to +every nodename in a file. This can be useful if you're trying to +avoid nodename clashes between nodes in different parts of a big +document (two of which might, for example, have nodes named +``Introduction''). + +APRIL91: A feeble solution; see \sectionref{clumsy-node-namespace}. + +\subsection*[g_option]{\pl{-g <node-name>} option} +\index{g option@-g <node-name> option} +(\tr{lit2latex} only.) Grab the sub-tree of text for which node +\tr{<node-name>} is the root. Used when you want to print a whole chapter +or section or something, rather than just one Info node. + +{\em At this time, this option is only suitable for printing drafts.} + +What is actually done: the output \LaTeX{}-file consists of the +pre-amble (really: everything before the first \tr{\section} +command---not quite what you want), the subtree you asked for, and +\tr{\end{document}}. Your section will be numbered \tr{1} no matter +what. + +\subsection*[H_option]{\pl{-H <dir1>:<dir2>} option} +\index{h option@-H <dir1>:<dir2> option} +(For hackers only.) Used by villanous people to override the hardwired +directories (\tr{<dir1>} for platform-specific files and \tr{<dir2>} for +platform-independent \tr{perl} libraries) where the +literate-programming system finds its stuff. Also see the \tr{-A} +flag. + +\subsection*[i_option]{\pl{-i <input-file>} option} +\index{i option@-i <input-file> option} +Specify a specific input file. If not specified with \tr{-i}, then +the first non-option command-line argument; if no such thing, then +standard input. You may also specify standard input as the ``input +file'' with \tr{-i -}. + +\subsection*[capital_I_option]{\pl{-I <directories>} option} +\index{i option@-I <directories> option} +Add (colon-separated) \tr{<directories>} to the front of the +default path used to follow \tr{\input} commands (just \tr{.} at the +moment). Only give one \tr{-I} option; I cannot promise what will +happen if you give more than one. + +Slight magic: the \tr{.} in the path means: first, look in the +directory where the file doing the \tr{\input}'ing is; if not there, +look in the current working directory. (This is usually what you +want.) + +\subsection*[capital_L_option]{\pl{-L} option} +\index{l option@-L option} +(\tr{lit2texi} only.) Alternate style of node linking---puts in more +defaults for ``next'' and ``previous'' nodes. If a node doesn't have +a ``next'' [``previous''] at its level (e.g., it's the last section in +a chapter), then its ``next'' [``previous''] node will be the +physically-next [-previous] one, regardless of sectioning level. (The +default is for such nodes to have no next [previous] node.) + +[I like the -L node-linking scheme but \tr{makeinfo} issues warnings +about it. APRIL91: newer version of some Info readers achieve the +same effect using additional moving-around-the-tree commands.] + +\subsection*[l_option]{\pl{-l <language>} option} +\index{l option@-l <language> option} +(Not \tr{lit2pgm}.) Assume that any code in the input file is written in +\pl{<language>} and process accordingly (automatic indexing, etc.). +The \pl{<language>} is normally intuited from the input-file suffix +(e.g., \tr{.lhs} suggests \Haskell{} code). The \tr{-x}, +\tr{-p}, and \tr{-t} options may be used to tweak cross-referencing, +page-breaking, and typesetting of code, respectively. + +\subsection*[n_option]{\pl{-n} option} +\index{n option@-n option} +Follow \tr{\input} commands. + +\subsection*[capital_N_option]{\pl{-N <info-filename>} option} +\index{n option@-N <info-filename> option} +(\tr{lit2texi} only.) Arrange for the Info file to +be called \tr{<infofilename>}. By default, for input file \tr{foo.xxx}, the +Info file will be called \tr{foo.info}. For a multi-file +document, the Info filename will be derived from the name of the +first file encountered. + +\subsection*[o_option]{\pl{-o <output-file>} option} +\index{o option@-o <output-file> option} +Specify a specific output file. If not specified with \tr{-o}, then +it's determined by puzzling over the input file's suffix (see the +\tr{-i <input-file>} option). When in doubt, it reverts to the +standard output. You may also specify standard output as the ``output +file'' with \tr{-o -}. + +(For hackers only.) If the first character to the \tr{-o} argument is +a \tr{|}, then the output is piped through the shell command(s) that +presumably follow. + +\subsection*[capital_O_option]{\pl{-O} option} +\index{o option@-O option} +(\tr{lit2texi} and \tr{lit2latex} only.) At the beginning of each +section, list the owner of the source file from which it was extracted. + +[APRIL91: There is some doubt just how this option would work; see +\sectionref{recording-who-to-blame}.] + +\subsection*[p_option]{\pl{-p <pagebreak-hints>} option} +\index{p option@-p <pagebreak-hints> option} +(\tr{lit2latex} only.) The (language-specific) code for typesetting +the code in the document is passed the \pl{<pagebreak-hints>} to +further control how it is determined where pagebreaks are allowed. +This is because it is not always obvious where to do pagebreaks in +long stretches of code. + +These hints, if any, will be mentioned in the documentation of +language-specific processing (\Sectionref{Language_specific}). + +[NOT IMPLEMENTED FOR ANY LANGUAGE] + +\subsection*[q_option]{\pl{-q} option} +\index{q option@-q option} +(\tr{lit2pgm} only.) Take quick shortcut. This will work if you are +only using ribbon \tr{main} (i.e., the usual recommended practice). + +Should be much faster than the plain \tr{lit2pgm}. +The \tr{-q} option will be the {\em default} in the Glorious new +\Haskell{} compiler. + +\subsection*[r_option]{\pl{-r <ribbons-to-get>} option} +\index{r option@-r <ribbons-to-get> option} +(\tr{lit2pgm} only.) Extract code-ribbons \tr{<ribbons-to-get>} +(comma-separated), instead of the default ribbon, \tr{main}. +An artifact of the implementation is that \tr{-r ''} gets you +\tr{main}; use \tr{-r junkName} to extract nothing. + +\subsection*[s_option]{\pl{-s <stop-list-file>} option} +\index{s option@-s <stop-list-file> option} +(\tr{lit2texi} and \tr{lit2latex} only.) The file +\pl{<stop-list-file>} provides extra information for the automatic +code-indexing about words that should {\em not} be indexed. +One hacker's dross is another's gold. + +[I'm not sure this is used for any language yet. ToDo: check] + +\subsection*[capital_S_option]{\pl{-S} option} +\index{s option@-S option} +(Not \tr{lit2pgm}.) Process the input as if it is a standalone document. +It is so processed if a \tr{\documentstyle} command is seen, +\tr{-S} option or not. + +APRIL91: in jeopardy of going away; see +\sectionref{pseudo-C-preprocessor}. + +\subsection*[t_option]{\pl{-t <typesetting-hints>} option} +\index{t option@-t <typesetting-hints> option} +The (language-specific) routines for +typesetting (really: outputting) the code in the document is passed the +\pl{<typesetting-hints>} to further control how typesetting is done. + +These (comma-separated) hints, if any, will be mentioned in the +documentation of language-specific processing +(\Sectionref{Language_specific}). Available hints: +\begin{description} +\item[\tr{-t tgrind}:] +Typeset code blocks by passing them through the \tr{tgrind} program. +% +\item[\tr{-t ruled}:] +Put lines (rules) above and below blocks of code. +(The default may vary with other outputting options.) +% +\item[\tr{-t unruled}:] +Do {\em not} put lines (rules) above and below blocks of code. +% +\item[\tr{-t bird}:] +Format all code (but not pseudocode) with Bird-tracks in the first +column. By default, only code input with Bird-tracks is so formatted. +% +\item[\tr{-t nobird}:] +Format all code without Bird-tracks. +\end{description} + +\subsection*[v_option]{\pl{-v} option} +\index{v option@-v option} +Be verbose. This is really a debugging thing, too. + +\subsection*[x_option]{\pl{-x <xref-hints>} option} +\index{x option@-x <xref-hints> option} +The (language-specific) code for indexing +and/or cross-referencing the code in the document is passed the +\pl{<xref-hints>} to further control how things are done. + +A general one you can use is \tr{-x noindex}, to turn off code +indexing. + +These hints, if any, will be mentioned in the documentation of +language-specific processing (\Sectionref{Language_specific}). + +An example might be using \tr{-l cpp -x extra:make} on the +configuration files for \tr{jmake}. These files have both C +pre-processor and \tr{make} things worthy of +indexing/cross-referencing, and these options would ensure that the +code was put through the appropriate routines for both languages. diff --git a/web/glasgow/lit2x-0.16/literate/doc/sept92.lit b/web/glasgow/lit2x-0.16/literate/doc/sept92.lit new file mode 100644 index 0000000000..dbbab52216 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/sept92.lit @@ -0,0 +1,45 @@ +\section[sept92-thoughts]{SEPT92 THOUGHTS} + +These are further ruminations, having had another year to watch how +people do and do not use this system. + +\begin{description} +%------------------------------------------------------------------ +\item[Death to `ribbons' and code re-ordering:] + +No-one uses it, and it's pretty clunky in this system, both +conceptually and implementationally. + +%------------------------------------------------------------------ +\item[Suppressable `detail':] + +Be able to mark sections as `detail', as well as to be able to put +\tr{\begin{detail}/\end{detail}} around arbitrary stuff. Obviously, +you then want to format with/without the details in. + +%------------------------------------------------------------------ +\item[A minimally-extensible notation?] + +Texinfo now supports setting and testing of variables, and the using +the values thereof. + +%------------------------------------------------------------------ +\item[Support ``all non-code is raw XXX'':] + +Something like: given a flag \tr{-r latex}, then all non-code would be +taken to be pure \LaTeX{} and wouldn't be mangled {\em at all}. + +Another likely possibility: a \tr{-r verbatim}, to support the dubious +\tr{verbatim} script that's popular in some circles. + +%------------------------------------------------------------------ +\item[Stop automagic indexing of code-in-text:] + +I'm not sure it's useful. + +%------------------------------------------------------------------ +\item[Throw out tree-grabbing (\tr{-g <node>} option):] + +Too hacky, not used, probably inadequate. + +\end{description} diff --git a/web/glasgow/lit2x-0.16/literate/doc/using.lit b/web/glasgow/lit2x-0.16/literate/doc/using.lit new file mode 100644 index 0000000000..910091bb07 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/doc/using.lit @@ -0,0 +1,6 @@ +\section[Info_etc]{Using your processed literate documents} + +This section not written yet. + +It's supposed to be about all the neat ways to use your \LaTeX{}- and +Info-ised programs/documents. diff --git a/web/glasgow/lit2x-0.16/literate/furuta_ref b/web/glasgow/lit2x-0.16/literate/furuta_ref new file mode 100644 index 0000000000..fce03f7f3f --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/furuta_ref @@ -0,0 +1,28 @@ +From carm@tove.cs.umd.edu Sat Aug 10 10:54:17 1991 +From: carm@tove.cs.umd.edu (Richard Chimera) +Newsgroups: alt.hypertext,comp.editors,comp.text.sgml +Subject: Re: Conversion of documents from paper to electronic (hypertext) format +Date: 9 Aug 91 21:53:44 GMT +Reply-To: carm@tove.cs.umd.edu (Richard Chimera) +Followup-To: alt.hypertext +Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 + + +Check into: + +"A spectrum of automatic hypertext constructions," by Furuta, Plaisant, and +Shneiderman. _Hypermedia_(1) 2, 1989, pp179-195. + +and + +"Automatically transforming regularly structured linearly documents into +hypertext," by Furuta and Shneiderman. _Electronic Publishing - Origination, +Dissemination, and Design_ 2, 4, 1990, pp211-229. + + +-- + Richard "carm" Chimera | Zorched by Zarches, + Human Computer Interaction Lab, U Md. | spaceman Spiff's + A.V. Williams Bldg, room 4166 | crippled craft crashes + College Park, MD 20742-3255 | on planet Plootarg! + diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/ChangeLog b/web/glasgow/lit2x-0.16/literate/info-utils/ChangeLog new file mode 100644 index 0000000000..cb5bc8c745 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/ChangeLog @@ -0,0 +1,495 @@ +Sun Jun 7 10:24:37 1992 Brian Fox (bfox@cubit) + + * info.c: New version 1.44. + * makeinfo.c: New version 1.47 + + * info.c:(main) If the user speficied the info file to use, and it + wasn't found, then exit immediately. + + * makeinfo.texinfo: Updated documentation to include all of the + long options. Other minor cosmetic changes. + +Sat May 30 11:52:26 1992 Brian Fox (bfox@cubit) + + * info.c (show_version_info) New function displays version + information. New long option "--version" causes this function to + be called, and then Info to exit. + +Wed May 27 09:52:22 1992 Brian Fox (bfox@cubit) + + * info.c (dump_current_node) If the output filename is "-", then + dump to stdout. + +Sun May 24 11:30:20 1992 Brian Fox (bfox@cubit) + + * makeinfo.c (begin_insertion, end_insertion) Do not close + paragraphs if producing a file with --no-headers. + + * makeinfo.c (begin_insertion) Indentation of multiple paragraphs + appearing within an @enumerate is only done if the #define + INDENT_PARAGRAPHS_IN_TABLE is set (not the default). This makes + @enumerate paragraph indentation identical to @table and friends. + +Sat May 23 19:44:43 1992 Brian Fox (bfox@cubit) + + * makeinfo.c: New version 1.46. + + Changed `@set' to accept an equal sign followed by a value to + allow set variables to have values. + + New command `@value{FOO}' inserts the value of the variable FOO. + + @set accepts quoted values of the form: @set FOO="this is a list". + @ifclear and @ifset now count the conditionals encountered while + searching for their respective ends. + + Command line arguments "-Dfoo" and "-Ubar" set and clear foo and + bar. + +Thu Apr 23 14:44:30 1992 Brian Fox (bfox@cubit) + + * makeinfo.c: New version 1.45. + + * makeinfo.c (cm_center): Add fudge_factor to centering + calculation to give more pleasing results. Call cm_noindent () + before inserting any text. + + * makeinfo.c (cm_exdent): Execute the line so that @var{} and + friends will work correctly. + + * makeinfo.c (cm_node): When defaulting the next node, make sure + that the reference type is `menu'. + +Wed Apr 22 00:27:52 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * makeinfo.c: Indent #pragma. + +Wed Apr 8 23:11:51 1992 Charles Hannum (mycroft@hal.gnu.ai.mit.edu) + + * makeinfo.c (usage): Terminate lines in string correctly. + +Mon Mar 9 23:38:57 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * info.c, makeinfo.c: Document long options as starting with `--', + not `+'. + +Sat Feb 22 02:15:00 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: (begin_insertion) @group does absolutely nothing + when found inside of an @example. + + * texindex.c: New version 1.45 has cleanups, should compile under + VMS quietly. + +Thu Feb 20 16:21:54 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (cm_center) Inhibit output flushing to prevent the + executed line from disappearing before its length can be + calculated. + + * makeinfo.c (inhibit_output_flushing, uninhibit_output_flushing) + Turn off and on actual disk writing. + + * makeinfo.c: New version 1.44. + +Mon Feb 17 17:52:55 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (get_file_info_in_path, extract_colon_unit, + find_and_load_file) Two new functions, and modify + find_and_load_file () to use get_file_info_in_path (). You can + now supply multiple `-I<path>' flags to makeinfo in order to + specify directories which should be searched to find files + included with @include. + +Sat Feb 8 00:06:17 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (usage): Update the help message. + + * Makefile.in: Hack kludge to get -traditional into the CFLAGS. I + hate auto-configure, and worse, where does it get off deciding for + me that I want to use a specific compiler simply because I have a + file called gcc in my PATH? + + * makeinfo.c (new functions): New functions cm_macro, cm_unmacro, + add_macro, execute_macro, delete_macro () all implement new @macro + construct. This is conditionally compiled with #define HAVE_MACROS. + +Fri Feb 7 18:27:45 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (cm_center): Center the line *after* "executing" it. + + * info.c: Remove "true", "false", and "boolean", replacing them + with 1, 0, and int. + +Tue Jan 21 01:18:25 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (cm_titlefont) New function does nothing special but + makes life easier. + +Fri Jan 10 16:43:04 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (cm_code) Increment/decrement in_fixed_width_font + while processing the text inside of an @code (includes @samp, @file). + +Wed Jan 8 02:52:33 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: (close_insertion_paragraph) New function gets called + to close certain types of insertions. This includes @format, + @example, etc. New variable line_already_broken describes the + state of the output file to close/start_paragraph (). + +Tue Jan 7 02:24:10 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: (cm_node) Get and remember sectioning commands even + for those nodes which are not currently defaulting. Such nodes + can contain menus whose nodes are defaulted, and we need to know + the sectioning level of the node containing the menu. + + * makeinfo.c: Removed definitions for "true", "false", and the + typedef for "boolean". Changed all code accordingly. Added + defines for BRACE_ARGS and NO_BRACE_ARGS to increase readability + of the CommandTable. + + * makeinfo.c (begin_insertion) Do not + inhibit_paragraph_indentation for @table and friends. + +Mon Jan 6 11:52:36 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (convert) WHoops! Remove surrounding whitespace from + OUTPUT_FILENAME before using. + + * makeinfo.c: (end_insertion) If an @end INSERTION is followed by + a blank line, then start a new paragraph there, otherwise close + the current one without a blank line. + + * makeinfo.c: (main, convert) Add code to support -o FILE (+output + FILE) option. The output filename generated from this option + overrides the filename appearing in the @setfilename command. + +Mon Dec 23 23:46:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * texindex.c: Change POSIX ifdefs to HAVE_UNISTD_H and _POSIX_VERSION. + +Wed Dec 18 04:26:02 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (end_insertion) Close paragraphs removing last + inserted newline which comes from @end INSERTION. + + * makeinfo.c (start_paragraph) Do not unconditionally set the + output column from the desired indentation; use an interim value + instead and keep in mind that some indentation may have already + been done. + +Fri Dec 6 01:25:09 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * texindex.c: Conditionalize on _AIX (which is predefined) instead + of AIX, just like makeinfo does. + +Sat Nov 23 22:43:05 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: (cm_vtable) New command @vtable is just like + @ftable, but adds an entry to the variable index instead of the + function index. + +Thu Nov 21 00:12:51 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * info.c: #define S_ISREG macro if not defined, and use the + definition. + +Wed Nov 20 01:07:57 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: (flush_output) Turn off meta bit on sentence enders + that were ignored. + +Fri Nov 1 01:09:43 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * Makefile.in: Add texindex. + * texindex.c: Add more #ifdefs, for VMS and USG. + (usage): New function. + (decode_command): Call it if given invalid option or no files. + Use getopt. + +Sat Sep 21 17:02:42 1991 Info Maintainer (info at gnuwest.fsf.org) + + * makeinfo.c: New command @deftypemethod added. + + * makeinfo.c: (cm_cartouche) New function which is ignored in + makeinfo. + + * makeinfo.c: (cm_br) If we skip a newline then increment + line_number. + + * makeinfo.c: (reader_loop) ignore the whitespace on lines which + appear blank. + + * index_add_arg (), close_paragraph (); Call ignore_blank_line () + to tell the reader that the previous line disappeared from the + input stream. New function ignore_blank_line (). + +Tue Sep 3 22:38:18 1991 Info Maintainer (info at gnuwest.fsf.org) + + * makeinfo.c: (cm_footnotestyle, cm_paragraphindent) Fix bogus + call to get_rest_of_line (). + +Tue Jun 11 00:34:12 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * info.c: Fixed SIGWINCH display bugs. Windows can now be resized + at will. + +Mon Jun 10 11:25:01 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c New function cm_math () does nothing but accepts + arguments. + + * makeinfo.c (flush_output) only change the 8th bit for space, + tab, or newline. This protects ISO character sets. + + * info.c: opsys_filename (); Return only the names of regular + files, not directories or block special devices. + + * makeinfo.c (add_char) Fixed bug in filling which could cause 78 + character lines to be filled incorrectly when fill_column was 79. + +Tue Jun 4 13:34:57 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: Add @paragraphindent and @footnotesytle as + interactive commands to change default paragraph indentation and + footnote style. + +Thu Jan 31 10:55:34 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * @cite now produces `...' instead of ``...''. + +Tue Jan 29 16:47:01 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: add flushleft, and flushright. + (cm_xref): all calls to add_word_args () are now calls to + execute_string () so that @code{@@bullet} produces the correct + output. The call to normalize_node_name () from get_xref_token + () is removed, since xref now calls execute string. + (end_insertion) now sets last_char_was_newline so that no extra + indentation can appear on the following text line. + +Sun Jan 27 22:32:45 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (args_from_string): Hack tokenization to consider a + command followed immediately by braces to be a single token + (including the braces and contents of same). + +Thu Jun 28 15:01:51 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c, info.c, Makefile: Change SYSV to USG. + +Wed Jun 27 12:22:12 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: new function cm_today () produces the date in the + output document. + +Wed May 30 13:00:09 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c (cm_xref) If arguments 4 or 5 are present, then we + use argument 2 as the node name, unless it is empty, in which case + we use argument one. See how easy this is to use? + + * makeinfo.c (many index functions) Handle code indices by + inserting @code{} around the index entry item when it is being + printed. Keep track of which type of index was used to insert + this item into the index. + + * makeinfo.c (reader_loop) Paired single quotes turn into double + quote (outside of fixed-width font insertions. Multiple dashes + don't shrink down to double dashes inside of fixed-width font + insertions. + +Sun May 27 11:23:27 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c Merge in VMS changes. Adds single change to + find_and_load (), and mimics some things that SYSV needs for + headers. + +Mon May 21 11:39:43 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c Added @smallbook. + +Thu Apr 26 05:01:04 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c: Output newline before tag table leader. @sp X + doesn't close paragraph anymore, it just acts as if you personally + typed in X newlines. + +Mon Apr 16 02:26:11 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * makeinfo.c Fixed splitting to output the final node in a + separate subfile if outputting it in the current subfile would + make the subfile too large. + +Sun Jan 14 10:34:42 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * makeinfo.c: new function normalize_node_name () gets called from + get_node_token (), get_xref_token (), glean_node_from_menu (). It + allows (by hacking) @@ in the name of a node. This leaves @Top + undefined as to what action to take: that is to say that @@Top and + @Top are identical node names. + + * makeinfo.c:begin_insertion (). Made @example and friends + sensitive to newlines so that pending_indent wouldn't build up. + This fixed bug of extra indentation if @example was followed + immediately by a blank line, instead of text. + +Mon Dec 11 11:47:28 1989 Brian Fox (bfox at rice-chex) + + * Changed cons_string to savestring everywhere. + + * Added info.tar.Z as a target to the Makefile. + +Mon Dec 11 00:28:14 1989 David J. MacKenzie (djm at rice-chex) + + * Merge modification history comments from info.c and makeinfo.c + into the ChangeLog. + + * makeinfo.c (main): Use getopt_long. + (usage): Describe new option syntax, adding descriptions + of the verbose and paragraph-indent options. + + * Makefile: Add rules to link makeinfo with getopt. + +Sun Dec 10 01:26:34 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * Makefile: Move default info directory path definition from info.c + and shorten it, since it will now be changed appropriately for + each site. + Rearrange rules to put those that are likely to be changed locally + at the beginning. + Define SHELL, don't define DOC (wasn't used). + (dist): New rule to make info.tar and info.tar.Z. + + info.c (get_terminal_info): Use fgets instead of gets. + Flush output before reading. + (info_signal_handler): Don't declare extra unused args. + (help_possible_completions): Don't return a value; never used. + (help_use_info): Ditto. + (main): Add missing arg to call of get_node. + (toploop): Ditto. + (build_notes): Move misplaced ')'. + Global: Added some casts to function calls. + Commented out some unused code. + +Sat Dec 9 18:44:33 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * info.c: Move some function decl's outside of function bodies. + Include getopt.h. + (main): Use getopt_long. Fix error in use of printf. + Add /usr/local/emacs/info to the default directory path so it + works at the AI lab. + (usage): Rename from explain. Update message. + (eat_argument): Function removed. + + * Makefile: Add rules for linking info with getopt. + Rename DOT_OHS macro to OBJECTS. + +Tue Nov 7 17:48:31 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * makeinfo.c (CommandTable): Define `@ ' and `@RET'. + +Mon Nov 6 08:15:20 1989 Brian Fox (bfox at rice-chex) + + * makeinfo.c: Added defaulting Next, Prev, and Up pointers in a + @node command without arguments. Revamped validation to be more + robust. Added new validation rules (see comment at validat_file). + + * Changed Makefile to include ChangeLog and default-nodes.texinfo + in info.tar.Z. + +Sun Nov 5 02:27:35 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * makeinfo.c (convert): Split even if errors. + +Tue Aug 22 14:51:11 1989 Robert J. Chassell (bob at hobbes.ai.mit.edu) + + * makeinfo.c (defun_internal): Line that begin with an asterisk + are mistook for menu entries by info; so, replaced `* ' prior to + function, variable, etc. definitions with ` * '. + +... Aug .. ........ 1989 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: Added the @def... commands. + Added the -pi flag for paragraph_start_indent. + +Wed Jul 6 ........ 1989 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * info.c: Indirect tags are not assumed to point close to the node. + Instead, they point to where the node would have been, had the the + file never been split. Thus, the header of a split file is + compensated for, by dynamically figuring out how long it is every + time we read in a file. + +Mon Jun 12 19:48:58 1989 Robert J. Chassell (bob at rice-chex.ai.mit.edu) + + * makeinfo.c: @result, @expansion, @print, @error, @point, @equiv added + +... Jun .. ........ 1989 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: Make sure that the NEXT node has a PREV that points + to it. + + * makeinfo.c: Added @result, @expansion, @equiv, @print, @error + and @point. + +Tue May 2 23:41:37 1989 Randall Smith (randy at rice-chex.ai.mit.edu) + + * makeinfo.c (find_index): Fixed comparison to be versus -1. + +Fri Apr 7 14:24:27 1989 Randall Smith (randy at rice-chex.ai.mit.edu) + + * makeinfo.c: Installed new version from bfox. + * makeinfo.c (get_until): Fixed typo; == should have been =. + +... Apr .. ........ 1989 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: Added validation of Up fields. They now have to + have a menu item which points to them in the indicated node. + +Thu Feb 25 10:22:00 1989 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * info.c: Made info_directory_paths try to get its value from the + environment variable INFO_DIRECTORY_PATHS. Added cons_string + in an attempt to get rid of the brain-damage (read brian-damage) + I originally wrote in here. Death to static limits! + +... Oct .. ........ 1988 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: Allowed user defined commands. In the specific, + allowed the the user to make his/her own indices. We define the + default ones. + +Fri Oct 9 13:03:00 1988 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * info.c: Virgin release 1.0. + + * info.c: Made the completer not use static size variables. + Also made the completer more generic. Maybe this will be of + some use someday. + Changed file_error to incorporate code suggestions from + Roland McGrath. + Changed idiot error messages. We still need some canonical + location for the initial Info directory path. + +... Jul .. ........ 1988 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: added code to handle un-closed braces at the start + of a node, un-finished insertions at the start of a node, + and outputting the `header' at the start of each info split sub-file. + + * makeinfo.c: Made split_file NOT update the tags table to reflect + the changes in the output files. This means the reader has also + changed. + +... Jun .. ........ 1988 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: fixed filling to do the right thing at sentence ends. + stopped automatically removing filename extensions on output + split files. + +... Apr .. ........ 1988 Brian Fox (bfox at rice-chex.ai.mit.edu) + + * makeinfo.c: added splitting. diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/Jmakefile b/web/glasgow/lit2x-0.16/literate/info-utils/Jmakefile new file mode 100644 index 0000000000..177c56bb49 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/Jmakefile @@ -0,0 +1,52 @@ +/* makefile that comes with distribution is in Makefile.original */ + +PROGRAMS = makeinfo info postmakeinfo +/* the last is a script that helps cooperation w/ the literate programming stuff */ + +all:: $(PROGRAMS) + +MsubNeededHere(postmakeinfo) + +/* CC = gcc termcap'ping does not work right with gcc on sun4s for info */ + +# Colon-separated list of directories in which to look for info files. +DEFAULT_INFOPATH = DefaultInfoPath + +# Command used to print out a text file. The filename follows this command. +INFO_PRINT_COMMAND = lpr + +PATHSPEC = -DDEFAULT_INFOPATH='"$(DEFAULT_INFOPATH)"' +PRINTSPEC = -DINFO_PRINT_COMMAND='"$(INFO_PRINT_COMMAND)"' +INFO_DEFINES = $(PATHSPEC) $(PRINTSPEC) + +# TRACK_SRCFILE and ALLOW_JUNK are partain additions +MAKEINFO_DEFINES = -DTRACK_SRCFILE -DALLOW_JUNK + +/* roll them together; hurts nothing... */ +CPP_DEFINES = $(INFO_DEFINES) $(MAKEINFO_DEFINES) + +SRCS_C = info.c makeinfo.c getopt.c getopt1.c +INFO_OBJS_C = info.o getopt.o getopt1.o +MAKEINFO_OBJS_C = makeinfo.o getopt.o getopt1.o + +/* +HEADERS = getopt.h +SUPPORT = Makefile ChangeLog testfile.texinfo test-suite.texinfo\ + default-nodes.texinfo +*/ + +BuildPgm(info,$(CC),$(INFO_DEFINES) $(CFLAGS),$(INFO_OBJS_C),-ltermcap,) + +BuildPgm(makeinfo,$(CC),$(MAKEINFO_DEFINES) $(CFLAGS),$(MAKEINFO_OBJS_C),,) + +MsubProgramScriptTarget(PerlCmd,postmakeinfo,postmakeinfo.prl,,) + +InstallBinaryTarget(info, $(INSTBINDIR)) +InstallBinaryTarget(makeinfo, $(INSTBINDIR)) +InstallScriptTarget(postmakeinfo, $(INSTSCRIPTDIR)) + +CDependTarget( $(SRCS_C) ) + +EtagsNeededHere(tags) /* need this to do "make tags" */ +ClearTagsFile() +CTagsTarget( *.h $(SRCS_C) ) diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/Makefile.in b/web/glasgow/lit2x-0.16/literate/info-utils/Makefile.in new file mode 100644 index 0000000000..ab49868d92 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/Makefile.in @@ -0,0 +1,124 @@ +# Makefile for the info sources... -*- text -*- +# Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# 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. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +SHELL = /bin/sh + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +# Things you might add to DEFS: +# -DSTDC_HEADERS If you have ANSI C headers and libraries. +# -DHAVE_UNISTD_H If you have unistd.h. +# -DUSG If you have System V/ANSI C string and +# memory functions and headers. +# -DUSGr3 If you need to include sys/stream.h and sys/ptem.h +# to get the screen size from the kernel. +DEFS = @DEFS@ + +CFLAGS = -g +LDFLAGS = -g + +LIBS = @LIBS@ + +# Colon-separated list of directories in which to look for info files. +DEFAULT_INFOPATH = .:$(infodir):/usr/gnu/info:/usr/local/emacs/info:/usr/local/lib/emacs/info + +# Command used to print out a text file. The filename follows this command. +INFO_PRINT_COMMAND = lpr + +prefix = /usr/local +exec_prefix = $(prefix) + +# Where installed binaries go. +bindir = $(exec_prefix)/bin + +# Where info files go. +infodir = $(prefix)/info + +# Where manual pages go, and their extension (not including `.'). +mandir = $(prefix)/man/man1 +manext = 1 + +#### End of system configuration section. #### + +PATHSPEC = -DDEFAULT_INFOPATH='"$(DEFAULT_INFOPATH)"' +PRINTSPEC = -DINFO_PRINT_COMMAND='"$(INFO_PRINT_COMMAND)"' +INFO_FLAGS = $(PATHSPEC) $(PRINTSPEC) + +SOURCES = info.c makeinfo.c texindex.c getopt.c getopt1.c +OBJECTS = info.o makeinfo.o texindex.o getopt.o getopt1.o +HEADERS = getopt.h +SUPPORT = Makefile.in configure + +THINGS_TO_TAR = $(SOURCES) $(HEADERS) $(SUPPORT) + +PROGS = info makeinfo texindex + +all: $(PROGS) + +.c.o: + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) $< + +info: info.o getopt.o getopt1.o + $(CC) $(LDFLAGS) -o $@ info.o getopt.o getopt1.o -ltermcap $(LIBS) + +info.o: info.c + $(CC) -c $(CFLAGS) $(INFO_FLAGS) $info.c< + +makeinfo: makeinfo.o getopt.o getopt1.o + $(CC) $(LDFLAGS) -o $@ makeinfo.o getopt.o getopt1.o $(LIBS) + +makeinfo.o: makeinfo.c + $(CC) -c $(CFLAGS) $(MAKEINFO_FLAGS) $makeinfo.c< + +texindex: texindex.o getopt.o getopt1.o + $(CC) $(LDFLAGS) -o $@ texindex.o getopt.o getopt1.o $(LIBS) + +info.o makeinfo.o texindex.o getopt1.o: getopt.h + +install: all + for f in $(PROGS); do $(INSTALL_PROGRAM) $$f $(bindir)/$$f; done + +TAGS: $(SOURCES) + etags $(SOURCES) + +clean: + rm -f $(PROGS) $(OBJECTS) + +mostlyclean: clean + +distclean: clean + rm -f Makefile config.status + +realclean: distclean + rm -f TAGS + +dist: $(THINGS_TO_TAR) + rm -rf info-dist + mkdir info-dist + (cd info-dist; for i in $(THINGS_TO_TAR); do ln -s ../$$i .; done) + tar chzf info.tar.Z info-dist + rm -rf info-dist + +# Prevent GNU make v3 from overflowing arg limit on SysV. +.NOEXPORT: diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/Makefile.original b/web/glasgow/lit2x-0.16/literate/info-utils/Makefile.original new file mode 100644 index 0000000000..076350ba3b --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/Makefile.original @@ -0,0 +1,69 @@ +# Makefile for the info sources... -*- text -*- + +# Define OS = -DUSG if you are compiling for System V-like machines. +# OS = -DUSG + +# Define OS = -DVMS if you are compiling under VMS. +# OS = -DVMS + +CC = gcc +DEBUG_FLAG = -g +#PROFFLAGS = -pg +CFLAGS = $(DEBUG_FLAG) $(PROFFLAGS) $(OS) +LDFLAGS = $(PROFFLAGS) $(DEBUG_FLAG) #-Bstatic + +BINDIR = /usr/gnu/bin + +# Colon-separated list of directories in which to look for info files. +DEFAULT_INFOPATH = .:/local/doc/info + +# Command used to print out a text file. The filename follows this command. +INFO_PRINT_COMMAND = lpr + +PATHSPEC = -DDEFAULT_INFOPATH='"$(DEFAULT_INFOPATH)"' +PRINTSPEC = -DINFO_PRINT_COMMAND='"$(INFO_PRINT_COMMAND)"' +INFO_FLAGS = $(PATHSPEC) $(PRINTSPEC) + +SOURCES = info.c makeinfo.c getopt.c getopt1.c +OBJECTS = info.o makeinfo.o getopt.o getopt1.o +HEADERS = getopt.h +SUPPORT = Makefile ChangeLog testfile.texinfo test-suite.texinfo\ + default-nodes.texinfo makeinfo.texinfo info.1 + +THINGS_TO_TAR = $(SOURCES) $(HEADERS) $(SUPPORT) + +PROGS = info makeinfo + +all: $(PROGS) + +info: info.o getopt.o getopt1.o + $(CC) $(LDFLAGS) -o info info.o getopt.o getopt1.o -ltermcap + +info.o: info.c + $(CC) -c $(CFLAGS) $(INFO_FLAGS) info.c + +makeinfo: makeinfo.o getopt.o getopt1.o + $(CC) $(LDFLAGS) -o makeinfo makeinfo.o getopt.o getopt1.o + +makeinfo.o: makeinfo.c + $(CC) -c $(CFLAGS) $(MAKEINFO_FLAGS) makeinfo.c + +install: info makeinfo + for i in $(PROGS); \ + do install -c $$i $(BINDIR); \ + done + +info.tar.Z: $(THINGS_TO_TAR) + tar -chof info.tar $(THINGS_TO_TAR) + compress < info.tar > info.tar.Z + +dist: $(SOURCES) $(HEADERS) $(SUPPORT) + mkdir info-dist + (cd info-dist; for i in $(SOURCES) $(HEADERS) $(SUPPORT); do \ + ln -s ../$$i .; done) + tar chof info.tar info-dist + rm -r info-dist + compress < info.tar > info.tar.Z + +clean: + rm -f $(PROGS) $(OBJECTS) diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/README b/web/glasgow/lit2x-0.16/literate/info-utils/README new file mode 100644 index 0000000000..87ebf8a46d --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/README @@ -0,0 +1,15 @@ +This is a hacked version of the std GNU `info' and `makeinfo'. +The last version compared against was in the texinfo-2.15 package. + +The version of Dave Gillespie's info.el is 1.05; it's *great*! + +"makeinfo" is the only pgm which we've mangled significantly. The +diffs vs the GNU-distributed `makeinfo' and our "enhancements", both +turned on by #defines: + +* -DALLOW_JUNK puts the text of unrecognized commands through (vs + tossed away) + +* -DTRACK_SRCFILE puts in additional commands @srcfile and @srclineno, + which try to allow tracking of the original src file (assuming the + .texinfo file was generated from something else). diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/bug.texi b/web/glasgow/lit2x-0.16/literate/info-utils/bug.texi new file mode 100644 index 0000000000..70fa644493 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/bug.texi @@ -0,0 +1,12 @@ +@setfilename bug-info + +@node Top, , , (dir) + +@subsubsection Options for the driver @samp{ghc} + +@menu +* Controlling_phases:: What phases in what order. +* Verbosity:: How to be verbose. +* Forcing_options:: Forcing options to a particular phase. +* Many_versions_at_once:: Running several versions of the compiler at once. +@end menu diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/configure b/web/glasgow/lit2x-0.16/literate/info-utils/configure new file mode 100644 index 0000000000..ddd7422bca --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/configure @@ -0,0 +1,429 @@ +#!/bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf. +# Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# 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. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create] +# [--prefix=PREFIX] [--exec_prefix=PREFIX] [--with-PROGRAM] [TARGET] +# Ignores all args except --srcdir, --prefix, --exec_prefix, and --no-create. + +trap 'rm -f conftest* core; exit 1' 1 3 15 + +for arg +do + # Handle --exec_prefix with a space before the argument. + if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= + # Handle --host with a space before the argument. + elif test x$next_host = xyes; then next_host= + # Handle --prefix with a space before the argument. + elif test x$next_prefix = xyes; then prefix=$arg; next_prefix= + # Handle --srcdir with a space before the argument. + elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= + else + case $arg in + -exec_prefix=* | --exec_prefix=* | --exec_prefi=* | --exec_pref=* | --exec_pre=* | --exec_pr=* | --exec_p=* | --exec_=* | --exec=* | --exe=* | --ex=* | --e=*) + exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -exec_prefix | --exec_prefix | --exec_prefi | --exec_pref | --exec_pre | --exec_pr | --exec_p | --exec_ | --exec | --exe | --ex | --e) + next_exec_prefix=yes ;; + + -gas | --gas | --ga | --g) ;; + + -host=* | --host=* | --hos=* | --ho=* | --h=*) ;; + -host | --host | --hos | --ho | --h) + next_host=yes ;; + + -nfp | --nfp | --nf) ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no) + no_create=1 ;; + + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + next_prefix=yes ;; + + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*) + srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) + next_srcdir=yes ;; + + -with-* | --with-*) ;; + + *) ;; + esac + fi +done + +rm -f conftest* +compile='${CC-cc} $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +unique_file=makeinfo.c + +# Makefile rules whose targets are searched for in VPATH need to use $<. +# However, old makes do not support it, so we use a combination +# construction in Makefile.in: `$file<'. +# If srcdir is `.', we use sed to change that to `file' for old makes. +# Otherwise, we use sed to change it to `$<'. +# vpsub is the sed program, which changes `$file<' to one or the other. +vpsub='s,\$\([-./a-zA-Z0-9_][-./a-zA-Z0-9_]*\)<,\1,g' + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + srcdirdefaulted=yes; srcdir=. + if test ! -r $unique_file; then srcdir=..; fi +fi +if test ! -r $srcdir/$unique_file; then + if test x$srcdirdefaulted = xyes; then + echo "configure: Can not find sources in \`.' or \`..'." 1>&2 + else + echo "configure: Can not find sources in \`${srcdir}'." 1>&2 + fi + exit 1 +fi +if test $srcdir != .; then + vpsub='s,\$\([-./a-zA-Z0-9_][-./a-zA-Z0-9_]*\)<,\$<,g' +fi +# Preserve a srcdir of `.' to avoid automounter screwups with pwd. +# But we can't avoid them for `..', to make subdirectories work. +case $srcdir in + .|/*|~*) ;; + *) srcdir=`(cd $srcdir; pwd)` ;; # Make relative path absolute. +esac + + +# The Bourne shell writes "command not found" to /dev/tty, so if we get +# a usage message on stderr, we have the program. +# +# ksh and zsh write "command not found" to stderr, but test -n does not +# want any output if there is no program. So we use the `type' builtin +# instead for them (and bash). +if test "$RANDOM" = "$RANDOM"; then + checkfor='test -n "`$checkprog $checkargs 2>&1`"' +else + checkfor='type $checkprog >/dev/null 2>&1' +fi + +echo checking for gcc +checkprog=gcc checkargs='' +test -z "$CC" && eval $checkfor && CC='gcc ' +CC=${CC-cc} + +# Find out if we are using GNU C, under whatever name. +cat <<EOF > conftest.c +#ifdef __GNUC__ + yes +#endif +EOF +${CC-cc} -E conftest.c > conftest.out 2>&1 +if egrep yes conftest.out >/dev/null 2>&1; then + GCC=1 # For later tests. + CC="$CC -O" +fi +rm -f conftest* + +echo checking how to run the C preprocessor +if test -z "$CPP"; then + CPP='${CC-cc} -E' + cat <<EOF > conftest.c + +#include <stdio.h> +EOF +err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` +if test -z "$err"; then + : +else + CPP=/lib/cpp +fi +rm -f conftest* +fi + +if test -n "$GCC"; then + echo checking whether -traditional is needed + pattern="Autoconf.*'x'" + prog='#include <sgtty.h> +Autoconf TIOCGETP' + cat <<EOF > conftest.c + +$prog +EOF +eval "$CPP $DEFS conftest.c > conftest.out 2>&1" +if egrep "$pattern" conftest.out >/dev/null 2>&1; then + need_trad=1 +fi +rm -f conftest* + + + if test -z "$need_trad"; then + prog='#include <termio.h> +Autoconf TCGETA' + cat <<EOF > conftest.c + +$prog +EOF +eval "$CPP $DEFS conftest.c > conftest.out 2>&1" +if egrep "$pattern" conftest.out >/dev/null 2>&1; then + need_trad=1 +fi +rm -f conftest* + + fi + test -n "$need_trad" && CC="$CC -traditional" +fi + +echo checking for install +# Make sure to not get the incompatible SysV /etc/install and +# /usr/sbin/install, which might be in PATH before a BSD-like install. +if test -z "$INSTALL"; then + saveifs="$IFS"; IFS="$IFS:" + for dir in $PATH; do + test -z "$dir" && dir=. + case $dir in + /etc|/usr/sbin) ;; + *) + if test -f $dir/install; then + INSTALL="$dir/install -c" + INSTALL_PROGRAM='$(INSTALL)' + INSTALL_DATA='$(INSTALL) -m 644' + break + fi + ;; + esac + done + IFS="$saveifs" +fi +INSTALL=${INSTALL-cp} +INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'} +INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'} + +echo checking for AIX +cat <<EOF > conftest.c + +#ifdef _AIX + yes +#endif + +EOF +eval "$CPP $DEFS conftest.c > conftest.out 2>&1" +if egrep "yes" conftest.out >/dev/null 2>&1; then + DEFS="$DEFS -D_ALL_SOURCE=1" +fi +rm -f conftest* + + +echo checking for minix/config.h +cat <<EOF > conftest.c + +#include <minix/config.h> +EOF +err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` +if test -z "$err"; then + MINIX=1 +fi +rm -f conftest* + +# The Minix shell can't assign to the same variable on the same line! +if test -n "$MINIX"; then + DEFS="$DEFS -D_POSIX_SOURCE=1" + DEFS="$DEFS -D_POSIX_1_SOURCE=2" + DEFS="$DEFS -D_MINIX=1" +fi + +echo checking for POSIXized ISC +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + ISC=1 # If later tests want to check for ISC. + DEFS="$DEFS -D_POSIX_SOURCE=1" + if test -n "$GCC"; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +fi + +echo checking for sys/ptem.h +cat <<EOF > conftest.c + +#include <sys/ptem.h> +EOF +err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` +if test -z "$err"; then + DEFS="$DEFS -DUSGr3=1" +fi +rm -f conftest* + +echo checking for ANSI C header files +cat <<EOF > conftest.c + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <limits.h> +EOF +err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` +if test -z "$err"; then + DEFS="$DEFS -DSTDC_HEADERS=1" +fi +rm -f conftest* + +echo checking for unistd.h +cat <<EOF > conftest.c + +#include <unistd.h> +EOF +err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` +if test -z "$err"; then + DEFS="$DEFS -DHAVE_UNISTD_H=1" +fi +rm -f conftest* + +echo checking for BSD string and memory functions +echo "#include <strings.h> +main() { exit(0); } t() { rindex(0, 0); bzero(0, 0); }" > conftest.c +if eval $compile; then + : +else + DEFS="$DEFS -DUSG=1" +fi +rm -f conftest* + +echo checking for alloca.h +cat <<EOF > conftest.c + +#include <alloca.h> +EOF +err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` +if test -z "$err"; then + DEFS="$DEFS -DHAVE_ALLOCA_H=1" +fi +rm -f conftest* + +decl="#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#if HAVE_ALLOCA_H +#include <alloca.h> +#else +#ifdef _AIX + #pragma alloca +#else +char *alloca (); +#endif +#endif +#endif +" +echo checking for alloca +echo "$decl +main() { exit(0); } t() { char *p = (char *) alloca(1); }" > conftest.c +if eval $compile; then + : +else + alloca_missing=1 +fi +rm -f conftest* + +if test -n "$alloca_missing"; then + SAVELIBS="$LIBS" + # Maybe alloca is in a different library. + if test -f /usr/ucblib/libucb.a; then + LIBS="$LIBS -L/usr/ucblib -lucb" trylib=-lucb # SVR4 + elif test -f /lib/libPW.a; then + LIBS="$LIBS -lPW" trylib=-lPW # SVR2 and SVR3 + fi + if test -n "$trylib"; then + alloca_missing= + echo checking for alloca in $trylib +echo "$decl +main() { exit(0); } t() { char *p = (char *) alloca(1); }" > conftest.c +if eval $compile; then + : +else + alloca_missing=1 +fi +rm -f conftest* + + fi + if test -n "$alloca_missing"; then + LIBS="$SAVELIBS" ALLOCA=alloca.o + fi +fi + +if test -n "$prefix"; then + test -z "$exec_prefix" && exec_prefix='$(prefix)' + prsub="s,^prefix[ ]*=.*$,prefix = $prefix," +fi +if test -n "$exec_prefix"; then + prsub="$prsub +s,^exec_prefix[ ]*=.*$,exec_prefix = $exec_prefix," +fi + +trap 'rm -f config.status; exit 1' 1 3 15 +echo creating config.status +rm -f config.status +cat <<EOF > config.status +#!/bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +trap 'rm -f Makefile; exit 1' 1 3 15 +CC='$CC' +CPP='$CPP' +INSTALL='$INSTALL' +INSTALL_PROGRAM='$INSTALL_PROGRAM' +INSTALL_DATA='$INSTALL_DATA' +ALLOCA='$ALLOCA' +LIBS='$LIBS' +srcdir='$srcdir' +DEFS='$DEFS' +prefix='$prefix' +exec_prefix='$exec_prefix' +prsub='$prsub' +vpsub='$vpsub' +EOF +cat <<\EOF >> config.status + +top_srcdir=$srcdir +for file in Makefile; do + srcdir=$top_srcdir + # Remove last slash and all that follows it. Not all systems have dirname. + dir=`echo $file|sed 's,/[^/][^/]*$,,'` + if test "$dir" != "$file"; then + test "$top_srcdir" != . && srcdir=$top_srcdir/$dir + test ! -d $dir && mkdir $dir + fi + echo creating $file + rm -f $file + echo "# Generated automatically from `basename $file`.in by configure." > $file + sed -e " +$vpsub +$prsub +s,@CC@,$CC, +s,@CPP@,$CPP, +s,@INSTALL@,$INSTALL, +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM, +s,@INSTALL_DATA@,$INSTALL_DATA, +s,@ALLOCA@,$ALLOCA, +s,@LIBS@,$LIBS, +s,@srcdir@,$srcdir, +s,@DEFS@,$DEFS," $top_srcdir/${file}.in >> $file +done + +EOF +chmod +x config.status +test -n "$no_create" || ./config.status + diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/configure.in b/web/glasgow/lit2x-0.16/literate/info-utils/configure.in new file mode 100644 index 0000000000..0f220fcc84 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/configure.in @@ -0,0 +1,15 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(makeinfo.c) +AC_PROG_GCC +AC_PROG_CPP +AC_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_AIX +AC_MINIX +AC_ISC_POSIX +AC_HEADER_CHECK(sys/ptem.h, AC_DEFINE(USGr3)) +AC_STDC_HEADERS +AC_UNISTD_H +AC_USG +AC_ALLOCA +AC_OUTPUT(Makefile) diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/default-nodes.texinfo b/web/glasgow/lit2x-0.16/literate/info-utils/default-nodes.texinfo new file mode 100644 index 0000000000..27953e297d --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/default-nodes.texinfo @@ -0,0 +1,40 @@ +@setfilename default-nodes-example.info +@node Top +@chapter Introduction +@menu +* foo:: the foo node +* bar:: the bar node +* baz:: the baz node +* yan:: Yet Another Node +@end menu + +@node foo +@section foo +this is the foo node. + +@node bar +@section Bar +This is the Bar node. + +@menu +* subzero:: A subsection of bar. +* subone:: You thought I meant temperature? +@end menu + +@node subzero +@subsection subzero +This is subsection subzero + +@node subone +@subsection subone +This is subsection subone + +@node baz +@section Baz +This is the Baz node. + +@node yan +@section Yet Another Node + +Yes, this is yet another node. +@bye diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/getopt.c b/web/glasgow/lit2x-0.16/literate/info-utils/getopt.c new file mode 100644 index 0000000000..5b9970537a --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/getopt.c @@ -0,0 +1,681 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))) +#include <alloca.h> +#else +#ifdef _AIX + #pragma alloca +#else +char *alloca (); +#endif +#endif /* sparc */ +#endif /* not __GNUC__ */ + +/* partain: to go w/ "make world" */ +#if defined(SYSV) +#define USG 1 +#endif +/* end partain */ + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#undef alloca +#include <stdlib.h> +#include <string.h> +#else /* Not GNU C library. */ +#define __alloca alloca +#endif /* GNU C library. */ + + +#ifndef __STDC__ +#define const +#endif + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +#define GETOPT_COMPAT + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +#include <string.h> +#define my_index strchr +#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (string, chr) + char *string; + int chr; +{ + while (*string) + { + if (*string == chr) + return string; + string++; + } + return 0; +} + +static void +my_bcopy (from, to, size) + char *from, *to; + int size; +{ + int i; + for (i = 0; i < size; i++) + to[i] = from[i]; +} +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); + char **temp = (char **) __alloca (nonopts_size); + + /* Interchange the two blocks of data in ARGV. */ + + my_bcopy (&argv[first_nonopt], temp, nonopts_size); + my_bcopy (&argv[last_nonopt], &argv[first_nonopt], + (optind - last_nonopt) * sizeof (char *)); + my_bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size); + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); + } + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +/* partain: +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} +*/ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/getopt.h b/web/glasgow/lit2x-0.16/literate/info-utils/getopt.h new file mode 100644 index 0000000000..4d8b31ca59 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/getopt.h @@ -0,0 +1,121 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +enum _argtype +{ + no_argument, + required_argument, + optional_argument +}; + +#if __STDC__ +/* partain: extern int getopt (int argc, char *const *argv, const char *shortopts); */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +/* partain: extern int getopt (); */ +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/getopt1.c b/web/glasgow/lit2x-0.16/literate/info-utils/getopt1.c new file mode 100644 index 0000000000..ae7930d058 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/getopt1.c @@ -0,0 +1,158 @@ +/* Getopt for GNU. + Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef LIBC +/* For when compiled as part of the GNU C library. */ +#include <ansidecl.h> +#endif + +#include "getopt.h" + +#ifndef __STDC__ +#define const +#endif + +#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC) +#include <stdlib.h> +#else /* STDC_HEADERS or __GNU_LIBRARY__ */ +char *getenv (); +#endif /* STDC_HEADERS or __GNU_LIBRARY__ */ + +#if !defined (NULL) +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + +#ifdef TEST + +#include <stdio.h> + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/info.1 b/web/glasgow/lit2x-0.16/literate/info-utils/info.1 new file mode 100644 index 0000000000..f49dc2982d --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/info.1 @@ -0,0 +1,101 @@ +.TH INFO 1 "26 June 1988" +.SH NAME +info \- Hierarchal information tree peruser +.SH SYNOPSIS +.B info +[ -d info-directory-path ] +[ -f info-file ] +[ -o dump-file ] +[ -n node-name ] +[ menu-name ...] +.SH DESCRIPTION +.I Info +is an interactive tool for reading the on-line documentation made from +texinfo files. There are almost no differences between +.I Info +and the `M-x info' command from within +.I Emacs. +.I Info +is a standalone program, and can be invoked from the command line. The +.I menu-name +(s) are the series of menu options that you wish to follow from the main menu. +For example, to get info about using buffers in Emacs, you might type `info +emacs buffers'. Try it, you'll like it. +.PP +.SH OPTIONS + +.IP -o +dumps the contents of the node that you have specified, so that +you can do with it what you please. Note that you can print the node that you +are currently looking at with `C-p' from within +.I Info +, so it isn't clear what you want to do with the output from -o. +.PP +.IP -d +is a quick way for you to temporarily change the path searched by +.I Info +when it starts up. You can also set the environment variable +"INFO_DIRECTORY_PATHS" to a list of colon-separated directory names. +.PP +.IP -f +is for specifying which Info file to load. Normally, +.I Info +looks for the file `dir' in the info search path, and goes to node `Top' in +that file. The `dir' file contains a menu whose items all point to info +files. If the info file you wish to view is not in that menu, you can say +`info -f info-filename', and that file specifically will be used. +.PP +.IP -n +sets the initial node to look for. This allows you to read an info file that +doesn't have a `Top' node. +.PP +In order to find out more about +.I Info +, type `info', and press "h". (You will be reminded of your options when you +first start using the +.I Info +program anyway.) +.PP +You are welcome to submit documentation for use in +.I Info +, and in fact, whole-heartedly encouraged. Remember to read the node on +.I texinfo +before submitting the text though, since it will likely only be accepted in that format. +.PP + + +.SH BUGS +.PP +The display on slow terminals is pretty gosh darn slow. This is due to the +crufty implementation, and will be fixed as soon as someone complains +about it, or maybe before. +.PP +There is no specific X windows support. X windows should be supported, and +we should allow `hot spots' in the text of nodes, which could point to +other nodes. +.PP +An info file without a `Top' node can only be viewed if you know the name of a +node inside of it. Maybe the +.I Makeinfo +program should automatically make a menu of top-level nodes and place it in a +node called `Top' if there is no such node in the info file. +.SH FILES +.br +The default search path for a bare bones Info is +.br +".:/usr/gnu/info:/usr/local/emacs/info:/usr/local/lib/emacs/info" +.PP +You can change this with the INFOPATH environment variable. +.SH SEE ALSO +makeinfo (1) +.SH ACKNOWLEDGEMENT +Richard Stallman invented the Info concept many moons ago, even before +the advent of hypertext. He also suggested that I write this program. +.SH AUTHOR +Brian J. Fox (bfox@ai.mit.edu) +.br +Free Software Foundation +.br +Cambridge, MA +.br +September, 1987 diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/info.c b/web/glasgow/lit2x-0.16/literate/info-utils/info.c new file mode 100644 index 0000000000..941955c89c --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/info.c @@ -0,0 +1,4744 @@ +/* info -- a stand-alone Info program. + + Copyright (C) 1987, 1991 Free Software Foundation, Inc. + + This file is part of GNU Info. + + GNU Info is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. No author or distributor accepts + responsibility to anyone for the consequences of using it or for + whether it serves any particular purpose or works at all, unless he + says so in writing. Refer to the GNU Emacs General Public License + for full details. + + Everyone is granted permission to copy, modify and redistribute + GNU Info, but only under the conditions described in the GNU Emacs + General Public License. A copy of this license is supposed to + have been given to you along with GNU Emacs so you can know your + rights and responsibilities. It should be in a file named COPYING. + Among other things, the copyright notice and this notice must be + preserved on all copies. */ + +/* This is GNU Info: + + Version 1.44 (Change "major_version" and "minor_version" below.) + Fri Feb 7 1992 +*/ + +/* partain: to go w/ "make world" */ +#if defined(SYSV) +#define USG 1 +#endif +/* end partain */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <pwd.h> +#include <errno.h> + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include <ctype.h> +#include "getopt.h" + +#if defined (USG) + struct passwd *getpwnam (); +# include <fcntl.h> +# include <termio.h> +# include <string.h> + +# if defined (USGr3) +# if !defined (M_XENIX) +# include <sys/stream.h> +# include <sys/ptem.h> +# undef TIOCGETC +# else /* M_XENIX */ +# define tchars tc +# include <sys/ttold.h> +# endif /* M_XENIX */ +# endif /* USGr3 */ +# define bcopy(source, dest, count) memcpy(dest, source, count) + char *index(s,c) char *s; { char *strchr(); return strchr(s,c); } + char *rindex(s,c) char *s; { char *strrchr(); return strrchr(s,c); } +#else /* !USG */ +# include <sys/file.h> +# include <sgtty.h> +# include <strings.h> +#endif /* USG */ + +#if !defined (DEFAULT_INFOPATH) +# define DEFAULT_INFOPATH \ + ".:/usr/gnu/info:/usr/local/emacs/info:/usr/local/lib/emacs/info" +#endif /* !DEFAULT_INFOPATH */ + +typedef struct nodeinfo { + char *filename; + char *nodename; + int pagetop; + int nodetop; + struct nodeinfo *next; +} NODEINFO; + +typedef struct indirectinfo { + char *filename; + int first_byte; +} INDIRECT_INFO; + +typedef int Function (); +#define VOID_SIGHANDLER +#if defined (VOID_SIGHANDLER) +# define SigHandler void +#else +# define SigHandler int +#endif /* !VOID_SIGHANDLER */ +#define barf(msg) fprintf(stderr, "%s\n", msg) + +/* Some character stuff. */ +#define control_character_threshold 0x020 /* smaller than this is control */ +#define meta_character_threshold 0x07f /* larger than this is Meta. */ +#define control_character_bit 0x40 /* 0x000000, must be off. */ +#define meta_character_bit 0x080 /* x0000000, must be on. */ + +#define info_separator_char '\037' +#define start_of_node_string "\037" + +#ifdef CTRL +#undef CTRL +#endif + +#define CTRL(c) ((c) & (~control_character_bit)) +#define META(c) ((c) | meta_character_bit) + +#define UNMETA(c) ((c) & (~meta_character_bit)) +#define UNCTRL(c) to_upper(((c)|control_character_bit)) + +#ifndef to_upper +#define to_upper(c) (((c) < 'a' || (c) > 'z') ? (c) : (c) - 32) +#define to_lower(c) (((c) < 'A' || (c) > 'Z') ? (c) : (c) + 32) +#endif + +#define CTRL_P(c) ((unsigned char) (c) < control_character_threshold) +#define META_P(c) ((unsigned char) (c) > meta_character_threshold) + +#define NEWLINE '\n' +#define RETURN CTRL('M') +#define DELETE 0x07f +#define TAB '\t' +#define ABORT_CHAR CTRL('G') +#define PAGE CTRL('L') +#define SPACE 0x020 +#define ESC CTRL('[') +#define control_display_prefix '^' + +#define TAG_TABLE_END_STRING "\037\nEND TAG TABLE" +#define TAG_TABLE_BEG_STRING "\nTAG TABLE:\n" +#define NODE_ID "Node:" +#define NNODENAME 4 /* Default amount to grow nodename list by. */ +#define FILENAME_LEN 256 +#define NODENAME_LEN 256 +#define STRING_SIZE 256 +#define nodeend_sequence "\n\037" + +#define whitespace(c) ((c) == ' ' || (c) == '\t') +#define cr_whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') + +/* All right, some windows stuff. */ + +typedef struct { + /* Absolute x and y coordinates for usable portion of this window. */ + int left, top, right, bottom; + /* Absolute cursor position in this window. */ + int ch, cv; +} WINDOW; + +typedef struct _wind_list { + int left, top, right, bottom; + int ch, cv; + struct _wind_list *next_window; +} WINDOW_LIST; + +WINDOW the_window = {0, 0, 80, 24, 0, 0}; +WINDOW_LIST *window_stack = (WINDOW_LIST *)NULL; +WINDOW terminal_window = {0, 0, 80, 24, 0, 0}; + +/* Not really extern, but defined later in this file. */ +extern WINDOW echo_area; +void *xmalloc (), *xrealloc (); +char *getenv (), *next_info_file (), *opsys_filename (); +int build_menu (), find_menu_node (); +void swap_filestack (), pop_filestack (); + +/* A crock, this should be done in a different way. */ +#define MAX_INDIRECT_FILES 100 + +/* The info history list. */ +NODEINFO *Info_History = NULL; + +/* ?Can't have more than xx files in the indirect list? */ +INDIRECT_INFO indirect_list[MAX_INDIRECT_FILES]; + +/* The filename of the currently loaded info file. */ +char current_info_file[FILENAME_LEN]; + +/* The nodename of the node the user is looking at. */ +char current_info_node[NODENAME_LEN]; + +/* The last file actually loaded. Not the same as current info file. */ +char last_loaded_info_file[FILENAME_LEN]; + +/* Offsets in info_file of top and bottom of current_info_node. */ +int nodetop, nodebot; + +/* Number of lines in this node. */ +int nodelines; + +/* Buffer for the info file. */ +char *info_file = NULL; + +/* Length of the above buffer. */ +int info_buffer_len; + +/* Pointer to the start of a tag table, or NULL to show none. */ +char *tag_table = NULL; + +/* Length of the above buffer. */ +int tag_buffer_len; + +/* Non-zero means that the tag table is indirect. */ +int indirect = 0; +int indirect_top; + +/* Offset in the buffer of the current pagetop. */ +int pagetop; + +/* Offset in the buffer of the last displayed character. */ +int pagebot = 0; + +/* If non-NULL, this is a colon separated list of directories to search + for a specific info file. The user places this variable into his or + her environment. */ +char *infopath = NULL; + +/* If filled, the name of a file to write to. */ +char dumpfile[FILENAME_LEN] = ""; + +/* This is the command to print a node. A default value is compiled in, + or it can be found from the environment as $INFO_PRINT_COMMAND. */ +char *print_command; + +/* Non-zero means forst redisplay before prompt for the next command. */ +int window_bashed = 0; + +/* **************************************************************** */ +/* */ +/* Getting Started. */ +/* */ +/* **************************************************************** */ + +/* Begin the Info session. */ + +/* Global is on until we are out of trouble. */ +int totally_inhibit_errors = 1; + +/* Non-zero means print version info only. */ +int version_flag = 0; + +/* The major and minor versions of Info. */ +int major_version = 1; +int minor_version = 44; + +struct option long_options[] = { + { "directory", 1, 0, 'd' }, + { "node", 1, 0, 'n' }, + { "file", 1, 0, 'f' }, + { "output", 1, 0, 'o' }, + { "version", 0, &version_flag, 1 }, + {NULL, 0, NULL, 0} +}; + +#define savestring(x) (char *) strcpy ((char *) xmalloc (1 + strlen (x)), (x)) + +main (argc, argv) + int argc; + char **argv; +{ + int c, ind, no_such_node = 0; + char filename[FILENAME_LEN]; + char *nodename; + char **nodenames; + int nodenames_size, nodenames_index; + char *ptr, *env_infopath, *env_print_command; + + nodenames_index = 0; + nodenames = (char **) xmalloc ((nodenames_size = 1) * sizeof (char *)); + nodenames[0] = (char *)NULL; + + env_infopath = getenv ("INFOPATH"); + env_print_command = getenv ("INFO_PRINT_COMMAND"); + + filename[0] = '\0'; + + if (env_infopath && *env_infopath) + infopath = savestring (env_infopath); + else + infopath = savestring (DEFAULT_INFOPATH); + + if (env_print_command && *env_print_command) + print_command = savestring (env_print_command); + else + print_command = savestring (INFO_PRINT_COMMAND); + + while ((c = getopt_long (argc, argv, "d:n:f:o:", long_options, &ind)) != EOF) + { + if (c == 0 && long_options[ind].flag == 0) + c = long_options[ind].val; + switch (c) + { + case 0: + break; + + case 'd': + free (infopath); + infopath = savestring (optarg); + break; + + case 'n': + + if (nodenames_index + 2 > nodenames_size) + nodenames = (char **) + xrealloc (nodenames, (nodenames_size += 10) * sizeof (char *)); + + nodenames[nodenames_index++] = optarg; + nodenames[nodenames_index] = (char *)NULL; + break; + + case 'f': + strncpy (filename, optarg, FILENAME_LEN); + break; + + case 'o': + strncpy (dumpfile, optarg, FILENAME_LEN); + break; + + default: + usage (); + } + } + + /* If the user specified `--version' then simply show the version + info at this time and exit. */ + if (version_flag) + { + show_version_info (stdout); + exit (0); + } + + /* Okay, flags are parsed. Get possible Info menuname. */ + + if (*filename && (ptr = rindex (filename,'/')) != NULL ) + { + /* Add filename's directory to path. */ + char *temp; + + temp = (char *) xmalloc (2 + strlen (filename) + strlen (infopath)); + strncpy (temp, filename, ptr - filename); + sprintf (temp + (ptr - filename), ":%s", infopath); + free (infopath); + infopath = temp; + } + + /* Start with DIR or whatever was specified. */ + if (!get_node (filename, (nodenames[0] == NULL) ? "Top" : nodenames[0], 0)) + { + if (filename[0]) + { + fprintf (stderr, "Try just plain `info'.\n"); + exit (1); + } + else + { + strcpy (filename, "DIR"); + + if (!get_node ((char *)NULL, (char *)NULL, 1)) + { + fprintf (stderr, + "%s: Cannot find \"%s\", anywhere along the search ", + argv[0], filename); + fprintf (stderr, "path of\n\"%s\".\n", infopath); + exit (1); + } + } + } + + totally_inhibit_errors = 0; + + for (ind = 1 ; ind < nodenames_index ; ind++) + get_node (filename, nodenames[ind], 0); + + nodename = nodenames[nodenames_index > 0 ? nodenames_index - 1 : 0]; + if (!nodename) + { + nodename = (char *) xmalloc (NODENAME_LEN); + *nodename = '\0'; + } + + if (optind != argc) + { + while (optind != argc) + { + if (!build_menu ()) + { + display_error ("There is no menu in node \"%s\"", + current_info_node ); + no_such_node++; + break; + } + else if (!find_menu_node (argv[optind], nodename)) + { + display_error + ("There is no menu entry for \"%s\" in node \"%s\"", + argv[optind], nodename ); + no_such_node++; + break; + } + else if (!get_node ((char *)NULL, nodename, 0)) + { + no_such_node++; + break; + } + else + { +#if 1 + /* RMS says not to type this stuff out because he expects + programs to call Info instead of interactive users. */ + printf ("%s.. ",argv[optind]); + fflush (stdout); +#endif + optind++; + } + } + } + + /* If we are outputting to a file, and the node was not found, exit. */ + if (no_such_node && dumpfile[0]) + exit (1); + else + begin_info_session (); + + exit (0); +} + +usage () +{ + fprintf (stderr,"%s\n%s\n%s\n%s\n", +"Usage: info [-d dir-path] [-f info-file] [-n node-name -n node-name ...]", +" [-o output-file] [--directory dir-path] [--file info-file]", +" [--node node-name --node node-name ...] [--version]", +" [--output output-file] [menu-selection...]"); + exit (1); +} + +/* Print the version of info to standard output. */ +show_version_info (stream) + FILE *stream; +{ + fprintf (stream, "GNU Info version %d.%d\n", major_version, minor_version); + fflush (stream); +} + +#if defined (SIGTSTP) +Function *old_tstp; +Function *old_ttou, *old_ttin; +#endif /* SIGTSTP */ + +#if defined (SIGWINCH) +Function *old_winch; +#endif /* SIGWINCH */ + +/* Start using Info. */ +begin_info_session () +{ + SigHandler info_signal_handler (); + + /* If the user just wants to dump the node, then do that. */ + if (dumpfile[0]) + { + dump_current_node (dumpfile); + exit (0); + } + + init_terminal_io (); + + /* Install handlers for restoring/breaking the screen. */ + + install_signals (); + new_echo_area (); + + print_string ("Welcome to Info! Type \"?\" for help. "); + close_echo_area (); + toploop (); + goto_xy (the_window.left, the_window.bottom + 1); + restore_io (); +} + +/* What to do before processing a stop signal. */ +before_stop_signal () +{ + restore_io (); +} + +/* What to do after processing a stop signal. */ +after_stop_signal () +{ + clear_screen (); + display_page (); + goto_xy (the_window.ch, the_window.cv); + opsys_init_terminal (); +} + +/* partain: moved these here */ +char *widest_line; + +int terminal_columns; /* {tc_int, "co" */ +int terminal_rows; /* {tc_int, "li" */ + +/* Do the right thing with this signal. */ +SigHandler +info_signal_handler (sig) + int sig; +{ + switch (sig) + { +#if defined (SIGTSTP) + case SIGTSTP: + case SIGTTOU: + case SIGTTIN: + before_stop_signal (); + signal (sig, SIG_DFL); +#if !defined (USG) + sigsetmask (sigblock (0) & ~sigmask (sig)); +#endif /* !USG */ + kill (getpid (), sig); + after_stop_signal (); + signal (sig, info_signal_handler); + break; +#endif /* SIGTSTP */ + +#if defined (SIGWINCH) + case SIGWINCH: + /* Window has changed. Get the size of the new window, and rebuild our + window chain. */ + { + int display_page (); + extern char *widest_line; + extern WINDOW terminal_window; + extern WINDOW_LIST *window_stack; + extern int terminal_rows, terminal_columns; + int delta_width, delta_height, right, bottom; + + right = get_terminal_columns (); + bottom = get_terminal_rows (); + + delta_width = right - terminal_columns; + delta_height = bottom - terminal_rows; + + terminal_columns = right; + terminal_rows = bottom; + + /* Save current window, whatever it is. */ + push_window (); + + /* Change the value of the widest_line. */ + free (widest_line); + widest_line = (char *) xmalloc (right); + + /* Make the new window. Map over all windows in window list. */ + { + WINDOW_LIST *wind = window_stack; + extern WINDOW modeline_window; + + while (wind != (WINDOW_LIST *)NULL) + { + adjust_wind ((WINDOW *)wind, delta_width, delta_height); + wind = wind->next_window; + } + + /* Adjust the other windows that we know about. */ + adjust_wind (&terminal_window, delta_width, delta_height); + adjust_wind (&echo_area, delta_width, delta_height); + adjust_wind (&modeline_window, delta_width, delta_height); + } + + /* Clear and redisplay the entire terminal window. */ + set_window (&terminal_window); + clear_screen (); + + /* Redisplay the contents of the screen. */ + with_output_to_window (&terminal_window, display_page); + + /* Get back the current window. */ + pop_window (); + } + break; +#endif /* SIGWINCH */ + + case SIGINT: + restore_io (); + exit (1); + break; + } +} + +install_signals () +{ +#if defined (SIGTSTP) + old_tstp = (Function *) signal (SIGTSTP, info_signal_handler); + old_ttou = (Function *) signal (SIGTTOU, info_signal_handler); + old_ttin = (Function *) signal (SIGTTIN, info_signal_handler); +#endif /* SIGTSTP */ + +#if defined (SIGWINCH) + old_winch = (Function *) signal (SIGWINCH, info_signal_handler); +#endif /* SIGWINCH */ + + signal (SIGINT, info_signal_handler); +} + +adjust_wind (wind, delta_width, delta_height) + WINDOW *wind; + int delta_width, delta_height; +{ + wind->right += delta_width; + wind->bottom += delta_height; + wind->ch += delta_width; + wind->cv += delta_height; + + /* Ugly hack to fix busted windows code. If the window we are adjusting + already has a TOP offset, then adjust that also. */ + if (wind->top) + wind->top += delta_height; +} + +/* **************************************************************** */ +/* */ +/* Completing Things */ +/* */ +/* **************************************************************** */ + +typedef struct completion_entry +{ + char *identifier; + char *data; + struct completion_entry *next; +} COMP_ENTRY; + +/* The linked list of COMP_ENTRY structures that you create. */ +COMP_ENTRY *completion_list = (COMP_ENTRY *) NULL; + +/* The vector of COMP_ENTRY pointers that COMPLETE returns. */ +COMP_ENTRY **completions = NULL; + +/* The number of elements in the above vector. */ +int completion_count; + +/* Initial size of COMPLETIONS array. */ +#define INITIAL_COMPLETIONS_CORE_SIZE 200 + +/* Current size of the completion array in core. */ +int completions_core_size = 0; + +/* Ease the typing task. Another name for the I'th + IDENTIFIER of COMPLETIONS. */ +#define completion_id(i) ((completions[(i)])->identifier) + +/* The number of completions that can be present before the help + function starts asking you about whether it should print them + all or not. */ +int completion_query_threshold = 100; + +free_completion_list () +{ + COMP_ENTRY *temp; + while (completion_list) + { + temp = completion_list; + + if (completion_list->identifier) + free (completion_list->identifier); + + if (completion_list->data) + free (completion_list->data); + + completion_list = completion_list->next; + free (temp); + } +} + +/* Add a single completion to COMPLETION_LIST. + IDENTIFIER is the string that the user should type. + DATA should just be a pointer to some random data that you wish to + have associated with the identifier, but I'm too stupid for that, so + it must be a string as well. This allocates the space for the strings + so you don't necessarily have to. */ +add_completion (identifier, data) + char *identifier, *data; +{ + COMP_ENTRY *temp = (COMP_ENTRY *) xmalloc (sizeof (COMP_ENTRY)); + + temp->identifier = (char *) xmalloc (strlen (identifier) + 1); + strcpy (temp->identifier, identifier); + + temp->data = (char *) xmalloc (strlen (data) + 1); + strcpy (temp->data, data); + + temp->next = completion_list; + completion_list = temp; +} + +/* Function for reading a line. Supports completion on COMPLETION_LIST + if you pass COMPLETING as non-zero. Prompt is either a prompt or + NULL, LINE is the place to store the characters that are read. + LINE may start out already containing some characters; if so, they + are printed. MAXCHARS tells how many characters can fit in the + buffer at LINE. readline () returns zero if the user types the + abort character. LINE is returned with a '\0' at the end, not a '\n'. */ +int +readline (prompt, line, maxchars, completing) + char *prompt, *line; + int maxchars; + int completing; +{ + int character; + int readline_ch, readline_cv; + int current_len = strlen (line); + int just_completed = 0; /* Have we just done a completion? */ + int meta_flag = 0; + + new_echo_area (); + + if (prompt) + print_string ("%s", prompt); + + readline_ch = the_window.ch; + readline_cv = the_window.cv; + + print_string ("%s", line); + + while (1) + { + line[current_len] = '\0'; + goto_xy (readline_ch, readline_cv); + print_string ("%s", line); + clear_eol (); + + if (just_completed) + just_completed--; + + character = blink_cursor (); + if (meta_flag) + { + character = META (character); + meta_flag = 0; + } + + if (META_P (character)) + character = META (to_upper (UNMETA (character))); + + switch (character) + { + case EOF: + character = '\n'; + + case ESC: + meta_flag++; + break; + + case META (DELETE): + case CTRL ('W'): + while (current_len && line[current_len] == SPACE) + current_len--; + + if (!current_len) + break; + + while (current_len && line[current_len] != SPACE) + current_len--; + + break; + + case CTRL ('U'): + current_len = 0; + break; + + case '\b': + case 0x07f: + if (current_len) + current_len--; + else + ding (); + break; + + case '\n': + case '\r': + if (completing) + { + extern int completion_count; + + try_complete (line); + + if (completion_count >= 1) + { + close_echo_area (); + return (1); + } + else + { + current_len = strlen (line); + break; + } + } + else + { + close_echo_area (); + return (1); + } + + case ABORT_CHAR: + ding (); + + if (current_len) + { + current_len = 0; + } + else + { + close_echo_area (); + clear_echo_area (); + return (0); + } + break; + + case ' ': + case '\t': + case '?': + if (completing) + { + extern int completion_count; + + if (character == '?' || just_completed) + { + help_possible_completions (line); + break; + } + else + { + char temp_line[NODENAME_LEN]; + strcpy (temp_line, line); + try_complete (line); just_completed = 2; + if (completion_count != 1 && character == SPACE) + { + if (strcmp (temp_line, line) == 0) + { + line[current_len] = SPACE; + line[current_len + 1] = '\0'; + strcpy (temp_line, line); + try_complete (line); + if (completion_count == 0) + { + line[current_len] = '\0'; + ding (); + } + } + } + current_len = strlen (line); + if (completion_count == 0) + ding (); + break; + } + } + /* Do *NOT* put anything in-between the completing cases and + the default: case. No. Because the SPC, TAB and `?' get + treated as normal characters by falling through the + "if (completing)" test above. */ + default: + if (!CTRL_P (character) && + !META_P (character) && + current_len < maxchars) + line[current_len++] = character; + else + ding (); + } + } +} + +/* Initialize whatever the completer is using. */ +init_completer () +{ + if (completions_core_size != INITIAL_COMPLETIONS_CORE_SIZE) + { + if (completions) + free (completions); + + completions = (COMP_ENTRY **) + xmalloc ((sizeof (COMP_ENTRY *)) + * (completions_core_size = INITIAL_COMPLETIONS_CORE_SIZE)); + } + completion_count = 0; +} + +/* Reverse the completion list passed in LIST, and + return a pointer to the new head. */ +COMP_ENTRY * +reverse_list (list) + COMP_ENTRY *list; +{ + COMP_ENTRY *next; + COMP_ENTRY *prev = (COMP_ENTRY *) NULL; + + while (list) + { + next = list->next; + list->next = prev; + prev = list; + list = next; + } + return (prev); +} + +/* Remember the possible completion passed in POINTER on the + completions list. */ +remember_completion (pointer) + COMP_ENTRY *pointer; +{ + if (completion_count == completions_core_size) + { + COMP_ENTRY **temp = (COMP_ENTRY **) + realloc (completions, ((sizeof (COMP_ENTRY *)) + * (completions_core_size += + INITIAL_COMPLETIONS_CORE_SIZE))); + if (!temp) + { + display_error ("Too many completions (~d)! Out of core!", + completion_count); + return; + } + else + completions = temp; + } + completions[completion_count++] = pointer; +} + +/* Complete TEXT from identifiers in LIST. Place the resultant + completions in COMPLETIONS, and the number of completions in + COMPLETION_COUNT. Modify TEXT to contain the least common + denominator of all the completions found. */ +int +complete (text, list) + char *text; + COMP_ENTRY *list; +{ + int low_match, i, idx; + int string_length = strlen (text); + + init_completer (); + low_match = 100000; /* Some large number. */ + + while (list) + { + if (strnicmp (text, list->identifier, string_length) == 0) + remember_completion (list); + list = list->next; + } + + if (completion_count == 0) + return (0); + + if (completion_count == 1) + { /* One completion */ + strcpy (text, completion_id (0)); + return (1); + } + + /* Else find the least common denominator */ + + idx = 1; + + while (idx < completion_count) + { + int c1, c2; + for (i = 0; + (c1 = to_lower (completion_id (idx - 1)[i])) && + (c2 = to_lower (completion_id (idx)[i])); + i++) + if (c1 != c2) + break; + + if (low_match > i) + low_match = i; + idx++; + } + + strncpy (text, completion_id (0), low_match); + text[low_match] = '\0'; + return (1); +} + +/* Complete TEXT from the completion structures in COMPLETION_LIST. */ +int +try_complete (text) + char *text; +{ + return (complete (text, completion_list)); +} + +/* The function that prints out the possible completions. */ +help_possible_completions (text) + char *text; +{ + char temp_string[2000]; + + goto_xy (the_window.left, the_window.top); + strcpy (temp_string, text); + try_complete (temp_string); + + open_typeout (); + + if (completion_count == 0) + { + print_string ("There are no possible completions.\n"); + goto print_done; + } + + if (completion_count == 1) + { + print_string + ("The only possible completion of what you have typed is:\n\n"); + print_string ("%s", completion_id(0)); + goto print_done; + } + + if (completion_count >= completion_query_threshold) + { + print_string + ("\nThere are %d completions. Do you really want to see them all", + completion_count); + + if (!get_y_or_n_p ()) + return; + } + + print_string ("\nThe %d completions of what you have typed are:\n\n", + completion_count); + + { + int idx = 0; + int counter = 0; + int columns = (the_window.right - the_window.left) / 30; + + while (idx < completion_count) + { + if (counter == columns) + { + charout ('\n'); + counter = 0; + } + indent_to (counter * 30); + print_string ("%s", completion_id (idx)); + counter++; + idx++; + } + } + +print_done: + print_string ("\n\n-----------------\n"); + close_typeout (); +} + +/* Return the next file that should be searched, or NULL if we are at the end + of the info file. If the FILE argument is provided, begin the search there, + if REWIND is non-zero start the search at the beginning of the list. + + The list is the one built by an indirect tag table, on the supposition + that those files form a logical set to search if we are in one of them. + If no such list is current (either it doesn't exist, or FILE isn't on + it) the search list is set to be last_loaded_info_file */ +char * +next_info_file (file, rewind) + char *file; /* file to set `next' to. May be NULL. */ + int rewind; /* should I rewind the file list? */ +{ + static int index = -1; + + if (file != NULL) + { + char *ptr = rindex (file,'/'); + + if (ptr != NULL) + file = ptr + 1; + + for (index = 0; + index < MAX_INDIRECT_FILES && + indirect_list[index].filename != (char *)NULL; + index++) + { + if (strcmp (file, indirect_list[index].filename) == 0) + return (file); + } + + /* OK, we are not on the current indirect_list. This means that + we have switched to another node that has no indirect list, + so forget the old one. */ + for (index = 0; + index < MAX_INDIRECT_FILES && + indirect_list[index].filename != (char *)NULL; + index++) + { + free (indirect_list[index].filename); + indirect_list[index].filename = (char *)NULL; + } + return (indirect_list[0].filename = savestring (file)); + } + else if (rewind) + { + index = 0; + + if (indirect_list[0].filename == (char *)NULL) + indirect_list[0].filename = savestring (last_loaded_info_file); + } + else + index++; + + if (index < MAX_INDIRECT_FILES && + indirect_list[index].filename != (char *)NULL) + return (indirect_list[index].filename); + + index = -1; + return (NULL); +} + +/* **************************************************************** */ +/* */ +/* Getting Nodes */ +/* */ +/* **************************************************************** */ + +/* A node name looks like: + Node: nodename with spaces but not a comma, +or Node: (filename-containing-node)node-within-file +or Node: (filename) + + The latter case implies a nodename of "Top". All files are + supposed to have one. + + Lastly, the nodename specified could be "*", which specifies the + entire file. */ + +/* Return the directory portion of FILENAME, i.e., everything before the + last slash. */ +static char * +file_directory (filename) + char *filename; +{ + register char *scan; + register int length; + char *result; + + scan = filename; + + while (*scan++ != '\0'); + + while (1) + { + if (scan == filename) + break; + + if ((*--scan) == '/') + { + scan++; + break; + } + } + + length = scan - filename; + result = (char *) xmalloc (length + 1); + strncpy (result, filename, length); + result[length] = '\0'; + + return (result); +} + +/* Given FILENAME and DIRECTORY return a newly allocated string which + is either the two concatenated, or simply FILENAME if it is absolute + already. */ +static char * +file_absolutize (filename, directory) + char *filename, *directory; +{ + register int filename_len, directory_len; + char *result; + + if (filename[0] == '/') + return (savestring (filename)); + + filename_len = strlen (filename); + directory_len = strlen (directory); + result = (char *) xmalloc (directory_len + filename_len + 1); + + strcpy (result, directory); + strcat (result, filename); + + return (result); +} + +/* Load FILENAME. If REMEMBER_NAME is non-zero, then remember the + loaded filename in CURRENT_INFO_FILE. In either case, remember + the name of this file in LAST_LOADED_INFO_FILE. */ +int +get_info_file (filename, remember_name) + char *filename; + int remember_name; +{ + FILE *input_stream; + struct stat file_info; + int pointer, result; + char tempname[FILENAME_LEN]; + + /* Get real filename. */ + strcpy (tempname, opsys_filename (filename)); + + /* If the file doesn't exist, try again with the name in lower case. */ + result = stat (tempname, &file_info); + + if (result < 0) + { + register int i; + char *lowered_name; + + lowered_name = (char *)xmalloc (1 + strlen (filename)); + + for (i = 0; lowered_name[i] = to_lower (filename[i]); i++) + ; + + strcpy (tempname, opsys_filename (lowered_name)); + result = stat (tempname, &file_info); + } + + /* See if this file is the last loaded one. */ + if (!result && (strcmp (last_loaded_info_file, tempname) == 0)) + return (1); + + /* Now try to open the file. */ + if (result || (input_stream = fopen (tempname, "r")) == NULL) + { + file_error (tempname); + return (0); + } + + /* If we already have a file loaded, then free it first. */ + if (info_file) + { + free (info_file); + + if (!indirect) + { + /* Then the tag table is also no longer valid. */ + tag_table = (char *) NULL; + } + } + + /* Read the contents of the file into a new buffer. */ + + info_file = (char *) xmalloc (info_buffer_len = file_info.st_size); + fread (info_file, 1, info_buffer_len, input_stream); + fclose (input_stream); + strcpy (last_loaded_info_file, tempname); + if (remember_name) + { + strcpy (current_info_file, tempname); + if (indirect) + { + int idx; + indirect = 0; + free (tag_table); + } + } + else + return (1); + + /* Force redisplay, since we are looking at a new file. */ + window_bashed = 1; + + /* The file has been read, and we don't know anything about it. + Find out if it contains a tag table. */ + + tag_table = NULL; /* assume none. */ + indirect = 0; + tag_buffer_len = 0; + + set_search_constraints (info_file, info_buffer_len); + + /* Go to the last few lines in the file. */ + pointer = back_lines (8, info_buffer_len); + pointer = search_forward (TAG_TABLE_END_STRING, pointer); + + if (pointer > -1) + { + /* Then there is a tag table. Find the start of it, + and remember that. */ + pointer = search_backward (TAG_TABLE_BEG_STRING, pointer); + + /* Handle error for malformed info file. */ + if (pointer < 0) + display_error ("Start of tag table not found!"); + else + { + /* No problem. If this file is an indirect file, then the contents + of the tag table must remain in RAM the entire time. Otherwise, + we can flush the tag table with the file when the file is flushed. + So, if indirect, remember that, and copy the table to another + place.*/ + + int indirect_check = forward_lines (2, pointer); + + tag_table = info_file + pointer; + tag_buffer_len = info_buffer_len - pointer; + + /* Shorten the search constraints. */ + info_buffer_len = pointer; + + if (looking_at ("(Indirect)\n", indirect_check)) + { + /* We have to find the start of the indirect file's + information. */ + tag_table = (char *) xmalloc (tag_buffer_len); + + bcopy (&info_file[indirect_check], tag_table, tag_buffer_len); + + /* Find the list of filenames. */ + indirect_top = search_backward ("Indirect:\n", indirect_check); + if (indirect_top < 0) + { + free (tag_table); + tag_table = (char *) NULL; + display_error ("Start of INDIRECT tag table not found!"); + return (0); + } + + /* Remember the filenames, and their byte offsets. */ + { + /* Index into the filename/offsets array. */ + int idx, temp_first_byte; + char temp_filename[FILENAME_LEN]; + char *directory = file_directory (tempname); + + info_buffer_len = indirect_top; + + /* For each line, scan the info into globals. Then save + the information in the INDIRECT_INFO structure. */ + + for (idx = 0; idx < MAX_INDIRECT_FILES && + indirect_list[idx].filename != (char *) NULL; + idx++) + { + free (indirect_list[idx].filename); + indirect_list[idx].filename = (char *) NULL; + } + + for (idx = 0;info_file[indirect_top] != info_separator_char && + idx < MAX_INDIRECT_FILES;) + { + indirect_top = forward_lines (1, indirect_top); + if (info_file[indirect_top] == info_separator_char) + break; + + /* Ignore blank lines. */ + if (info_file[indirect_top] == '\n') + continue; + + sscanf (&info_file[indirect_top], "%s%d", + temp_filename, &temp_first_byte); + + if (strlen (temp_filename)) + { + temp_filename[strlen (temp_filename) - 1] = '\0'; + indirect_list[idx].filename = + file_absolutize (temp_filename, directory); + indirect_list[idx].first_byte = temp_first_byte; + idx++; + } + } + + free (directory); + + /* Terminate the table. */ + if (idx == MAX_INDIRECT_FILES) + { + display_error + ("Sorry, the INDIRECT file array isn't large enough."); + idx--; + } + indirect_list[idx].filename = (char *) NULL; + } + indirect = 1; + } else { + ; + } + } + } + return (1); +} + +/* Make current_info_node be NODENAME. This could involve loading + a file, etc. POPPING is non-zero if we got here because we are + popping one level. */ +int +get_node (filename, nodename, popping) + char *nodename, *filename; + int popping; +{ + int pointer; + char internal_filename[FILENAME_LEN]; + char internal_nodename[NODENAME_LEN]; + + if (nodename && *nodename) + { + /* Maybe nodename looks like: (filename)nodename, or worse: (filename). + If so, extract the stuff out. */ + if (*nodename == '(') + { + int temp = 1, temp1 = 0; + char character; + + filename = internal_filename; + + while ((character = nodename[temp]) && character != ')') + { + filename[temp - 1] = character; + temp++; + } + filename[temp - 1] = '\0'; + temp++; /* skip the closing ')' */ + + /* We have the filename now. The nodename follows. */ + internal_nodename[0] = '\0'; + + while (nodename[temp] == ' ' || + nodename[temp] == '\t' || + nodename[temp] == '\n') + temp++; + + if (nodename[temp]) + while (internal_nodename[temp1++] = nodename[temp++]) + ; + else if (*filename != '\0') + strcpy (internal_nodename,"Top"); + + nodename = internal_nodename; + } + } + + if (!popping) + push_node (current_info_file, current_info_node, pagetop, nodetop); + + if (!nodename || !*nodename) + { + nodename = internal_nodename; + strcpy (nodename, "Top"); + } + + if (!filename || !*filename) + { + filename = internal_filename; + strcpy (filename, current_info_file); + } + + if (!*filename) + strcpy (filename, "DIR"); + + if (!get_info_file (filename, 1)) + goto node_not_found; + + if (strcmp (nodename, "*") == 0) + { + /* The "node" that we want is the entire file. */ + pointer = 0; + goto found_node; + } + + /* If we are using a tag table, see if we can find the nodename in it. */ + if (tag_table) + { + pointer = find_node_in_tag_table (nodename, 0); + if (pointer < 1) + { + int pop_node (); + + /* The search through the tag table failed. Maybe we + should try searching the buffer? Nahh, just barf. */ + node_not_found: + if (popping) + return (0); /* Second time through. */ + + { + int save_inhibit = totally_inhibit_errors; + + totally_inhibit_errors = 0; + display_error + ("Sorry, unable to find the node \"%s\" in the file \"%s\".", + nodename, filename); + totally_inhibit_errors = save_inhibit; + } + + current_info_file[0] = '\0'; + current_info_node[0] = '\0'; + last_loaded_info_file[0] = '\0'; + pop_node (internal_filename, internal_nodename, &nodetop, &pagetop); + get_node (internal_filename, internal_nodename, 1); + return (0); + } + + /* Otherwise, the desired location is right here. + Scarf the position byte. */ + while (tag_table[pointer] != '\177') + pointer++; + + sscanf (&tag_table[pointer + 1], "%d", &pointer); + + /* Okay, we have a position pointer. If this is an indirect file, + then we should look through the indirect_list for the first + element.first_byte which is larger than this. Then we can load + the specified file, and win. */ + if (indirect) + { + /* Find the filename for this node. */ + int idx; + for (idx = 0; idx < MAX_INDIRECT_FILES && + indirect_list[idx].filename != (char *) NULL; idx++) + { + if (indirect_list[idx].first_byte > pointer) + { + /* We found it. */ + break; + } + } + if (!get_info_file (indirect_list[idx - 1].filename, 1)) + goto node_not_found; + pointer -= indirect_list[idx - 1].first_byte; + + /* Here is code to compensate for the header of an indirect file. */ + { + int tt = find_node_start (0); + if (tt > -1) + pointer += tt; + } + } + else + { + /* This tag table is *not* indirect. The filename of the file + containing this node is the same as the current file. The + line probably looks like: + File: info, Node: Checking25796 */ + } + } + else + { +#if defined (NOTDEF) + /* We don't have a tag table. The node can only be found by + searching this file in its entirety. */ + if (!get_info_file (filename, 1)) + return (0); +#endif /* NOTDEF */ + pointer = 0; + } + + /* Search this file, using pointer as a good guess where to start. */ + /* This is the same number that RMS used. It might be right or wrong. */ + pointer -= 1000; + if (pointer < 0) + pointer = 0; + + pointer = find_node_in_file (nodename, pointer); + if (pointer < 0) + goto node_not_found; + + /* We found the node in its file. Remember exciting information. */ + +found_node: + back_lines (0, pointer); + nodetop = pagetop = pointer; + strcpy (current_info_node, nodename); + strcpy (current_info_file, filename); + get_node_extent (); + return (1); +} + +/* Get the bounds for this node. NODETOP points to the start of the + node. Scan forward looking for info_separator_char, and remember + that in NODEBOT. */ +get_node_extent () +{ + int idx = nodetop; + int character; + int do_it_till_end = (strcmp (current_info_node, "*") == 0); + + nodelines = 0; + +again: + while ((idx < info_buffer_len) && + ((character = info_file[idx]) != info_separator_char)) + { + if (character == '\n') + nodelines++; + idx++; + } + if (do_it_till_end && idx != info_buffer_len) + { + idx++; + goto again; + } + nodebot = idx; +} + +/* Locate the start of a node in the current search_buffer. Return + the offset to the node start, or minus one. START is the place in + the file at where to begin the search. */ +find_node_start (start) + int start; +{ + return (search_forward (start_of_node_string, start)); +} + +/* Find NODENAME in TAG_TABLE. */ +find_node_in_tag_table (nodename, offset) + char *nodename; + int offset; +{ + int temp; + + set_search_constraints (tag_table, tag_buffer_len); + + temp = offset; + while (1) + { + offset = search_forward (NODE_ID, temp); + + if (offset < 0) + return (offset); + + temp = skip_whitespace (offset + strlen (NODE_ID)); + + if (strnicmp (tag_table + temp, nodename, strlen (nodename)) == 0) + if (*(tag_table + temp + strlen (nodename)) == '\177') + return (temp); + } +} + +/* Find NODENAME in INFO_FILE. */ +find_node_in_file (nodename, offset) + char *nodename; + int offset; +{ + int temp, last_offset = -1; + + set_search_constraints (info_file, info_buffer_len); + + while (1) + { + offset = find_node_start (offset); + + if (offset == last_offset) + offset = -1; + else + last_offset = offset; + + if (offset < 0) + return (offset); + else + temp = forward_lines (1, offset); + + if (temp == offset) + return (-1); /* At last line now, just a node start. */ + else + offset = temp; + + temp = string_in_line (NODE_ID, offset); + + if (temp > -1) + { + temp = skip_whitespace (temp + strlen (NODE_ID)); + if (strnicmp (info_file + temp, nodename, strlen (nodename)) == 0) + { + int check_exact = *(info_file + temp + strlen (nodename)); + + if (check_exact == '\t' || + check_exact == ',' || + check_exact == '.' || + check_exact == '\n') + return (offset); + } + } + } +} + + +/* **************************************************************** */ +/* */ +/* Dumping and Printing Nodes */ +/* */ +/* **************************************************************** */ + +/* Make a temporary filename based on STARTER and the PID of this Info. */ +char * +make_temp_filename (starter) + char *starter; +{ + register int i; + char *temp; + + temp = (char *) xmalloc (strlen (starter) + 10); + sprintf (temp, "%s-%d", starter, getpid ()); + + for (i = 0; temp[i]; i++) + if (!isalnum (temp[i])) + temp[i] = '-'; + + return (temp); +} + +/* Delete a file. Print errors if necessary. */ +deletefile (filename) + char *filename; +{ + if (unlink (filename) != 0) + { + file_error (filename); + return (1); + } + return (0); +} + +printfile (filename) + char *filename; +{ + int length = strlen (print_command) + strlen (filename) + strlen ("\n") + 1; + char *command = (char *) xmalloc (length); + int error; + + display_error ("Printing file `%s'...\n", filename); + sprintf (command, "%s %s", print_command, filename); + error = system (command); + if (error) + display_error ("Can't invoke `%s'", command); + free (command); + return (error); +} + +/* Dump the current node into a file named FILENAME. + Return 0 if the dump was successful, otherwise, + print error and exit. */ +dump_current_node (filename) + char *filename; +{ + int c, i = nodetop; + FILE *output_stream; + + if (strcmp (filename, "-") == 0) + output_stream = stdout; + else + output_stream = fopen (filename, "w"); + + if (output_stream == (FILE *) NULL) + { + file_error (filename); + return (1); + } + + while (i < nodebot && i < info_buffer_len) + { + c = info_file[i]; + if (CTRL_P (c) && !(index ("\n\t\f", c))) + { + putc ('^', output_stream); + c = UNCTRL (c); + } + + if (putc (c, output_stream) == EOF) + { + if (output_stream != stdout) + fclose (output_stream); + + file_error (filename); + return (1); + } + i++; + } + + if (output_stream != stdout) + fclose (output_stream); + + return (0); +} + +/* **************************************************************** */ +/* */ +/* Toplevel eval loop. */ +/* */ +/* **************************************************************** */ + +#define MENU_HEADER "\n* Menu:" +#define MENU_ID "\n* " +#define FOOTNOTE_HEADER "*Note" + +/* Number of items that the current menu has. */ +int the_menu_size = 0; + +/* The node that last made a menus completion list. */ +char menus_nodename[NODENAME_LEN]; +char menus_filename[NODENAME_LEN]; + +static int search_start = 0; + +/* The default prompt string for the Follow Reference command. */ +char *visible_footnote = (char *)NULL; +toploop () +{ + int done, inhibit_display; + int command, last_command; + int last_pointer, count, new_ypos, last_pagetop; + char nodename[NODENAME_LEN]; + + done = inhibit_display = 0; + command = last_command = 0; + new_ypos = last_pagetop = -1; + + while (!done) + { + if (!inhibit_display && + (window_bashed || (pagetop != last_pagetop))) + display_page (); + + inhibit_display = window_bashed = 0; + last_pagetop = pagetop; + + nodename[0] = '\0'; /* Don't display old text in input line. */ + + last_command = command; + + if (last_command == 'S') + cursor_to (search_start); + else + goto_xy (echo_area.left, echo_area.top); + + command = blink_cursor (); + clear_echo_area (); + + if (command == EOF) + { + done = 1; + continue; + } + command = to_upper (command); + + switch (command) + { + case 'D': + get_node ((char *) NULL, "(dir)Top", 0); + break; + + case 'H': + if ((the_window.bottom - the_window.top) < 24) + get_node ((char *) NULL, "(info)Help-Small-Screen", 0); + else + get_node ((char *) NULL, "(info)Help", 0); + break; + + case 'N': + if (!next_node ()) + { + display_error ("No NEXT for this node!"); + inhibit_display = 1; + } + break; + + case 'P': + if (!prev_node ()) + { + display_error ("No PREV for this node!"); + inhibit_display = 1; + } + break; + + case 'U': + { + int savetop = pagetop; + + if (!up_node ()) + { + display_error ("No UP for this node!"); + inhibit_display = 1; + pagetop = savetop; + } + break; + } + + case 'M': + if (!build_menu ()) + { + display_error ("No menu in this node!"); + inhibit_display = 1; + break; + } + + if (!readline ("Menu item: ", nodename, NODENAME_LEN, 1)) + { + clear_echo_area (); + inhibit_display = 1; + break; + } + + I_goto_xy (echo_area.left, echo_area.top); + if (!find_menu_node (nodename, nodename)) + { + display_error ("\"%s\" is not a menu item!", nodename); + inhibit_display = 1; + break; + } + + if (get_node ((char *) NULL, nodename, 0)) + clear_echo_area (); + break; + + case 'F': + { + char footnote[NODENAME_LEN]; + + if (!build_notes ()) + { + display_error ("No cross-references in this node!"); + inhibit_display = 1; + break; + } + + strcpy (footnote, visible_footnote); + if (!readline ("Follow reference: ", footnote, NODENAME_LEN, 1)) + { + inhibit_display = 1; + break; + } + + I_goto_xy (echo_area.left, echo_area.top); + if (!find_note_node (footnote, nodename)) + { + display_error ("\"%s\" is not a cross-reference in this node!", + footnote); + inhibit_display = 1; + break; + } + + if (get_node ((char *)NULL, nodename, 0)) + clear_echo_area (); + break; + } + + case 'L': + { + char filename[FILENAME_LEN], nodename[NODENAME_LEN]; + int ptop, ntop; + if (pop_node (filename, nodename, &ntop, &ptop) && + get_node (filename, nodename, 1)) + { + pagetop = ptop; + } + else + inhibit_display = 1; + break; + } + + case SPACE: + case CTRL ('V'): + if (!next_page ()) + { + display_error ("At last page of this node now!"); + inhibit_display = 1; + } + break; + + case META ('V'): + case DELETE: + if (!prev_page ()) + { + display_error ("At first page of this node now!"); + inhibit_display = 1; + } + break; + + case 'B': + if (pagetop == nodetop) + { + display_error ("Already at beginning of this node!"); + inhibit_display = 1; + } + else + pagetop = nodetop; + break; + + /* I don't want to do this this way, but the documentation + clearly states that '6' doesn't work. It states this for a + reason, and ours is not to wonder why... */ + case '1': + case '2': + case '3': + case '4': + case '5': + { + int item = command - '0'; + + if (!build_menu ()) + { + display_error ("No menu in this node!"); + inhibit_display = 1; + break; + } + + if (item > the_menu_size) + { + display_error ("There are only %d items in the menu!", + the_menu_size); + inhibit_display = 1; + break; + } + + if (!get_menu (item)) + inhibit_display = 1; + } + break; + + case 'G': + if (!readline ("Goto node: ", nodename, NODENAME_LEN, 0)) + { + inhibit_display = 1; + break; + } + + if (get_node ((char *) NULL, nodename, 0)) + clear_echo_area (); + break; + + /* Search from the starting position forward for a string. + Select the node containing the desired string. Put the + top of the page screen_lines / 2 lines behind it, but not + before nodetop. */ + case 'S': + { + int pointer, temp; + char prompt[21 + NODENAME_LEN + 1]; + static char search_string[NODENAME_LEN] = ""; + static char *starting_filename = NULL, + *starting_nodename = NULL; + static int starting_pagetop = 0; + static int wrap_search = 0; + + sprintf (prompt, "Search for string [%s]: ", search_string); + + if (!readline (prompt , nodename, NODENAME_LEN, 0)) + { + inhibit_display = 1; + break; + } + + /* If the user defaulted the search string, and the previous + command was search, then this is a continuation of the + previous search. */ + if (((strcmp (nodename, search_string) == 0) || + (!*nodename && *search_string)) && + (last_command == 'S')) + { + search_start++; + } + else + { + /* Initialize the start of a new search. */ + if (starting_filename) + free (starting_filename); + + starting_filename = savestring (last_loaded_info_file); + + if (starting_nodename) + free (starting_nodename); + + starting_nodename = savestring (nodename ? nodename : ""); + + starting_pagetop = pagetop; + search_start = pagetop; + wrap_search = 0; + + if (*nodename != '\0') + strcpy (search_string, nodename); + } + + I_goto_xy (echo_area.left, echo_area.top); + + { + static int pushed = 0; /* How many files are pushed? */ + int found_string = 0; /* Did we find our string? */ + + if (wrap_search) + { + push_filestack (next_info_file ((char *)NULL, 1), 0); + pushed++; + search_start = 0; + } + + for (;;) + { + set_search_constraints (info_file, info_buffer_len); + pointer = search_forward (search_string, search_start); + + if (pointer != -1) + { + found_string = 1; + break; + } + else + { + char *next_file; + + next_file = next_info_file ((char *)NULL, 0); + + if (next_file != NULL) + { + if (pushed) + { + pop_filestack (); + pushed--; + } + + push_filestack (next_file, 0); + pushed++; + search_start = 0; +#if 1 + I_goto_xy (echo_area.left, echo_area.top); + print_string ("Searching file %s...\n", next_file); +#endif + continue; + } + + if (wrap_search) + { + display_error + ("\"%s\" not found!", + search_string); + + inhibit_display = 1; + wrap_search = 0; + + if (pushed) + { + pop_filestack (); + pushed--; + } + break; + } + else + { + display_error ("Search: End of file"); + inhibit_display = 1; + wrap_search = 1; + + if (pushed) + { + pop_filestack (); + pushed--; + } + break; + } + } + } + + if (pushed) + { + swap_filestack (); + pop_filestack (); + pushed--; + } + + if (!found_string) + break; + + wrap_search = 0; + temp = search_backward (start_of_node_string, pointer); + + if (temp != -1) + { + search_start = pointer; + pointer = forward_lines (1, temp); + } + + if (temp == -1 || !extract_field ("Node:", nodename, pointer)) + { + display_error + ("There doesn't appear to be a nodename for this node."); + get_node ((char *)NULL, "*", 0); + pagetop = pointer; + break; + } + + /* Get the node if it is different than the one already + loaded. */ + if (strcmp (nodename, starting_nodename) != 0) + { + free (starting_nodename); + starting_nodename = savestring (nodename); + + if (get_node ((char *) NULL, nodename, 0)) + clear_echo_area (); + } + + /* Reset the top of page if necessary. */ + { + if ((strcmp (last_loaded_info_file, starting_filename) != 0) || + (starting_pagetop != pagetop) || + (search_start > pagebot)) + { + pointer = + back_lines ((the_window.bottom - the_window.top) / 2, + forward_lines (1, search_start)); + + if (pointer < nodetop) + pointer = nodetop; + + pagetop = pointer; + window_bashed = 1; + } + else + inhibit_display = 1; + } + break; + } + } + + case CTRL ('H'): + case '?': + help_use_info (); + last_pagetop = -1; + break; + + case 'Q': + done = 1; + break; + + case CTRL ('L'): /* Control-l is redisplay. */ + window_bashed = 1; + if (last_command == 'S') + command = 'S'; + break; + + case '(': /* You *must* be trying to type a complete nodename. */ + strcpy (nodename, "("); + if (!readline ("Goto node: ", nodename, NODENAME_LEN, 0)) + { + inhibit_display = 1; + clear_echo_area (); + break; + } + I_goto_xy (echo_area.left, echo_area.top); + if (get_node ((char *) NULL, nodename, 0)) + clear_echo_area (); + break; + + case CTRL ('P'): + /* Print the contents of this node on the default printer. We + would like to let the user specify the printer, but we don't + want to ask her each time which printer to use. Besides, he + might not know, which is why it (the user) is in the need of + Info. */ + { + char *tempname = make_temp_filename (current_info_node); + if (dump_current_node (tempname) == 0 && + printfile (tempname) == 0 && + deletefile (tempname) == 0) + { + display_error ("Printed node. Go pick up your output.\n"); + } + inhibit_display = 1; + free (tempname); + } + break; + + default: + inhibit_display = 1; + display_error ("Unknown command! Press '?' for help."); + + } + } +} + +/* Return the screen column width that the line from START to END + requires to display. */ +line_length (start, end) + int start, end; +{ + int count = 0; + + while (start < end) + { + if (info_file[start] == '\t') + count += 7 - (count % 8); + else if (CTRL_P (info_file[start])) + count += 2; + else + count++; + + start++; + } + + return (count); +} + +/* Tell this person how to use Info. */ +help_use_info () +{ + open_typeout (); + clear_screen (); + print_string ("\n\ + Commands in Info\n\ +\n\ +h Invoke the Info tutorial.\n\ +\n\ +Selecting other nodes:\n\ +n Move to the \"next\" node of this node.\n\ +p Move to the \"previous\" node of this node.\n\ +u Move \"up\" from this node.\n\ +m Pick menu item specified by name.\n\ + Picking a menu item causes another node to be selected.\n\ +f Follow a cross reference. Reads name of reference.\n\ +l Move to the last node you were at.\n\ +d Move to the `directory' node. Equivalent to `gDIR'.\n\ +\n\ +Moving within a node:\n\ +Space Scroll forward a page.\n\ +DEL Scroll backward a page.\n\ +b Go to the beginning of this node.\n\ +\n\ +Advanced commands:\n\ +q Quit Info.\n\ +1 Pick first item in node's menu.\n\ +2 - 5 Pick second ... fifth item in node's menu.\n\ +g Move to node specified by name.\n\ + You may include a filename as well, as (FILENAME)NODENAME.\n\ +s Search through this Info file for a specified string,\n\ + and select the node in which the next occurrence is found.\n\ +Ctl-p Print the contents of this node using `%s'.\n\ +\n\ +Done.\n\n",print_command); + close_typeout (); +} + +/* Move to the node specified in the NEXT field. */ +int +next_node () +{ + char nodename[NODENAME_LEN]; + + if (!extract_field ("Next:", nodename, nodetop)) + return (0); + return (get_node ((char *) NULL, nodename, 0)); +} + +/* Move to the node specified in the PREVIOUS field. */ +int +prev_node () +{ + char nodename[NODENAME_LEN]; + + if (!extract_field ("Previous:", nodename, nodetop) + && !extract_field ("Prev:", nodename, nodetop)) + return (0); + return (get_node ((char *) NULL, nodename, 0)); +} + +/* Move to the node specified in the UP field. */ +int +up_node () +{ + char nodename[NODENAME_LEN]; + + if (!extract_field ("Up:", nodename, nodetop)) + return (0); + return (get_node ((char *) NULL, nodename, 0)); +} + +/* Build a completion list of menuname/nodename for each + line in this node that is a menu item. */ +int +build_menu () +{ + int pointer = nodetop; + char menuname[NODENAME_LEN]; + char nodename[NODENAME_LEN]; + + if (strcmp (menus_nodename, current_info_node) == 0 && + strcmp (menus_filename, current_info_file) == 0) + return (the_menu_size != 0); + + strcpy (menus_nodename, current_info_node); + strcpy (menus_filename, current_info_file); + free_completion_list (); + the_menu_size = 0; + + set_search_constraints (info_file, nodebot); + if ((pointer = search_forward (MENU_HEADER, nodetop)) < 0) + return (0); + + /* There is a menu here. Look for members of it. */ + pointer += strlen (MENU_HEADER); + + while (1) + { + int idx; + + pointer = search_forward (MENU_ID, pointer); + if (pointer < 0) + break; /* No more menus in this node. */ + + pointer = (skip_whitespace (pointer + strlen (MENU_ID))); + + idx = 0; + while ((menuname[idx] = info_file[pointer]) && menuname[idx] != ':') + idx++, pointer++; + + menuname[idx] = '\0'; + pointer++; + + if (info_file[pointer] == ':') + { + strcpy (nodename, menuname); + } + else + { + int in_parens; + + pointer = skip_whitespace (pointer); + idx = in_parens = 0; + + while ((nodename[idx] = info_file[pointer]) && + (in_parens || + (nodename[idx] != '\t' && + nodename[idx] != '.' && + nodename[idx] != ','))) + { + if (nodename[idx] == '(') + in_parens++; + else if (nodename[idx] == ')') + in_parens--; + + idx++, pointer++; + } + nodename[idx] = '\0'; + } + add_completion (menuname, nodename); + the_menu_size++; + } + if (the_menu_size) + completion_list = reverse_list (completion_list); + return (the_menu_size != 0); +} + +/* Select ITEMth item from a list built by build_menu (). */ +int +get_menu (item) + int item; +{ + if (!build_menu ()) + return (0); + + if (item > the_menu_size) + return (0); + else + { + COMP_ENTRY *temp = completion_list; + + while (--item && temp) + temp = temp->next; + + return (get_node ((char *) NULL, temp->data, 0)); + } +} + +/* Scan through the ?already? built menu list looking + for STRING. If you find it, put the corresponding nodes + name in NODENAME. */ +int +find_menu_node (string, nodename) + char *string, *nodename; +{ + return (scan_list (string, nodename)); +} + +/* The work part of find_menu_node and find_note_node. */ +int +scan_list (string, nodename) + char *string, *nodename; +{ + COMP_ENTRY *temp = completion_list; + + while (temp) + { + if (stricmp (string, temp->identifier, strlen (string)) == 0) + { + strcpy (nodename, temp->data); + return (1); + } + temp = temp->next; + } + return (0); +} + +/* Remove <CR> and whitespace from string, replacing them with + only one space. Exception: <CR> at end of string disappears. */ +clean_up (string) + char *string; +{ + char *to; + + /* Skip all whitespace characters found at the start of STRING. */ + while (whitespace (*string)) + string++; + + to = string; + + while (*to = *string++) + { + if (*to == '\n' || *to == ' ') + { + *to = ' '; + + while (*string == ' ' || *string == '\t') + string++; + } + to++; + } +} + +/* Find a reference to "*Note". Return the offset of the start + of that reference, or -1. */ +find_footnote_ref (from) + int from; +{ + while (1) + { + from = search_forward (FOOTNOTE_HEADER, from); + if (from < 0) + return (from); + else + from += strlen (FOOTNOTE_HEADER); + if (info_file[from] == ' ' || + info_file[from] == '\n' || + info_file[from] == '\t') + return (from); + } +} + +/* Build an array of (footnote.nodename) for each footnote in this node. */ +int +build_notes () +{ + int pointer; + char notename[NODENAME_LEN]; + char nodename[NODENAME_LEN]; + + set_search_constraints (info_file, nodebot); + + if ((find_footnote_ref (nodetop)) < 0) + return (0); + pointer = nodetop; + + menus_filename[0] = menus_nodename[0] = '\0'; + visible_footnote = ""; + free_completion_list (); + + while (1) + { + int idx; + + pointer = find_footnote_ref (pointer); + if (pointer < 0) + break; /* no more footnotes in this node. */ + + pointer = skip_whitespace_and_cr (pointer); + idx = 0; + + while ((notename[idx] = info_file[pointer]) && notename[idx] != ':') + { + idx++, pointer++; + } + + notename[idx] = '\0'; + clean_up (notename); + pointer++; + if (info_file[pointer] == ':') + { + strcpy (nodename, notename); + } + else + { + int in_parens = 0; + + pointer = skip_whitespace (pointer); + idx = 0; + + while ((nodename[idx] = info_file[pointer]) && + (in_parens || + (nodename[idx] != '\t' && + nodename[idx] != '.' && + nodename[idx] != ','))) + { + if (nodename[idx] == '(') + in_parens++; + else if (nodename[idx] == ')') + in_parens--; + + idx++, pointer++; + } + nodename[idx] = '\0'; + clean_up (nodename); + } + /* Add the notename/nodename to the list. */ + add_completion (notename, nodename); + the_menu_size++; + + /* Remember this identifier as the default if it is the first one in the + page. */ + if (!(*visible_footnote) && + pointer > pagetop && + pointer < forward_lines (the_window.bottom - the_window.top, pointer)) + visible_footnote = completion_list->identifier; + } + if (the_menu_size) + completion_list = reverse_list (completion_list); + return (the_menu_size != 0); +} + +/* Scan through the ?already? built footnote list looking for STRING. + If found, place the corresponding node name in NODENAME. */ +int +find_note_node (string, nodename) + char *string, *nodename; +{ + return (scan_list (string, nodename)); +} + +/* **************************************************************** */ +/* */ +/* Page Display */ +/* */ +/* **************************************************************** */ + + +/* The display functions for GNU Info. */ +int display_ch, display_cv; +int display_point; + +/* Display the current page from pagetop down to the bottom of the + page or the bottom of the node, whichever comes first. */ +display_page () +{ + display_point = pagetop; + display_ch = the_window.left; + display_cv = the_window.top; + generic_page_display (); +} + +/* Print the page from display_point to bottom of node, or window, + whichever comes first. Start printing at display_ch, display_cv. */ +generic_page_display () +{ + int done_with_display = 0; + int character; + + goto_xy (display_ch, display_cv); + + while (!done_with_display) + { + if (display_point == nodebot) + { + clear_eop (); + goto display_finish; + } + + character = info_file[display_point]; + + if ((display_width (character, the_window.ch) + the_window.ch) + >= the_window.right) + display_carefully (character); + else + charout (character); + + if ((the_window.cv >= the_window.bottom) + || (the_window.cv == the_window.top + && the_window.ch == the_window.left)) + { + display_finish: + pagebot = display_point; + make_modeline (); + done_with_display++; + continue; + } + else + display_point++; + } + fflush (stdout); +} + +/* Display character carefully, ensuring that no scrolling takes + place, even in the case of funky control characters. */ +display_carefully (character) + int character; +{ + if (CTRL_P (character)) + { + switch (character) + { + case RETURN: + case NEWLINE: + case TAB: + clear_eol (); + advance (the_window.right - the_window.ch); + break; + default: + charout ('^'); + if (the_window.cv == the_window.bottom) + break; + else + charout (UNCTRL (character)); + } + } + else + charout (character); +} + +/* Move the cursor to POSITION in page. Return non-zero if successful. */ +cursor_to (position) + int position; +{ + int ch, cv, character; + int point; + + if (position > pagebot || position < pagetop) + return (0); + + point = pagetop; + ch = the_window.left; + cv = the_window.top; + + while (point < position) + { + character = info_file[point++]; + + ch += display_width (character, ch); + + if (ch >= the_window.right) + { + ch = ch - the_window.right; + cv++; + + if (cv >= the_window.bottom) + return (0); + } + } + goto_xy (ch, cv); + return (1); +} + +/* Move to the next page in this node. Return 0 if + we can't get to the next page. */ +int +next_page () +{ + int pointer; + + pointer = + forward_lines ((the_window.bottom - the_window.top) - 2, pagetop); + + if (pointer >= nodebot) + return (0); + + /* Hack for screens smaller than displayed line width. */ + if (pointer > display_point) + { + pointer = display_point; + back_lines (1); + } + pagetop = pointer; + return (1); +} + +/* Move to the previous page in this node. Return zero if + there is no previous page. */ +int +prev_page () +{ + int pointer = + back_lines ((the_window.bottom - the_window.top) - 2, pagetop); + + if (pagetop == nodetop) + return (0); + + if (pointer < nodetop) + pointer = nodetop; + + pagetop = pointer; + return (1); +} + + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +char *search_buffer; /* area in ram to scan through. */ +int buffer_bottom; /* Length of this area. */ + +/* Set the global variables that all of these routines use. */ +set_search_constraints (buffer, extent) + char *buffer; + int extent; +{ + search_buffer = buffer; + buffer_bottom = extent; +} + +/* Move back to the start of this line. */ +to_beg_line (from) + int from; +{ + while (from && search_buffer[from - 1] != '\n') + from--; + return (from); +} + +/* Move forward to the end of this line. */ +to_end_line (from) +{ + while (from < buffer_bottom && search_buffer[from] != '\n') + from++; + return (from); +} + +/* Move back count lines in search_buffer starting at starting_pos. + Returns the start of that line. */ +back_lines (count, starting_pos) + int count, starting_pos; +{ + starting_pos = to_beg_line (starting_pos); + while (starting_pos && count) + { + starting_pos = to_beg_line (starting_pos - 1); + count--; + } + return (starting_pos); +} + +/* Move forward count lines starting at starting_pos. + Returns the start of that line. */ +forward_lines (count, starting_pos) + int count, starting_pos; +{ + starting_pos = to_end_line (starting_pos); + while (starting_pos < buffer_bottom && count) + { + starting_pos = to_end_line (starting_pos + 1); + count--; + } + return (to_beg_line (starting_pos)); +} + +/* Search for STRING in SEARCH_BUFFER starting at STARTING_POS. + Return the location of the string, or -1 if not found. */ +search_forward (string, starting_pos) + char *string; + int starting_pos; +{ + register int c, i, len; + register char *buff, *end; + char *alternate; + + + /* We match characters in SEARCH_BUFFER against STRING and ALTERNATE. + ALTERNATE is a case reversed version of STRING; this is cheaper than + case folding each character before comparison. */ + + /* Build the alternate string. */ + alternate = savestring (string); + len = strlen (string); + + for (i = 0; i < len; i++) + { + c = alternate[i]; + + if (c >= 'a' && c <= 'z') + alternate[i] = c - 32; + else if (c >= 'A' && c <= 'Z') + alternate[i] = c + 32; + } + + buff = search_buffer + starting_pos; + end = search_buffer + buffer_bottom + 1; + + while (buff < end) + { + for (i = 0; i < len; i++) + { + c = buff[i]; + + if (c != string[i] && c != alternate[i]) + break; + } + + if (!string[i]) + { + free (alternate); + return (buff - search_buffer); + } + + buff++; + } + + free (alternate); + return (-1); +} + +/* Search for STRING in SEARCH_BUFFER starting at STARTING_POS. + Return the location of the string, or -1 if not found. */ +search_backward (string, starting_pos) + char *string; + int starting_pos; +{ + int len = strlen (string); + while (starting_pos - len > -1) + { + if (strnicmp (search_buffer + (starting_pos - len), string, len) == 0) + return (starting_pos - len); + else + starting_pos--; + } + return (-1); +} + +/* Only search for STRING from POINTER to end of line. Return offset + of string, or -1 if not found. */ +string_in_line (string, pointer) + char *string; + int pointer; +{ + int old_buffer_bottom = buffer_bottom; + + set_search_constraints (search_buffer, to_end_line (pointer)); + pointer = search_forward (string, pointer); + buffer_bottom = old_buffer_bottom; + return (pointer); +} + +/* Skip whitespace characters at OFFSET in SEARCH_BUFFER. + Return the next non-whitespace character or -1 if BUFFER_BOTTOM + is reached. */ +skip_whitespace (offset) + int offset; +{ + int character; + + while (offset < buffer_bottom) + { + character = search_buffer[offset]; + if (character == ' ' || character == '\t') + offset++; + else + return (offset); + } + return (-1); +} + +/* Skip whitespace characters including <CR> at OFFSET in + SEARCH_BUFFER. Return the position of the next non-whitespace + character, or -1 if BUFFER_BOTTOM is reached. */ +skip_whitespace_and_cr (offset) + int offset; +{ + while (1) + { + offset = skip_whitespace (offset); + if (offset > 0 && search_buffer[offset] != '\n') + return (offset); + else + offset++; + } +} + +/* Extract the node name part of the of the text after the FIELD. + Place the node name into NODENAME. Assume the line starts at + OFFSET in SEARCH_BUFFER. */ +int +extract_field (field_name, nodename, offset) + char *field_name, *nodename; + int offset; +{ + int temp, character; + + temp = string_in_line (field_name, offset); + if (temp < 0) + return (0); + + temp += strlen (field_name); + temp = skip_whitespace (temp); + + /* Okay, place the following text into NODENAME. */ + + while ((character = search_buffer[temp]) != ',' + && character != '\n' + && character != '\t') + { + *nodename = character; + nodename++; + temp++; + } + *nodename = '\0'; + return (1); +} + +/* Return non-zero if pointer is exactly at string, else zero. */ +int +looking_at (string, pointer) + char *string; + int pointer; +{ + if (strnicmp (search_buffer + pointer, string, strlen (string)) == 0) + return (1); + else + return (0); +} + +/* File stack stuff. This is currently only used to push one file while + searching indirect files, but we may as well write it in full + generality. */ +typedef struct filestack +{ + struct filestack *next; + char filename[FILENAME_LEN]; + char current_filename[FILENAME_LEN]; + char *tag_table; + char *info_file; + int info_buffer_len; +} FILESTACK; + +FILESTACK *filestack = NULL; + +int +push_filestack (filename, remember_name) + char *filename; + int remember_name; +{ + FILESTACK *element = (FILESTACK *) xmalloc (sizeof (FILESTACK)); + + element->next = filestack; + filestack = element; + + strcpy (filestack->filename, last_loaded_info_file); + strcpy (filestack->current_filename, current_info_file); + filestack->tag_table = tag_table; + filestack->info_file = info_file; + filestack->info_buffer_len = info_buffer_len; + + *last_loaded_info_file = '\0'; /* force the file to be read */ + info_file = (char *)NULL; /* Pretend we have no buffer. */ + if (get_info_file (filename, remember_name)) + { + return (1); + } + else + { + pop_filestack (); + return (0); + } +} + +void +pop_filestack () +{ + FILESTACK *temp; + + if (filestack == NULL) + { + fprintf (stderr , "File stack is empty and can't be popped\n"); + brians_error (); + return; + } + + free (info_file); + + strcpy (last_loaded_info_file, filestack->filename); + strcpy (current_info_file, filestack->current_filename); + tag_table = filestack->tag_table; + info_file = filestack->info_file; + info_buffer_len = filestack->info_buffer_len; + set_search_constraints (info_file, info_buffer_len); + + temp = filestack; + filestack = filestack->next; + free ((char *)temp); +} + +/* Swap the current info file with the bottom of the filestack */ +void +swap_filestack () +{ + char t_last_loaded_info_file[FILENAME_LEN]; + char t_current_info_file[FILENAME_LEN]; + char *t_tag_table; + char *t_info_file; + int t_info_buffer_len; + + if (filestack == NULL) + { + fprintf (stderr , "File stack is empty and can't be swapped\n"); + brians_error (); + return; + } + + strcpy (t_last_loaded_info_file, filestack->filename); + strcpy (t_current_info_file, filestack->current_filename); + t_tag_table = filestack->tag_table; + t_info_file = info_file; + t_info_buffer_len = info_buffer_len; + + strcpy (filestack->filename, last_loaded_info_file); + strcpy (filestack->current_filename, current_info_file); + filestack->tag_table = tag_table; + filestack->info_file = info_file; + filestack->info_buffer_len = info_buffer_len; + + strcpy (last_loaded_info_file, t_last_loaded_info_file); + strcpy (current_info_file, t_current_info_file); + tag_table = t_tag_table; + info_file = t_info_file; + info_buffer_len = t_info_buffer_len; +} + +/* Now the node history stack */ + +extern NODEINFO *Info_History; + +/* Save the current filename, nodename, and position on the history list. + We prepend. */ +int +push_node (filename, nodename, page_position, node_position) + char *filename, *nodename; + int page_position, node_position; +{ + NODEINFO *newnode = (NODEINFO *) xmalloc (sizeof (NODEINFO)); + + newnode->next = Info_History; + + newnode->filename = (char *) xmalloc (strlen (filename) + 1); + strcpy (newnode->filename, filename); + + newnode->nodename = (char *) xmalloc (strlen (nodename) + 1); + strcpy (newnode->nodename, nodename); + + newnode->pagetop = page_position; + newnode->nodetop = node_position; + + Info_History = newnode; + return (1); +} + +/* Pop one node from the node list, leaving the values in + passed variables. */ +int +pop_node (filename, nodename, nodetop, pagetop) + char *filename, *nodename; + int *nodetop, *pagetop; +{ + if (Info_History->next == (NODEINFO *) NULL) + { + display_error ("At beginning of history now!"); + return (0); + } + else + { + NODEINFO *releaser = Info_History; + + /* If the popped file is not the current file, then force + the popped file to be loaded. */ + if (strcmp (Info_History->filename, last_loaded_info_file) != 0) + last_loaded_info_file[0] = '\0'; + + strcpy (filename, Info_History->filename); + strcpy (nodename, Info_History->nodename); + *pagetop = Info_History->pagetop; + *nodetop = Info_History->nodetop; + free (Info_History->nodename); + free (Info_History->filename); + Info_History = Info_History->next; + free (releaser); + return (1); + } +} + +/* Whoops, Unix doesn't have strnicmp. */ + +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +int +strnicmp (string1, string2, count) + char *string1, *string2; +{ + char ch1, ch2; + + while (count) + { + ch1 = *string1++; + ch2 = *string2++; + if (to_upper (ch1) == to_upper (ch2)) + count--; + else + break; + } + return (count); +} + +/* Compare string1 to string2. Case doesn't matter. */ +int +stricmp (string1, string2) + char *string1, *string2; +{ + char ch1, ch2; + + while (1) + { + ch1 = *string1++; + ch2 = *string2++; + + if (ch1 == '\0') + return (ch2 != '\0'); + + if ((ch2 == '\0') || + (to_upper (ch1) != to_upper (ch2))) + return (1); + } +} + +/* Make the user type "Y" or "N". */ +int +get_y_or_n_p () +{ + int character; + print_string (" (Y or N)?"); + clear_eol (); + +until_we_like_it: + + character = blink_cursor (); + if (character == EOF) + return (0); + if (to_upper (character) == 'Y') + { + charout (character); + return (1); + } + + if (to_upper (character) == 'N') + { + charout (character); + return (0); + } + + if (character == ABORT_CHAR) + { + ding (); + return (0); + } + + goto until_we_like_it; +} + +/* Move the cursor to the desired column in the window. */ +indent_to (screen_column) + int screen_column; +{ + int counter = screen_column - the_window.ch; + if (counter > 0) + { + while (counter--) + charout (' '); + } + else if (screen_column != 0) + charout (' '); +} + + +/* **************************************************************** */ +/* */ +/* Error output/handling. */ +/* */ +/* **************************************************************** */ + +/* Display specific error from known file error table. */ +file_error (file) + char *file; +{ + extern int errno; + extern int sys_nerr; + extern char *sys_errlist[]; + + if (errno < sys_nerr) + display_error ("%s: %s", file, sys_errlist[errno]); + else + display_error ("%s: Unknown error %d", file, errno); +} + +/* Display the error in the echo-area using format_string and args. + This is a specialized interface to printf. */ +display_error (format_string, arg1, arg2) + char *format_string; +{ + extern int terminal_inited_p; + char output_buffer[1024]; + + if (totally_inhibit_errors) + return; + + sprintf (output_buffer, format_string, arg1, arg2); + if (terminal_inited_p) + { + new_echo_area (); + ding (); + print_string ("%s", output_buffer); + close_echo_area (); + } + else + { + fprintf (stderr, "%s\n", output_buffer); + } +} + +/* Tell everybody what a loser I am. If you see this error, + send me a bug report. */ +brians_error () +{ + display_error ("You are never supposed to see this error.\n"); + display_error ("Tell bfox@ai.mit.edu to fix this someday.\n"); + return (-1); +} + +/* **************************************************************** */ +/* */ +/* Terminal IO, and Driver */ +/* */ +/* **************************************************************** */ + +/* The Unix termcap interface code. */ + +#define NO_ERROR 0 +#define GENERIC_ERROR 1 +#define NO_TERMINAL_DESCRIPTOR 2 +#define OUT_OF_MEMORY 3 +#define BAD_TERMINAL 4 + +#define FERROR(msg) fprintf (stderr, msg); exit (GENERIC_ERROR) + +extern int tgetnum (), tgetflag (); +extern char *tgetstr (); +extern char *tgoto (); + +#define Certainly_enough_space 2048 /* page 3, Section 1.1, para 4 */ + +#if defined (unix) +char termcap_buffer[Certainly_enough_space]; +#else /* !unix */ +#define termcap_buffer NULL +#endif /* !unix */ + +/* You CANNOT remove these next four vars. TERMCAP needs them to operate. */ +char PC; +char *BC; +char *UP; + +/* A huge array of stuff to get from termcap initialization. */ + +#define tc_int 0 +#define tc_char tc_int+1 +#define tc_flag tc_char+1 +#define tc_last tc_flag+1 + +typedef int flag; + +/* First, the variables which this array refers to */ + +/* Capabilities */ + +#if 0 /* partain moved them */ +int terminal_columns; /* {tc_int, "co" */ +int terminal_rows; /* {tc_int, "li" */ +#endif +flag terminal_is_generic; /* {tc_flag,"gn" */ + + /* Cursor Motion */ + +char *terminal_goto; /* {tc_char,"cm" */ +char *terminal_home; /* {tc_char,"ho" */ + +char *terminal_cursor_left; /* {tc_char,"le" */ +char *terminal_cursor_right; /* {tc_char,"nd" */ +char *terminal_cursor_up; /* {tc_char,"up" */ +char *terminal_cursor_down; /* {tc_char,"do" */ + +/* Screen Clearing */ + +char *terminal_clearpage; /* {tc_char,"cl" */ +char *terminal_clearEOP; /* {tc_char,"cd" */ +char *terminal_clearEOL; /* {tc_char,"ce" */ + +/* "Standout" */ +char *terminal_standout_begin; /* {tc_char,"so" */ +char *terminal_standout_end; /* {tc_char,"se" */ + +/* Reverse Video */ +char *terminal_inverse_begin; /* {tc_char,"mr" */ +char *terminal_end_attributes; /* {tc_char,"me" */ + +/* Ding! */ + +char *terminal_ear_bell; /* {tc_char,"bl" */ + +/* Terminal Initialization */ + +char *terminal_use_begin; /* {tc_char,"ti" */ +char *terminal_use_end; /* {tc_char,"te" */ + +/* Padding Stuff */ + +char *terminal_padding; /* {tc_char,"pc" */ + +/* Now the whopping big array */ + +typedef struct { + char type; + char *name; + char *value; +} termcap_capability_struct; + +termcap_capability_struct capabilities[] = { + +/* Capabilities */ + + {tc_int, "co", (char *) &terminal_columns}, + {tc_int, "li", (char *) &terminal_rows}, + {tc_flag, "gn", (char *) &terminal_is_generic}, + +/* Cursor Motion */ + + {tc_char, "cm", (char *) &terminal_goto}, + {tc_char, "ho", (char *) &terminal_home}, + + {tc_char, "le", (char *) &terminal_cursor_left}, + {tc_char, "nd", (char *) &terminal_cursor_right}, + {tc_char, "up", (char *) &terminal_cursor_up}, + {tc_char, "do", (char *) &terminal_cursor_down}, + +/* Screen Clearing */ + + {tc_char, "cl", (char *) &terminal_clearpage}, + {tc_char, "cd", (char *) &terminal_clearEOP}, + {tc_char, "ce", (char *) &terminal_clearEOL}, + +/* "Standout" */ + {tc_char, "so", (char *) &terminal_standout_begin}, + {tc_char, "se", (char *) &terminal_standout_end}, + +/* Reverse Video */ + {tc_char, "mr", (char *) &terminal_inverse_begin}, + {tc_char, "me", (char *) &terminal_end_attributes}, + +/* Ding! */ + + {tc_char, "bl", (char *) &terminal_ear_bell}, + +/* Terminal Initialization */ + + {tc_char, "ti", (char *) &terminal_use_begin}, + {tc_char, "te", (char *) &terminal_use_end}, + +/* Padding Stuff */ + + {tc_char, "pc", (char *) &terminal_padding}, + +/* Terminate this array with a var of type tc_last */ + {tc_last, NULL, NULL} + +}; + +int terminal_opened_p = 0; + +open_terminal_io () +{ + int error; + + if (terminal_opened_p) + return (NO_ERROR); + + if ((error = get_terminal_info ()) != NO_ERROR) + return (error); + + if ((error = get_terminal_vars (capabilities)) != NO_ERROR) + return (error); + + /* Now, make sure we have the capabilites that we need. */ + if (terminal_is_generic) + return (BAD_TERMINAL); + + terminal_opened_p++; + return (NO_ERROR); +} + +get_terminal_info () +{ + char temp_string_buffer[256]; + int result; + + char *terminal_name = getenv ("TERM"); + + if (terminal_name == NULL || *terminal_name == 0 + || (strcmp (terminal_name, "dialup") == 0)) + { + terminal_name = temp_string_buffer; + printf ("\nTerminal Type:"); + fflush (stdout); + fgets (terminal_name, 256, stdin); + if (!(*terminal_name)) + return (NO_TERMINAL_DESCRIPTOR); + } + +/* #define VERBOSE_GET_TERMINAL 1 */ +#ifdef VERBOSE_GET_TERMINAL + +#define buffer_limit 256 +#define opsys_termcap_filename "/etc/termcap" + + /* We hack question mark if that is what the user typed. All this means + is we read /etc/termcap, and prettily print out the names of terminals + that we find. */ + + if (terminal_name[0] == '?' && !terminal_name[1]) + { + FILE *termcap_file; + if ((termcap_file = fopen (opsys_termcap_filename, "r")) != NULL) + { + int result; + char line_buffer[buffer_limit]; + int terminal_count = 0; + + while ((readline_termcap (termcap_file, line_buffer)) != EOF) + { + char first_char = *line_buffer; + if (first_char == '#' || first_char == ' ' + || first_char == '\t' || first_char == '\n') + ; + else + { + /* Print the names the pretty way. */ + printf ("\n%s", line_buffer); /* liar */ + terminal_count++; + } + } + fclose (termcap_file); + + if (terminal_count) + printf ("\n%d terminals listed.\n", terminal_count); + else + printf ("\nNo terminals were listed. Brian's mistake.\n"); + } + else + { + fprintf (stderr, + "\nNo such system file as %s!\nWe lose badly.\n", + opsys_termcap_filename); + return (NO_TERMINAL_DESCRIPTOR); + } + return (get_terminal_info ()); + } +#endif /* VERBOSE_GET_TERMINAL */ + + result = tgetent (termcap_buffer, terminal_name); + + if (!result) + return (NO_TERMINAL_DESCRIPTOR); + else + return (NO_ERROR); +} + +#ifdef VERBOSE_GET_TERMINAL +readline_termcap (stream, buffer) + FILE *stream; + char *buffer; +{ + int c; + int buffer_index = 0; + + while ((c = getc (stream)) != EOF && c != '\n') + { + if (buffer_index != buffer_limit - 1) + buffer[buffer_index++] = c; + } + + buffer[buffer_index] = 0; + + if (c == EOF) + return ((buffer_index) ? 0 : EOF); + else + return (0); +} +#endif /* VERBOSE_GET_TERMINAL */ + +/* For each element of "from_array", read the corresponding variable's + value into the right place. */ +get_terminal_vars (from_array) + termcap_capability_struct from_array[]; +{ + int i; + register termcap_capability_struct *item; + char *buffer; + +#if !defined (GNU_TERMCAP) + buffer = (char *) xmalloc (sizeof (termcap_buffer) + 1); +# define buffer_space &buffer +#else +# define buffer_space 0 +#endif + + for (i = 0; (item = &from_array[i]) && (item->type != tc_last); i++) + { + switch (item->type) + { + case tc_int: + *((int *) (item->value)) = tgetnum (item->name); + break; + + case tc_flag: + *((int *) item->value) = tgetflag (item->name); + break; + + case tc_char: + *((char **) item->value) = tgetstr (item->name, buffer_space); + break; + + default: + FERROR ("Bad entry scanned in tc_struct[].\n \ + Ask bfox@ai.mit.edu to fix this someday.\n"); + } + } + + PC = terminal_padding ? terminal_padding[0] : 0; + BC = terminal_cursor_left; + UP = terminal_cursor_up; + return (NO_ERROR); +} + +/* Return the number of rows this terminal has. */ +int +get_terminal_rows () +{ + int rows = 0; + +#if defined (TIOCGWINSZ) + { + int tty; + struct winsize size; + + tty = fileno (stdin); + + if (ioctl (tty, TIOCGWINSZ, &size) != -1) + rows = size.ws_row; + } +#endif /* TIOCGWINSZ */ + + if (!rows) + rows = tgetnum ("li"); + + if (rows <= 0) + rows = 24; + + return (rows); +} + +/* Return the number of columns this terminal has. */ +get_terminal_columns () +{ + int columns = 0; + +#if defined (TIOCGWINSZ) + { + int tty; + struct winsize size; + + tty = fileno (stdin); + + if (ioctl (tty, TIOCGWINSZ, &size) != -1) + columns = size.ws_col; + } +#endif /* TIOCGWINSZ */ + + if (!columns) + columns = tgetnum ("co"); + + if (columns <= 0) + columns = 80; + + return (columns); +} + +/* #define TERMINAL_INFO_PRINTING */ +#ifdef TERMINAL_INFO_PRINTING + +/* Scan this (already "get_terminal_vars"ed) array, printing out the + capability name, and value for each entry. Pretty print the value + so that the terminal doesn't actually do anything, shitbrain. */ +show_terminal_info (from_array) + termcap_capability_struct from_array[]; +{ + register int i; + register termcap_capability_struct *item; + + for (i = 0; ((item = &from_array[i]) && ((item->type) != tc_last)); i++) + { + + char *type_name; + switch (item->type) + { + case tc_int: + type_name = "int "; + break; + case tc_flag: + type_name = "flag"; + break; + case tc_char: + type_name = "char"; + break; + default: + type_name = "Broken"; + } + + printf ("\t%s\t%s = ", type_name, item->name); + + switch (item->type) + { + case tc_int: + case tc_flag: + printf ("%d", *((int *) item->value)); + break; + case tc_char: + tc_pretty_print (*((char **) item->value)); + break; + } + printf ("\n"); + } +} + +/* Print the contents of string without sending anything that isn't + a normal printing ASCII character. */ +tc_pretty_print (string) + register char *string; +{ + register char c; + + while (c = *string++) + { + if (CTRLP (c)) + { + putchar ('^'); + c += 64; + } + putchar (c); + } +} +#endif /* TERMINAL_INFO_PRINTING */ + + +/* **************************************************************** */ +/* */ +/* Character IO, and driver */ +/* */ +/* **************************************************************** */ + +int terminal_inited_p = 0; + +/* Start up the character io stuff. */ +init_terminal_io () +{ + if (!terminal_inited_p) + { + opsys_init_terminal (); + terminal_rows = get_terminal_rows (); + terminal_columns = get_terminal_columns (); + + widest_line = (char *) xmalloc (terminal_columns); + + terminal_inited_p = 1; + } + + terminal_window.left = 0; + terminal_window.top = 0; + terminal_window.right = terminal_columns; + terminal_window.bottom = terminal_rows; + + set_window (&terminal_window); + + terminal_window.bottom -= 2; + + set_window (&terminal_window); + + init_echo_area (the_window.left, the_window.bottom + 1, + the_window.right, terminal_rows); + + /* Here is a list of things that the terminal has to be able to do. Do + you think that this is too harsh? */ + if (!terminal_goto || /* We can't move the cursor. */ + !terminal_rows) /* We don't how many lines it has. */ + { + fprintf (stderr, + "Your terminal is not clever enough to run info. Sorry.\n"); + exit (1); + } +} + +/* Ring the terminal bell. */ +ding () +{ + extern char *terminal_ear_bell; + + if (terminal_ear_bell) + do_term (terminal_ear_bell); + else + putchar (CTRL ('G')); + + fflush (stdout); +} + +int untyi_char = 0; +int inhibit_output = 0; + +/* Return a character from stdin, or the last unread character + if there is one available. */ +blink_cursor () +{ + int character; + + fflush (stdout); + if (untyi_char) + { + character = untyi_char; + untyi_char = 0; + } + else + do { character = getc (stdin); } while (character == -1 && errno == EINTR); + + return (character); +} + +/* Display single character on the terminal screen. If the + character would run off the right hand edge of the screen, + advance the cursor to the next line. */ +charout (character) + int character; +{ + if (inhibit_output) + return; + + /* This character may need special treatment if it is + a control character. */ + if (CTRL_P (character)) + { + switch (character) + { + case NEWLINE: + case RETURN: + print_cr (); + break; + + case TAB: + print_tab (); + break; + + default: + charout ('^'); + charout (UNCTRL (character)); + } + } + else + { + putchar (character); + advance (1); + } +} + +/* Move the cursor AMOUNT character positions. */ +advance (amount) + int amount; +{ + int old_window_cv = the_window.cv; + + while (amount-- > 0) + { + the_window.ch++; + if (the_window.ch >= the_window.right) + { + the_window.ch = (the_window.ch - the_window.right) + the_window.left; + the_window.cv++; + + if (the_window.cv >= the_window.bottom) + the_window.cv = the_window.top; + } + } + + if (the_window.cv != old_window_cv) + goto_xy (the_window.ch, the_window.cv); +} + +/* Print STRING and args using charout */ +print_string (string, a1, a2, a3, a4, a5) + char *string; +{ + int character; + char buffer[2048]; + int idx = 0; + + sprintf (buffer, string, a1, a2, a3, a4, a5); + + while (character = buffer[idx++]) + charout (character); + + fflush (stdout); +} + +/* Display a carriage return. + Clears to the end of the line first. */ +print_cr () +{ + extern int typing_out; + clear_eol (); + + if (typing_out) + { /* Do the "MORE" stuff. */ + int response; + + if (the_window.cv + 2 == the_window.bottom) + { + goto_xy (the_window.left, the_window.cv + 1); + clear_eol (); + print_string ("[More]"); + response = blink_cursor (); + if (response != SPACE) + { + untyi_char = response; + inhibit_output = 1; + return; + } + else + { + goto_xy (the_window.left, the_window.cv); + clear_eol (); + goto_xy (the_window.left, the_window.top); + return; + } + } + } + advance (the_window.right - the_window.ch); +} + +/* Move the cursor to the next tab stop, blanking the intervening + spaces along the way. */ +print_tab () +{ + int hpos, width, destination; + + hpos = the_window.ch - the_window.left; + width = ((hpos + 8) & 0xf8) - hpos; + + destination = hpos + width + the_window.left; + + if (destination >= the_window.right) + destination -= the_window.right; + + while (the_window.ch != destination) + charout (SPACE); +} + +display_width (character, hpos) + int character, hpos; +{ + int width = 1; + + if (CTRL_P (character)) + { + switch (character) + { + case RETURN: + case NEWLINE: + width = the_window.right - hpos; + break; + case TAB: + width = ((hpos + 8) & 0xf8) - hpos; + break; + default: + width = 2; + } + } + return (width); +} + +/* Like GOTO_XY, but do it right away. */ +I_goto_xy (xpos, ypos) + int xpos, ypos; +{ + goto_xy (xpos, ypos); + fflush (stdout); +} + +/* Move the cursor, (and cursor variables) to xpos, ypos. */ +goto_xy (xpos, ypos) + int xpos, ypos; +{ + the_window.ch = xpos; + the_window.cv = ypos; + opsys_goto_pos (xpos, ypos); +} + +/* Clear the screen, leaving ch and cv at the top of the window. */ +clear_screen () +{ + goto_xy (the_window.left, the_window.top); + clear_eop_slowly (); +} + +clear_eop_slowly () +{ + int temp_ch = the_window.ch; + int temp_cv = the_window.cv; + + clear_eol (); + + while (++the_window.cv < the_window.bottom) + { + goto_xy (the_window.left, the_window.cv); + clear_eol (); + } + goto_xy (temp_ch, temp_cv); +} + +/* Clear from current cursor position to end of page. */ +clear_eop () +{ + if (terminal_clearEOP) + do_term (terminal_clearEOP); + else + clear_eop_slowly (); +} + +/* Clear from current cursor position to end of screen line */ +clear_eol () +{ + int temp_ch = the_window.ch; + + if (terminal_clearEOL) + do_term (terminal_clearEOL); + else + { + char *line = widest_line; + int i; + + for (i = 0; i < the_window.right - the_window.ch; i++) + line[i] = ' '; + line[i] = '\0'; + + printf ("%s", line); + } + goto_xy (temp_ch, the_window.cv); +} + +/* Call FUNCTION with WINDOW active. You can pass upto 5 args to the + function. This returns whatever FUNCTION returns. */ +int +with_output_to_window (window, function, arg1, arg2, arg3, arg4, arg5) + WINDOW *window; + Function *function; +{ + int result; + + push_window (); + set_window (window); + result = (*function) (arg1, arg2, arg3, arg4, arg5); + pop_window (); + return (result); +} + +/* Given a pointer to a window data structure, make that + the current window. */ +set_window (window) + WINDOW *window; +{ + bcopy (window, &the_window, sizeof (WINDOW)); +} + +/* Save the current window on the window stack. */ +push_window () +{ + WINDOW_LIST *new_window = (WINDOW_LIST *) xmalloc (sizeof (WINDOW_LIST)); + + new_window->next_window = window_stack; + window_stack = new_window; + new_window->ch = the_window.ch; + new_window->cv = the_window.cv; + new_window->top = the_window.top; + new_window->bottom = the_window.bottom; + new_window->left = the_window.left; + new_window->right = the_window.right; +} + +/* Pop the top of the window_stack into the_window. */ +pop_window () +{ + set_window ((WINDOW *)window_stack); + + if (window_stack->next_window) + { + WINDOW_LIST *thing_to_free = window_stack; + window_stack = window_stack->next_window; + free (thing_to_free); + } + + goto_xy (the_window.ch, the_window.cv); +} + +/* **************************************************************** */ +/* */ +/* "Opsys" functions. */ +/* */ +/* **************************************************************** */ + +/* The lowlevel terminal/file interface. Nothing ever really gets + low level when you're writing in C, though. + + This file contains all of the "opsys" labels. You have to make + a different one if you want GNU Info to run on machines that don't + have Unix. */ + +extern char *terminal_use_begin, *terminal_use_end, *terminal_goto; + +#if defined (TIOCGETC) +struct tchars original_tchars; +#endif + +#if defined (TIOCGLTC) +struct ltchars original_ltchars; +#endif + +#if defined (USG) +struct termio original_termio, ttybuff; +#else +int original_tty_flags = 0; +int original_lmode; +struct sgttyb ttybuff; +#endif /* !USG */ + +/* Yes, that's right, do things that the machine needs to get + the terminal into a usable mode. */ +opsys_init_terminal () +{ + int tty = fileno (stdin); + +#if defined (USG) + ioctl (tty, TCGETA, &original_termio); + ioctl (tty, TCGETA, &ttybuff); + ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL &~IXON); + ttybuff.c_oflag &= (~ONLCR & ~OCRNL); + ttybuff.c_lflag &= (~ICANON & ~ECHO); + + ttybuff.c_cc[VMIN] = 1; + ttybuff.c_cc[VTIME] = 0; + + if (ttybuff.c_cc[VINTR] = DELETE) + ttybuff.c_cc[VINTR] = -1; + + if (ttybuff.c_cc[VQUIT] = DELETE) + ttybuff.c_cc[VQUIT] = -1; + + ioctl (tty, TCSETA, &ttybuff); +#else /* !USG */ + + ioctl (tty, TIOCGETP, &ttybuff); + + if (!original_tty_flags) + original_tty_flags = ttybuff.sg_flags; + + /* Make this terminal pass 8 bits around while we are using it. */ +#ifdef PASS8 + ttybuff.sg_flags |= PASS8; +#endif + +#if defined (TIOCLGET) && defined (LPASS8) + { + int flags; + ioctl (tty, TIOCLGET, &flags); + original_lmode = flags; + flags |= LPASS8; + ioctl (tty, TIOCLSET, &flags); + } +#endif + +#ifdef TIOCGETC + { + struct tchars temp; + + ioctl (tty, TIOCGETC, &original_tchars); + bcopy (&original_tchars, &temp, sizeof (struct tchars)); + + temp.t_startc = temp.t_stopc = -1; + + /* If the quit character conflicts with one of our commands, then + make it go away. */ + if (temp.t_intrc == DELETE) + temp.t_intrc == -1; + + if (temp.t_quitc == DELETE) + temp.t_quitc == -1; + + ioctl (tty, TIOCSETC, &temp); + } +#endif /* TIOCGETC */ + +#ifdef TIOCGLTC + { + struct ltchars temp; + + ioctl (tty, TIOCGLTC, &original_ltchars); + bcopy (&original_ltchars, &temp, sizeof (struct ltchars)); + + /* Make the interrupt keys go away. Just enough to make people happy. */ + temp.t_lnextc = -1; /* C-v */ + + ioctl (tty, TIOCSLTC, &temp); + } +#endif /* TIOCGLTC */ + + ttybuff.sg_flags &= ~ECHO; + ttybuff.sg_flags |= CBREAK; + ioctl (tty, TIOCSETN, &ttybuff); +#endif /* !USG */ + + open_terminal_io (); + do_term (terminal_use_begin); +} + +/* Fix the terminal that I broke. */ +restore_io () +{ + int tty = fileno (stdin); + +#if defined (USG) + ioctl (tty, TCSETA, &original_termio); +#else + ioctl (tty, TIOCGETP, &ttybuff); + ttybuff.sg_flags = original_tty_flags; + ioctl (tty, TIOCSETN, &ttybuff); + +#ifdef TIOCGETC + ioctl (tty, TIOCSETC, &original_tchars); +#endif /* TIOCGETC */ + +#ifdef TIOCGLTC + ioctl (tty, TIOCSLTC, &original_ltchars); +#endif /* TIOCGLTC */ + +#if defined (TIOCLGET) && defined (LPASS8) + ioctl (tty, TIOCLSET, &original_lmode); +#endif + +#endif /* !USG */ + do_term (terminal_use_end); +} + +opsys_goto_pos (xpos, ypos) + int xpos, ypos; +{ + do_term (tgoto (terminal_goto, xpos, ypos)); +} + +character_output_function (character) + char character; +{ + putchar (character); +} + +/* Generic interface to tputs. */ +do_term (command) + char *command; +{ + /* Send command to the terminal, with appropriate padding. */ + if (command) + tputs (command, 1, character_output_function); +} + +/* Filename manipulators, and the like. */ +char local_temp_filename[FILENAME_LEN]; + +char *info_suffixes[] = { + "", + ".info", + "-info", + (char *)NULL +}; + +/* A structure which associates the argument passed into a function with + the result from that function. */ +typedef struct { + char *called; + char *result; +} CALLED_RESULTS; + +/* An array of remembered arguments and results. */ +static CALLED_RESULTS **opsys_callers_and_results = (CALLED_RESULTS **)NULL; +static int next_caller_and_result = 0; +static int callers_and_results_size = 0; + +/* Find the result for having already called opsys_filename () with CALLER. */ +char * +find_opsys_filename_result (caller) + char *caller; +{ + if (caller && opsys_callers_and_results) + { + register int i; + for (i = 0; opsys_callers_and_results[i]; i++) + { + if (strcmp (opsys_callers_and_results[i]->called, caller) == 0) + return (opsys_callers_and_results[i]->result); + } + } + return (char *)NULL;; +} + +/* Add an argument and result to our list. */ +void +add_caller_and_result (caller, result) + char *caller, *result; +{ + CALLED_RESULTS *new; + + if (next_caller_and_result + 2 > callers_and_results_size) + { + int alloc_size; + callers_and_results_size += 10; + + alloc_size = callers_and_results_size * sizeof (CALLED_RESULTS *); + + opsys_callers_and_results = (CALLED_RESULTS **) + xrealloc (opsys_callers_and_results, alloc_size); + } + + new = (CALLED_RESULTS *)xmalloc (sizeof (CALLED_RESULTS)); + new->called = savestring (caller); + new->result = result ? savestring (result) : (char *)NULL; + + opsys_callers_and_results[next_caller_and_result++] = new; + opsys_callers_and_results[next_caller_and_result] = (CALLED_RESULTS *)NULL; +} + +/* Expand the filename in partial to make a real name for + this operating system. This looks in INFO_PATHS in order to + find the correct file. If it can't find the file, it just + returns the path as you gave it. */ +char * +opsys_filename (partial) + char *partial; +{ + int initial_character; + char *my_infopath; + + if (partial && (initial_character = *partial)) + { + char *possible_result; + + if (initial_character == '/') + return (partial); + + possible_result = find_opsys_filename_result (partial); + if (possible_result) + return (possible_result); + + if (initial_character == '~') + { + if (partial[1] == '/') + { + /* Return the concatenation of HOME and the rest + of the string. */ + strcpy (local_temp_filename, getenv ("HOME")); + strcat (local_temp_filename, &partial[2]); + return (local_temp_filename); + } + else + { + struct passwd *user_entry; + int i, c; + char username[257]; + + for (i = 1; c = partial[i]; i++) + { + if (c == '/') + break; + else + username[i - 1] = c; + } + username[i - 1] = '\0'; + + if (!(user_entry = getpwnam (username))) + { + display_error ("Not a registered user!"); + return (partial); + } + strcpy (local_temp_filename, user_entry->pw_dir); + strcat (local_temp_filename, &partial[i]); + return (local_temp_filename); + } + } + + if (initial_character == '.' && + (partial[1]) == '/' || (partial[1] == '.' && partial[2] == '/')) + { +#if defined (USG) + if (!getcwd (local_temp_filename, FILENAME_LEN)) +#else + if (!getwd (local_temp_filename)) +#endif + { + display_error (local_temp_filename); + return (partial); + } + + strcat (local_temp_filename, "/"); + strcat (local_temp_filename, partial); + return (local_temp_filename); + } + + /* If the current info file has a directory, then search that directory + first. */ + { + register char *ptr, *file; + + file = find_opsys_filename_result (current_info_file); + + if (file && (ptr = (char *)rindex (file, '/')) != (char *)NULL) + { + register int len = (ptr - file); + + my_infopath = (char *) + xmalloc (2 + strlen (file) + strlen (infopath)); + + strncpy (my_infopath, file, len); + sprintf (my_infopath + len, ":%s", infopath); + } + else + my_infopath = savestring (infopath); + } + + if (opsys_info_file_in_path (partial, my_infopath, local_temp_filename)) + { + free (my_infopath); + add_caller_and_result (partial, local_temp_filename); + return (local_temp_filename); + } + + free (my_infopath); + } + return (partial); +} + +#if !defined (S_ISREG) && defined (S_IFREG) +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif /* !S_ISREG && S_IFREG */ + +#if !defined (S_ISDIR) && defined (S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif /* !S_ISDIR && S_IFDIR */ + +/* Scan the list of directories in PATH looking for FILENAME. + If we find one that is a regular file, stuff the answer into + RETURN_STRING. Return non-zero if a file was found, zero otherwise. */ +int +opsys_info_file_in_path (filename, path, return_string) + char *filename, *path; + char *return_string; +{ + struct stat finfo; + char *temp_dirname, *extract_colon_unit (); + char *test_file = return_string; + int statable, dirname_index = 0; + + while (temp_dirname = extract_colon_unit (path, &dirname_index)) + { + register int i, pre_suffix_length; + + strcpy (test_file, temp_dirname); + if (temp_dirname[(strlen (temp_dirname)) - 1] != '/') + strcat (test_file, "/"); + strcat (test_file, filename); + + pre_suffix_length = strlen (test_file); + + free (temp_dirname); + + for (i = 0; info_suffixes[i]; i++) + { + strcpy (test_file + pre_suffix_length, info_suffixes[i]); + + statable = (stat (test_file, &finfo) == 0); + + /* If we have found a regular file, then use that. Else, if we + have found a directory, look in that directory for this file. */ + if (statable) + { + if (S_ISREG (finfo.st_mode)) + return (1); + else if (S_ISDIR (finfo.st_mode)) + { + char *newpath = savestring (test_file); + char *filename_only = (char *)rindex (filename, '/'); + + if (opsys_info_file_in_path + (filename_only ? filename_only : filename, + newpath, return_string)) + { + free (newpath); + return (1); + } + } + } + } + } + return (0); +} + +/* Given a string containing units of information separated by colons, + return the next one pointed to by IDX, or NULL if there are no more. + Advance IDX to the character after the colon. */ +char * +extract_colon_unit (string, idx) + char *string; + int *idx; +{ + register int i, start; + + i = start = *idx; + if ((i >= strlen (string)) || !string) + return ((char *) NULL); + + while (string[i] && string[i] != ':') + i++; + if (i == start) + { + return ((char *) NULL); + } + else + { + char *value = (char *) xmalloc (1 + (i - start)); + strncpy (value, &string[start], (i - start)); + value[i - start] = '\0'; + if (string[i]) + ++i; + *idx = i; + return (value); + } +} + +/* **************************************************************** */ +/* */ +/* The echo area. */ +/* */ +/* **************************************************************** */ + +WINDOW echo_area = {0, 0, 0, 0, 0, 0}; +int echo_area_open_p = 0; +char modeline[256]; +WINDOW modeline_window = {0, 0, 0, 0, 0, 0}; + +/* Define the location of the echo area. Also inits the + modeline as well. */ +init_echo_area (left, top, right, bottom) + int left, top, right, bottom; +{ + echo_area.left = modeline_window.left = left; + echo_area.top = top; + modeline_window.top = top - 1; + echo_area.right = modeline_window.right = right; + echo_area.bottom = bottom; + modeline_window.bottom = modeline_window.top; +} + +/* Make the echo_area_window be the current window, and only allow + output in there. Clear the window to start. */ +new_echo_area () +{ + if (!echo_area_open_p) + { + push_window (); + set_window (&echo_area); + echo_area_open_p = 1; + } + goto_xy (the_window.left, the_window.top); + clear_eop (); +} + +/* Return output to the previous window. */ +close_echo_area () +{ + if (!echo_area_open_p) + return; + + pop_window (); + echo_area_open_p = 0; +} + +/* Clear the contents of the echo area. */ +clear_echo_area () +{ + new_echo_area (); + close_echo_area (); +} + +/* Create and display the modeline. */ +make_modeline () +{ + int width = modeline_window.right - modeline_window.left; + char textual_position[6]; + + if (pagetop == nodetop) + { + if (pagebot == nodebot) + sprintf (textual_position, "All"); + else + sprintf (textual_position, "Top"); + } + else + { + if (pagebot == nodebot) + sprintf (textual_position, "Bot"); + else + sprintf (textual_position, "%2d%%", + 100 * (pagetop - nodetop) / (nodebot - nodetop)); + } + + sprintf (modeline, "Info: (%s)%s, %d lines ---%s", + current_info_file, current_info_node, nodelines, textual_position); + + if (strnicmp + (opsys_filename (current_info_file), last_loaded_info_file, + strlen (last_loaded_info_file)) != 0) + { + sprintf (&modeline[strlen (modeline)], ", Subfile: %s", + last_loaded_info_file); + } + + if (strlen (modeline) < width) + { + int idx = strlen (modeline); + while (idx != width) + modeline[idx++] = '-'; + modeline[idx] = '\0'; + } + + if (strlen (modeline) > width) + modeline[width] = '\0'; + push_window (); + set_window (&modeline_window); + goto_xy (the_window.left, the_window.top); + + if (terminal_inverse_begin) + do_term (terminal_inverse_begin); + print_string ("%s", modeline); + if (terminal_inverse_begin) + do_term (terminal_end_attributes); + + pop_window (); +} + +int typing_out = 0; + +/* Prepare to do output to the typeout window. If the + typeout window is already open, ignore this clown. */ +open_typeout () +{ + if (typing_out) + return; + + push_window (); + set_window (&terminal_window); + goto_xy (the_window.ch, the_window.cv); + typing_out = window_bashed = 1; +} + +/* Close the currently open typeout window. */ +close_typeout () +{ + if (inhibit_output) + inhibit_output = 0; + else + { + do { untyi_char = getc (stdin); } + while (untyi_char == -1 && errno == EINTR); + + if (untyi_char == SPACE) + untyi_char = 0; + } + pop_window (); + typing_out = 0; +} + +void * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + void *temp; + + if (pointer == (char *)NULL) + temp = (void *) xmalloc (bytes); + else + temp = (void *) realloc (pointer, bytes); + + if (temp == (void *)NULL) + { + fprintf (stderr, "Virtual memory exhausted\n"); + restore_io (); + exit (2); + } + return (temp); +} + +void * +xmalloc (bytes) + int bytes; +{ + void *temp = (void *) malloc (bytes); + + if (temp == (void *) NULL) + { + fprintf (stderr, "Virtual memory exhausted\n"); + restore_io (); + exit (2); + } + return (temp); +} diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/info.el b/web/glasgow/lit2x-0.16/literate/info-utils/info.el new file mode 100644 index 0000000000..00e7146230 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/info.el @@ -0,0 +1,1910 @@ +;; Info package for Emacs -- Dave Gillespie's version 1.05 of 3/8/92. +;; Copyright (C) 1985, 1986 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 1, or (at your option) +;; any later version. + +;; GNU Emacs 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. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +;; This is based on the version 19 info.el file. +;; +;; Note that Info-directory has been replaced by Info-directory-list, +;; a search path of directories in which to find Info files. +;; Also, Info tries adding ".info" to a file name if the name itself +;; is not found. +;; +;; This file also has several small bug fixes compared to the 18.57 version. + + +;; LCD Archive Entry: +;; info-dg|Dave Gillespie|daveg@synaptics.com +;; |Info reader with many enhancements; replaces standard info.el. +;; |92-03-08|1.05|~/modes/info.el + +;; Also available from anonymous FTP on csvax.cs.caltech.edu. + + +;; Modified 3/7/1991 by Dave Gillespie: +;; (Author's address: daveg@synaptics.com or daveg@csvax.cs.caltech.edu) +;; +;; Added keys: i, t, <, >, [, ], {, }, 6, 7, 8, 9, 0. +;; Look at help for info-mode (type ? in Info) for descriptions. +;; +;; If Info-directory-list is undefined and there is no INFOPATH +;; in the environment, use value of Info-directory for compatibility +;; with Emacs 18.57. +;; +;; All files named "localdir" found in the path are appended to "dir", +;; the Info directory. For this to work, "dir" should contain only +;; one node (Top), and each "localdir" should contain no ^_ or ^L +;; characters. Generally they will contain only one or several +;; additional lines for the top-level menu. Note that "dir" is +;; modified in memory each time it is loaded, but not on disk. +;; +;; If "dir" contains a line of the form: "* Locals:" +;; then the "localdir"s are inserted there instead of at the end. + + +;; Modified 4/3/1991 by Dave Gillespie: +;; +;; Added Info-mode-hook (suggested by Sebastian Kremer). +;; Also added epoch-info-startup/select-hooks from Simon Spero's info.el. +;; +;; Added automatic decoding of compressed Info files. +;; See documentation for the variable Info-suffix-list. Default is to +;; run "uncompress" on ".Z" files and "unyabba" on ".Y" files. +;; (See comp.sources.unix v24i073-076 for yabba/unyabba, a free software +;; alternative to compress/uncompress.) +;; Note: "dir" and "localdir" files should not be compressed. +;; +;; Changed variables like Info-enable-edit to be settable by M-x set-variable. +;; +;; Added Info-auto-advance variable. If t, SPC and DEL will act like +;; } and {, i.e., they advance to the next/previous node if at the end +;; of the buffer. +;; +;; Changed `u' to restore point to most recent location in that node. +;; Added `=' to do this manually at any time. (Suggested by David Fox). +;; +;; Changed `m' and `0-9' to try interpreting menu name as a file name +;; if not found as a node name. This allows (dir) menus of the form, +;; Emacs:: Cool text editor +;; as a shorthand for +;; Emacs:(emacs). Cool text editor +;; +;; Enhanced `i' to use line-number information in the index. +;; Added `,' to move among all matches to a previous `i' command. +;; +;; Added `a' (Info-annotate) for adding personal notes to any Info node. +;; Notes are not stored in the actual Info files, but in the user's own +;; ~/.infonotes file. +;; +;; Added Info-footnote-tag, made default be "Ref" instead of "Note". +;; +;; Got mouse-click stuff to work under Emacs version 18. Check it out! +;; Left and right clicks scroll the Info window. +;; Middle click goes to clicked-on node, e.g., "Next:", a menu, or a note. + + +;; Modified 6/29/1991 by Dave Gillespie: +;; +;; Renamed epoch-info-startup/select-hooks to Info-startup/select-hook. +;; +;; Made Info-select-node into a command on the `!' key. +;; +;; Added Info-mouse-support user option. +;; +;; Cleaned up the implementation of some routines. +;; +;; Added special treatment of quoted words in annotations: The `g' +;; command for a nonexistent node name scans for an annotation +;; (in any node of any file) containing that name in quotes: g foo RET +;; looks for an annotation containing: "foo" +;; If found, it goes to that file and node. +;; +;; Added a call to set up Info-directory-list in Info-find-node to +;; work around a bug in GNUS where it calls Info-goto-node before info. +;; +;; Added completion for `g' command (inspired by Richard Kim's infox.el). +;; Completion knows all node names for the current file, and all annotation +;; tags (see above). It does not complete file names or node names in +;; other files. +;; +;; Added `k' (Info-emacs-key) and `*' (Info-elisp-ref) commands. You may +;; wish to bind these to global keys outside of Info mode. +;; +;; Allowed localdir files to be full dir-like files; only the menu part +;; of each localdir is copied. Also, redundant menu items are omitted. +;; +;; Changed Info-history to hold only one entry at a time for each node, +;; and to be circular so that multiple `l's come back again to the most +;; recent node. Note that the format of Info-history entries has changed, +;; which may interfere with external programs that try to operate on it. +;; (Also inspired by Kim's infox.el). +;; +;; Changed `n', `]', `l', etc. to accept prefix arguments to move several +;; steps at once. Most accept negative arguments to move oppositely. +;; +;; Changed `?' to bury *Help* buffer afterwards to keep it out of the way. +;; +;; Rearranged `?' key's display to be a little better for new users. +;; +;; Changed `a' to save whole window configuration and restore on C-c C-c. +;; +;; Fixed the bug reported by Bill Reynolds on gnu.emacs.bugs. +;; +;; Changed Info-last to restore window-start as well as cursor position. +;; +;; Changed middle mouse button in space after end of node to do Info-last +;; if we got here by following a cross reference, else do Info-global-next. +;; +;; Added some new mouse bindings: shift-left = Info-global-next, +;; shift-right = Info-global-prev, shift-middle = Info-last. +;; +;; Fixed Info-follow-reference not to make assumptions about length +;; of Info-footnote-tag [Linus Tolke]. +;; +;; Changed default for Info-auto-advance mode to be press-twice-for-next-node. +;; +;; Modified x-mouse-ignore to preserve last-command variable, so that +;; press-twice Info-auto-advance mode works with the mouse. + + +;; Modified 3/4/1992 by Dave Gillespie: +;; +;; Added an "autoload" command to help autoload.el. +;; +;; Changed `*' command to look for file `elisp' as well as for `lispref'. +;; +;; Fixed a bug involving footnote names containing regexp special characters. +;; +;; Fixed a bug in completion during `f' (or `r') command. +;; +;; Added TAB (Info-next-reference), M-TAB, and RET keys to Info mode. +;; +;; Added new bindings, `C-h C-k' for Info-emacs-key and `C-h C-f' for +;; Info-elisp-ref. These bindings are made when info.el is loaded, and +;; only if those key sequences were previously unbound. These bindings +;; work at any time, not just when Info is already running. + + +;; Modified 3/8/1992 by Dave Gillespie: +;; +;; Fixed some long lines that were causing trouble with mailers. + + + +(provide 'info) + +(defvar Info-mouse-support t + "*Non-nil means to install Info mouse drivers for Emacs version 18. +Set this to nil if you have your own Info mouse support.") + +(defvar Info-history nil + "List of info nodes user has visited. +Each element of list is a list (\"(FILENAME)NODENAME\" BUFPOS WINSTART).") + +(defvar Info-keeping-history t + "Non-nil if Info-find-node should modify Info-history. +This is for use only by certain internal Info routines.") + +(defvar Info-enable-edit nil + "*Non-nil means the \\[Info-edit] command in Info can edit the current node.") + +(defvar Info-enable-active-nodes t + "*Non-nil allows Info to execute Lisp code associated with nodes. +The Lisp code is executed when the node is selected.") + +(defvar Info-restoring-point t + "*Non-nil means to restore the cursor position when re-entering a node.") + +(defvar Info-auto-advance 'twice + "*Control what SPC and DEL do when they can't scroll any further. +If nil, they beep and remain in the current node. +If t, they move to the next node (like Info-global-next/prev). +If anything else, they must be pressed twice to move to the next node.") + +(defvar Info-directory-list (getenv "INFOPATH") + "List of directories to search for Info documentation files. +Default is to use the environment variable INFOPATH if it exists, +else to use Info-directory if it exists.") + +(defvar Info-suffix-list '( (".info" . nil) + (".Z" . "uncompress -c %s") + (".Y" . "unyabba") + (".info.Z" . "uncompress -c %s") + (".info.Y" . "unyabba") ) + "List of file name suffixes and associated decoding commands. +Each entry should be (SUFFIX . STRING); if STRING contains %s, that is +changed to name of the file to decode, otherwise the file is given to +the command as standard input. If STRING is nil, no decoding is done.") + +(defvar Info-footnote-tag "Ref" + "*Symbol that identifies a footnote or cross-reference. +All \"*Note\" references will be changed to use this word instead.") + +(defvar Info-current-file nil + "Info file that Info is now looking at, or nil.") + +(defvar Info-current-subfile nil + "Info subfile that is actually in the *info* buffer now, +or nil if current info file is not split into subfiles.") + +(defvar Info-current-node nil + "Name of node that Info is now looking at, or nil.") + +(defvar Info-tag-table-marker (make-marker) + "Marker pointing at beginning of current Info file's tag table. +Marker points nowhere if file has no tag table.") + +(defvar Info-current-file-completions nil + "Cached completion list for current Info file.") + +(defvar Info-index-alternatives nil + "List of possible matches for last Info-index command.") + +(defvar Info-annotations-path '("~/.infonotes" "/usr/lib/info.notes") + "*Names of files that contain annotations for different Info nodes. +By convention, the first one should reside in your personal directory. +The last should be a world-writable \"public\" annotations file.") + +(defvar Info-in-cross-reference nil) +(defvar Info-window-configuration nil) + +;;;###autoload +(defun info (&optional file) + "Enter Info, the documentation browser. +Optional argument FILE specifies the file to examine; +the default is the top-level directory of Info. + +In interactive use, a prefix argument directs this command +to read a file name from the minibuffer." + (interactive (if current-prefix-arg + (list (read-file-name "Info file name: " nil nil t)))) + (Info-find-directory-list) + (Info-setup-x) + (if file + (Info-goto-node (concat "(" file ")")) + (if (get-buffer "*info*") + (switch-to-buffer "*info*") + (let ((f Info-annotations-path)) + (while f + (if (file-exists-p (car f)) + (bury-buffer (find-file-noselect (car f)))) + (setq f (cdr f)))) + (Info-directory)))) + +(defun Info-find-directory-list () + (if (stringp Info-directory-list) + (let ((path Info-directory-list) + list) + (while (> (length path) 0) + (let ((idx (or (string-match ":" path) (length path)))) + (setq list (cons (substring path 0 idx) list) + path (substring path (min (1+ idx) (length path)))))) + (setq Info-directory-list (nreverse list)))) + (or Info-directory-list + (setq Info-directory-list (list (if (boundp 'Info-directory) + Info-directory + "."))))) +(Info-find-directory-list) + +;; Go to an info node specified as separate filename and nodename. +;; no-going-back is non-nil if recovering from an error in this function; +;; it says do not attempt further (recursive) error recovery. +(defun Info-find-node (filename nodename &optional no-going-back tryfile line) + ;; Convert filename to lower case if not found as specified. + ;; Expand it. + (if filename + (let (temp temp-downcase found) + (setq filename (substitute-in-file-name filename)) + (let ((dirs (if (string-match "^\\./" filename) + ;; If specified name starts with `./' + ;; then just try current directory. + '("./") + Info-directory-list))) + ;; Search the directory list for file FILENAME. + (while (and dirs (not found)) + (setq temp (expand-file-name filename (car dirs))) + (setq temp-downcase + (expand-file-name (downcase filename) (car dirs))) + (if (equal temp-downcase temp) (setq temp-downcase nil)) + ;; Try several variants of specified name. + ;; Try downcasing, appending a suffix, or both. + (setq found (Info-suffixed-file temp temp-downcase)) + (setq dirs (cdr dirs)))) + (if found + (setq filename found) + (error "Info file %s does not exist" filename)))) + ;; Go into info buffer. + (switch-to-buffer "*info*") + (run-hooks 'Info-startup-hook) + (or (eq major-mode 'Info-mode) + (Info-mode)) + ;; Record the node we are leaving. + (if (and Info-current-file (not no-going-back)) + (Info-history-add Info-current-file Info-current-node (point))) + (widen) + (setq Info-current-node nil + Info-in-cross-reference nil) + (unwind-protect + (progn + ;; Switch files if necessary + (or (null filename) + (equal Info-current-file filename) + (let ((buffer-read-only nil)) + (setq Info-current-file nil + Info-current-subfile nil + Info-index-alternatives nil + Info-current-file-completions nil + buffer-file-name nil) + (erase-buffer) + (Info-insert-file-contents filename t) + ;; Add all "localdir" files in search path to "dir" file. + (if (string-match "^dir$" (file-name-nondirectory filename)) + (let ((d Info-directory-list) + name) + (goto-char (point-max)) + (if (re-search-backward "^ *\\* *Locals *: *\n" nil t) + (delete-region (match-beginning 0) (match-end 0)) + (search-backward "\^L" nil t)) + (while d + (setq name (expand-file-name "localdir" (car d))) + (if (or (file-exists-p name) + (file-exists-p + (setq name (concat name ".info")))) + ;; Insert menu part of the file + (let* ((pt (point)) + (len (nth 1 (insert-file-contents name)))) + (if (search-forward "* menu:" (+ pt len) t) + (progn + (forward-line 1) + (delete-region pt (point)))))) + (setq d (cdr d))) + ;; Eliminate redundant menu entries. + (goto-char (point-min)) + (while (re-search-forward "\n\\* \\([^:\n]*\\):" nil t) + (let ((str (buffer-substring (match-beginning 1) + (match-end 1)))) + (save-excursion + (if (search-forward (format "\n* %s:" str) nil t) + (let ((pt (- (point) 3 (length str)))) + (forward-line 1) + (delete-region pt (point))))))))) + (set-buffer-modified-p nil) + (setq default-directory (file-name-directory filename)) + ;; See whether file has a tag table. Record the location if yes. + (set-marker Info-tag-table-marker nil) + (goto-char (point-max)) + (forward-line -8) + (or (equal nodename "*") + (not (search-forward "\^_\nEnd tag table\n" nil t)) + (let (pos) + ;; We have a tag table. Find its beginning. + ;; Is this an indirect file? + (search-backward "\nTag table:\n") + (setq pos (point)) + (if (save-excursion + (forward-line 2) + (looking-at "(Indirect)\n")) + ;; It is indirect. Copy it to another buffer + ;; and record that the tag table is in that buffer. + (save-excursion + (let ((buf (current-buffer))) + (set-buffer + (get-buffer-create " *info tag table*")) + (setq case-fold-search t) + (erase-buffer) + (insert-buffer-substring buf) + (set-marker Info-tag-table-marker + (match-end 0)))) + (set-marker Info-tag-table-marker pos)))) + (setq Info-current-file + (file-name-sans-versions buffer-file-name)))) + (if (equal nodename "*") + (progn (setq Info-current-node nodename) + (Info-set-mode-line) + (goto-char (point-min))) + ;; Search file for a suitable node. + ;; First get advice from tag table if file has one. + ;; Also, if this is an indirect info file, + ;; read the proper subfile into this buffer. + (let ((guesspos (point-min))) + (if (marker-position Info-tag-table-marker) + (save-excursion + (set-buffer (marker-buffer Info-tag-table-marker)) + (goto-char Info-tag-table-marker) + (if (search-forward (concat "Node: " nodename "\177") nil t) + (progn + (setq guesspos (read (current-buffer))) + ;; If this is an indirect file, + ;; determine which file really holds this node + ;; and read it in. + (if (not (eq (current-buffer) (get-buffer "*info*"))) + (setq guesspos + (Info-read-subfile guesspos))))))) + (goto-char (max (point-min) (- guesspos 1000)))) + ;; Now search from our advised position (or from beg of buffer) + ;; to find the actual node. + (let ((regexp (concat "Node: *" (regexp-quote nodename) " *[,\t\n]")) + (found t)) + (catch 'foo + (while (search-forward "\n\^_" nil t) + (forward-line 1) + (let ((beg (point))) + (forward-line 1) + (if (re-search-backward regexp beg t) + (throw 'foo t)))) + (setq found nil) + (let ((bufs (delq nil (mapcar 'get-file-buffer + Info-annotations-path))) + (pattern (concat "\"" nodename "\"")) + (pat2 (concat "------ *File: *\\([^ ].*[^ ]\\) *Node: " + "*\\([^ ].*[^ ]\\) *Line: *\\([0-9]+\\)")) + (afile nil) anode aline) + (while (and bufs (not anode)) + (save-excursion + (set-buffer (car bufs)) + (goto-char (point-min)) + (if (search-forward pattern nil t) + (if (re-search-backward pat2 nil t) + (setq afile + (buffer-substring (match-beginning 1) + (match-end 1)) + anode + (buffer-substring (match-beginning 2) + (match-end 2)) + aline + (string-to-int + (buffer-substring (match-beginning 3) + (match-end 3))))))) + (setq bufs (cdr bufs))) + (if anode + (Info-find-node afile anode t nil aline) + (if tryfile + (condition-case err + (Info-find-node nodename "Top" t) + (error nil))))) + (or Info-current-node + (error "No such node: %s" nodename))) + (if found + (progn + (Info-select-node) + (goto-char (point-min)) + (if line (forward-line line))))))) + ;; If we did not finish finding the specified node, + ;; go back to the previous one. + (or Info-current-node no-going-back + (let ((hist (car Info-history))) + ;; The following is no longer safe with new Info-history system + ;; (setq Info-history (cdr Info-history)) + (Info-goto-node (car hist) t) + (goto-char (nth 1 hist)))))) + +(defun Info-history-add (file node point) + (if Info-keeping-history + (let* ((name (format "(%s)%s" (Info-file-name-only file) node)) + (found (assoc name Info-history))) + (if found + (setq Info-history (delq found Info-history))) + (setq Info-history (cons (list name point + (and (eq (window-buffer) + (current-buffer)) + (window-start))) + Info-history))))) + +(defun Info-file-name-only (file) + (let ((dir (file-name-directory file)) + (p Info-directory-list)) + (while (and p (not (equal (car p) dir))) + (setq p (cdr p))) + (if p (file-name-nondirectory file) file))) + +(defun Info-read-subfile (nodepos) + (set-buffer (marker-buffer Info-tag-table-marker)) + (goto-char (point-min)) + (search-forward "\n\^_") + (let (lastfilepos + lastfilename) + (forward-line 2) + (catch 'foo + (while (not (looking-at "\^_")) + (if (not (eolp)) + (let ((beg (point)) + thisfilepos thisfilename) + (search-forward ": ") + (setq thisfilename (buffer-substring beg (- (point) 2))) + (setq thisfilepos (read (current-buffer))) + ;; read in version 19 stops at the end of number. + ;; Advance to the next line. + ;; (forward-line 1) + (if (> thisfilepos nodepos) + (throw 'foo t)) + (setq lastfilename thisfilename) + (setq lastfilepos thisfilepos)) + (throw 'foo t)))) + (set-buffer (get-buffer "*info*")) + (or (equal Info-current-subfile lastfilename) + (let ((buffer-read-only nil)) + (setq buffer-file-name nil) + (widen) + (erase-buffer) + (Info-insert-file-contents (Info-suffixed-file lastfilename)) + (set-buffer-modified-p nil) + (setq Info-current-subfile lastfilename))) + (goto-char (point-min)) + (search-forward "\n\^_") + (+ (- nodepos lastfilepos) (point)))) + +(defun Info-suffixed-file (name &optional name2) + (cond ((file-exists-p name) + name) + ((and name2 (file-exists-p name2)) + name2) + (t + (let ((suff Info-suffix-list) + (found nil)) + (while (and suff (not found)) + (if (file-exists-p (concat name (car (car suff)))) + (setq found (concat name (car (car suff)))) + (if (and name2 (file-exists-p (concat name2 (car (car suff))))) + (setq found (concat name2 (car (car suff)))) + (setq suff (cdr suff))))) + found)))) + +(defun Info-insert-file-contents (file &optional visit) + (let ((suff Info-suffix-list)) + (while (and suff (or (<= (length file) (length (car (car suff)))) + (not (equal (substring file + (- (length (car (car suff))))) + (car (car suff)))))) + (setq suff (cdr suff))) + (if (stringp (cdr (car suff))) + (let ((command (if (string-match "%s" (cdr (car suff))) + (format (cdr (car suff)) file) + (concat (cdr (car suff)) " < " file)))) + (message "%s..." command) + (call-process shell-file-name nil t nil "-c" command) + (message "") + (if visit + (progn + (setq buffer-file-name file) + (set-buffer-modified-p nil) + (clear-visited-file-modtime)))) + (insert-file-contents file visit)))) + +(defun Info-select-node () + "Select the node that point is in, after using `g *' to select whole file." + (interactive) + (widen) + (save-excursion + ;; Find beginning of node. + (search-backward "\n\^_") + (forward-line 2) + ;; Get nodename spelled as it is in the node. + (re-search-forward "Node:[ \t]*") + (setq Info-current-node + (buffer-substring (point) + (progn + (skip-chars-forward "^,\t\n") + (point)))) + (Info-set-mode-line) + ;; Find the end of it, and narrow. + (beginning-of-line) + (let (active-expression) + (narrow-to-region (point) + (if (re-search-forward "\n[\^_\f]" nil t) + (prog1 + (1- (point)) + (if (looking-at "[\n\^_\f]*execute: ") + (progn + (goto-char (match-end 0)) + (setq active-expression + (read (current-buffer)))))) + (point-max))) + (or (equal Info-footnote-tag "Note") + (progn + (goto-char (point-min)) + (let ((buffer-read-only nil) + (bufmod (buffer-modified-p))) + (while (re-search-forward "\\*Note\\([ \n]\\)" nil t) + (replace-match (concat "*" Info-footnote-tag "\\1"))) + (set-buffer-modified-p bufmod)))) + (Info-reannotate-node) + (run-hooks 'Info-select-hook) + (if Info-enable-active-nodes (eval active-expression))))) + +(defun Info-set-mode-line () + (setq mode-line-buffer-identification + (concat + "Info: (" + (if Info-current-file + (file-name-nondirectory Info-current-file) + "") + ")" + (or Info-current-node "")))) + +;; Go to an info node specified with a filename-and-nodename string +;; of the sort that is found in pointers in nodes. + +(defun Info-goto-node (nodename &optional no-going-back tryfile) + "Go to info node named NAME. Give just NODENAME or (FILENAME)NODENAME. +Actually, the following interpretations of NAME are tried in order: + (FILENAME)NODENAME + (FILENAME) (using Top node) + NODENAME (in current file) + TAGNAME (see below) + FILENAME (using Top node) +where TAGNAME is a string that appears in quotes: \"TAGNAME\", in an +annotation for any node of any file. (See `a' for annotations.)" + (interactive (list (Info-read-node-name "Goto node, file or tag: ") + nil t)) + (let (filename) + (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)" + nodename) + (setq filename (if (= (match-beginning 1) (match-end 1)) + "" + (substring nodename (match-beginning 2) (match-end 2))) + nodename (substring nodename (match-beginning 3) (match-end 3))) + (let ((trim (string-match "\\s *\\'" filename))) + (if trim (setq filename (substring filename 0 trim)))) + (let ((trim (string-match "\\s *\\'" nodename))) + (if trim (setq nodename (substring nodename 0 trim)))) + (Info-find-node (if (equal filename "") nil filename) + (if (equal nodename "") "Top" nodename) + no-going-back (and tryfile (equal filename ""))))) + +(defun Info-restore-point (&optional always) + "Restore point to same location it had last time we were in this node." + (interactive "p") + (if (or Info-restoring-point always) + (let* ((name (format "(%s)%s" + (Info-file-name-only Info-current-file) + Info-current-node)) + (p (assoc name Info-history))) + (if p (Info-restore-history-entry p))))) + +(defun Info-restore-history-entry (entry) + (goto-char (nth 1 entry)) + (and (nth 2 entry) + (get-buffer-window (current-buffer)) + (set-window-start (get-buffer-window (current-buffer)) + (nth 2 entry)))) + +(defun Info-read-node-name (prompt &optional default) + (Info-build-node-completions) + (let* ((completion-ignore-case t) + (nodename (completing-read prompt Info-current-file-completions))) + (if (equal nodename "") + (or default + (Info-read-node-name prompt)) + nodename))) + +(defun Info-build-node-completions () + (or Info-current-file-completions + (let ((compl nil)) + (save-excursion + (save-restriction + (if (marker-buffer Info-tag-table-marker) + (progn + (set-buffer (marker-buffer Info-tag-table-marker)) + (goto-char Info-tag-table-marker) + (while (re-search-forward "\nNode: \\(.*\\)\177" nil t) + (setq compl + (cons (list (buffer-substring (match-beginning 1) + (match-end 1))) + compl)))) + (widen) + (goto-char (point-min)) + (while (search-forward "\n\^_" nil t) + (forward-line 1) + (let ((beg (point))) + (forward-line 1) + (if (re-search-backward "Node: *\\(.*\\) *[,\n\t]" beg t) + (setq compl + (cons (list (buffer-substring (match-beginning 1) + (match-end 1))) + compl))))))) + (let ((bufs (delq nil (mapcar 'get-file-buffer + Info-annotations-path)))) + (while bufs + (set-buffer (car bufs)) + (goto-char (point-min)) + (while (re-search-forward "\"\\(.*\\)\"" nil t) + (setq compl + (cons (list (buffer-substring (match-beginning 1) + (match-end 1))) + compl))) + (setq bufs (cdr bufs))))) + (setq Info-current-file-completions compl)))) + +(defvar Info-last-search nil + "Default regexp for Info S command to search for.") + +(defun Info-search (regexp) + "Search for REGEXP, starting from point, and select node it's found in." + (interactive "sSearch (regexp): ") + (if (equal regexp "") + (setq regexp Info-last-search) + (setq Info-last-search regexp)) + (let ((found ()) current + (onode Info-current-node) + (ofile Info-current-file) + (opoint (point)) + (osubfile Info-current-subfile)) + (save-excursion + (save-restriction + (widen) + (if (null Info-current-subfile) + (progn (re-search-forward regexp) (setq found (point))) + (condition-case err + (progn (re-search-forward regexp) (setq found (point))) + (search-failed nil))))) + (if (not found) ;can only happen in subfile case -- else would have erred + (unwind-protect + (let ((list ())) + (set-buffer (marker-buffer Info-tag-table-marker)) + (goto-char (point-min)) + (search-forward "\n\^_\nIndirect:") + (save-restriction + (narrow-to-region (point) + (progn (search-forward "\n\^_") + (1- (point)))) + (goto-char (point-min)) + (search-forward (concat "\n" osubfile ": ")) + (beginning-of-line) + (while (not (eobp)) + (re-search-forward "\\(^.*\\): [0-9]+$") + (goto-char (+ (match-end 1) 2)) + (setq list (cons (cons (read (current-buffer)) + (buffer-substring (match-beginning 1) + (match-end 1))) + list)) + (goto-char (1+ (match-end 0)))) + (setq list (nreverse list) + current (car (car list)) + list (cdr list))) + (while list + (message "Searching subfile %s..." (cdr (car list))) + (Info-read-subfile (car (car list))) + (setq list (cdr list)) + (goto-char (point-min)) + (if (re-search-forward regexp nil t) + (setq found (point) list ()))) + (if found + (message "") + (signal 'search-failed (list regexp)))) + (if (not found) + (progn (Info-read-subfile opoint) + (goto-char opoint) + (Info-select-node))))) + (widen) + (goto-char found) + (Info-select-node) + (or (and (equal onode Info-current-node) + (equal ofile Info-current-file)) + (Info-history-add ofile onode opoint)))) + +(defun Info-extract-pointer (name &optional errorname) + (save-excursion + (goto-char (point-min)) + (forward-line 1) + (if (re-search-backward (concat name ":") nil t) + (progn + (goto-char (match-end 0)) + (Info-following-node-name)) + (if (eq errorname t) + nil + (error (concat "Node has no " (capitalize (or errorname name)))))))) + +(defun Info-following-node-name (&optional allowedchars) + (skip-chars-forward " \t") + (buffer-substring + (point) + (progn + (while (looking-at (concat "[" (or allowedchars "^,\t\n") "]")) + (skip-chars-forward (concat (or allowedchars "^,\t\n") "(")) + (if (looking-at "(") + (skip-chars-forward "^)"))) + (skip-chars-backward " ") + (point)))) + +(defun Info-next (&optional n) + "Go to the next node of this node. +A positive or negative prefix argument moves by multiple nodes." + (interactive "p") + (or n (setq n 1)) + (if (< n 0) + (Info-prev (- n)) + (while (>= (setq n (1- n)) 0) + (Info-goto-node (Info-extract-pointer "next"))))) + +(defun Info-prev (&optional n) + "Go to the previous node of this node. +A positive or negative prefix argument moves by multiple nodes." + (interactive "p") + (or n (setq n 1)) + (if (< n 0) + (Info-next (- n)) + (while (>= (setq n (1- n)) 0) + (Info-goto-node (Info-extract-pointer "prev[ious]*" "previous"))))) + +(defun Info-up (&optional n) + "Go to the superior node of this node. +A positive prefix argument moves up several times." + (interactive "p") + (or n (setq n 1)) + (while (>= (setq n (1- n)) 0) + (Info-goto-node (Info-extract-pointer "up"))) + (if (interactive-p) (Info-restore-point))) + +(defun Info-last (&optional n) + "Go back to the last node visited. +With a prefix argument, go to Nth most recently visited node. History is +circular; after oldest node, history comes back around to most recent one. +Argument can be negative to go through the circle in the other direction. +\(In other words, `l' is like \"undo\" and `C-u - l' is like \"redo\".)" + (interactive "p") + (or n (setq n 1)) + (or Info-history + (error "This is the first Info node you looked at")) + (let ((len (1+ (length Info-history)))) + (setq n (% (+ n (* len 100)) len))) + (if (> n 0) + (let ((entry (nth (1- n) Info-history))) + (Info-history-add Info-current-file Info-current-node (point)) + (while (>= (setq n (1- n)) 0) + (setq Info-history (nconc (cdr Info-history) + (list (car Info-history))))) + (setq Info-history (cdr Info-history)) + (let ((Info-keeping-history nil)) + (Info-goto-node (car entry))) + (Info-restore-history-entry entry)))) + +(defun Info-directory () + "Go to the Info directory node." + (interactive) + (Info-find-node "dir" "top")) + +(defun Info-follow-reference (footnotename) + "Follow cross reference named NAME to the node it refers to. +NAME may be an abbreviation of the reference name." + (interactive + (let ((completion-ignore-case t) + completions default (start-point (point)) str i) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward (format "\\*%s[ \n\t]*\\([^:]*\\):" + Info-footnote-tag) + nil t) + (setq str (buffer-substring + (match-beginning 1) + (1- (point)))) + ;; See if this one should be the default. + (and (null default) + (< (match-beginning 0) start-point) + (<= start-point (point)) + (setq default t)) + (setq i 0) + (while (setq i (string-match "[ \n\t]+" str i)) + (setq str (concat (substring str 0 i) " " + (substring str (match-end 0)))) + (setq i (1+ i))) + ;; Record as a completion and perhaps as default. + (if (eq default t) (setq default str)) + (setq completions + (cons (cons str nil) + completions)))) + (if completions + (let ((item (completing-read (if default + (concat "Follow reference named: (" + default ") ") + "Follow reference named: ") + completions nil t))) + (if (and (string= item "") default) + (list default) + (list item))) + (error "No cross-references in this node")))) + (let (target beg i (str (concat "\\*" Info-footnote-tag " " + (regexp-quote footnotename)))) + (while (setq i (string-match " " str i)) + (setq str (concat (substring str 0 i) "\\([ \t\n]+\\)" + (substring str (1+ i)))) + (setq i (+ i 10))) + (save-excursion + (goto-char (point-min)) + (or (re-search-forward str nil t) + (error "No cross-reference named %s" footnotename)) + (goto-char (match-end 1)) + (setq target + (Info-extract-menu-node-name "Bad format cross reference" t))) + (while (setq i (string-match "[ \t\n]+" target i)) + (setq target (concat (substring target 0 i) " " + (substring target (match-end 0)))) + (setq i (+ i 1))) + (Info-goto-node target) + (setq Info-in-cross-reference t))) + +(defun Info-next-reference (n) + (interactive "p") + (let ((pat (format "\\*%s[ \n\t]*\\([^:]*\\):\\|^\\* .*:" + Info-footnote-tag)) + (case-fold-search nil) + (old-pt (point))) + (while (< n 0) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward pat nil t) + (setq n (1+ n))) + (goto-char (point-min)) + (if (re-search-forward "^\\* Menu:" nil t) + (setq n (1- n))))) + (while (>= (setq n (1- n)) 0) + (or (eobp) (forward-char 1)) + (or (re-search-forward pat nil t) + (progn + (goto-char (point-min)) + (or (re-search-forward pat nil t) + (progn + (goto-char old-pt) + (error "No cross references in this node"))))) + (goto-char (match-beginning 0)) + (if (looking-at "\\* Menu:") + (setq n (1+ n)))))) + +(defun Info-prev-reference (n) + (interactive "p") + (Info-next-reference (- n))) + +(defun Info-extract-menu-node-name (&optional errmessage multi-line) + (skip-chars-forward " \t\n") + (let ((beg (point)) + str i) + (skip-chars-forward "^:") + (forward-char 1) + (setq str + (if (looking-at ":") + (buffer-substring beg (1- (point))) + (skip-chars-forward " \t\n") + (Info-following-node-name (if multi-line "^.,\t" "^.,\t\n")))) + (while (setq i (string-match "\n" str i)) + (aset str i ?\ )) + str)) + +(defun Info-menu (menu-item) + "Go to node for menu item named (or abbreviated) NAME. +Completion is allowed, and the menu item point is on is the default." + (interactive + (let ((completions '()) + ;; If point is within a menu item, use that item as the default + (default nil) + (p (point)) + (last nil)) + (save-excursion + (goto-char (point-min)) + (if (not (search-forward "\n* menu:" nil t)) + (error "No menu in this node")) + (while (re-search-forward + "\n\\* \\([^:\t\n]*\\):" nil t) + (if (and (null default) + (prog1 (if last (< last p) nil) + (setq last (match-beginning 0))) + (<= p last)) + (setq default (car (car completions)))) + (setq completions (cons (cons (buffer-substring + (match-beginning 1) + (match-end 1)) + (match-beginning 1)) + completions))) + (if (and (null default) last + (< last p) + (<= p (progn (end-of-line) (point)))) + (setq default (car (car completions))))) + (let ((item nil)) + (while (null item) + (setq item (let ((completion-ignore-case t)) + (completing-read (if default + (format "Menu item (default %s): " + default) + "Menu item: ") + completions nil t))) + ;; we rely on the bug (which RMS won't change for his own reasons) + ;; that ;; completing-read accepts an input of "" even when the + ;; require-match argument is true and "" is not a valid possibility + (if (string= item "") + (if default + (setq item default) + ;; ask again + (setq item nil)))) + (list item)))) + ;; there is a problem here in that if several menu items have the same + ;; name you can only go to the node of the first with this command. + (Info-goto-node (Info-extract-menu-item menu-item) nil t)) + +(defun Info-extract-menu-item (menu-item &optional noerror) + (save-excursion + (goto-char (point-min)) + (if (search-forward "\n* menu:" nil t) + (if (or (search-forward (concat "\n* " menu-item ":") nil t) + (search-forward (concat "\n* " menu-item) nil t)) + (progn + (beginning-of-line) + (forward-char 2) + (Info-extract-menu-node-name)) + (and (not noerror) (error "No such item in menu"))) + (and (not noerror) (error "No menu in this node"))))) + +(defun Info-extract-menu-counting (count &optional noerror noindex) + (save-excursion + (goto-char (point-min)) + (if (and (search-forward "\n* menu:" nil t) + (or (not noindex) + (not (string-match "\\<Index\\>" Info-current-node)))) + (if (search-forward "\n* " nil t count) + (progn + (or count + (while (search-forward "\n* " nil t))) + (Info-extract-menu-node-name)) + (and (not noerror) (error "Too few items in menu"))) + (and (not noerror) (error "No menu in this node"))))) + +(defun Info-nth-menu-item (n) + "Go to the node of the Nth menu item." + (interactive "P") + (or n (setq n (- last-command-char ?0))) + (if (< n 1) (error "Index must be at least 1")) + (Info-goto-node (Info-extract-menu-counting n) nil t)) + +(defun Info-last-menu-item () + "Go to the node of the tenth menu item." + (interactive) + (Info-goto-node (Info-extract-menu-counting nil) nil t)) + +(defun Info-top () + "Go to the Top node of this file." + (interactive) + (Info-goto-node "Top")) + +(defun Info-end () + "Go to the final node in this file." + (interactive) + (Info-top) + (let ((Info-keeping-history nil) + node) + (Info-last-menu-item) + (while (setq node (or (Info-extract-pointer "next" t) + (Info-extract-menu-counting nil t t))) + (Info-goto-node node)) + (or (equal (Info-extract-pointer "up" t) "Top") + (let ((executing-kbd-macro "")) ; suppress messages + (condition-case err + (Info-global-next 10000) + (error nil)))))) + +(defun Info-global-next (&optional n) + "Go to the next node in this file, traversing node structure as necessary. +This works only if the Info file is structured as a hierarchy of nodes. +A positive or negative prefix argument moves by multiple nodes." + (interactive "p") + (or n (setq n 1)) + (if (< n 0) + (Info-global-prev (- n)) + (while (>= (setq n (1- n)) 0) + (let (node) + (cond ((and (string-match "^Top$" Info-current-node) + (setq node (Info-extract-pointer "next" t)) + (Info-extract-menu-item node t)) + (Info-goto-node node)) + ((setq node (Info-extract-menu-counting 1 t t)) + (message "Going down...") + (Info-goto-node node)) + (t + (let ((Info-keeping-history Info-keeping-history) + (orignode Info-current-node) + (ups "")) + (while (not (Info-extract-pointer "next" t)) + (if (and (setq node (Info-extract-pointer "up" t)) + (not (equal node "Top"))) + (progn + (message "Going%s..." (setq ups (concat ups " up"))) + (Info-goto-node node) + (setq Info-keeping-history nil)) + (if orignode + (let ((Info-keeping-history nil)) + (Info-goto-node orignode))) + (error "Last node in file"))) + (Info-next)))))))) + +(defun Info-page-next (&optional n) + "Scroll forward one screenful, or go to next global node. +A positive or negative prefix argument moves by multiple screenfuls." + (interactive "p") + (or n (setq n 1)) + (if (< n 0) + (Info-page-prev (- n)) + (while (>= (setq n (1- n)) 0) + (if (pos-visible-in-window-p (point-max)) + (progn + (Info-global-next) + (message "Node: %s" Info-current-node)) + (scroll-up))))) + +(defun Info-scroll-next (arg) + (interactive "P") + (if Info-auto-advance + (if (and (pos-visible-in-window-p (point-max)) + (not (eq Info-auto-advance t)) + (not (eq last-command this-command))) + (message "Hit %s again to go to next node" + (if (= last-command-char 0) + "mouse button" + (key-description (char-to-string last-command-char)))) + (Info-page-next) + (setq this-command 'Info)) + (scroll-up arg))) + +(defun Info-global-prev (&optional n) + "Go to the previous node in this file, traversing structure as necessary. +This works only if the Info file is structured as a hierarchy of nodes. +A positive or negative prefix argument moves by multiple nodes." + (interactive "p") + (or n (setq n 1)) + (if (< n 0) + (Info-global-next (- n)) + (while (>= (setq n (1- n)) 0) + (let ((upnode (Info-extract-pointer "up" t)) + (prevnode (Info-extract-pointer "prev[ious]*" t))) + (if (or (not prevnode) + (equal prevnode upnode)) + (if (string-match "^Top$" Info-current-node) + (error "First node in file") + (message "Going up...") + (Info-up)) + (Info-goto-node prevnode) + (let ((downs "") + (Info-keeping-history nil) + node) + (while (setq node (Info-extract-menu-counting nil t t)) + (message "Going%s..." (setq downs (concat downs " down"))) + (Info-goto-node node)))))))) + +(defun Info-page-prev (&optional n) + "Scroll backward one screenful, or go to previous global node. +A positive or negative prefix argument moves by multiple screenfuls." + (interactive "p") + (or n (setq n 1)) + (if (< n 0) + (Info-page-next (- n)) + (while (>= (setq n (1- n)) 0) + (if (pos-visible-in-window-p (point-min)) + (progn + (Info-global-prev) + (message "Node: %s" Info-current-node) + (sit-for 0) + ;;(scroll-up 1) ; work around bug in pos-visible-in-window-p + ;;(scroll-down 1) + (while (not (pos-visible-in-window-p (point-max))) + (scroll-up))) + (scroll-down))))) + +(defun Info-scroll-prev (arg) + (interactive "P") + (if Info-auto-advance + (if (and (pos-visible-in-window-p (point-min)) + (not (eq Info-auto-advance t)) + (not (eq last-command this-command))) + (message "Hit %s again to go to previous node" + (if (= last-command-char 0) + "mouse button" + (key-description (char-to-string last-command-char)))) + (Info-page-prev) + (setq this-command 'Info)) + (scroll-down arg))) + +(defun Info-index (topic) + "Look up a string in the index for this file. +The index is defined as the first node in the top-level menu whose +name contains the word \"Index\", plus any immediately following +nodes whose names also contain the word \"Index\". +If there are no exact matches to the specified topic, this chooses +the first match which is a case-insensitive substring of a topic. +Use the `,' command to see the other matches. +Give a blank topic name to go to the Index node itself." + (interactive "sIndex topic: ") + (let ((orignode Info-current-node) + (rnode nil) + (pattern (format "\n\\* \\([^\n:]*%s[^\n:]*\\):[ \t]*%s" + (regexp-quote topic) + "\\([^.\n]*\\)\\.[ t]*\\([0-9]*\\)")) + node) + (Info-goto-node "Top") + (or (search-forward "\n* menu:" nil t) + (error "No index")) + (or (re-search-forward "\n\\* \\(.*\\<Index\\>\\)" nil t) + (error "No index")) + (goto-char (match-beginning 1)) + (let ((Info-keeping-history nil)) + (Info-goto-node (Info-extract-menu-node-name))) + (or (equal topic "") + (let ((matches nil) + (exact nil) + (Info-keeping-history nil) + found) + (while + (progn + (goto-char (point-min)) + (while (re-search-forward pattern nil t) + (setq matches + (cons (list (buffer-substring (match-beginning 1) + (match-end 1)) + (buffer-substring (match-beginning 2) + (match-end 2)) + Info-current-node + (string-to-int (concat "0" + (buffer-substring + (match-beginning 3) + (match-end 3))))) + matches))) + (and (setq node (Info-extract-pointer "next" t)) + (string-match "\\<Index\\>" node))) + (Info-goto-node node)) + (or matches + (progn + (Info-last) + (error "No \"%s\" in index" topic))) + ;; Here it is a feature that assoc is case-sensitive. + (while (setq found (assoc topic matches)) + (setq exact (cons found exact) + matches (delq found matches))) + (setq Info-index-alternatives (nconc exact (nreverse matches))) + (Info-index-next 0))))) + +(defun Info-index-next (num) + "Go to the next matching index item from the last `i' command." + (interactive "p") + (or Info-index-alternatives + (error "No previous `i' command in this file")) + (while (< num 0) + (setq num (+ num (length Info-index-alternatives)))) + (while (> num 0) + (setq Info-index-alternatives + (nconc (cdr Info-index-alternatives) + (list (car Info-index-alternatives))) + num (1- num))) + (Info-goto-node (nth 1 (car Info-index-alternatives))) + (if (> (nth 3 (car Info-index-alternatives)) 0) + (forward-line (nth 3 (car Info-index-alternatives))) + (forward-line 3) ; don't search in headers + (let ((name (car (car Info-index-alternatives)))) + (if (or (re-search-forward (format + "\\(Function\\|Command\\): %s\\( \\|$\\)" + (regexp-quote name)) nil t) + (search-forward (format "`%s'" name) nil t) + (and (string-match "\\`.*\\( (.*)\\)\\'" name) + (search-forward + (format "`%s'" (substring name 0 (match-beginning 1))) + nil t)) + (search-forward name nil t)) + (beginning-of-line) + (goto-char (point-min))))) + (message "Found \"%s\" in %s. %s" + (car (car Info-index-alternatives)) + (nth 2 (car Info-index-alternatives)) + (if (cdr Info-index-alternatives) + "(Press `,' for more)" + "(Only match)"))) + +(defun Info-emacs-key (key) + "Look up an Emacs key sequence in the Emacs manual in the Info system. +This command is designed to be used whether you are already in Info or not." + (interactive "kLook up key in Emacs manual: ") + (if (equal key "\C-g") + (keyboard-quit)) + (info) + (Info-find-node "emacs" "Top") + (setq key (key-description key)) + (let (p) + (if (setq p (string-match "[@{}]" key)) + (setq key (concat (substring key 0 p) "@" (substring key p)))) + (if (string-match "^ESC " key) + (setq key (concat "M-" (substring key 4)))) + (if (string-match "^M-C-" key) + (setq key (concat "C-M-" (substring key 4))))) + (Info-index key)) + +(defun Info-elisp-ref (func) + "Look up an Emacs Lisp function in the Elisp manual in the Info system. +This command is designed to be used whether you are already in Info or not." + (interactive (let ((fn (function-called-at-point)) + (enable-recursive-minibuffers t) + val) + (setq val (completing-read + (format "Look up Emacs Lisp function%s: " + (if fn + (format " (default %s)" fn) + "")) + obarray 'fboundp t)) + (list (if (equal val "") + fn (intern val))))) + (info) + (condition-case err + (Info-find-node "elisp" "Top") + (error (Info-find-node "lispref" "Top"))) + (Info-index (symbol-name func))) + +(defun Info-reannotate-node () + (let ((bufs (delq nil (mapcar 'get-file-buffer Info-annotations-path)))) + (if bufs + (let ((ibuf (current-buffer)) + (file (regexp-quote + (file-name-nondirectory Info-current-file))) + (node (regexp-quote Info-current-node)) + (savept (point))) + (goto-char (point-min)) + (if (search-forward "\n------ NOTE:\n" nil t) + (let ((buffer-read-only nil) + (bufmod (buffer-modified-p)) + top) + (setq savept (copy-marker savept)) + (goto-char (point-min)) + (while (search-forward "\n------ NOTE:" nil t) + (setq top (1+ (match-beginning 0))) + (if (search-forward "\n------\n" nil t) + (delete-region top (point))) + (backward-char 1)) + (set-buffer-modified-p bufmod))) + (save-excursion + (while bufs + (set-buffer (car bufs)) + (goto-char (point-min)) + (while (re-search-forward + (format + "------ *File: *%s *Node: *%s *Line: *\\([0-9]+\\) *\n" + file node) + nil t) + (let ((line (string-to-int + (buffer-substring (match-beginning 1) + (match-end 1)))) + (top (point)) + bot) + (search-forward "\n------\n" nil t) + (setq bot (point)) + (save-excursion + (set-buffer ibuf) + (if (integerp savept) (setq savept (copy-marker savept))) + (if (= line 0) + (goto-char (point-max)) + (goto-char (point-min)) + (forward-line line)) + (let ((buffer-read-only nil) + (bufmod (buffer-modified-p))) + (insert "------ NOTE:\n") + (insert-buffer-substring (car bufs) top bot) + (set-buffer-modified-p bufmod))))) + (setq bufs (cdr bufs)))) + (goto-char savept))))) + +(defvar Info-annotate-map nil + "Local keymap used within `a' command of Info.") +(if Info-annotate-map + nil + ;; (setq Info-annotate-map (nconc (make-sparse-keymap) text-mode-map)) + (setq Info-annotate-map (copy-keymap text-mode-map)) + (define-key Info-annotate-map "\C-c\C-c" 'Info-cease-annotate)) + +(defun Info-annotate-mode () + "Major mode for adding an annotation to an Info node. +Like text mode with the addition of Info-cease-annotate +which returns to Info mode for browsing. +\\{Info-annotate-map}") + +(defun Info-annotate (arg) + "Add a personal annotation to the current Info node. +Only you will be able to see this annotation. +Annotations are stored in the file ~/.infonotes by default. +If point is inside an existing annotation, edit that annotation. +A prefix argument specifies which annotations file (from +Info-annotations-path) is to be edited; default is 1." + (interactive "p") + (setq arg (1- arg)) + (if (or (< arg 0) (not (nth arg Info-annotations-path))) + (if (= arg 0) + (setq Info-annotations-path + (list (read-file-name + "Annotations file: " "~/" "~/.infonotes"))) + (error "File number must be in the range from 1 to %d" + (length Info-annotations-path)))) + (let ((which nil) + where pt) + (if (and (save-excursion + (goto-char (min (point-max) (+ (point) 13))) + (and (search-backward "------ NOTE:\n" nil t) + (setq pt (match-end 0)) + (search-forward "\n------\n" nil t))) + (< (point) (match-end 0))) + (setq which (format "File: *%s *Node: *%s *Line:.*\n%s" + (regexp-quote + (file-name-nondirectory Info-current-file)) + (regexp-quote Info-current-node) + (regexp-quote + (buffer-substring pt (match-beginning 0)))) + where (max (- (point) pt) 0))) + (let ((file (file-name-nondirectory Info-current-file)) + (node Info-current-node) + (line (if (looking-at "[ \n]*\\'") 0 + (count-lines (point-min) (point))))) + (or which + (let ((buffer-read-only nil) + (bufmod (buffer-modified-p)) + top) + (beginning-of-line) + (if (bobp) (goto-char (point-max))) + (insert "------ NOTE:\n------\n") + (backward-char 20) + (set-buffer-modified-p bufmod))) + ;; (setq Info-window-start (window-start)) + (setq Info-window-configuration (current-window-configuration)) + (pop-to-buffer (find-file-noselect (nth arg Info-annotations-path))) + (use-local-map Info-annotate-map) + (setq major-mode 'Info-annotate-mode) + (setq mode-name "Info Annotate") + (if which + (if (save-excursion + (goto-char (point-min)) + (re-search-forward which nil t)) + (progn + (goto-char (match-beginning 0)) + (forward-line 1) + (forward-char where))) + (let ((bufmod (buffer-modified-p))) + (goto-char (point-max)) + (insert (format "\n------ File: %s Node: %s Line: %d\n" + file node line)) + (setq pt (point)) + (insert "\n------\n" + "\nPress C-c C-c to save and return to Info.\n") + (goto-char pt) + (set-buffer-modified-p bufmod)))))) + +(defun Info-cease-annotate () + (interactive) + (let ((bufmod (buffer-modified-p))) + (while (save-excursion + (goto-char (point-min)) + (re-search-forward "\n\n?Press .* to save and return to Info.\n" + nil t)) + (delete-region (1+ (match-beginning 0)) (match-end 0))) + (while (save-excursion + (goto-char (point-min)) + (re-search-forward "\n------ File:.*Node:.*Line:.*\n+------\n" + nil t)) + (delete-region (match-beginning 0) (match-end 0))) + (set-buffer-modified-p bufmod)) + (save-buffer) + (fundamental-mode) + (bury-buffer) + (or (one-window-p) (delete-window)) + (info) + (setq Info-current-file-completions nil) + (set-window-configuration Info-window-configuration) + (Info-reannotate-node)) + +(defun Info-exit () + "Exit Info by selecting some other buffer." + (interactive) + (switch-to-buffer (prog1 (other-buffer (current-buffer)) + (bury-buffer (current-buffer))))) + +(defun Info-undefined () + "Make command be undefined in Info." + (interactive) + (ding)) + +(defun Info-help () + "Enter the Info tutorial." + (interactive) + (delete-other-windows) + (Info-find-node "info" + (if (< (window-height) 23) + "Help-Small-Screen" + "Help"))) + +(defun Info-summary () + "Display a brief summary of all Info commands." + (interactive) + (save-window-excursion + (switch-to-buffer "*Help*") + (erase-buffer) + (insert (documentation 'Info-mode)) + (goto-char (point-min)) + (let (ch flag) + (while (progn (setq flag (not (pos-visible-in-window-p (point-max)))) + (message (if flag "Type Space to see more" + "Type Space to return to Info")) + (if (/= ?\ (setq ch (read-char))) + (progn (setq unread-command-char ch) nil) + flag)) + (scroll-up))) + (bury-buffer "*Help*"))) + +(defun Info-get-token (pos start all &optional errorstring) + "Return the token around POS, +POS must be somewhere inside the token +START is a regular expression which will match the + beginning of the tokens delimited string +ALL is a regular expression with a single + parenthized subpattern which is the token to be + returned. E.g. '{\(.*\)}' would return any string + enclosed in braces around POS. +SIG optional fourth argument, controls action on no match + nil: return nil + t: beep + a string: signal an error, using that string." + (save-excursion + (goto-char pos) + (re-search-backward start (max (point-min) (- pos 200)) 'yes) + (while (and (re-search-forward all (min (point-max) (+ pos 200)) 'yes) + (not (and (<= (match-beginning 0) pos) + (> (match-end 0) pos))))) + (if (and (<= (match-beginning 0) pos) + (> (match-end 0) pos) + (match-beginning 1)) + (buffer-substring (match-beginning 1) (match-end 1)) + (cond ((null errorstring) + nil) + ((eq errorstring t) + (beep) + nil) + (t + (error "No %s around position %d" errorstring pos)))))) + +(defun Info-follow-clicked-node (event) + "Follow a node reference near clicked point. Like M, F, N, P or U command. +At end of the node's text, moves to the next node." + (interactive "@e") + (let* ((relative-coordinates (coordinates-in-window-p (car event) + (selected-window))) + (rel-x (car relative-coordinates)) + (rel-y (car (cdr relative-coordinates))) + (point (save-excursion + (move-to-window-line rel-y) + (move-to-column (+ rel-x (current-column))) + (point)))) + (Info-follow-nearest-node (max point (1+ (point-min)))))) + +(defun Info-follow-nearest-node (point) + "Follow a node reference near point. Like M, F, N, P or U command. +At end of the node's text, moves to the next node." + (interactive "d") + (let (node) + (cond + ((= point (point-min))) ; don't trigger on accidental RET. + ((setq node (Info-get-token point + (format "\\*%s[ \n]" Info-footnote-tag) + (format "\\*%s[ \n]\\([^:]*\\):" + Info-footnote-tag))) + (message "Following cross-reference %s..." node) + (Info-follow-reference node)) + ((setq node (Info-get-token point "\\* " "\\* \\([^:]*\\)::")) + (message "Selecting menu item %s..." node) + (Info-goto-node node)) + ((setq node (Info-get-token point "\\* " "\\* \\([^:]*\\):")) + (message "Selecting menu item %s..." node) + (Info-menu node)) + ((setq node (Info-get-token point "Up: " "Up: \\([^,\n\t]*\\)")) + (message "Going up...") + (Info-goto-node node)) + ((setq node (Info-get-token point "Next: " "Next: \\([^,\n\t]*\\)")) + (message "Next node...") + (Info-goto-node node)) + ((setq node (Info-get-token point "File: " "File: \\([^,\n\t]*\\)")) + (message "Top node...") + (Info-goto-node "Top")) + ((setq node (Info-get-token point "Prev[ious]*: " + "Prev[ious]*: \\([^,\n\t]*\\)")) + (message "Previous node...") + (Info-goto-node node)) + ((save-excursion (goto-char point) (looking-at "[ \n]*\\'")) + (if Info-in-cross-reference + (progn + (message "Back to last node...") + (Info-last)) + (message "Next node...") + (Info-global-next)))) + )) + +;;; Provide Emacs 18 support for mouse clicks. +(defvar Info-prev-x-right-click nil) +(defvar Info-prev-x-middle-click nil) +(defvar Info-prev-x-left-click nil) +(defvar Info-prev-x-s-right-click nil) +(defvar Info-prev-x-s-middle-click nil) +(defvar Info-prev-x-s-left-click nil) +(defun Info-setup-x () + (and (eq window-system 'x) + (not Info-prev-x-left-click) + Info-mouse-support + (progn + (setq Info-prev-x-right-click (aref mouse-map 0) + Info-prev-x-middle-click (aref mouse-map 1) + Info-prev-x-left-click (aref mouse-map 2) + Info-prev-x-s-right-click (aref mouse-map 16) + Info-prev-x-s-middle-click (aref mouse-map 17) + Info-prev-x-s-left-click (aref mouse-map 18)) + (aset mouse-map 0 'Info-x-right-click) + (aset mouse-map 1 'Info-x-middle-click) + (aset mouse-map 2 'Info-x-left-click) + (aset mouse-map 16 'Info-x-s-right-click) + (aset mouse-map 17 'Info-x-s-middle-click) + (aset mouse-map 18 'Info-x-s-left-click)))) + +(defun Info-x-left-click (arg) + "Handle a left-button mouse click in Info window." + (Info-handle-click '(condition-case err (Info-scroll-next nil) (error nil)) + arg Info-prev-x-left-click)) + +(defun Info-x-right-click (arg) + "Handle a right-button mouse click in Info window." + (Info-handle-click '(condition-case err (Info-scroll-prev nil) (error nil)) + arg Info-prev-x-right-click)) + +(defun Info-x-middle-click (arg) + "Handle a middle-button mouse click in Info window." + (Info-handle-click '(Info-follow-clicked-node (list arg)) + arg Info-prev-x-middle-click)) + +(defun Info-x-s-left-click (arg) + "Handle a shift-left-button mouse click in Info window." + (Info-handle-click '(Info-global-next) arg Info-prev-x-s-left-click)) + +(defun Info-x-s-right-click (arg) + "Handle a shift-right-button mouse click in Info window." + (Info-handle-click '(Info-global-prev) arg Info-prev-x-s-right-click)) + +(defun Info-x-s-middle-click (arg) + "Handle a shift-middle-button mouse click in Info window." + (Info-handle-click '(Info-last) arg Info-prev-x-s-middle-click)) + +(defun Info-handle-click (form arg prev) + (if (and (get-buffer-window "*info*") + (coordinates-in-window-p arg (get-buffer-window "*info*"))) + (let ((win (selected-window))) + (unwind-protect + (progn + (select-window (get-buffer-window "*info*")) + (eval form)) + (and (window-point win) + (select-window win)))) + (funcall prev arg))) + +(defun x-mouse-ignore (arg) + "Don't do anything." + ;; Added the following line to support Info-auto-advance mode. + (setq this-command last-command)) + +(defvar Info-mode-map nil + "Keymap containing Info commands.") +(if Info-mode-map + nil + (setq Info-mode-map (make-keymap)) + (suppress-keymap Info-mode-map) + (define-key Info-mode-map "." 'beginning-of-buffer) + (define-key Info-mode-map " " 'Info-scroll-next) + (define-key Info-mode-map "1" 'Info-nth-menu-item) + (define-key Info-mode-map "2" 'Info-nth-menu-item) + (define-key Info-mode-map "3" 'Info-nth-menu-item) + (define-key Info-mode-map "4" 'Info-nth-menu-item) + (define-key Info-mode-map "5" 'Info-nth-menu-item) + (define-key Info-mode-map "6" 'Info-nth-menu-item) + (define-key Info-mode-map "7" 'Info-nth-menu-item) + (define-key Info-mode-map "8" 'Info-nth-menu-item) + (define-key Info-mode-map "9" 'Info-nth-menu-item) + (define-key Info-mode-map "0" 'Info-last-menu-item) + (define-key Info-mode-map "?" 'Info-summary) + (define-key Info-mode-map "a" 'Info-annotate) + (define-key Info-mode-map "b" 'beginning-of-buffer) + (define-key Info-mode-map "d" 'Info-directory) + (define-key Info-mode-map "e" 'Info-edit) + (define-key Info-mode-map "f" 'Info-follow-reference) + (define-key Info-mode-map "g" 'Info-goto-node) + (define-key Info-mode-map "h" 'Info-help) + (define-key Info-mode-map "i" 'Info-index) + (define-key Info-mode-map "k" 'Info-emacs-key) + (define-key Info-mode-map "l" 'Info-last) + (define-key Info-mode-map "m" 'Info-menu) + (define-key Info-mode-map "n" 'Info-next) + (define-key Info-mode-map "p" 'Info-prev) + (define-key Info-mode-map "q" 'Info-exit) + (define-key Info-mode-map "r" 'Info-follow-reference) + (define-key Info-mode-map "s" 'Info-search) + (define-key Info-mode-map "t" 'Info-top) + (define-key Info-mode-map "u" 'Info-up) + (define-key Info-mode-map "<" 'Info-top) + (define-key Info-mode-map ">" 'Info-end) + (define-key Info-mode-map "[" 'Info-global-prev) + (define-key Info-mode-map "]" 'Info-global-next) + (define-key Info-mode-map "{" 'Info-page-prev) + (define-key Info-mode-map "}" 'Info-page-next) + (define-key Info-mode-map "=" 'Info-restore-point) + (define-key Info-mode-map "!" 'Info-select-node) + (define-key Info-mode-map "@" 'Info-follow-nearest-node) + (define-key Info-mode-map "," 'Info-index-next) + (define-key Info-mode-map "*" 'Info-elisp-ref) + (define-key Info-mode-map "\t" 'Info-next-reference) + (define-key Info-mode-map "\e\t" 'Info-prev-reference) + (define-key Info-mode-map "\r" 'Info-follow-nearest-node) + (define-key Info-mode-map "\177" 'Info-scroll-prev)) + +(or (lookup-key help-map "\C-k") + (define-key help-map "\C-k" 'Info-emacs-key)) + +(or (lookup-key help-map "\C-f") + (define-key help-map "\C-f" 'Info-elisp-ref)) + +(let ((help (symbol-function 'help-for-help)) + (doc (documentation 'help-for-help))) + (and (consp help) (eq (car help) 'lambda) + (not (string-match "C-k" doc)) + (setq doc (concat + doc + "\n\nC-k Info-emacs-key. Look up a key in Emacs manual." + "\nC-f Info-elisp-ref." + " Look up a function in Emacs Lisp manual.")) + (fset 'help-for-help + (cons 'lambda (cons (nth 1 help) (cons doc (nthcdr 2 help))))))) + + +;;; The following stuff is for Emacs 19 only---it's ignored in Emacs 18. +(defvar Info-mode-mouse-map nil + "Mouse map for use with Info mode.") + +(if Info-mode-mouse-map + nil + (if (or (not (boundp 'global-mouse-map)) + (null (cdr global-mouse-map))) + nil + (setq Info-mode-mouse-map (make-sparse-keymap)) + (define-key Info-mode-mouse-map mouse-button-middle + 'Info-follow-clicked-node) + (define-key Info-mode-mouse-map mouse-button-left 'mouse-scroll-up-full) + (define-key Info-mode-mouse-map mouse-button-right + 'mouse-scroll-down-full))) + +;; Info mode is suitable only for specially formatted data. +(put 'info-mode 'mode-class 'special) + +(defun Info-mode () + "Info mode is for browsing through the Info documentation tree. +Documentation in Info is divided into \"nodes\", each of which +discusses one topic and contains references to other nodes +which discuss related topics. Info has commands to follow +the references and show you other nodes. + +h Invoke the Info tutorial. +q Quit Info: return to previously selected file or buffer. + +Selecting other nodes: +n Move to the \"next\" node of this node. +p Move to the \"previous\" node of this node. +m Pick menu item specified by name (or abbreviation). +1-9, 0 Pick first..ninth, last item in node's menu. + Menu items select nodes that are \"subsections\" of this node. +u Move \"up\" from this node (i.e., from a subsection to a section). +f or r Follow a cross reference by name (or abbrev). Type `l' to get back. +RET Follow cross reference or menu item indicated by cursor. +i Look up a topic in this file's Index and move to that node. +, (comma) Move to the next match from a previous `i' command. +l (letter L) Move back to the last node you were in. + +Moving within a node: +Space Scroll forward a full screen. DEL Scroll backward. +b Go to beginning of node. Meta-> Go to end of node. +TAB Go to next cross-reference. Meta-TAB Go to previous ref. + +Mouse commands: Shifted mouse commands: +Middle Follow reference (RET). S-Middle Back to last node (`l'). +Left Next page or node (Space). S-Left Next node (`]'). +Right Prev page or node (DEL). S-Right Prev node (`['). + +Advanced commands: +g Move to node, file, or annotation tag specified by name. + Examples: `g Rectangles' `g (Emacs)Rectangles' `g Emacs'. +k Look up a key sequence in Emacs manual (also C-h C-k at any time). +* Look up a function name in Emacs Lisp manual (also C-h C-f). +d Go to the main directory of Info files. +< or t Go to Top (first) node of this file. +> Go to last node in this file. +\[ Go to previous node, treating file as one linear document. +\] Go to next node, treating file as one linear document. +{ Scroll backward, or go to previous node if at top. +} Scroll forward, or go to next node if at bottom. += Restore cursor position from last time in this node. +a Add a private note (annotation) to the current node. +s Search this Info file for a node containing the specified regexp. +e Edit the contents of the current node." + (kill-all-local-variables) + (setq major-mode 'Info-mode) + (setq mode-name "Info") + (use-local-map Info-mode-map) + (set-syntax-table text-mode-syntax-table) + (setq local-abbrev-table text-mode-abbrev-table) + (setq case-fold-search t) + (setq buffer-read-only t) + (setq buffer-mouse-map Info-mode-mouse-map) + (make-local-variable 'Info-current-file) + (make-local-variable 'Info-current-subfile) + (make-local-variable 'Info-current-node) + (make-local-variable 'Info-tag-table-marker) + (make-local-variable 'Info-current-file-completions) + (make-local-variable 'Info-index-alternatives) + (make-local-variable 'Info-history) + (run-hooks 'Info-mode-hook) + (Info-set-mode-line)) + +(defvar Info-edit-map nil + "Local keymap used within `e' command of Info.") +(if Info-edit-map + nil + ;; (setq Info-edit-map (nconc (make-sparse-keymap) text-mode-map)) + (setq Info-edit-map (copy-keymap text-mode-map)) + (define-key Info-edit-map "\C-c\C-c" 'Info-cease-edit)) + +;; Info-edit mode is suitable only for specially formatted data. +(put 'info-edit-mode 'mode-class 'special) + +(defun Info-edit-mode () + "Major mode for editing the contents of an Info node. +Like text mode with the addition of Info-cease-edit +which returns to Info mode for browsing. +\\{Info-edit-map}" + ) + +(defun Info-edit () + "Edit the contents of this Info node. +Allowed only if variable Info-enable-edit is non-nil." + (interactive) + (or Info-enable-edit + (error "Editing info nodes is not enabled")) + (use-local-map Info-edit-map) + (setq major-mode 'Info-edit-mode) + (setq mode-name "Info Edit") + (kill-local-variable 'mode-line-buffer-identification) + (setq buffer-read-only nil) + ;; Make mode line update. + (set-buffer-modified-p (buffer-modified-p)) + (message (substitute-command-keys + "Editing: Type \\[Info-cease-edit] to return to info"))) + +(defun Info-cease-edit () + "Finish editing Info node; switch back to Info proper." + (interactive) + ;; Do this first, so nothing has changed if user C-g's at query. + (and (buffer-modified-p) + (y-or-n-p "Save the file? ") + (save-buffer)) + (use-local-map Info-mode-map) + (setq major-mode 'Info-mode) + (setq mode-name "Info") + (Info-set-mode-line) + (setq buffer-read-only t) + ;; Make mode line update. + (set-buffer-modified-p (buffer-modified-p)) + (and (marker-position Info-tag-table-marker) + (buffer-modified-p) + (message "Tags may have changed. Use Info-tagify if necessary"))) + +(run-hooks 'Info-load-hook) + +;;; End. diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/linebreaks.texi b/web/glasgow/lit2x-0.16/literate/info-utils/linebreaks.texi new file mode 100644 index 0000000000..df18fdb5c8 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/linebreaks.texi @@ -0,0 +1,18 @@ +@setfilename linebreaks.info + +@node Top, , , (dir) +@comment node, next, previous, up +@srcfilename handbook.lit +@srclineno 1 + +@c see the bug if paragraph-indent is run at zero + +The one command that needs more explanation is the @w{@samp{m}} command, which is +short for "menu", becuase you have to specify which subsection you want to +visit. + +An example of a menu appears just below. It gives the names and title +of the subsections of this section. These give further information +about using the index to find your way around, using cross-references, +printing parts of the handbook, and so on. You can use the @w{@samp{m}} +command to read them. diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/makeinfo.c b/web/glasgow/lit2x-0.16/literate/info-utils/makeinfo.c new file mode 100644 index 0000000000..b595ee0432 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/makeinfo.c @@ -0,0 +1,7522 @@ +/* Makeinfo -- convert texinfo format files into info files. + + Copyright (C) 1987, 1991 Free Software Foundation, Inc. + + This file is part of GNU Info. + + Makeinfo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. No author or distributor accepts + responsibility to anyone for the consequences of using it or for + whether it serves any particular purpose or works at all, unless he + says so in writing. Refer to the GNU Emacs General Public License + for full details. + + Everyone is granted permission to copy, modify and redistribute + Makeinfo, but only under the conditions described in the GNU Emacs + General Public License. A copy of this license is supposed to + have been given to you along with GNU Emacs so you can know your + rights and responsibilities. It should be in a file named COPYING. + Among other things, the copyright notice and this notice must be + preserved on all copies. */ + +/* This is Makeinfo version 1.47. If you change the version number of + Makeinfo, please change it here and at the lines reading: + + int major_version = 1; + int minor_version = 47; + + in the code below. */ + +/* You can change some of the behaviour of Makeinfo by changing the + following defines: */ + +/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which + appear within an @table, @ftable, or @itemize environment to have + standard paragraph indentation. Without this, such paragraphs have + no starting indentation. */ +/* #define INDENT_PARAGRAPHS_IN_TABLE */ + +/* Define DEFAULT_INDENTATION_INCREMENT as an integer which is the amount + that @example should increase indentation by. This increment is used + for all insertions which indent the enclosed text. */ +#define DEFAULT_INDENTATION_INCREMENT 5 + +/* Define PARAGRAPH_START_INDENT to be the amount of indentation that + the first lines of paragraphs receive by default, where no other + value has been specified. Users can change this value on the command + line, with the +paragraph-indent option, or within the texinfo file, + with the @paragraphindent command. */ +#define PARAGRAPH_START_INDENT 0 /* partain changed from 3 */ + +/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you + wish to appear between paragraphs. A value of 1 creates a single blank + line between paragraphs. Paragraphs are defined by 2 or more consecutive + newlines in the input file (i.e., one or more blank lines). */ +#define DEFAULT_PARAGRAPH_SPACING 1 + +/* **************************************************************** */ +/* */ +/* Include File Declarations */ +/* */ +/* **************************************************************** */ + +/* Indent #pragma so that older Cpp's don't try to parse it. */ +#if defined (_AIX) + # pragma alloca +#endif /* _AIX */ + +/* partain: to go w/ "make world" */ +#if defined(SYSV) +#define USG 1 +#endif +/* end partain */ + +#include <stdio.h> +#include <sys/types.h> +#include <ctype.h> +#include <sys/stat.h> +#include <ctype.h> +#include <pwd.h> +#include <errno.h> +#include "getopt.h" + +#if defined (VMS) +# include <perror.h> +#endif + +#if defined (USG) || defined (VMS) +# include <string.h> +# include <time.h> +#else /* !USG && !VMS */ +# include <strings.h> +# include <sys/time.h> +#endif /* !USG && !VMS */ + +#include <fcntl.h> +#include <sys/file.h> + +#if defined (USG) || defined (hpux) +#define bcopy(source, dest, count) memcpy (dest, source, count) +char *index (s, c) char *s; { char *strchr (); return strchr (s, c); } +char *rindex (s, c) char *s; { char *strrchr (); return (strrchr (s, c)); } +#endif /* USG || hpux */ + +#if defined (__GNUC__) +# define alloca __builtin_alloca +#else +# if defined (sparc) +# include <alloca.h> +# else +# if !defined (_AIX) +extern char *alloca (); +# endif /* _AIX */ +# endif /* !sparc */ +#endif /* !__GNUC__ */ + +/* Forward declarations. */ +void *xmalloc (), *xrealloc (); + +/* Non-zero means that we are currently hacking the insides of an + insertion which would use a fixed width font. */ +static int in_fixed_width_font = 0; + +/* Non-zero means that start_paragraph () MUST be called before we pay + any attention to close_paragraph () calls. */ +int must_start_paragraph = 0; + +/* Some systems don't declare this function in pwd.h. */ +struct passwd *getpwnam (); + + +/* **************************************************************** */ +/* */ +/* Global Defines */ +/* */ +/* **************************************************************** */ + +/* Error levels */ +#define NO_ERROR 0 +#define SYNTAX 2 +#define FATAL 4 + +/* How to allocate permanent storage for STRING. */ +#define savestring(x) \ + ((char *)strcpy ((char *)xmalloc (1 + ((x) ? strlen (x) : 0)), \ + (x) ? (x) : "")) + +/* C's standard macros don't check to make sure that the characters being + changed are within range. So I have to check explicitly. */ + +/* GNU Library doesn't have toupper(). Until GNU gets this fixed, I will + have to do it. */ +#ifndef toupper +#define toupper(c) ((c) - 32) +#endif + +#define coerce_to_upper(c) ((islower(c) ? toupper(c) : (c))) +#define coerce_to_lower(c) ((isupper(c) ? tolower(c) : (c))) + +#define control_character_bit 0x40 /* %01000000, must be off. */ +#define meta_character_bit 0x080/* %10000000, must be on. */ +#define CTL(c) ((c) & (~control_character_bit)) +#define UNCTL(c) coerce_to_upper(((c)|control_character_bit)) +#define META(c) ((c) | (meta_character_bit)) +#define UNMETA(c) ((c) & (~meta_character_bit)) + +#define whitespace(c) (((c) == '\t') || ((c) == ' ')) +#define sentence_ender(c) ((c) == '.' || (c) == '?' || (c) == '!') +#define cr_or_whitespace(c) (((c) == '\t') || ((c) == ' ') || ((c) == '\n')) + +#ifndef isletter +#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) +#endif + +#ifndef isupper +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#endif + +#ifndef isdigit +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef digit_value +#define digit_value(c) ((c) - '0') +#endif + +#define member(c, s) (index (s, c) != NULL) + +#define COMMAND_PREFIX '@' + +/* Stuff for splitting large files. */ +#define SPLIT_SIZE_THRESHOLD 70000 /* What's good enough for Stallman... */ +#define DEFAULT_SPLIT_SIZE 50000/* Is probably good enough for me. */ +/* partain: orig +int splitting = 1; /? Always true for now. ?/ +*/ +int splitting = 0; /* Always false for now. */ + +typedef int FUNCTION (); /* So I can say FUNCTION *foo; */ + + +/* **************************************************************** */ +/* */ +/* Global Variables */ +/* */ +/* **************************************************************** */ + +/* Global pointer to argv[0]. */ +char *progname; + +/* The current input file state. */ +char *input_filename; +#ifdef TRACK_SRCFILE +char *src_filename; +int src_lineno; +#endif /* TRACK_SRCFILE */ +char *input_text; +int size_of_input_text; +int input_text_offset; +int line_number; + +#define curchar() input_text[input_text_offset] + +#define command_char(c) ((!whitespace(c)) && \ + ((c) != '\n') && \ + ((c) != '{') && \ + ((c) != '}') && \ + ((c) != '=')) + +#define skip_whitespace() while (input_text_offset != size_of_input_text \ + && whitespace(curchar()))\ + input_text_offset++ + +/* Return non-zero if STRING is the text at input_text + input_text_offset, + else zero. */ +#define looking_at(string) \ + (strncmp (input_text + input_text_offset, string, strlen (string)) == 0) + +/* And writing to the output. */ + +/* The output file name. */ +char *output_filename = (char *)NULL; +char *pretty_output_filename; + +/* Name of the output file that the user elected to pass on the command line. + Such a name overrides any name found with the @setfilename command. */ +char *command_output_filename = (char *)NULL; + +/* A colon separated list of directories to search for files included + with @include. This can be controlled with the `-I' option to makeinfo. */ +char *include_files_path = (char *)NULL; + +/* Current output stream. */ +FILE *output_stream; + +/* Position in the output file. */ +int output_position; + +/* Output paragraph buffer. */ +unsigned char *output_paragraph; + +/* Offset into OUTPUT_PARAGRAPH. */ +int output_paragraph_offset; + +/* The output paragraph "cursor" horizontal position. */ +int output_column = 0; + +/* Non-zero means output_paragraph contains text. */ +int paragraph_is_open = 0; + +#define INITIAL_PARAGRAPH_SPACE 5000 +int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE; + +/* Filling.. */ +/* Non-zero indicates that filling will take place on long lines. */ +int filling_enabled = 1; + +/* Non-zero means that words are not to be split, even in long lines. This + gets changed for cm_w (). */ +int non_splitting_words = 0; + +/* Non-zero indicates that filling a line also indents the new line. */ +int indented_fill = 0; + +/* The column at which long lines are broken. */ +int fill_column = 72; + +/* The amount of indentation to apply at the start of each line. */ +int current_indent = 0; + +/* The amount of indentation to add at the starts of paragraphs. + 0 means don't change existing indentation at paragraph starts. + > 0 is amount to indent new paragraphs by. + < 0 means indent to column zero by removing indentation if necessary. + + This is normally zero, but some people prefer paragraph starts to be + somewhat more indented than paragraph bodies. A pretty value for + this is 3. */ +int paragraph_start_indent = PARAGRAPH_START_INDENT; + +/* Non-zero means that the use of paragraph_start_indent is inhibited. + @example uses this to line up the left columns of the example text. + A negative value for this variable is incremented each time it is used. + @noindent uses this to inhibit indentation for a single paragraph. */ +int inhibit_paragraph_indentation = 0; + +/* Indentation that is pending insertion. We have this for hacking lines + which look blank, but contain whitespace. We want to treat those as + blank lines. */ +int pending_indent = 0; + +/* The amount that indentation increases/decreases by. */ +int default_indentation_increment = DEFAULT_INDENTATION_INCREMENT; + +/* Non-zero indicates that indentation is temporarily turned off. */ +int no_indent = 1; + +/* Non-zero means forcing output text to be flushright. */ +int force_flush_right = 0; + +/* Non-zero means that the footnote style for this document was set on + the command line, which overrides any other settings. */ +int footnote_style_preset = 0; + +/* Non-zero means that we automatically number footnotes that have no + specified marker. */ +int number_footnotes = 1; + +/* The current footnote number in this node. Each time a new node is + started this is reset to 1. */ +int current_footnote_number = 1; + +/* Command name in the process of being hacked. */ +char *command; + +/* The index in our internal command table of the currently + executing command. */ +int command_index; + +/* A stack of file information records. If a new file is read in with + "@input", we remember the old input file state on this stack. */ +typedef struct fstack +{ + struct fstack *next; + char *filename; + char *text; + int size; + int offset; + int line_number; +#ifdef TRACK_SRCFILE + char *src_filename; + int src_lineno; +#endif /* TRACK_SRCFILE */ +} FSTACK; + +FSTACK *filestack = (FSTACK *) NULL; + +/* Stuff for nodes. */ +/* The current nodes node name. */ +char *current_node = (char *)NULL; + +/* The current nodes section level. */ +int current_section = 0; + +/* The filename of the current input file. This is never freed. */ +char *node_filename = (char *)NULL; +#ifdef TRACK_SRCFILE +char *node_src_filename = (char *)NULL; +#endif /* TRACK_SRCFILE */ + +/* What we remember for each node. */ +typedef struct tentry +{ + struct tentry *next_ent; + char *node; /* name of this node. */ + char *prev; /* name of "Prev:" for this node. */ + char *next; /* name of "Next:" for this node. */ + char *up; /* name of "Up:" for this node. */ + int position; /* output file position of this node. */ + int line_no; /* defining line in source file. */ + char *filename; /* The file that this node was found in. */ +#ifdef TRACK_SRCFILE + char *src_filename; /* The ORIG file that this node was found in. */ + int src_lineno; /* defining line in ORIG source file. */ +#endif /* TRACK_SRCFILE */ + int touched; /* non-zero means this node has been referenced. */ + int flags; /* Room for growth. Right now, contains 1 bit. */ +} TAG_ENTRY; + +/* If node-a has a "Next" for node-b, but node-b has no "Prev" for node-a, + we turn on this flag bit in node-b's tag entry. This means that when + it is time to validate node-b, we don't report an additional error + if there was no "Prev" field. */ +#define PREV_ERROR 0x1 +#define NEXT_ERROR 0x2 +#define UP_ERROR 0x4 +#define NO_WARN 0x8 +#define IS_TOP 0x10 + +TAG_ENTRY *tag_table = (TAG_ENTRY *) NULL; + +#define HAVE_MACROS +#if defined (HAVE_MACROS) +/* Macro definitions for user-defined commands. */ +typedef struct { + char *name; /* Name of the macro. */ + char *definition; /* Definition text. */ + char *filename; /* File where this macro is defined. */ + int lineno; /* Line number within FILENAME. */ +} MACRO_DEF; + +void add_macro (), execute_macro (); +MACRO_DEF *find_macro (), *delete_macro (); +#endif /* HAVE_MACROS */ + +/* Menu reference, *note reference, and validation hacking. */ + +/* The various references that we know about. */ +enum reftype +{ + menu_reference, followed_reference +}; + +/* A structure to remember references with. A reference to a node is + either an entry in a menu, or a cross-reference made with [px]ref. */ +typedef struct node_ref +{ + struct node_ref *next; + char *node; /* Name of node referred to. */ + char *containing_node; /* Name of node containing this reference. */ + int line_no; /* Line number where the reference occurs. */ +#ifdef TRACK_SRCFILE + int src_lineno; +#endif /* TRACK_SRCFILE */ + int section; /* Section level where the reference occurs. */ + char *filename; /* Name of file where the reference occurs. */ +#ifdef TRACK_SRCFILE + char *src_filename; +#endif /* TRACK_SRCFILE */ + enum reftype type; /* Type of reference, either menu or note. */ +} NODE_REF; + +/* The linked list of such structures. */ +NODE_REF *node_references = (NODE_REF *) NULL; + +/* Flag which tells us whether to examine menu lines or not. */ +int in_menu = 0; + +/* Flags controlling the operation of the program. */ + +/* Default is to notify users of bad choices. */ +int print_warnings = 1; + +/* Default is to check node references. */ +int validating = 1; + +/* Non-zero means do not output "Node: Foo" for node separations. */ +int no_headers = 0; + +/* Number of errors that we tolerate on a given fileset. */ +int max_error_level = 100; + +/* Maximum number of references to a single node before complaining. */ +int reference_warning_limit = 1000; + +/* Non-zero means print out information about what is going on when it + is going on. */ +int verbose_mode = 0; + +/* The list of commands that we hack in texinfo. Each one + has an associated function. When the command is encountered in the + text, the associated function is called with START as the argument. + If the function expects arguments in braces, it remembers itself on + the stack. When the corresponding close brace is encountered, the + function is called with END as the argument. */ + +#define START 0 +#define END 1 + +typedef struct brace_element +{ + struct brace_element *next; + FUNCTION *proc; + int pos, line; +#ifdef TRACK_SRCFILE + int src_lineno; +#endif /* TRACK_SRCFILE */ +} BRACE_ELEMENT; + +BRACE_ELEMENT *brace_stack = (BRACE_ELEMENT *) NULL; + +/* Forward declarations. */ + +int insert_self (), cm_ignore_line (); + +int + cm_tex (), cm_asterisk (), cm_dots (), cm_bullet (), cm_TeX (), + cm_copyright (), cm_code (), cm_samp (), cm_file (), cm_kbd (), + cm_key (), cm_ctrl (), cm_var (), cm_dfn (), cm_emph (), cm_strong (), + cm_cite (), cm_italic (), cm_bold (), cm_roman (), cm_title (), cm_w (), + cm_refill (), cm_titlefont (); + +int + cm_chapter (), cm_unnumbered (), cm_appendix (), cm_top (), + cm_section (), cm_unnumberedsec (), cm_appendixsec (), + cm_subsection (), cm_unnumberedsubsec (), cm_appendixsubsec (), + cm_subsubsection (), cm_unnumberedsubsubsec (), cm_appendixsubsubsec (), + cm_heading (), cm_chapheading (), cm_subheading (), cm_subsubheading (), + cm_majorheading (); + +/* All @defxxx commands map to cm_defun (). */ +int cm_defun (); + +int + cm_node (), cm_menu (), cm_xref (), cm_ftable (), cm_vtable (), cm_pxref (), + cm_inforef (), cm_quotation (), cm_display (), cm_itemize (), + cm_enumerate (), cm_table (), cm_itemx (), cm_noindent (), cm_setfilename (), + cm_br (), cm_sp (), cm_page (), cm_group (), cm_center (), cm_include (), + cm_bye (), cm_item (), cm_end (), cm_infoinclude (), cm_ifinfo (), + cm_kindex (), cm_cindex (), cm_findex (), cm_pindex (), cm_vindex (), + cm_tindex (), cm_asis (), cm_synindex (), cm_printindex (), cm_minus (), + cm_footnote (), cm_force_abbreviated_whitespace (), cm_example (), + cm_smallexample (), cm_lisp (), cm_format (), cm_exdent (), cm_defindex (), + cm_defcodeindex (), cm_sc (), cm_result (), cm_expansion (), cm_equiv (), + cm_print (), cm_error (), cm_point (), cm_today (), cm_flushleft (), + cm_flushright (), cm_smalllisp (), cm_finalout (), cm_math (), + cm_cartouche (), cm_ignore_sentence_ender (); + +#ifdef TRACK_SRCFILE +int cm_srcfilename (), cm_srclineno (); +#endif /* TRACK_SRCFILE */ + +/* Conditionals. */ +int cm_set (), cm_clear (), cm_ifset (), cm_ifclear (), cm_value (); + +#if defined (HAVE_MACROS) +/* Define a user-defined command which is simple substitution. */ +int cm_macro (), cm_unmacro (); +#endif /* HAVE_MACROS */ + +/* Options. */ +int cm_paragraphindent (), cm_footnotestyle (); + +/* Internals. */ +int do_nothing (), command_name_condition (); +int misplaced_brace (), cm_obsolete (); + +typedef struct +{ + char *name; + FUNCTION *proc; + int argument_in_braces; +} COMMAND; + +/* Stuff for defining commands on the fly. */ +COMMAND **user_command_array = (COMMAND **) NULL; +int user_command_array_len = 0; + +#define NO_BRACE_ARGS 0 +#define BRACE_ARGS 1 + +static COMMAND CommandTable[] = { + { "!", cm_ignore_sentence_ender, NO_BRACE_ARGS }, + { "'", insert_self, NO_BRACE_ARGS }, + { "*", cm_asterisk, NO_BRACE_ARGS }, + { ".", cm_ignore_sentence_ender, NO_BRACE_ARGS }, + { ":", cm_force_abbreviated_whitespace, NO_BRACE_ARGS }, + { "?", cm_ignore_sentence_ender, NO_BRACE_ARGS }, + { "@", insert_self, NO_BRACE_ARGS }, + { " ", insert_self, NO_BRACE_ARGS }, + { "\n", insert_self, NO_BRACE_ARGS }, + { "TeX", cm_TeX, BRACE_ARGS }, + { "`", insert_self, NO_BRACE_ARGS }, + { "appendix", cm_appendix, NO_BRACE_ARGS }, + { "appendixsection", cm_appendixsec, NO_BRACE_ARGS }, + { "appendixsec", cm_appendixsec, NO_BRACE_ARGS }, + { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS }, + { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS }, + { "asis", cm_asis, BRACE_ARGS }, + { "b", cm_bold, BRACE_ARGS }, + { "br", cm_br, NO_BRACE_ARGS }, + { "bullet", cm_bullet, BRACE_ARGS }, + { "bye", cm_bye, NO_BRACE_ARGS }, + { "c", cm_ignore_line, NO_BRACE_ARGS }, + { "cartouche", cm_cartouche, NO_BRACE_ARGS }, + { "center", cm_center, NO_BRACE_ARGS }, + { "chapheading", cm_chapheading, NO_BRACE_ARGS }, + { "chapter", cm_chapter, NO_BRACE_ARGS }, + { "cindex", cm_cindex, NO_BRACE_ARGS }, + { "cite", cm_cite, BRACE_ARGS }, + { "clear", cm_clear, NO_BRACE_ARGS }, + { "code", cm_code, BRACE_ARGS }, + { "comment", cm_ignore_line, NO_BRACE_ARGS }, + { "contents", do_nothing, NO_BRACE_ARGS }, + { "copyright", cm_copyright, BRACE_ARGS }, + { "ctrl", cm_ctrl, BRACE_ARGS }, + { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS }, + { "defindex", cm_defindex, NO_BRACE_ARGS }, + { "dfn", cm_dfn, BRACE_ARGS }, + +/* The `def' commands. */ + { "deffn", cm_defun, NO_BRACE_ARGS }, + { "deffnx", cm_defun, NO_BRACE_ARGS }, + { "defun", cm_defun, NO_BRACE_ARGS }, + { "defunx", cm_defun, NO_BRACE_ARGS }, + { "defmac", cm_defun, NO_BRACE_ARGS }, + { "defmacx", cm_defun, NO_BRACE_ARGS }, + { "defspec", cm_defun, NO_BRACE_ARGS }, + { "defspecx", cm_defun, NO_BRACE_ARGS }, + { "defvr", cm_defun, NO_BRACE_ARGS }, + { "defvrx", cm_defun, NO_BRACE_ARGS }, + { "defvar", cm_defun, NO_BRACE_ARGS }, + { "defvarx", cm_defun, NO_BRACE_ARGS }, + { "defopt", cm_defun, NO_BRACE_ARGS }, + { "defoptx", cm_defun, NO_BRACE_ARGS }, + { "deftypefn", cm_defun, NO_BRACE_ARGS }, + { "deftypefnx", cm_defun, NO_BRACE_ARGS }, + { "deftypefun", cm_defun, NO_BRACE_ARGS }, + { "deftypefunx", cm_defun, NO_BRACE_ARGS }, + { "deftypevr", cm_defun, NO_BRACE_ARGS }, + { "deftypevrx", cm_defun, NO_BRACE_ARGS }, + { "deftypevar", cm_defun, NO_BRACE_ARGS }, + { "deftypevarx", cm_defun, NO_BRACE_ARGS }, + { "defcv", cm_defun, NO_BRACE_ARGS }, + { "defcvx", cm_defun, NO_BRACE_ARGS }, + { "defivar", cm_defun, NO_BRACE_ARGS }, + { "defivarx", cm_defun, NO_BRACE_ARGS }, + { "defop", cm_defun, NO_BRACE_ARGS }, + { "defopx", cm_defun, NO_BRACE_ARGS }, + { "defmethod", cm_defun, NO_BRACE_ARGS }, + { "defmethodx", cm_defun, NO_BRACE_ARGS }, + { "deftypemethod", cm_defun, NO_BRACE_ARGS }, + { "deftypemethodx", cm_defun, NO_BRACE_ARGS }, + { "deftp", cm_defun, NO_BRACE_ARGS }, + { "deftpx", cm_defun, NO_BRACE_ARGS }, +/* The end of the `def' commands. */ + + { "display", cm_display, NO_BRACE_ARGS }, + { "dots", cm_dots, BRACE_ARGS }, + { "dmn", do_nothing, BRACE_ARGS }, + { "emph", cm_emph, BRACE_ARGS }, + { "end", cm_end, NO_BRACE_ARGS }, + { "enumerate", cm_enumerate, NO_BRACE_ARGS }, + { "equiv", cm_equiv, BRACE_ARGS }, + { "error", cm_error, BRACE_ARGS }, + { "example", cm_example, NO_BRACE_ARGS }, + { "exdent", cm_exdent, NO_BRACE_ARGS }, + { "expansion", cm_expansion, BRACE_ARGS }, + { "file", cm_file, BRACE_ARGS }, + { "findex", cm_findex, NO_BRACE_ARGS }, + { "finalout", do_nothing, NO_BRACE_ARGS }, + { "flushleft", cm_flushleft, NO_BRACE_ARGS }, + { "flushright", cm_flushright, NO_BRACE_ARGS }, + { "format", cm_format, NO_BRACE_ARGS }, + { "ftable", cm_ftable, NO_BRACE_ARGS }, + { "group", cm_group, NO_BRACE_ARGS }, + { "heading", cm_heading, NO_BRACE_ARGS }, + { "headings", cm_ignore_line, NO_BRACE_ARGS }, + { "i", cm_italic, BRACE_ARGS }, + { "iappendix", cm_appendix, NO_BRACE_ARGS }, + { "iappendixsection", cm_appendixsec, NO_BRACE_ARGS }, + { "iappendixsec", cm_appendixsec, NO_BRACE_ARGS }, + { "iappendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS }, + { "iappendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS }, + { "ichapter", cm_chapter, NO_BRACE_ARGS }, + { "ifclear", cm_ifclear, NO_BRACE_ARGS }, + { "ifinfo", cm_ifinfo, NO_BRACE_ARGS }, + { "ifset", cm_ifset, NO_BRACE_ARGS }, + { "iftex", command_name_condition, NO_BRACE_ARGS }, + { "ignore", command_name_condition, NO_BRACE_ARGS }, + { "include", cm_include, NO_BRACE_ARGS }, + { "inforef", cm_inforef, BRACE_ARGS }, + { "input", cm_include, NO_BRACE_ARGS }, + { "isection", cm_section, NO_BRACE_ARGS }, + { "isubsection", cm_subsection, NO_BRACE_ARGS }, + { "isubsubsection", cm_subsubsection, NO_BRACE_ARGS }, + { "item", cm_item, NO_BRACE_ARGS }, + { "itemize", cm_itemize, NO_BRACE_ARGS }, + { "itemx", cm_itemx, NO_BRACE_ARGS }, + { "iunnumbered", cm_unnumbered, NO_BRACE_ARGS }, + { "iunnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS }, + { "iunnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS }, + { "iunnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS }, + { "kbd", cm_kbd, BRACE_ARGS }, + { "key", cm_key, BRACE_ARGS }, + { "kindex", cm_kindex, NO_BRACE_ARGS }, + { "lisp", cm_lisp, NO_BRACE_ARGS }, + { "macro", cm_macro, NO_BRACE_ARGS }, + { "majorheading", cm_majorheading, NO_BRACE_ARGS }, + { "math", cm_math, BRACE_ARGS }, + { "menu", cm_menu, NO_BRACE_ARGS }, + { "minus", cm_minus, BRACE_ARGS }, + { "need", cm_ignore_line, NO_BRACE_ARGS }, + { "node", cm_node, NO_BRACE_ARGS }, + { "noindent", cm_noindent, NO_BRACE_ARGS }, + { "nwnode", cm_node, NO_BRACE_ARGS }, + { "overfullrule", cm_ignore_line, NO_BRACE_ARGS }, + { "page", do_nothing, NO_BRACE_ARGS }, + { "pindex", cm_pindex, NO_BRACE_ARGS }, + { "point", cm_point, BRACE_ARGS }, + { "print", cm_print, BRACE_ARGS }, + { "printindex", cm_printindex, NO_BRACE_ARGS }, + { "pxref", cm_pxref, BRACE_ARGS }, + { "quotation", cm_quotation, NO_BRACE_ARGS }, + { "r", cm_roman, BRACE_ARGS }, + { "ref", cm_xref, BRACE_ARGS }, + { "refill", cm_refill, NO_BRACE_ARGS }, + { "result", cm_result, BRACE_ARGS }, + { "samp", cm_samp, BRACE_ARGS }, + { "sc", cm_sc, BRACE_ARGS }, + { "section", cm_section, NO_BRACE_ARGS }, + { "set", cm_set, NO_BRACE_ARGS }, + { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS }, + { "setchapterstyle", cm_ignore_line, NO_BRACE_ARGS }, + { "setfilename", cm_setfilename, NO_BRACE_ARGS }, + { "settitle", cm_ignore_line, NO_BRACE_ARGS }, + { "shortcontents", do_nothing, NO_BRACE_ARGS }, + { "smallbook", cm_ignore_line, NO_BRACE_ARGS }, + { "smallexample", cm_smallexample, NO_BRACE_ARGS }, + { "smalllisp", cm_smalllisp, NO_BRACE_ARGS }, + { "sp", cm_sp, NO_BRACE_ARGS }, +#ifdef TRACK_SRCFILE + { "srcfilename", cm_srcfilename, NO_BRACE_ARGS }, + { "srclineno", cm_srclineno, NO_BRACE_ARGS }, +#endif /* TRACK_SRCFILE */ + { "strong", cm_strong, BRACE_ARGS }, + { "subheading", cm_subheading, NO_BRACE_ARGS }, + { "subsection", cm_subsection, NO_BRACE_ARGS }, + { "subsubheading", cm_subsubheading, NO_BRACE_ARGS }, + { "subsubsection", cm_subsubsection, NO_BRACE_ARGS }, + { "summarycontents", do_nothing, NO_BRACE_ARGS }, + { "syncodeindex", cm_synindex, NO_BRACE_ARGS }, + { "synindex", cm_synindex, NO_BRACE_ARGS }, + { "t", cm_title, BRACE_ARGS }, + { "table", cm_table, NO_BRACE_ARGS }, + { "tex", command_name_condition, NO_BRACE_ARGS }, + { "tindex", cm_tindex, NO_BRACE_ARGS }, + { "titlefont", cm_titlefont, BRACE_ARGS }, + { "titlepage", command_name_condition, NO_BRACE_ARGS }, + { "titlespec", command_name_condition, NO_BRACE_ARGS }, + { "today", cm_today, BRACE_ARGS }, + { "top", cm_top, NO_BRACE_ARGS }, + { "unmacro", cm_unmacro, NO_BRACE_ARGS }, + { "unnumbered", cm_unnumbered, NO_BRACE_ARGS }, + { "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS }, + { "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS }, + { "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS }, + { "value", cm_value, BRACE_ARGS }, + { "var", cm_var, BRACE_ARGS }, + { "vindex", cm_vindex, NO_BRACE_ARGS }, + { "vtable", cm_vtable, NO_BRACE_ARGS }, + { "w", cm_w, BRACE_ARGS }, + { "xref", cm_xref, BRACE_ARGS }, + { "{", insert_self, NO_BRACE_ARGS }, + { "}", insert_self, NO_BRACE_ARGS }, + + /* Some obsoleted commands. */ + { "infotop", cm_obsolete, NO_BRACE_ARGS }, + { "infounnumbered", cm_obsolete, NO_BRACE_ARGS }, + { "infounnumberedsec", cm_obsolete, NO_BRACE_ARGS }, + { "infounnumberedsubsec", cm_obsolete, NO_BRACE_ARGS }, + { "infounnumberedsubsubsec", cm_obsolete, NO_BRACE_ARGS }, + { "infoappendix", cm_obsolete, NO_BRACE_ARGS }, + { "infoappendixsec", cm_obsolete, NO_BRACE_ARGS }, + { "infoappendixsubsec", cm_obsolete, NO_BRACE_ARGS }, + { "infoappendixsubsubsec", cm_obsolete, NO_BRACE_ARGS }, + { "infochapter", cm_obsolete, NO_BRACE_ARGS }, + { "infosection", cm_obsolete, NO_BRACE_ARGS }, + { "infosubsection", cm_obsolete, NO_BRACE_ARGS }, + { "infosubsubsection", cm_obsolete, NO_BRACE_ARGS }, + + /* Now @include does what this was supposed to. */ + { "infoinclude", cm_infoinclude, NO_BRACE_ARGS }, + { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */ + { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS }, + { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS }, + + {(char *) NULL, (FUNCTION *) NULL}, NO_BRACE_ARGS}; + +int major_version = 1; +int minor_version = 47; + +struct option long_options[] = +{ + { "error-limit", 1, 0, 'e' }, /* formerly -el */ + { "fill-column", 1, 0, 'f' }, /* formerly -fc */ + { "footnote-style", 1, 0, 's' }, /* formerly -ft */ + { "no-headers", 0, &no_headers, 1 }, /* Do not output Node: foo */ + { "no-pointer-validate", 0, &validating, 0 }, /* formerly -nv */ + { "no-validate", 0, &validating, 0 }, /* formerly -nv */ + { "no-split", 0, &splitting, 0 }, /* formerly -ns */ + { "no-warn", 0, &print_warnings, 0 }, /* formerly -nw */ + { "number-footnotes", 0, &number_footnotes, 1 }, + { "no-number-footnotes", 0, &number_footnotes, 0 }, + { "output", 1, 0, 'o' }, + { "paragraph-indent", 1, 0, 'p' }, /* formerly -pi */ + { "reference-limit", 1, 0, 'r' }, /* formerly -rl */ + { "verbose", 0, &verbose_mode, 1 }, /* formerly -verbose */ + { "version", 0, 0, 'V' }, + {NULL, 0, NULL, 0} +}; + +/* Values for calling handle_variable_internal (). */ +#define SET 1 +#define CLEAR 2 +#define IFSET 3 +#define IFCLEAR 4 + +/* **************************************************************** */ +/* */ +/* Main () Start of code */ +/* */ +/* **************************************************************** */ + +/* For each file mentioned in the command line, process it, turning + texinfo commands into wonderfully formatted output text. */ +main (argc, argv) + int argc; + char **argv; +{ + extern int errors_printed; + char *filename_part (); + int c, ind; + + /* The name of this program is the last filename in argv[0]. */ + progname = filename_part (argv[0]); + + /* Parse argument flags from the input line. */ + while ((c = getopt_long + (argc, argv, "D:U:I:f:o:p:e:r:s:V", long_options, &ind)) + != EOF) + { + if (c == 0 && long_options[ind].flag == 0) + c = long_options[ind].val; + + switch (c) + { + /* User specified variable to set or clear? */ + case 'D': + case 'U': + handle_variable_internal ((c == 'D') ? SET : CLEAR, optarg); + break; + + /* User specified include file path? */ + case 'I': + if (!include_files_path) + include_files_path = savestring ("."); + + include_files_path = (char *) + xrealloc (include_files_path, + 2 + strlen (include_files_path) + strlen (optarg)); + strcat (include_files_path, ":"); + strcat (include_files_path, optarg); + break; + + /* User specified fill_column? */ + case 'f': + if (sscanf (optarg, "%d", &fill_column) != 1) + usage (); + break; + + /* User specified output file? */ + case 'o': + command_output_filename = savestring (optarg); + break; + + /* User specified paragraph indent (paragraph_start_index)? */ + case 'p': + if (set_paragraph_indent (optarg) < 0) + usage (); + break; + + /* User specified error level? */ + case 'e': + if (sscanf (optarg, "%d", &max_error_level) != 1) + usage (); + break; + + /* User specified reference warning limit? */ + case 'r': + if (sscanf (optarg, "%d", &reference_warning_limit) != 1) + usage (); + break; + + /* User specified footnote style? */ + case 's': + if (set_footnote_style (optarg) < 0) + usage (); + footnote_style_preset = 1; + break; + + /* User requested version info? */ + case 'V': + print_version_info (); + exit (NO_ERROR); + break; + + case '?': + usage (); + } + } + + if (optind == argc) + usage (); + else if (verbose_mode) + print_version_info (); + + /* Remaining arguments are file names of texinfo files. + Convert them, one by one. */ + while (optind != argc) + convert (argv[optind++]); + + if (errors_printed) + exit (SYNTAX); + else + exit (NO_ERROR); +} + +/* Display the version info of this invocation of Makeinfo. */ +print_version_info () +{ + fprintf (stderr, "This is GNU Makeinfo version %d.%d.\n", + major_version, minor_version); +} + +/* **************************************************************** */ +/* */ +/* Generic Utilities */ +/* */ +/* **************************************************************** */ + +/* Just like malloc, but kills the program in case of fatal error. */ +void * +xmalloc (nbytes) + int nbytes; +{ + void *temp = (void *) malloc (nbytes); + + if (nbytes && temp == (void *)NULL) + memory_error ("xmalloc", nbytes); + + return (temp); +} + +/* Like realloc (), but barfs if there isn't enough memory. */ +void * +xrealloc (pointer, nbytes) + void *pointer; + int nbytes; +{ + void *temp; + + if (!pointer) + temp = (void *)xmalloc (nbytes); + else + temp = (void *)realloc (pointer, nbytes); + + if (nbytes && !temp) + memory_error ("xrealloc", nbytes); + + return (temp); +} + +memory_error (callers_name, bytes_wanted) + char *callers_name; + int bytes_wanted; +{ + char printable_string[80]; + + sprintf (printable_string, + "Virtual memory exhausted in %s ()! Needed %d bytes.", + callers_name, bytes_wanted); + + error (printable_string); + abort (); +} + +/* Tell the user how to use this program. */ +usage () +{ + fprintf (stderr, "Usage: %s [options] texinfo-file...\n\ +\n\ +This program accepts as input files of texinfo commands and text\n\ +and outputs a file suitable for reading with GNU Info.\n\ +\n\ +The options are:\n\ +`-I DIR' to add DIR to the directory search list for including\n\ + files with the `@include' command.\n\ +-D VAR to define a variable, as with `@set'.\n\ +-U VAR to undefine a variable, as with `@clear'.\n\ +`--no-validate' to suppress node cross reference validation.\n\ +`--no-warn' to suppress warning messages (errors are still output).\n\ +`--no-split' to suppress the splitting of large files.\n\ +`--no-headers' to suppress the output of Node: Foo headers.\n\ +`--verbose' to print information about what is being done.\n\ +`--version' to print the version number of Makeinfo.\n\ +`--output FILE' or `-o FILE'\n\ + to specify the output file. When you specify the\n\ + output file in this way, any `@setfilename' in the\n\ + input file is ignored.\n\ +`--paragraph-indent NUM'\n\ + to set the paragraph indent to NUM (default %d).\n\ +`--fill-column NUM' to set the filling column to NUM (default %d).\n\ +`--error-limit NUM' to set the error limit to NUM (default %d).\n\ +`--reference-limit NUM'\n\ + to set the reference warning limit to NUM (default %d).\n\ +`--footnote-style STYLE'\n\ + to set the footnote style to STYLE. STYLE should\n\ + either be `separate' to place footnotes in their own\n\ + node, or `end', to place the footnotes at the end of\n\ + the node in which they are defined (the default).\n\n", + progname, paragraph_start_indent, + fill_column, max_error_level, reference_warning_limit); + exit (FATAL); +} + +/* **************************************************************** */ +/* */ +/* Manipulating Lists */ +/* */ +/* **************************************************************** */ + +typedef struct generic_list { + struct generic_list *next; +} GENERIC_LIST; + +/* Reverse the chain of structures in LIST. Output the new head + of the chain. You should always assign the output value of this + function to something, or you will lose the chain. */ +GENERIC_LIST * +reverse_list (list) + register GENERIC_LIST *list; +{ + register GENERIC_LIST *next; + register GENERIC_LIST *prev = (GENERIC_LIST *) NULL; + + while (list) + { + next = list->next; + list->next = prev; + prev = list; + list = next; + } + return (prev); +} + + +/* **************************************************************** */ +/* */ +/* Pushing and Popping Files */ +/* */ +/* **************************************************************** */ + +/* Find and load the file named FILENAME. Return a pointer to + the loaded file, or NULL if it can't be loaded. */ +char * +find_and_load (filename) + char *filename; +{ + struct stat fileinfo; + int file, n, i, count = 0; + char *fullpath, *result, *get_file_info_in_path (); + + result = fullpath = (char *)NULL; + + fullpath = get_file_info_in_path (filename, include_files_path, &fileinfo); + + if (!fullpath) + goto error_exit; + + filename = fullpath; + + file = open (filename, O_RDONLY); + if (file < 0) + goto error_exit; + + /* Load the file. */ + result = (char *)xmalloc (fileinfo.st_size); + + /* VMS stat lies about the st_size value. The actual number of + readable bytes is always less than this value. The arcane + mysteries of VMS/RMS are too much to probe, so this hack + suffices to make things work. */ +#if defined (VMS) + while ((n = read (file, result + count, fileinfo.st_size)) > 0) + count += n; + if (n == -1) +#else /* !VMS */ + count = fileinfo.st_size; + if (read (file, result, fileinfo.st_size) != fileinfo.st_size) +#endif /* !VMS */ + error_exit: + { + if (result) + free (result); + + if (fullpath) + free (fullpath); + + if (file != -1) + close (file); + + return ((char *) NULL); + } + close (file); + + /* Set the globals to the new file. */ + input_text = result; + size_of_input_text = fileinfo.st_size; + input_filename = savestring (filename); + node_filename = savestring (filename); +#ifdef TRACK_SRCFILE + node_src_filename = savestring (filename); +#endif /* TRACK_SRCFILE */ + input_text_offset = 0; + line_number = 1; +#ifdef TRACK_SRCFILE + src_filename = savestring (filename); + src_lineno = 1; +#endif /* TRACK_SRCFILE */ + return (result); +} + +/* Save the state of the current input file. */ +pushfile () +{ + FSTACK *newstack = (FSTACK *) xmalloc (sizeof (FSTACK)); + newstack->filename = input_filename; + newstack->text = input_text; + newstack->size = size_of_input_text; + newstack->offset = input_text_offset; + newstack->line_number = line_number; +#ifdef TRACK_SRCFILE + newstack->src_filename = src_filename; + newstack->src_lineno = src_lineno; +#endif /* TRACK_SRCFILE */ + newstack->next = filestack; + + filestack = newstack; + push_node_filename (); +} + +/* Make the current file globals be what is on top of the file stack. */ +popfile () +{ + extern int executing_string; + FSTACK *temp = filestack; + + if (!filestack) + abort (); /* My fault. I wonder what I did? */ + + /* Make sure that commands with braces have been satisfied. */ + if (!executing_string) + discard_braces (); + + /* Get the top of the stack into the globals. */ + input_filename = filestack->filename; + input_text = filestack->text; + size_of_input_text = filestack->size; + input_text_offset = filestack->offset; + line_number = filestack->line_number; +#ifdef TRACK_SRCFILE + src_filename = filestack->src_filename; + src_lineno = filestack->src_lineno; +#endif /* TRACK_SRCFILE */ + + /* Pop the stack. */ + filestack = filestack->next; + free (temp); + pop_node_filename (); +} + +/* Flush all open files on the file stack. */ +flush_file_stack () +{ + while (filestack) + { + free (input_filename); +#ifdef TRACK_SRCFILE + free (src_filename); +#endif /* TRACK_SRCFILE */ + free (input_text); + popfile (); + } +} + +int node_filename_stack_index = 0; +int node_filename_stack_size = 0; +char **node_filename_stack = (char **)NULL; +#ifdef TRACK_SRCFILE +char **node_src_filename_stack = (char **)NULL; +#endif /* TRACK_SRCFILE */ + +push_node_filename () +{ + if (node_filename_stack_index + 1 > node_filename_stack_size) + { + if (!node_filename_stack) + { + node_filename_stack = + (char **)xmalloc ((node_filename_stack_size += 10) + * sizeof (char *)); +#ifdef TRACK_SRCFILE + node_src_filename_stack = + (char **)xmalloc ((node_filename_stack_size += 10) + * sizeof (char *)); +#endif /* TRACK_SRCFILE */ + } + else + { + node_filename_stack = + (char **)xrealloc (node_filename_stack, + (node_filename_stack_size + 10) + * sizeof (char *)); +#ifdef TRACK_SRCFILE + node_src_filename_stack = + (char **)xrealloc (node_filename_stack, + (node_filename_stack_size + 10) + * sizeof (char *)); +#endif /* TRACK_SRCFILE */ + } + } + + node_filename_stack[node_filename_stack_index] = node_filename; +#ifdef TRACK_SRCFILE + node_src_filename_stack[node_filename_stack_index] = node_src_filename; +#endif /* TRACK_SRCFILE */ + node_filename_stack_index++; +} + +pop_node_filename () +{ + node_filename = node_filename_stack[--node_filename_stack_index]; +#ifdef TRACK_SRCFILE + node_src_filename = node_src_filename_stack[node_filename_stack_index]; +#endif /* TRACK_SRCFILE */ + +} + +/* Return just the simple part of the filename; i.e. the + filename without the path information, or extensions. + This conses up a new string. */ +char * +filename_part (filename) + char *filename; +{ + register int i = strlen (filename) - 1; + + while (i && filename[i] != '/') + i--; + if (filename[i] == '/') + i++; + +#if defined (REMOVE_OUTPUT_EXTENSIONS) + result = savestring (&filename[i]); + + /* See if there is an extension to remove. If so, remove it. */ + if (rindex (result, '.')) + *(rindex (result, '.')) = '\0'; + return (result); +#else + return (savestring (&filename[i])); +#endif /* REMOVE_OUTPUT_EXTENSIONS */ +} + +/* Return the pathname part of filename. This can be NULL. */ +char * +pathname_part (filename) + char *filename; +{ + char *expand_filename (); + char *result = (char *) NULL; + register int i; + + filename = expand_filename (filename, ""); + + i = strlen (filename) - 1; + + while (i && filename[i] != '/') + i--; + if (filename[i] == '/') + i++; + + if (i) + { + result = (char *)xmalloc (1 + i); + strncpy (result, filename, i); + result[i] = '\0'; + } + free (filename); + return (result); +} + +/* Return the expansion of FILENAME. */ +char * +expand_filename (filename, input_name) + char *filename, *input_name; +{ + char *full_pathname (); + filename = full_pathname (filename); + + if (filename[0] == '.') + return (filename); + + if (filename[0] != '/' && input_name[0] == '/') + { + /* Make it so that relative names work. */ + char *result; + int i = strlen (input_name) - 1; + + result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename)); + strcpy (result, input_name); + + while (result[i] != '/' && i) + i--; + + if (result[i] == '/') + i++; + + strcpy (&result[i], filename); + free (filename); + return (result); + } + return (filename); +} + +/* Return the full path to FILENAME. */ +char * +full_pathname (filename) + char *filename; +{ + int initial_character; + + if (filename && (initial_character = *filename)) + { + if (initial_character == '/') + return (savestring (filename)); + if (initial_character != '~') + { + return (savestring (filename)); + } + else + { + if (filename[1] == '/') + { + /* Return the concatenation of HOME and the rest of the string. */ + char *temp_home; + char *temp_name; + + temp_home = (char *) getenv ("HOME"); + temp_name = (char *)xmalloc (strlen (&filename[2]) + + 1 + + temp_home ? strlen (temp_home) + : 0); + if (temp_home) + strcpy (temp_name, temp_home); + + strcat (temp_name, &filename[2]); + return (temp_name); + } + else + { + struct passwd *user_entry; + int i, c; + char *username = (char *)xmalloc (257); + char *temp_name; + + for (i = 1; c = filename[i]; i++) + { + if (c == '/') + break; + else + username[i - 1] = c; + } + if (c) + username[i - 1] = '\0'; + + user_entry = getpwnam (username); + + if (!user_entry) + return (savestring (filename)); + + temp_name = (char *)xmalloc (1 + strlen (user_entry->pw_dir) + + strlen (&filename[i])); + strcpy (temp_name, user_entry->pw_dir); + strcat (temp_name, &filename[i]); + return (temp_name); + } + } + } + else + { + return (savestring (filename)); + } +} + +/* **************************************************************** */ +/* */ +/* Error Handling */ +/* */ +/* **************************************************************** */ + +/* Number of errors encountered. */ +int errors_printed = 0; + +/* Print the last error gotten from the file system. */ +fs_error (filename) + char *filename; +{ + remember_error (); + perror (filename); + return (0); +} + +/* Print an error message, and return false. */ +error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + remember_error (); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return ((int) 0); +} + +/* Just like error (), but print the line number as well. */ +line_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + remember_error (); +#ifdef TRACK_SRCFILE + fprintf (stderr, "%s:%d: ", src_filename, src_lineno); +#else + fprintf (stderr, "%s:%d: ", input_filename, line_number); +#endif /* TRACK_SRCFILE */ + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, ".\n"); + return ((int) 0); +} + +warning (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + if (print_warnings) + { +#ifdef TRACK_SRCFILE + fprintf (stderr, "%s:%d: Warning: ", src_filename, src_lineno); +#else + fprintf (stderr, "%s:%d: Warning: ", input_filename, line_number); +#endif /* TRACK_SRCFILE */ + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, ".\n"); + } + return ((int) 0); +} + +/* Remember that an error has been printed. If this is the first + error printed, then tell them which program is printing them. + If more than max_error_level have been printed, then exit the + program. */ +remember_error () +{ + errors_printed++; + if (max_error_level && (errors_printed > max_error_level)) + { + fprintf (stderr, "Too many errors! Gave up.\n"); + flush_file_stack (); + cm_bye (); + exit (1); + } +} + + +/* **************************************************************** */ +/* */ +/* Hacking Tokens and Strings */ +/* */ +/* **************************************************************** */ + +/* Return the next token as a string pointer. We cons the + string. */ +char * +read_token () +{ + int i, character; + char *result; + + /* If the first character to be read is self-delimiting, then that + is the command itself. */ + character = curchar (); + if (self_delimiting (character)) + { + input_text_offset++; + result = savestring (" "); + *result = character; + return (result); + } + + for (i = 0; ((input_text_offset != size_of_input_text) + && (character = curchar ()) + && command_char (character)); + i++, input_text_offset++); + result = (char *)xmalloc (i + 1); + bcopy (&input_text[input_text_offset - i], result, i); + result[i] = '\0'; + return (result); +} + +/* Return non-zero if CHARACTER is self-delimiting. */ +int +self_delimiting (character) + int character; +{ + return (member (character, "{}:.@*'`,!?; \n")); +} + +/* Clear whitespace from the front and end of string. */ +canon_white (string) + char *string; +{ + int len = strlen (string); + int x; + + if (!len) + return; + + for (x = 0; x < len; x++) + { + if (!whitespace (string[x])) + { + strcpy (string, string + x); + break; + } + } + len = strlen (string); + if (len) + len--; + while (len > -1 && cr_or_whitespace (string[len])) + len--; + string[len + 1] = '\0'; +} + +/* Bash STRING, replacing all whitespace with just one space. */ +fix_whitespace (string) + char *string; +{ + char *temp = (char *)xmalloc (strlen (string) + 1); + int string_index = 0; + int temp_index = 0; + int c; + + canon_white (string); + + while (string[string_index]) + { + c = temp[temp_index++] = string[string_index++]; + + if (c == ' ' || c == '\n' || c == '\t') + { + temp[temp_index - 1] = ' '; + while ((c = string[string_index]) && (c == ' ' || + c == '\t' || + c == '\n')) + string_index++; + } + } + temp[temp_index] = '\0'; + strcpy (string, temp); + free (temp); +} + +/* Discard text until the desired string is found. The string is + included in the discarded text. */ +discard_until (string) + char *string; +{ + int temp = search_forward (string, input_text_offset); + + int tt = (temp < 0) ? size_of_input_text : temp + strlen (string); + int from = input_text_offset; + + /* Find out what line we are on. */ + while (from != tt) + if (input_text[from++] == '\n') +#ifdef TRACK_SRCFILE + { line_number++; src_lineno++; } +#else + line_number++; +#endif /* TRACK_SRCFILE */ + + if (temp < 0) + { + input_text_offset = size_of_input_text - strlen (string); + + if (strcmp (string, "\n") != 0) + { + line_error ("Expected `%s'", string); + return; + } + } + else + input_text_offset = temp; + + input_text_offset += strlen (string); +} + +/* Read characters from the file until we are at MATCH. + Place the characters read into STRING. + On exit input_text_offset is after the match string. + Return the offset where the string starts. */ +int +get_until (match, string) + char *match, **string; +{ + int len, current_point, x, new_point, tem; + + current_point = x = input_text_offset; + new_point = search_forward (match, input_text_offset); + + if (new_point < 0) + new_point = size_of_input_text; + len = new_point - current_point; + + /* Keep track of which line number we are at. */ + tem = new_point + (strlen (match) - 1); + while (x != tem) + if (input_text[x++] == '\n') +#ifdef TRACK_SRCFILE + { line_number++; src_lineno++; } +#else + line_number++; +#endif /* TRACK_SRCFILE */ + + *string = (char *)xmalloc (len + 1); + + bcopy (&input_text[current_point], *string, len); + (*string)[len] = '\0'; + + /* Now leave input_text_offset in a consistent state. */ + input_text_offset = tem; + + if (input_text_offset > size_of_input_text) + input_text_offset = size_of_input_text; + + return (new_point); +} + +/* Read characters from the file until we are at MATCH or end of line. + Place the characters read into STRING. */ +get_until_in_line (match, string) + char *match, **string; +{ + int real_bottom, temp; + + real_bottom = size_of_input_text; + temp = search_forward ("\n", input_text_offset); + + if (temp < 0) + temp = size_of_input_text; + + size_of_input_text = temp; + get_until (match, string); + size_of_input_text = real_bottom; +} + +get_rest_of_line (string) + char **string; +{ + get_until ("\n", string); + canon_white (*string); + + if (curchar () == '\n') /* as opposed to the end of the file... */ + { + line_number++; +#ifdef TRACK_SRCFILE + src_lineno++; +#endif /* TRACK_SRCFILE */ + input_text_offset++; + } +} + +/* Backup the input pointer to the previous character, keeping track + of the current line number. */ +backup_input_pointer () +{ + if (input_text_offset) + { + input_text_offset--; + if (curchar () == '\n') + line_number--; + } +} + +/* Read characters from the file until we are at MATCH or closing brace. + Place the characters read into STRING. */ +get_until_in_braces (match, string) + char *match, **string; +{ + int i, brace = 0; + int match_len = strlen (match); + char *temp; + + for (i = input_text_offset; i < size_of_input_text; i++) + { + if (input_text[i] == '{') + brace++; + else if (input_text[i] == '}') + brace--; + else if (input_text[i] == '\n') +#ifdef TRACK_SRCFILE + { line_number++; src_lineno++; } +#else + line_number++; +#endif /* TRACK_SRCFILE */ + + if (brace < 0 || + (brace == 0 && strncmp (input_text + i, match, match_len) == 0)) + break; + } + + match_len = i - input_text_offset; + temp = (char *)xmalloc (2 + match_len); + strncpy (temp, input_text + input_text_offset, match_len); + temp[match_len] = '\0'; + input_text_offset = i; + *string = temp; +} + +/* **************************************************************** */ +/* */ +/* Converting the File */ +/* */ +/* **************************************************************** */ + +/* Convert the file named by NAME. The output is saved on the file + named as the argument to the @setfilename command. */ +static char *suffixes[] = { + "", + ".texinfo", + ".texi", + ".txinfo", + (char *)NULL +}; + +convert (name) + char *name; +{ + char *real_output_filename, *expand_filename (), *filename_part (); + char *filename = (char *)xmalloc (strlen (name) + 50); + register int i; + + init_tag_table (); + init_indices (); + init_internals (); + init_paragraph (); + + /* Try to load the file specified by NAME. If the file isn't found, and + there is no suffix in NAME, then try NAME.texinfo, and NAME.texi. */ + for (i = 0; suffixes[i]; i++) + { + strcpy (filename, name); + strcat (filename, suffixes[i]); + + if (find_and_load (filename)) + break; + + if (!suffixes[i][0] && rindex (filename, '.')) + { + fs_error (filename); + free (filename); + return; + } + } + + if (!suffixes[i]) + { + fs_error (name); + free (filename); + return; + } + +#ifdef TRACK_SRCFILE + { + input_filename = filename; + src_filename = filename; + } +#else + input_filename = filename; +#endif /* TRACK_SRCFILE */ + + /* Search this file looking for the special string which starts conversion. + Once found, we may truly begin. */ + + input_text_offset = search_forward ("@setfilename", 0); + + if (input_text_offset < 0) + { + if (!command_output_filename) + { + error ("No `@setfilename' found in `%s'", name); + goto finished; + } + } + else + input_text_offset += strlen ("@setfilename"); + + real_output_filename = (char *)NULL; + + if (!command_output_filename) + get_until ("\n", &output_filename); + else + { + discard_until ("\n"); + real_output_filename = output_filename = command_output_filename; + command_output_filename = (char *)NULL; + } + + canon_white (output_filename); + printf ("Making info file `%s' from `%s'.\n", output_filename, name); + + if (verbose_mode) + fprintf (stderr, " The input file contains %d characters.\n", + size_of_input_text); + + if (real_output_filename && + strcmp (real_output_filename, "-") == 0) + { + output_stream = stdout; + } + else + { + if (!real_output_filename) + real_output_filename = expand_filename (output_filename, name); + + output_stream = fopen (real_output_filename, "w"); + } + + if (output_stream == NULL) + { + fs_error (real_output_filename); + goto finished; + } + + /* Make the displayable filename from output_filename. Only the base + portion of the filename need be displayed. */ + pretty_output_filename = filename_part (output_filename); + + /* For this file only, count the number of newlines from the top of + the file to here. This way, we keep track of line numbers for + error reporting. Line_number starts at 1, since the user isn't + zero-based. */ + { + int temp = 0; + line_number = 1; +#ifdef TRACK_SRCFILE + src_lineno = 1; +#endif /* TRACK_SRCFILE */ + while (temp != input_text_offset) + if (input_text[temp++] == '\n') +#ifdef TRACK_SRCFILE + { line_number++; src_lineno++; } +#else + line_number++; +#endif /* TRACK_SRCFILE */ + } + + add_word_args ("This is Info file %s, produced by Makeinfo-%d.%d from ", + output_filename, major_version, minor_version); + add_word_args ("the input file %s.\n", input_filename); + close_paragraph (); + + reader_loop (); + +finished: + close_paragraph (); + flush_file_stack (); + if (output_stream != NULL) + { + output_pending_notes (); + free_pending_notes (); + if (tag_table != NULL) + { + tag_table = (TAG_ENTRY *) reverse_list (tag_table); + if (!no_headers) + write_tag_table (); + } + + if (output_stream != stdout) + fclose (output_stream); + + /* If validating, then validate the entire file right now. */ + if (validating) + validate_file (real_output_filename, tag_table); + + /* This used to test && !errors_printed. + But some files might have legit warnings. So split anyway. */ + if (splitting) + split_file (real_output_filename, 0); + } +} + +free_and_clear (pointer) + char **pointer; +{ + if ((*pointer) != (char *) NULL) + { + free (*pointer); + *pointer = (char *) NULL; + } +} + + /* Initialize some state. */ +init_internals () +{ + free_and_clear (¤t_node); + free_and_clear (&output_filename); + free_and_clear (&command); + free_and_clear (&input_filename); +#ifdef TRACK_SRCFILE + free_and_clear (&src_filename); +#endif /* TRACK_SRCFILE */ + free_node_references (); + init_insertion_stack (); + init_brace_stack (); + command_index = 0; + in_menu = 0; +} + +init_paragraph () +{ + free_and_clear (&output_paragraph); + output_paragraph = (unsigned char *)xmalloc (paragraph_buffer_len); + output_position = 0; + output_paragraph[0] = '\0'; + output_paragraph_offset = 0; + output_column = 0; + paragraph_is_open = 0; + current_indent = 0; +} + +/* Okay, we are ready to start the conversion. Call the reader on + some text, and fill the text as it is output. Handle commands by + remembering things like open braces and the current file position on a + stack, and when the corresponding close brace is found, you can call + the function with the proper arguments. */ +reader_loop () +{ + int character; + int done = 0; + int dash_count = 0; + + while (!done) + { + if (input_text_offset >= size_of_input_text) + { + if (filestack) + { + free (input_filename); +#ifdef TRACK_SRCFILE + free (src_filename); +#endif /* TRACK_SRCFILE */ + free (input_text); + popfile (); + } + else + break; + } + + character = curchar (); + + if (!in_fixed_width_font && + (character == '\'' || character == '`') && + input_text[input_text_offset + 1] == character) + { + input_text_offset++; + character = '"'; + } + + if (character == '-') + { + dash_count++; + if (dash_count == 3 && !in_fixed_width_font) + { + input_text_offset++; + continue; + } + } + else + { + dash_count = 0; + } + + /* If this is a whitespace character, then check to see if the line + is blank. If so, advance to the carriage return. */ + if (whitespace (character)) + { + register int i = input_text_offset + 1; + + while (i < size_of_input_text && whitespace (input_text[i])) + i++; + + if (i == size_of_input_text || input_text[i] == '\n') + { + if (i == size_of_input_text) + i--; + + input_text_offset = i; + character = curchar (); + } + } + + if (character == '\n') + { + line_number++; +#ifdef TRACK_SRCFILE + src_lineno++; +#endif /* TRACK_SRCFILE */ + if (in_menu && input_text_offset + 1 < size_of_input_text) + { + char *glean_node_from_menu (), *tem; + + /* Note that the value of TEM is discarded, since it is + gauranteed to be NULL when glean_node_from_menu () is + called with a non-zero argument. */ + tem = glean_node_from_menu (1); + } + } + + switch (character) + { + case COMMAND_PREFIX: + read_command (); + if (strcmp (command, "bye") == 0) + { + done = 1; + continue; + } + break; + + case '{': + + /* Special case. I'm not supposed to see this character by itself. + If I do, it means there is a syntax error in the input text. + Report the error here, but remember this brace on the stack so + you can ignore its partner. */ + +#ifdef ALLOW_JUNK + warning ("Misplaced `{'"); + add_word ("{"); +#else + line_error ("Misplaced `{'"); +#endif + remember_brace (misplaced_brace); + + /* Don't advance input_text_offset since this happens in + remember_brace (). + input_text_offset++; + */ + break; + + case '}': + pop_and_call_brace (); + input_text_offset++; + break; + + default: + add_char (character); + input_text_offset++; + } + } +} + +/* Find the command corresponding to STRING. If the command + is found, return a pointer to the data structure. Otherwise + return (-1). */ +COMMAND * +get_command_entry (string) + char *string; +{ + register int i; + + for (i = 0; CommandTable[i].name; i++) + if (strcmp (CommandTable[i].name, string) == 0) + return (&CommandTable[i]); + + /* This command is not in our predefined command table. Perhaps + it is a user defined command. */ + for (i = 0; i < user_command_array_len; i++) + if (user_command_array[i] && + (strcmp (user_command_array[i]->name, string) == 0)) + return (user_command_array[i]); + + /* Nope, we never heard of this command. */ + return ((COMMAND *) -1); +} + +/* input_text_offset is right at the command prefix character. + Read the next token to determine what to do. */ +read_command () +{ + COMMAND *entry; + input_text_offset++; + free_and_clear (&command); + command = read_token (); + +#if defined (HAVE_MACROS) + /* Check to see if this command is a macro. If so, execute it here. */ + { + MACRO_DEF *def; + + def = find_macro (command); + + if (def) + { + execute_macro (def); + return; + } + } +#endif /* HAVE_MACROS */ + + entry = get_command_entry (command); + + if ((int) entry == -1) + { +#ifdef ALLOW_JUNK + warning ("Unknown info command `%s'", command); + add_word_args ("\\%s", command); +#else + line_error ("Unknown info command `%s'", command); +#endif /* ALLOW_JUNK */ + return; + } + + if (entry->argument_in_braces) + remember_brace (entry->proc); + + (*(entry->proc)) (START); +} + +/* Return the string which invokes PROC; a pointer to a function. */ +char * +find_proc_name (proc) + FUNCTION *proc; +{ + register int i; + + for (i = 0; CommandTable[i].name; i++) + if (proc == CommandTable[i].proc) + return (CommandTable[i].name); + return ("NO_NAME!"); +} + +init_brace_stack () +{ + brace_stack = (BRACE_ELEMENT *) NULL; +} + +remember_brace (proc) + FUNCTION *proc; +{ + if (curchar () != '{') + line_error ("@%s expected `{..}'", command); + else + input_text_offset++; + remember_brace_1 (proc, output_paragraph_offset); +} + +/* Remember the current output position here. Save PROC + along with it so you can call it later. */ +remember_brace_1 (proc, position) + FUNCTION *proc; + int position; +{ + BRACE_ELEMENT *new = (BRACE_ELEMENT *) xmalloc (sizeof (BRACE_ELEMENT)); + new->next = brace_stack; + new->proc = proc; + new->pos = position; + new->line = line_number; +#ifdef TRACK_SRCFILE + new->src_lineno = src_lineno; +#endif /* TRACK_SRCFILE */ + brace_stack = new; +} + +/* Pop the top of the brace stack, and call the associated function + with the args END and POS. */ +pop_and_call_brace () +{ + BRACE_ELEMENT *temp; + FUNCTION *proc; + int pos; + + if (brace_stack == (BRACE_ELEMENT *) NULL) + return (line_error ("Unmatched close brace")); + + pos = brace_stack->pos; + proc = brace_stack->proc; + temp = brace_stack->next; + free (brace_stack); + brace_stack = temp; + + return ((*proc) (END, pos, output_paragraph_offset)); +} + +/* You call discard_braces () when you shouldn't have any braces on the stack. + I used to think that this happens for commands that don't take arguments + in braces, but that was wrong because of things like @code{foo @@}. So now + I only detect it at the beginning of nodes. */ +discard_braces () +{ + int temp_line_number = line_number; +#ifdef TRACK_SRCFILE + int temp_src_lineno = src_lineno; +#endif /* TRACK_SRCFILE */ + char *proc_name; + + if (!brace_stack) + return; + + while (brace_stack) + { + line_number = brace_stack->line; +#ifdef TRACK_SRCFILE + src_lineno = brace_stack->src_lineno; +#endif /* TRACK_SRCFILE */ + proc_name = find_proc_name (brace_stack->proc); + line_error ("@%s missing close brace", proc_name); + line_number = temp_line_number; +#ifdef TRACK_SRCFILE + src_lineno = temp_src_lineno; +#endif /* TRACK_SRCFILE */ + pop_and_call_brace (); + } +} + +get_char_len (character) + int character; +{ + /* Return the printed length of the character. */ + int len; + + switch (character) + { + case '\t': + len = (output_column + 8) & 0xf7; + if (len > fill_column) + len = fill_column - output_column; + else + len = len - output_column; + break; + + case '\n': + len = fill_column - output_column; + break; + + default: + if (character < ' ') + len = 2; + else + len = 1; + } + return (len); +} + +add_word_args (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + char buffer[1000]; + sprintf (buffer, format, arg1, arg2, arg3, arg4, arg5); + add_word (buffer); +} + +/* Add STRING to output_paragraph. */ +add_word (string) + char *string; +{ + while (*string) + add_char (*string++); +} + +/* Non-zero if the last character inserted has the syntax class of NEWLINE. */ +int last_char_was_newline = 1; + +/* The actual last inserted character. Note that this may be something + other than NEWLINE even if last_char_was_newline is 1. */ +int last_inserted_character = 0; + +/* Non-zero means that a newline character has already been + inserted, so close_paragraph () should insert one less. */ +int line_already_broken = 0; + +/* When non-zero we have finished an insertion (see end_insertion ()) and we + want to ignore false continued paragraph closings. */ +int insertion_paragraph_closed = 0; + +/* Add the character to the current paragraph. If filling_enabled is + non-zero, then do filling as well. */ +add_char (character) + int character; +{ + /* If we are avoiding outputting headers, and we are currently + in a menu, then simply return. */ + if (no_headers && in_menu) + return; + + /* If we are adding a character now, then we don't have to + ignore close_paragraph () calls any more. */ + if (must_start_paragraph && character != '\n') + { + must_start_paragraph = 0; + line_already_broken = 0; /* The line is no longer broken. */ + if (current_indent > output_column) + { + indent (current_indent - output_column); + output_column = current_indent; + } + } + + if (non_splitting_words && member (character, " \t\n")) + character = ' ' | 0x80; + + insertion_paragraph_closed = 0; + + switch (character) + { + case '\n': + if (!filling_enabled) + { + insert ('\n'); + + if (force_flush_right) + { + close_paragraph (); + /* Hack to force single blank lines out in this mode. */ + flush_output (); + } + + output_column = 0; + + if (!no_indent && paragraph_is_open) + indent (output_column = current_indent); + break; + } + else /* CHARACTER is newline, and filling is enabled. */ + { +#if defined (NOTDEF) + if (sentence_ender (last_inserted_character)) + { + insert (' '); + output_column++; + last_inserted_character = character; + } +#endif /* NOTDEF */ + } + + if (last_char_was_newline) + { + close_paragraph (); + pending_indent = 0; + } + else + { + last_char_was_newline = 1; + insert (' '); + output_column++; + } + break; + + default: + { + int len = get_char_len (character); + + if ((character == ' ') && (last_char_was_newline)) + { + if (!paragraph_is_open) + { + pending_indent++; + return; + } + } + + if (!paragraph_is_open) + { + start_paragraph (); + + /* If the paragraph is supposed to be indented a certain way, + then discard all of the pending whitespace. Otherwise, we + let the whitespace stay. */ + if (!paragraph_start_indent) + indent (pending_indent); + pending_indent = 0; + } + + if ((output_column += len) > fill_column) + { + if (filling_enabled) + { + int temp = output_paragraph_offset; + while (--temp > 0 && output_paragraph[temp] != '\n') + { + /* If we have found a space, we have the place to break + the line. */ + if (output_paragraph[temp] == ' ') + { + output_paragraph[temp++] = '\n'; + + /* We have correctly broken the line where we want + to. What we don't want is spaces following where + we have decided to break the line. We get rid of + them. */ + { + int t1 = temp; + while (t1 < output_paragraph_offset + && whitespace (output_paragraph[t1])) + t1++; + + if (t1 != temp) + { + strncpy ((char *) &output_paragraph[temp], + (char *) &output_paragraph[t1], + (output_paragraph_offset - t1)); + output_paragraph_offset -= (t1 - temp); + } + } + + /* Filled, but now indent if that is right. */ + if (indented_fill && current_indent) + { + int buffer_len = ((output_paragraph_offset - temp) + + current_indent); + char *temp_buffer = (char *)xmalloc (buffer_len); + int indentation = 0; + + /* We have to shift any markers that are in + front of the wrap point. */ + { + register BRACE_ELEMENT *stack = brace_stack; + + while (stack) + { + if (stack->pos > temp) + stack->pos += current_indent; + stack = stack->next; + } + } + + while (current_indent > 0 && + indentation != current_indent) + temp_buffer[indentation++] = ' '; + + strncpy ((char *) &temp_buffer[current_indent], + (char *) &output_paragraph[temp], + buffer_len - current_indent); + + if (output_paragraph_offset + buffer_len + >= paragraph_buffer_len) + { + unsigned char *tt = xrealloc + (output_paragraph, + (paragraph_buffer_len += buffer_len)); + output_paragraph = tt; + } + strncpy ((char *) &output_paragraph[temp], + temp_buffer, buffer_len); + output_paragraph_offset += current_indent; + free (temp_buffer); + } + output_column = 0; + while (temp < output_paragraph_offset) + output_column += + get_char_len (output_paragraph[temp++]); + output_column += len; + break; + } + } + } + } + insert (character); + line_already_broken = 0; + last_char_was_newline = 0; + last_inserted_character = character; + } + } +} + +/* Insert CHARACTER into OUTPUT_PARAGRAPH. */ +insert (character) + int character; +{ + output_paragraph[output_paragraph_offset++] = character; + if (output_paragraph_offset == paragraph_buffer_len) + { + output_paragraph = + xrealloc (output_paragraph, (paragraph_buffer_len += 100)); + } +} + +/* Remove upto COUNT characters of whitespace from the + the current output line. If COUNT is less than zero, + then remove until none left. */ +kill_self_indent (count) + int count; +{ + /* Handle infinite case first. */ + if (count < 0) + { + output_column = 0; + while (output_paragraph_offset) + { + if (whitespace (output_paragraph[output_paragraph_offset - 1])) + output_paragraph_offset--; + else + break; + } + } + else + { + while (output_paragraph_offset && count--) + if (whitespace (output_paragraph[output_paragraph_offset - 1])) + output_paragraph_offset--; + else + break; + } +} + +/* Non-zero means do not honor calls to flush_output (). */ +static int flushing_ignored = 0; + +/* Prevent calls to flush_output () from having any effect. */ +inhibit_output_flushing () +{ + flushing_ignored++; +} + +/* Allow calls to flush_output () to write the paragraph data. */ +uninhibit_output_flushing () +{ + flushing_ignored--; +} + +flush_output () +{ + register int i; + + if (!output_paragraph_offset || flushing_ignored) + return; + + for (i = 0; i < output_paragraph_offset; i++) + { + if (output_paragraph[i] == (unsigned char)(' ' | 0x80) || + output_paragraph[i] == (unsigned char)('\t' | 0x80) || + output_paragraph[i] == (unsigned char)('\n' | 0x80) || + sentence_ender (UNMETA (output_paragraph[i]))) + output_paragraph[i] &= 0x7f; + } + + fwrite (output_paragraph, 1, output_paragraph_offset, output_stream); + + output_position += output_paragraph_offset; + output_paragraph_offset = 0; +} + +/* How to close a paragraph controlling the number of lines between + this one and the last one. */ + +/* Paragraph spacing is controlled by this variable. It is the number of + blank lines that you wish to appear between paragraphs. A value of + 1 creates a single blank line between paragraphs. */ +int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING; + +/* Close the current paragraph, leaving no blank lines between them. */ +close_single_paragraph () +{ + close_paragraph_with_lines (0); +} + +/* Close a paragraph after an insertion has ended. */ +close_insertion_paragraph () +{ + if (!insertion_paragraph_closed) + { + /* Close the current paragraph, breaking the line. */ + close_single_paragraph (); + + /* Start a new paragraph here, inserting whatever indention is correct + for the now current insertion level (one above the one that we are + ending). */ + start_paragraph (); + + /* Tell close_paragraph () that the previous line has already been + broken, so it should insert one less newline. */ + line_already_broken = 1; + + /* Let functions such as add_char () know that we have already found a + newline. */ + ignore_blank_line (); + } + else + { + /* If the insertion paragraph is closed already, then we are seeing + two `@end' commands in a row. Note that the first one we saw was + handled in the first part of this if-then-else clause, and at that + time start_paragraph () was called, partially to handle the proper + indentation of the current line. However, the indentation level + may have just changed again, so we may have to outdent the current + line to the new indentation level. */ + if (current_indent < output_column) + kill_self_indent (output_column - current_indent); + } + + insertion_paragraph_closed = 1; +} + +close_paragraph_with_lines (lines) + int lines; +{ + int old_spacing = paragraph_spacing; + paragraph_spacing = lines; + close_paragraph (); + paragraph_spacing = old_spacing; +} + +/* Close the currently open paragraph. */ +close_paragraph () +{ + register int i; + + /* The insertion paragraph is no longer closed. */ + insertion_paragraph_closed = 0; + + if (paragraph_is_open && !must_start_paragraph) + { + register int tindex, c; + + tindex = output_paragraph_offset; + + /* Back up to last non-newline/space character, forcing all such + subsequent characters to be newlines. This isn't strictly + necessary, but a couple of functions use the presence of a newline + to make decisions. */ + for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex) + { + c = output_paragraph[tindex]; + + if (c == ' '|| c == '\n') + output_paragraph[tindex] = '\n'; + else + break; + } + + /* All trailing whitespace is ignored. */ + output_paragraph_offset = ++tindex; + + /* Break the line if that is appropriate. */ + if (paragraph_spacing >= 0) + insert ('\n'); + + /* Add as many blank lines as is specified in PARAGRAPH_SPACING. */ + if (!force_flush_right) + { + for (i = 0; i < (paragraph_spacing - line_already_broken); i++) + insert ('\n'); + } + + /* If we are doing flush right indentation, then do it now + on the paragraph (really a single line). */ + if (force_flush_right) + do_flush_right_indentation (); + + flush_output (); + paragraph_is_open = 0; + no_indent = 0; + output_column = 0; + } + ignore_blank_line (); +} + +/* Make the last line just read look as if it were only a newline. */ +ignore_blank_line () +{ + last_inserted_character = '\n'; + last_char_was_newline = 1; +} + +/* Align the end of the text in output_paragraph with fill_column. */ +do_flush_right_indentation () +{ + char *temp; + int temp_len; + + kill_self_indent (-1); + + if (output_paragraph[0] != '\n') + { + output_paragraph[output_paragraph_offset] = '\0'; + + if (output_paragraph_offset < fill_column) + { + register int i; + + if (fill_column >= paragraph_buffer_len) + output_paragraph = + xrealloc (output_paragraph, + (paragraph_buffer_len += fill_column)); + + temp_len = strlen ((char *)output_paragraph); + temp = (char *)xmalloc (temp_len + 1); + bcopy ((char *)output_paragraph, temp, temp_len); + + for (i = 0; i < fill_column - output_paragraph_offset; i++) + output_paragraph[i] = ' '; + + bcopy (temp, (char *)output_paragraph + i, temp_len); + free (temp); + output_paragraph_offset = fill_column; + } + } +} + +/* Begin a new paragraph. */ +start_paragraph () +{ + /* First close existing one. */ + if (paragraph_is_open) + close_paragraph (); + + /* In either case, the insertion paragraph is no longer closed. */ + insertion_paragraph_closed = 0; + + /* However, the paragraph is open! */ + paragraph_is_open = 1; + + /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph () + had to be called before we would allow any other paragraph operations + to have an effect. */ + if (!must_start_paragraph) + { + int amount_to_indent = 0; + + /* If doing indentation, then insert the appropriate amount. */ + if (!no_indent) + { + if (inhibit_paragraph_indentation) + { + amount_to_indent = current_indent; + if (inhibit_paragraph_indentation < 0) + inhibit_paragraph_indentation++; + } + else if (paragraph_start_indent < 0) + amount_to_indent = current_indent; + else + amount_to_indent = current_indent + paragraph_start_indent; + + if (amount_to_indent >= output_column) + { + amount_to_indent -= output_column; + indent (amount_to_indent); + output_column += amount_to_indent; + } + } + } + else + must_start_paragraph = 0; +} + +/* Insert the indentation specified by AMOUNT. */ +indent (amount) + int amount; +{ + while (--amount >= 0) + insert (' '); +} + +/* Search forward for STRING in input_text. + FROM says where where to start. */ +search_forward (string, from) + char *string; + int from; +{ + int len = strlen (string); + + while (from < size_of_input_text) + { + if (strnicmp (input_text + from, string, len) == 0) + return (from); + from++; + } + return (-1); +} + +/* Whoops, Unix doesn't have stricmp, or strnicmp. */ + +/* Case independent string compare. */ +stricmp (string1, string2) + char *string1, *string2; +{ + char ch1, ch2; + + for (;;) + { + ch1 = *string1++; + ch2 = *string2++; + if (!(ch1 | ch2)) + return (0); + + ch1 = coerce_to_upper (ch1); + ch2 = coerce_to_upper (ch2); + + if (ch1 != ch2) + return (1); + } +} + +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +strnicmp (string1, string2, count) + char *string1, *string2; +{ + char ch1, ch2; + + while (count) + { + ch1 = *string1++; + ch2 = *string2++; + if (coerce_to_upper (ch1) == coerce_to_upper (ch2)) + count--; + else + break; + } + return (count); +} + +enum insertion_type { menu, quotation, lisp, smalllisp, example, + smallexample, display, itemize, format, enumerate, cartouche, table, + ftable, vtable, group, ifinfo, flushleft, flushright, ifset, ifclear, deffn, + defun, defmac, defspec, defvr, defvar, defopt, deftypefn, + deftypefun, deftypevr, deftypevar, defcv, defivar, defop, defmethod, + deftypemethod, deftp, bad_type }; + +char *insertion_type_names[] = { "menu", "quotation", "lisp", + "smalllisp", "example", "smallexample", "display", "itemize", + "format", "enumerate", "cartouche", "table", "ftable", "vtable", "group", + "ifinfo", "flushleft", "flushright", "ifset", "ifclear", "deffn", + "defun", "defmac", "defspec", "defvr", "defvar", "defopt", + "deftypefn", "deftypefun", "deftypevr", "deftypevar", "defcv", + "defivar", "defop", "defmethod", "deftypemethod", "deftp", + "bad_type" }; + +int insertion_level = 0; +typedef struct istack_elt +{ + struct istack_elt *next; + char *item_function; + int line_number; +#ifdef TRACK_SRCFILE + int src_lineno; +#endif /* TRACK_SRCFILE */ + int filling_enabled; + int indented_fill; + enum insertion_type insertion; + int inhibited; +} INSERTION_ELT; + +INSERTION_ELT *insertion_stack = (INSERTION_ELT *) NULL; + +init_insertion_stack () +{ + insertion_stack = (INSERTION_ELT *) NULL; +} + +/* Return the type of the current insertion. */ +enum insertion_type +current_insertion_type () +{ + if (!insertion_level) + return (bad_type); + else + return (insertion_stack->insertion); +} + +/* Return a pointer to the string which is the function + to wrap around items. */ +char * +current_item_function () +{ + if (!insertion_level) + return ((char *) NULL); + else + return (insertion_stack->item_function); +} + +char * +get_item_function () +{ + char *item_function; + get_rest_of_line (&item_function); + backup_input_pointer (); + canon_white (item_function); + return (item_function); +} + + /* Push the state of the current insertion on the stack. */ +push_insertion (type, item_function) + enum insertion_type type; + char *item_function; +{ + INSERTION_ELT *new = (INSERTION_ELT *) xmalloc (sizeof (INSERTION_ELT)); + + new->item_function = item_function; + new->filling_enabled = filling_enabled; + new->indented_fill = indented_fill; + new->insertion = type; + new->line_number = line_number; +#ifdef TRACK_SRCFILE + new->src_lineno = src_lineno; +#endif /* TRACK_SRCFILE */ + new->inhibited = inhibit_paragraph_indentation; + new->next = insertion_stack; + insertion_stack = new; + insertion_level++; +} + + /* Pop the value on top of the insertion stack into the + global variables. */ +pop_insertion () +{ + INSERTION_ELT *temp = insertion_stack; + + if (temp == (INSERTION_ELT *) NULL) + return; + + inhibit_paragraph_indentation = temp->inhibited; + filling_enabled = temp->filling_enabled; + indented_fill = temp->indented_fill; + free_and_clear (&(temp->item_function)); + insertion_stack = insertion_stack->next; + free (temp); + insertion_level--; +} + + /* Return a pointer to the print name of this + enumerated type. */ +char * +insertion_type_pname (type) + enum insertion_type type; +{ + if ((int) type < (int) bad_type) + return (insertion_type_names[(int) type]); + else + return ("Broken-Type in insertion_type_pname"); +} + +/* Return the insertion_type associated with NAME. + If the type is not one of the known ones, return BAD_TYPE. */ +enum insertion_type +find_type_from_name (name) + char *name; +{ + int index = 0; + while (index < (int) bad_type) + { + if (stricmp (name, insertion_type_names[index]) == 0) + return (enum insertion_type) index; + index++; + } + return (bad_type); +} + +do_nothing () +{ +} + +int +defun_insertion (type) + enum insertion_type type; +{ + return + ((type == deffn) + || (type == defun) + || (type == defmac) + || (type == defspec) + || (type == defvr) + || (type == defvar) + || (type == defopt) + || (type == deftypefn) + || (type == deftypefun) + || (type == deftypevr) + || (type == deftypevar) + || (type == defcv) + || (type == defivar) + || (type == defop) + || (type == defmethod) + || (type == deftypemethod) + || (type == deftp)); +} + +/* MAX_NS is the maximum nesting level for enumerations. I picked 100 + which seemed reasonable. This doesn't control the number of items, + just the number of nested lists. */ +#define max_stack_depth 100 +#define ENUM_DIGITS 1 +#define ENUM_ALPHA 2 +typedef struct { + int enumtype; + int enumval; +} DIGIT_ALPHA; + +DIGIT_ALPHA enumstack[max_stack_depth]; +int enumstack_offset = 0; +int current_enumval = 1; +int current_enumtype = ENUM_DIGITS; +char *enumeration_arg = (char *)NULL; + +start_enumerating (at, type) + int at, type; +{ + if ((enumstack_offset + 1) == max_stack_depth) + { + line_error ("Enumeration stack overflow"); + return; + } + enumstack[enumstack_offset].enumtype = current_enumtype; + enumstack[enumstack_offset].enumval = current_enumval; + enumstack_offset++; + current_enumval = at; + current_enumtype = type; +} + +stop_enumerating () +{ + --enumstack_offset; + if (enumstack_offset < 0) + enumstack_offset = 0; + + current_enumval = enumstack[enumstack_offset].enumval; + current_enumtype = enumstack[enumstack_offset].enumtype; +} + +/* Place a letter or digits into the output stream. */ +enumerate_item () +{ + char temp[10]; + + if (current_enumtype == ENUM_ALPHA) + { + if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1)) + { + current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A'); + warning ("Lettering overflow, restarting at %c", current_enumval); + } + sprintf (temp, "%c. ", current_enumval); + } + else + sprintf (temp, "%d. ", current_enumval); + + indent (output_column += (current_indent - strlen (temp))); + add_word (temp); + current_enumval++; +} + +/* This is where the work for all the "insertion" style + commands is done. A huge switch statement handles the + various setups, and generic code is on both sides. */ +begin_insertion (type) + enum insertion_type type; +{ + int no_discard = 0; + + if (defun_insertion (type)) + { + push_insertion (type, savestring ("")); + no_discard++; + } + else + push_insertion (type, get_item_function ()); + + switch (type) + { + case menu: + if (!no_headers) + close_paragraph (); + + filling_enabled = no_indent = 0; + inhibit_paragraph_indentation = 1; + + if (!no_headers) + add_word ("* Menu:\n"); + + in_menu++; + no_discard++; + break; + + /* I think @quotation is meant to do filling. + If you don't want filling, then use @example. */ + case quotation: + close_single_paragraph (); + last_char_was_newline = no_indent = 0; + indented_fill = filling_enabled = 1; + inhibit_paragraph_indentation = 1; + current_indent += default_indentation_increment; + break; + + case display: + case example: + case smallexample: + case lisp: + case smalllisp: + /* Just like @example, but no indentation. */ + case format: + + close_single_paragraph (); + inhibit_paragraph_indentation = 1; + in_fixed_width_font++; + filling_enabled = 0; + last_char_was_newline = 0; + + if (type != format) + current_indent += default_indentation_increment; + + break; + + case table: + case ftable: + case vtable: + case itemize: + close_single_paragraph (); + current_indent += default_indentation_increment; + filling_enabled = indented_fill = 1; +#if defined (INDENT_PARAGRAPHS_IN_TABLE) + inhibit_paragraph_indentation = 0; +#else + inhibit_paragraph_indentation = 1; +#endif /* !INDENT_PARAGRAPHS_IN_TABLE */ + + /* Make things work for losers who forget the itemize syntax. */ + if (type == itemize) + { + if (!(*insertion_stack->item_function)) + { + free (insertion_stack->item_function); + insertion_stack->item_function = savestring ("@bullet"); + } + } + break; + + case enumerate: + close_single_paragraph (); + no_indent = 0; +#if defined (INDENT_PARAGRAPHS_IN_TABLE) + inhibit_paragraph_indentation = 0; +#else + inhibit_paragraph_indentation = 1; +#endif /* !INDENT_PARAGRAPHS_IN_TABLE */ + + current_indent += default_indentation_increment; + filling_enabled = indented_fill = 1; + + if (isdigit (*enumeration_arg)) + start_enumerating (atoi (enumeration_arg), ENUM_DIGITS); + else + start_enumerating (*enumeration_arg, ENUM_ALPHA); + break; + + /* Does nothing special in makeinfo. */ + case group: + /* Only close the paragraph if we are not inside of an @example. */ + if (!insertion_stack->next || + insertion_stack->next->insertion != example) + close_single_paragraph (); + break; + + /* Insertions that are no-ops in info, but do something in TeX. */ + case ifinfo: + case ifset: + case ifclear: + case cartouche: + break; + + case deffn: + case defun: + case defmac: + case defspec: + case defvr: + case defvar: + case defopt: + case deftypefn: + case deftypefun: + case deftypevr: + case deftypevar: + case defcv: + case defivar: + case defop: + case defmethod: + case deftypemethod: + case deftp: + inhibit_paragraph_indentation = 1; + filling_enabled = indented_fill = 1; + current_indent += default_indentation_increment; + no_indent = 0; + break; + + case flushleft: + close_single_paragraph (); + inhibit_paragraph_indentation = 1; + filling_enabled = indented_fill = no_indent = 0; + break; + + case flushright: + close_single_paragraph (); + filling_enabled = indented_fill = no_indent = 0; + inhibit_paragraph_indentation = 1; + force_flush_right++; + break; + } + + if (!no_discard) + discard_until ("\n"); +} + +/* Try to end the insertion with the specified TYPE. + TYPE, with a value of bad_type, gets translated to match + the value currently on top of the stack. + Otherwise, if TYPE doesn't match the top of the insertion stack, + give error. */ +end_insertion (type) + enum insertion_type type; +{ + enum insertion_type temp_type; + + if (!insertion_level) + return; + + temp_type = current_insertion_type (); + + if (type == bad_type) + type = temp_type; + + if (type != temp_type) + { + line_error + ("Expected `%s', but saw `%s'.", + insertion_type_pname (temp_type), insertion_type_pname (type)); + return; + } + + pop_insertion (); + + switch (type) + { + /* "Insertions which have no effect on paragraph formatting. */ + case ifinfo: + case ifset: + case ifclear: + break; + + case menu: + in_menu--; /* No longer hacking menus. */ + if (!no_headers) + close_insertion_paragraph (); + break; + + case enumerate: + stop_enumerating (); + close_insertion_paragraph (); + current_indent -= default_indentation_increment; + break; + + case flushleft: + case group: + case cartouche: + close_insertion_paragraph (); + break; + + case format: + case display: + case example: + case smallexample: + case lisp: + case smalllisp: + case quotation: + + /* @quotation is the only one of the above without a fixed width + font. */ + if (type != quotation) + in_fixed_width_font--; + + /* @format is the only fixed_width insertion without a change + in indentation. */ + if (type != format) + current_indent -= default_indentation_increment; + + /* The ending of one of these insertions always marks the + start of a new paragraph. */ + close_insertion_paragraph (); + break; + + case table: + case ftable: + case vtable: + case itemize: + current_indent -= default_indentation_increment; + break; + + case flushright: + force_flush_right--; + close_insertion_paragraph (); + break; + + /* Handle the @defun style insertions with a default clause. */ + default: + current_indent -= default_indentation_increment; + close_insertion_paragraph (); + break; + } +} + +/* Insertions cannot cross certain boundaries, such as node beginnings. In + code that creates such boundaries, you should call discard_insertions () + before doing anything else. It prints the errors for you, and cleans up + the insertion stack. */ +discard_insertions () +{ + int real_line_number = line_number; +#ifdef TRACK_SRCFILE + int real_src_lineno = src_lineno; +#endif /* TRACK_SRCFILE */ + while (insertion_stack) + { + if (insertion_stack->insertion == ifinfo || + insertion_stack->insertion == ifset || + insertion_stack->insertion == ifclear || + insertion_stack->insertion == cartouche) + break; + else + { + char *offender = (char *) + insertion_type_pname (insertion_stack->insertion); + + line_number = insertion_stack->line_number; +#ifdef TRACK_SRCFILE + src_lineno = insertion_stack->src_lineno; +#endif /* TRACK_SRCFILE */ + line_error ("This `%s' doesn't have a matching `%cend %s'", offender, + COMMAND_PREFIX, offender); + pop_insertion (); + } + } + line_number = real_line_number; +#ifdef TRACK_SRCFILE + src_lineno = real_src_lineno; +#endif /* TRACK_SRCFILE */ + +} + +/* The actual commands themselves. */ + +/* Commands which insert themselves. */ +insert_self () +{ + add_word (command); +} + +/* Force a line break in the output. */ +cm_asterisk () +{ + close_single_paragraph (); +#if !defined (ASTERISK_NEW_PARAGRAPH) + cm_noindent (); +#endif /* ASTERISK_NEW_PARAGRAPH */ +} + +/* Insert ellipsis. */ +cm_dots (arg) + int arg; +{ + if (arg == START) + add_word ("..."); +} + +cm_bullet (arg) + int arg; +{ + if (arg == START) + add_char ('*'); +} + +cm_minus (arg) + int arg; +{ + if (arg == START) + add_char ('-'); +} + +/* Insert "TeX". */ +cm_TeX (arg) + int arg; +{ + if (arg == START) + add_word ("TeX"); +} + +cm_copyright (arg) + int arg; +{ + if (arg == START) + add_word ("(C)"); +} + +cm_today (arg) + int arg; +{ + static char * months [12] = + { "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" }; + if (arg == START) + { +/*partain: long timer = (time (0)); */ + time_t timer = (time (0)); + struct tm * ts = (localtime (&timer)); + add_word_args + ("%d %s %d", + (ts -> tm_mday), + (months [ts -> tm_mon]), + ((ts -> tm_year) + 1900)); + } +} + +cm_code (arg) + int arg; +{ + extern int printing_index; + + if (printing_index) + return; + + if (arg == START) + { + in_fixed_width_font++; + add_char ('`'); + } + else + { + add_word ("'"); + in_fixed_width_font--; + } +} + +cm_samp (arg) + int arg; +{ + cm_code (arg); +} + +cm_file (arg) + int arg; +{ + cm_code (arg); +} + +cm_kbd (arg) + int arg; +{ + cm_code (arg); +} + +cm_key (arg) + int arg; +{ +} + +/* Convert the character at position into CTL. */ +cm_ctrl (arg, position) + int arg, position; +{ + if (arg == END) + output_paragraph[position - 1] = CTL (output_paragraph[position]); +} + +/* Small Caps in makeinfo just does all caps. */ +cm_sc (arg, start_pos, end_pos) + int arg, start_pos, end_pos; +{ + if (arg == END) + { + while (start_pos < end_pos) + { + output_paragraph[start_pos] = + coerce_to_upper (output_paragraph[start_pos]); + start_pos++; + } + } +} + +/* @var in makeinfo just uppercases the text. */ +cm_var (arg, start_pos, end_pos) + int arg, start_pos, end_pos; +{ + if (arg == END) + { + while (start_pos < end_pos) + { + output_paragraph[start_pos] = + coerce_to_upper (output_paragraph[start_pos]); + start_pos++; + } + } +} + +cm_dfn (arg, position) + int arg, position; +{ + add_char ('"'); +} + +cm_emph (arg) + int arg; +{ + add_char ('*'); +} + +cm_strong (arg, position) + int arg, position; +{ + cm_emph (arg); +} + +cm_cite (arg, position) + int arg, position; +{ + if (arg == START) + add_word ("`"); + else + add_word ("'"); +} + +/* Current text is italicized. */ +cm_italic (arg, start, end) + int arg, start, end; +{ +} + +/* Current text is highlighted. */ +cm_bold (arg, start, end) + int arg, start, end; +{ + cm_italic (arg); +} + +/* Current text is in roman font. */ +cm_roman (arg, start, end) + int arg, start, end; +{ +} + +/* Current text is in roman font. */ +cm_titlefont (arg, start, end) + int arg, start, end; +{ +} + +/* Italicize titles. */ +cm_title (arg, start, end) + int arg, start, end; +{ + cm_italic (arg); +} + +/* @refill is a NOP. */ +cm_refill () +{ +} + +/* Prevent the argument from being split across two lines. */ +cm_w (arg, start, end) + int arg, start, end; +{ + if (arg == START) + non_splitting_words++; + else + non_splitting_words--; +} + + +/* Explain that this command is obsolete, thus the user shouldn't + do anything with it. */ +cm_obsolete (arg, start, end) + int arg, start, end; +{ + if (arg == START) + warning ("The command `@%s' is obsolete", command); +} + +/* Insert the text following input_text_offset up to the end of the line + in a new, separate paragraph. Directly underneath it, insert a + line of WITH_CHAR, the same length of the inserted text. */ +insert_and_underscore (with_char) + int with_char; +{ + int len, i, old_no_indent; + char *temp; + + close_paragraph (); + filling_enabled = indented_fill = 0; + old_no_indent = no_indent; + no_indent = 1; + get_rest_of_line (&temp); + + len = output_position; + execute_string ("%s\n", temp); + free (temp); + + len = ((output_position + output_paragraph_offset) - 1) - len; + for (i = 0; i < len; i++) + add_char (with_char); + insert ('\n'); + close_paragraph (); + filling_enabled = 1; + no_indent = old_no_indent; +} + +/* The remainder of the text on this line is a chapter heading. */ +cm_chapter () +{ + insert_and_underscore ('*'); +} + +/* The remainder of the text on this line is a section heading. */ +cm_section () +{ + insert_and_underscore ('='); +} + +/* The remainder of the text on this line is a subsection heading. */ +cm_subsection () +{ + insert_and_underscore ('-'); +} + +/* The remainder of the text on this line is a subsubsection heading. */ +cm_subsubsection () +{ + insert_and_underscore ('.'); +} + +/* Here is a structure which associates sectioning commands with + an integer, hopefully to reflect the `depth' of the current + section. */ +struct { + char *name; + int level; +} section_alist[] = { + { "unnumberedsubsubsec", 5 }, + { "unnumberedsubsec", 4 }, + { "unnumberedsec", 3 }, + { "unnumbered", 2 }, + { "appendixsubsubsec", 5 }, + { "appendixsubsec", 4 }, + { "appendixsec", 3 }, + { "appendixsection", 3 }, + { "appendix", 2 }, + { "subsubsec", 5 }, + { "subsubsection", 5 }, + { "subsection", 4 }, + { "section", 3 }, + { "chapter", 2 }, + { "top", 1 }, + + { (char *)NULL, 0 } +}; + +/* Return an integer which identifies the type section present in TEXT. */ +int +what_section (text) + char *text; +{ + register int i, j; + char *t; + + find_section_command: + for (j = 0; text[j] && cr_or_whitespace (text[j]); j++); + if (text[j] != '@') + return (-1); + + text = text + j + 1; + + /* We skip @comment commands. */ + if ((strncmp (text, "comment", strlen ("comment")) == 0) || + (strncmp (text, "c ", strlen ("c ")) == 0)) + { + while (*text++ != '\n'); + goto find_section_command; + } + + /* Handle italicized sectioning commands. */ + if (*text == 'i') + text++; + + for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++); + + for (i = 0; t = section_alist[i].name; i++) + { + if (j == strlen (t) && strncmp (t, text, j) == 0) + return (section_alist[i].level); + } + return (-1); +} + +/* Treat this just like @unnumbered. The only difference is + in node defaulting. */ +cm_top () +{ + static int top_encountered = 0; + cm_unnumbered (); + + /* It is an error to have more than one @top. */ + if (top_encountered) + { + TAG_ENTRY *tag = tag_table; + + line_error ("There already is a node having @top as a section"); + + while (tag != (TAG_ENTRY *)NULL) + { + if ((tag->flags & IS_TOP)) + { + int old_line_number = line_number; + line_number = tag->line_no; + line_error ("Here is the @top node."); + line_number = old_line_number; + return; + } + tag = tag->next_ent; + } + } + else + { + top_encountered = 1; + + /* The most recently defined node is the top node. */ + if (tag_table) + tag_table->flags |= IS_TOP; + + /* Now set the logical hierarchical level of the Top node. */ + { + int orig_offset = input_text_offset; + + input_text_offset = search_forward ("\n@node", orig_offset); + + if (input_text_offset > 0) + { + int this_section; + + /* Move to the end of this line, and find out what the + sectioning command is here. */ + while (input_text[input_text_offset] != '\n') + input_text_offset++; + + if (input_text_offset < size_of_input_text) + input_text_offset++; + + this_section = what_section (input_text + input_text_offset); + + /* If we found a sectioning command, then give the top section + a level of this section - 1. */ + if (this_section != -1) + { + register int i; + + for (i = 0; section_alist[i].name; i++) + if (strcmp (section_alist[i].name, "Top") == 0) + { + section_alist[i].level = this_section - 1; + break; + } + } + } + input_text_offset = orig_offset; + } + } +} + +/* The remainder of the text on this line is an unnumbered heading. */ +cm_unnumbered () +{ + cm_chapter (); +} + +/* The remainder of the text on this line is an unnumbered section heading. */ +cm_unnumberedsec () +{ + cm_section (); +} + +/* The remainder of the text on this line is an unnumbered + subsection heading. */ +cm_unnumberedsubsec () +{ + cm_subsection (); +} + +/* The remainder of the text on this line is an unnumbered + subsubsection heading. */ +cm_unnumberedsubsubsec () +{ + cm_subsubsection (); +} + +/* The remainder of the text on this line is an appendix heading. */ +cm_appendix () +{ + cm_chapter (); +} + +/* The remainder of the text on this line is an appendix section heading. */ +cm_appendixsec () +{ + cm_section (); +} + +/* The remainder of the text on this line is an appendix subsection heading. */ +cm_appendixsubsec () +{ + cm_subsection (); +} + +/* The remainder of the text on this line is an appendix + subsubsection heading. */ +cm_appendixsubsubsec () +{ + cm_subsubsection (); +} + +/* Compatibility functions substitute for chapter, section, etc. */ +cm_majorheading () +{ + cm_chapheading (); +} + +cm_chapheading () +{ + cm_chapter (); +} + +cm_heading () +{ + cm_section (); +} + +cm_subheading () +{ + cm_subsection (); +} + +cm_subsubheading () +{ + cm_subsubsection (); +} + + +/* **************************************************************** */ +/* */ +/* Adding nodes, and making tags */ +/* */ +/* **************************************************************** */ + +/* Start a new tag table. */ +init_tag_table () +{ + while (tag_table != (TAG_ENTRY *) NULL) + { + TAG_ENTRY *temp = tag_table; + free (temp->node); + free (temp->prev); + free (temp->next); + free (temp->up); + tag_table = tag_table->next_ent; + free (temp); + } +} + +write_tag_table () +{ + return (write_tag_table_internal (0)); /* Not indirect. */ +} + +write_tag_table_indirect () +{ + return (write_tag_table_internal (1)); +} + +/* Write out the contents of the existing tag table. + INDIRECT_P says how to format the output. */ +write_tag_table_internal (indirect_p) + int indirect_p; +{ + TAG_ENTRY *node = tag_table; + int old_indent = no_indent; + + no_indent = 1; + filling_enabled = 0; + must_start_paragraph = 0; + close_paragraph (); + + if (!indirect_p) + { + no_indent = 1; + insert ('\n'); + } + + add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : ""); + + while (node != (TAG_ENTRY *) NULL) + { + add_word_args ("Node: %s\177%d\n", node->node, node->position); + node = node->next_ent; + } + + add_word ("\037\nEnd Tag Table\n"); + flush_output (); + no_indent = old_indent; +} + +char * +get_node_token () +{ + char *string; + + get_until_in_line (",", &string); + + if (curchar () == ',') + input_text_offset++; + + canon_white (string); + + /* Allow things like @@nodename. */ + normalize_node_name (string); + + return (string); +} + +/* Given a node name in STRING, remove double @ signs, replacing them + with just one. */ +normalize_node_name (string) + char *string; +{ + register int i, l = strlen (string); + + for (i = 0; i < l; i++) + { + if (string[i] == '@' && string[i + 1] == '@') + { + strncpy (string + i, string + i + 1, l - i); + l--; + } + } +} + +/* Look up NAME in the tag table, and return the associated + tag_entry. If the node is not in the table return NULL. */ +TAG_ENTRY * +find_node (name) + char *name; +{ + TAG_ENTRY *tag = tag_table; + + while (tag != (TAG_ENTRY *) NULL) + { + if (stricmp (tag->node, name) == 0) + return (tag); + tag = tag->next_ent; + } + return ((TAG_ENTRY *) NULL); +} + +/* Remember NODE and associates. */ +#ifdef TRACK_SRCFILE +remember_node (node, prev, next, up, position, line_no, src_line_no, no_warn) + int src_line_no; +#else +remember_node (node, prev, next, up, position, line_no, no_warn) +#endif /* TRACK_SRCFILE */ + char *node, *prev, *next, *up; + int position, line_no, no_warn; +{ + /* Check for existence of this tag already. */ + if (validating) + { + register TAG_ENTRY *tag = find_node (node); + if (tag) + { + line_error ("Node `%s' multiply defined (%d is first definition)", + node, tag->line_no); + return; + } + } + + /* First, make this the current node. */ + current_node = node; + + /* Now add it to the list. */ + { + TAG_ENTRY *new = (TAG_ENTRY *) xmalloc (sizeof (TAG_ENTRY)); + new->node = node; + new->prev = prev; + new->next = next; + new->up = up; + new->position = position; + new->line_no = line_no; + new->filename = node_filename; +#ifdef TRACK_SRCFILE + new->src_lineno = src_line_no; + new->src_filename = node_src_filename; +#endif /* TRACK_SRCFILE */ + new->touched = 0; /* not yet referenced. */ + new->flags = 0; + if (no_warn) + new->flags |= NO_WARN; + new->next_ent = tag_table; + tag_table = new; + } +} + +/* The order is: nodename, nextnode, prevnode, upnode. + If all of the NEXT, PREV, and UP fields are empty, they are defaulted. + You must follow a node command which has those fields defaulted + with a sectioning command (e.g. @chapter) giving the "level" of that node. + It is an error not to do so. + The defaults come from the menu in this nodes parent. */ +cm_node () +{ + char *node, *prev, *next, *up; + int new_node_pos, defaulting, this_section, no_warn = 0; + extern int already_outputting_pending_notes; + + if (strcmp (command, "nwnode") == 0) + no_warn = 1; + + /* Get rid of unmatched brace arguments from previous commands. */ + discard_braces (); + + /* There also might be insertions left lying around that haven't been + ended yet. Do that also. */ + discard_insertions (); + + if (!already_outputting_pending_notes) + { + close_paragraph (); + output_pending_notes (); + free_pending_notes (); + } + + filling_enabled = indented_fill = 0; + new_node_pos = output_position + 1; + current_footnote_number = 1; + + node = get_node_token (); + next = get_node_token (); + prev = get_node_token (); + up = get_node_token (); + + no_indent = 1; + if (!no_headers) + add_word_args ("\037\nFile: %s, Node: %s", pretty_output_filename, node); + + /* Check for defaulting of this node's next, prev, and up fields. */ + defaulting = ((strlen (next) == 0) && + (strlen (prev) == 0) && + (strlen (up) == 0)); + + this_section = what_section (input_text + input_text_offset); + + /* If we are defaulting, then look at the immediately following + sectioning command (error if none) to determine the node's + level. Find the node that contains the menu mentioning this node + that is one level up (error if not found). That node is the "Up" + of this node. Default the "Next" and "Prev" from the menu. */ + if (defaulting) + { + NODE_REF *last_ref = (NODE_REF *)NULL; + NODE_REF *ref = node_references; + + if (this_section < 0) + { + char *polite_section_name = "top"; + int i; + + for (i = 0; section_alist[i].name; i++) + if (section_alist[i].level == current_section + 1) + { + polite_section_name = section_alist[i].name; + break; + } + + line_error + ("Node `%s' requires a sectioning command (e.g. @%s)", + node, polite_section_name); + } + else + { + if (stricmp (node, "Top") == 0) + { + /* Default the NEXT pointer to be the first menu item in + this node, if there is a menu in this node. */ + { + int orig_offset, orig_size; + char *glean_node_from_menu (); + + orig_offset = input_text_offset; + orig_size = search_forward ("\n@node ", orig_offset); + + if (orig_size < 0) + orig_size = size_of_input_text; + + input_text_offset = search_forward ("\n@menu", orig_offset); + if (input_text_offset > -1) + { + input_text_offset = + search_forward ("\n* ", input_text_offset); + + if (input_text_offset > -1) + next = glean_node_from_menu (0); + + if (next) + { + prev = savestring ("(DIR)"); + up = savestring ("(DIR)"); + } + } + input_text_offset = orig_offset; + } + } + + while (ref) + { + if (ref->section == (this_section - 1) && + ref->type == menu_reference && + stricmp (ref->node, node) == 0) + { + char *containing_node = ref->containing_node; + + free (up); + up = savestring (containing_node); + + if (last_ref && last_ref->type == menu_reference && + strcmp + (last_ref->containing_node, containing_node) == 0) + { + free (next); + next = savestring (last_ref->node); + } + + while ((ref->section == this_section - 1) && + (ref->next) && + (ref->next->type != menu_reference)) + ref = ref->next; + + if (ref->next && ref->type == menu_reference && + strcmp + (ref->next->containing_node, containing_node) == 0) + { + free (prev); + prev = savestring (ref->next->node); + } + else if (!ref->next && + stricmp (ref->containing_node, "Top") == 0) + { + free (prev); + prev = savestring (ref->containing_node); + } + break; + } + last_ref = ref; + ref = ref->next; + } + } + } + + if (!no_headers) + { + if (*next) + add_word_args (", Next: %s", next); + + if (*prev) + add_word_args (", Prev: %s", prev); + + if (*up) + add_word_args (", Up: %s", up); + } + + insert ('\n'); + close_paragraph (); + no_indent = 0; + + if (!*node) + { + line_error ("No node name specified for `@%s' command", command); + free (node); + free (next); + free (prev); + free (up); + } + else + { + if (!*next) { free (next); next = (char *)NULL; } + if (!*prev) { free (prev); prev = (char *)NULL; } + if (!*up) { free (up); up = (char *)NULL; } +#ifdef TRACK_SRCFILE + remember_node (node, prev, next, up, new_node_pos, line_number, src_lineno, no_warn); +#else + remember_node (node, prev, next, up, new_node_pos, line_number, no_warn); +#endif /* TRACK_SRCFILE */ + } + + /* Change the section only if there was a sectioning command. */ + if (this_section >= 0) + current_section = this_section; + + filling_enabled = 1; +} + +/* Validation of an info file. + Scan through the list of tag entrys touching the Prev, Next, and Up + elements of each. It is an error not to be able to touch one of them, + except in the case of external node references, such as "(DIR)". + + If the Prev is different from the Up, + then the Prev node must have a Next pointing at this node. + + Every node except Top must have an Up. + The Up node must contain some sort of reference, other than a Next, + to this node. + + If the Next is different from the Next of the Up, + then the Next node must have a Prev pointing at this node. */ +validate_file (filename, tag_table) + char *filename; + TAG_ENTRY *tag_table; +{ + char *old_input_filename = input_filename; +#ifdef TRACK_SRCFILE + char *old_src_filename = src_filename; +#endif /* TRACK_SRCFILE */ + TAG_ENTRY *tags = tag_table; + + while (tags != (TAG_ENTRY *) NULL) + { + register TAG_ENTRY *temp_tag; + + input_filename = tags->filename; + line_number = tags->line_no; +#ifdef TRACK_SRCFILE + src_filename = tags->src_filename; + src_lineno = tags->src_lineno; +#endif /* TRACK_SRCFILE */ + + /* If this node has a Next, then make sure that the Next exists. */ + if (tags->next) + { +#ifdef TRACK_SRCFILE + validate (tags->next, tags->line_no, tags->src_lineno, "Next"); +#else + validate (tags->next, tags->line_no, "Next"); +#endif /* TRACK_SRCFILE */ + + /* If the Next node exists, and there is no Up, then make + sure that the Prev of the Next points back. */ + if (temp_tag = find_node (tags->next)) + { + char *prev = temp_tag->prev; + if (!prev || (stricmp (prev, tags->node) != 0)) + { + line_error + ("Node `%s''s Next field not pointed back to", tags->node); + line_number = temp_tag->line_no; + input_filename = temp_tag->filename; +#ifdef TRACK_SRCFILE + src_lineno = temp_tag->src_lineno; + src_filename = temp_tag->src_filename; +#endif /* TRACK_SRCFILE */ + line_error + ("This node (`%s') is the one with the bad `Prev'", + temp_tag->node); + input_filename = tags->filename; + line_number = tags->line_no; +#ifdef TRACK_SRCFILE + src_lineno = tags->src_lineno; + src_filename = tags->src_filename; +#endif /* TRACK_SRCFILE */ + temp_tag->flags |= PREV_ERROR; + } + } + } + + /* Validate the Prev field if there is one, and we haven't already + complained about it in some way. You don't have to have a Prev + field at this stage. */ + if (!(tags->flags & PREV_ERROR) && tags->prev) + { +#ifdef TRACK_SRCFILE + int valid = validate (tags->prev, tags->line_no, tags->src_lineno, "Prev"); +#else + int valid = validate (tags->prev, tags->line_no, "Prev"); +#endif /* TRACK_SRCFILE */ + + if (!valid) + tags->flags |= PREV_ERROR; + else + { + /* If the Prev field is not the same as the Up field, + then the node pointed to by the Prev field must have + a Next field which points to this node. */ + if (tags->up && (stricmp (tags->prev, tags->up) != 0)) + { + temp_tag = find_node (tags->prev); + if (!temp_tag->next || + (stricmp (temp_tag->next, tags->node) != 0)) + { + line_error ("Node `%s''s Prev field not pointed back to", + tags->node); + line_number = temp_tag->line_no; + input_filename = temp_tag->filename; +#ifdef TRACK_SRCFILE + src_filename = temp_tag->src_filename; + src_lineno = temp_tag->src_lineno; +#endif /* TRACK_SRCFILE */ + line_error + ("This node (`%s') is the one with the bad `Next'", + temp_tag->node); + input_filename = tags->filename; + line_number = tags->line_no; +#ifdef TRACK_SRCFILE + src_filename = tags->src_filename; + src_lineno = tags->src_lineno; +#endif /* TRACK_SRCFILE */ + temp_tag->flags |= NEXT_ERROR; + } + } + } + } + + if (!tags->up && (stricmp (tags->node, "Top") != 0)) + line_error ("Node `%s' is missing an \"Up\" field", tags->node); + else if (tags->up) + { +#ifdef TRACK_SRCFILE + int valid = validate (tags->up, tags->line_no, tags->src_lineno, "Up"); +#else + int valid = validate (tags->up, tags->line_no, "Up"); +#endif /* TRACK_SRCFILE */ + + /* If node X has Up: Y, then warn if Y fails to have a menu item + or note pointing at X, if Y isn't of the form "(Y)". */ + if (valid && *tags->up != '(') + { + NODE_REF *nref, *tref, *list; + NODE_REF *find_node_reference (); + + tref = (NODE_REF *) NULL; + list = node_references; + + for (;;) + { + if (!(nref = find_node_reference (tags->node, list))) + break; + + if (stricmp (nref->containing_node, tags->up) == 0) + { + if (nref->type != menu_reference) + { + tref = nref; + list = nref->next; + } + else + break; + } + list = nref->next; + } + + if (!nref) + { + temp_tag = find_node (tags->up); + line_number = temp_tag->line_no; + filename = temp_tag->filename; +#ifdef TRACK_SRCFILE + src_filename = temp_tag->src_filename; + src_lineno = temp_tag->src_lineno; +#endif /* TRACK_SRCFILE */ + if (!tref) + line_error ( +"`%s' has an Up field of `%s', but `%s' has no menu item for `%s'", + tags->node, tags->up, tags->up, tags->node); + line_number = tags->line_no; + filename = tags->filename; +#ifdef TRACK_SRCFILE + src_filename = tags->src_filename; + src_lineno = tags->src_lineno; +#endif /* TRACK_SRCFILE */ + } + } + } + tags = tags->next_ent; + } + + validate_other_references (node_references); + /* We have told the user about the references which didn't exist. + Now tell him about the nodes which aren't referenced. */ + + tags = tag_table; + while (tags != (TAG_ENTRY *) NULL) + { + /* Special hack. If the node in question appears to have + been referenced more than REFERENCE_WARNING_LIMIT times, + give a warning. */ + if (tags->touched > reference_warning_limit) + { + input_filename = tags->filename; + line_number = tags->line_no; +#ifdef TRACK_SRCFILE + src_filename = tags->src_filename; + src_lineno = tags->src_lineno; +#endif /* TRACK_SRCFILE */ + warning ("Node `%s' has been referenced %d times", + tags->node, tags->touched); + } + + if (tags->touched == 0) + { + input_filename = tags->filename; + line_number = tags->line_no; +#ifdef TRACK_SRCFILE + src_filename = tags->src_filename; + src_lineno = tags->src_lineno; +#endif /* TRACK_SRCFILE */ + + /* Notice that the node "Top" is special, and doesn't have to + be referenced. */ + if (stricmp (tags->node, "Top") != 0) + warning ("Unreferenced node `%s'", tags->node); + } + tags = tags->next_ent; + } + input_filename = old_input_filename; +#ifdef TRACK_SRCFILE + src_filename = old_src_filename; +#endif /* TRACK_SRCFILE */ +} + +/* Return 1 if tag correctly validated, or 0 if not. */ +#ifdef TRACK_SRCFILE +validate (tag, line, src_line, label) +#else +validate (tag, line, label) +#endif /* TRACK_SRCFILE */ + char *tag; + int line; +#ifdef TRACK_SRCFILE + int src_line; +#endif /* TRACK_SRCFILE */ + char *label; +{ + TAG_ENTRY *result; + + /* If there isn't a tag to verify, or if the tag is in another file, + then it must be okay. */ + if (!tag || !*tag || *tag == '(') + return (1); + + /* Otherwise, the tag must exist. */ + result = find_node (tag); + + if (!result) + { + line_number = line; +#ifdef TRACK_SRCFILE + src_lineno = src_line; +#endif /* TRACK_SRCFILE */ + line_error ( +"Validation error. `%s' field points to node `%s', which doesn't exist", + label, tag); + return (0); + } + result->touched++; + return (1); +} + +/* Split large output files into a series of smaller files. Each file + is pointed to in the tag table, which then gets written out as the + original file. The new files have the same name as the original file + with a "-num" attached. SIZE is the largest number of bytes to allow + in any single split file. */ +split_file (filename, size) + char *filename; + int size; +{ + char *root_filename, *root_pathname; + char *the_file, *filename_part (); + struct stat fileinfo; + char *the_header; + int header_size; + + /* Can only do this to files with tag tables. */ + if (!tag_table) + return; + + if (size == 0) + size = DEFAULT_SPLIT_SIZE; + + if ((stat (filename, &fileinfo) != 0) || + (fileinfo.st_size < SPLIT_SIZE_THRESHOLD)) + return; + + the_file = find_and_load (filename); + if (!the_file) + return; + + root_filename = filename_part (filename); + root_pathname = pathname_part (filename); + + if (!root_pathname) + root_pathname = savestring (""); + + /* Start splitting the file. Walk along the tag table + outputting sections of the file. When we have written + all of the nodes in the tag table, make the top-level + pointer file, which contains indirect pointers and + tags for the nodes. */ + { + int which_file = 1; + TAG_ENTRY *tags = tag_table; + char *indirect_info = (char *)NULL; + + /* Remember the `header' of this file. The first tag in the file is + the bottom of the header; the top of the file is the start. */ + the_header = (char *)xmalloc (1 + (header_size = (tags->position - 2))); + bcopy (the_file, the_header, header_size); + + while (tags) + { + int file_top, file_bot, limit; + + /* Have to include the Control-_. */ + file_top = file_bot = tags->position - 2; + limit = file_top + size; + + /* If the rest of this file is only one node, then + that is the entire subfile. */ + if (!tags->next_ent) + { + int i = tags->position + 1; + char last_char = the_file[i]; + + while (i < fileinfo.st_size) + { + if ((the_file[i] == '\037') && + ((last_char == '\n') || + (last_char == '\014'))) + break; + else + last_char = the_file[i]; + i++; + } + file_bot = i; + tags = tags->next_ent; + goto write_region; + } + + /* Otherwise, find the largest number of nodes that can fit in + this subfile. */ + for (; tags; tags = tags->next_ent) + { + if (!tags->next_ent) + { + /* This entry is the last node. Search forward for the end + of this node, and that is the end of this file. */ + int i = tags->position + 1; + char last_char = the_file[i]; + + while (i < fileinfo.st_size) + { + if ((the_file[i] == '\037') && + ((last_char == '\n') || + (last_char == '\014'))) + break; + else + last_char = the_file[i]; + i++; + } + file_bot = i; + + if (file_bot < limit) + { + tags = tags->next_ent; + goto write_region; + } + else + { + /* Here we want to write out everything before the last + node, and then write the last node out in a file + by itself. */ + file_bot = tags->position; + goto write_region; + } + } + + if (tags->next_ent->position > limit) + { + if ((tags->position) - 2 == file_top) + tags = tags->next_ent; + file_bot = tags->position; + write_region: + { + int fd; + char *split_file = (char *) + xmalloc (10 + + strlen (root_pathname) + + strlen (root_filename)); + sprintf (split_file, + "%s%s-%d", root_pathname, root_filename, which_file); + + if (((fd = open (split_file, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0) + || (write (fd, the_header, header_size) != header_size) + || (write (fd, the_file + file_top, file_bot - file_top) + != (file_bot - file_top)) + || ((close (fd)) < 0)) + { + perror (split_file); + close (fd); + exit (FATAL); + } + + if (!indirect_info) + { + indirect_info = the_file + file_top; + sprintf (indirect_info, "\037\nIndirect:\n"); + indirect_info += strlen (indirect_info); + } + + sprintf (indirect_info, "%s-%d: %d\n", + root_filename, which_file, file_top); + + free (split_file); + indirect_info += strlen (indirect_info); + which_file++; + break; + } + } + } + } + + /* We have sucessfully created the subfiles. Now write out the + original again. We must use `output_stream', or + write_tag_table_indirect () won't know where to place the output. */ + output_stream = fopen (filename, "w"); + if (!output_stream) + { + perror (filename); + exit (FATAL); + } + + { + int distance = indirect_info - the_file; + fwrite (the_file, 1, distance, output_stream); + + /* Inhibit newlines. */ + paragraph_is_open = 0; + + write_tag_table_indirect (); + fclose (output_stream); + free (the_header); + free (the_file); + return; + } + } +} + +/* Some menu hacking. This is used to remember menu references while + reading the input file. After the output file has been written, if + validation is on, then we use the contents of NODE_REFERENCES as a + list of nodes to validate. */ +char * +reftype_type_string (type) + enum reftype type; +{ + switch (type) + { + case menu_reference: + return ("Menu"); + case followed_reference: + return ("Followed-Reference"); + default: + return ("Internal-bad-reference-type"); + } +} + +/* Remember this node name for later validation use. */ +#ifdef TRACK_SRCFILE +remember_node_reference (node, line, src_line, type) +#else +remember_node_reference (node, line, type) +#endif /* TRACK_SRCFILE */ + char *node; + int line; +#ifdef TRACK_SRCFILE + int src_line; +#endif /* TRACK_SRCFILE */ + enum reftype type; +{ + NODE_REF *temp = (NODE_REF *) xmalloc (sizeof (NODE_REF)); + + temp->next = node_references; + temp->node = savestring (node); + temp->line_no = line; +#ifdef TRACK_SRCFILE + temp->src_lineno = src_line; +#endif /* TRACK_SRCFILE */ + temp->section = current_section; + temp->type = type; + temp->containing_node = savestring (current_node); + temp->filename = node_filename; +#ifdef TRACK_SRCFILE + temp->src_filename = node_src_filename; +#endif /* TRACK_SRCFILE */ + + node_references = temp; +} + +validate_other_references (ref_list) + register NODE_REF *ref_list; +{ + char *old_input_filename = input_filename; +#ifdef TRACK_SRCFILE + char *old_src_filename = src_filename; +#endif /* TRACK_SRCFILE */ + + while (ref_list != (NODE_REF *) NULL) + { + input_filename = ref_list->filename; +#ifdef TRACK_SRCFILE + src_filename = ref_list->src_filename; +#endif /* TRACK_SRCFILE */ + validate (ref_list->node, ref_list->line_no, +#ifdef TRACK_SRCFILE + ref_list->src_lineno, +#endif /* TRACK_SRCFILE */ + reftype_type_string (ref_list->type)); + ref_list = ref_list->next; + } + input_filename = old_input_filename; +#ifdef TRACK_SRCFILE + src_filename = old_src_filename; +#endif /* TRACK_SRCFILE */ +} + +/* Find NODE in REF_LIST. */ +NODE_REF * +find_node_reference (node, ref_list) + char *node; + register NODE_REF *ref_list; +{ + while (ref_list) + { + if (stricmp (node, ref_list->node) == 0) + break; + ref_list = ref_list->next; + } + return (ref_list); +} + +free_node_references () +{ + register NODE_REF *list, *temp; + + list = node_references; + + while (list) + { + temp = list; + free (list->node); + free (list->containing_node); + list = list->next; + free (temp); + } + node_references = (NODE_REF *) NULL; +} + + /* This function gets called at the start of every line while inside of + a menu. It checks to see if the line starts with "* ", and if so, + remembers the node reference that this menu refers to. + input_text_offset is at the \n just before the line start. */ +#define menu_starter "* " +char * +glean_node_from_menu (remember_reference) + int remember_reference; +{ + int i, orig_offset = input_text_offset; + char *nodename; + + if (strncmp (&input_text[input_text_offset + 1], + menu_starter, + strlen (menu_starter)) != 0) + return ((char *)NULL); + else + input_text_offset += strlen (menu_starter) + 1; + + get_until_in_line (":", &nodename); + if (curchar () == ':') + input_text_offset++; + canon_white (nodename); + + if (curchar () == ':') + goto save_node; + + free (nodename); + get_rest_of_line (&nodename); + + /* Special hack: If the nodename follows the menu item name, + then we have to read the rest of the line in order to find + out what the nodename is. But we still have to read the + line later, in order to process any formatting commands that + might be present. So un-count the carriage return that has just + been counted. */ + line_number--; +#ifdef TRACK_SRCFILE + src_lineno--; +#endif /* TRACK_SRCFILE */ + + canon_white (nodename); + for (i = 0; i < strlen (nodename); i++) + { + if (nodename[i] == '\t' || + nodename[i] == '.' || + nodename[i] == ',') + { + nodename[i] = '\0'; + break; + } + } +save_node: + input_text_offset = orig_offset; + normalize_node_name (nodename); + i = strlen (nodename); + if (i && nodename[i - 1] == ':') + nodename[i - 1] = '\0'; + + if (remember_reference) + { +#ifdef TRACK_SRCFILE + remember_node_reference (nodename, line_number, src_lineno, menu_reference); +#else + remember_node_reference (nodename, line_number, menu_reference); +#endif /* TRACK_SRCFILE */ + free (nodename); + return ((char *)NULL); + } + else + return (nodename); +} + +cm_menu () +{ + begin_insertion (menu); +} + + +/* **************************************************************** */ +/* */ +/* Cross Reference Hacking */ +/* */ +/* **************************************************************** */ + +char * +get_xref_token () +{ + char *string; + + get_until_in_braces (",", &string); + if (curchar () == ',') + input_text_offset++; + fix_whitespace (string); + return (string); +} + +int px_ref_flag = 0; /* Controls initial output string. */ + +/* Make a cross reference. */ +cm_xref (arg) +{ + if (arg == START) + { + char *arg1, *arg2, *arg3, *arg4, *arg5; + + arg1 = get_xref_token (); + arg2 = get_xref_token (); + arg3 = get_xref_token (); + arg4 = get_xref_token (); + arg5 = get_xref_token (); + + add_word_args ("%s", px_ref_flag ? "*note " : "*Note "); + + if (*arg5 || *arg4) + { + char *node_name; + + if (!*arg2) + { + if (*arg3) + node_name = arg3; + else + node_name = arg1; + } + else + node_name = arg2; + + execute_string ("%s: (%s)%s", node_name, arg4, arg1); + return; + } + else +#ifdef TRACK_SRCFILE + remember_node_reference (arg1, line_number, src_lineno, followed_reference); +#else + remember_node_reference (arg1, line_number, followed_reference); +#endif /* TRACK_SRCFILE */ + + if (*arg3) + { + if (!*arg2) + execute_string ("%s: %s", arg3, arg1); + else + execute_string ("%s: %s", arg2, arg1); + return; + } + + if (*arg2) + execute_string ("%s: %s", arg2, arg1); + else + execute_string ("%s::", arg1); + } + else + { + + /* Check to make sure that the next non-whitespace character is either + a period or a comma. input_text_offset is pointing at the "}" which + ended the xref or pxref command. */ + int temp = input_text_offset + 1; + + if (output_paragraph[output_paragraph_offset - 2] == ':' && + output_paragraph[output_paragraph_offset - 1] == ':') + return; + while (temp < size_of_input_text) + { + if (cr_or_whitespace (input_text[temp])) + temp++; + else + { + if (input_text[temp] == '.' || + input_text[temp] == ',' || + input_text[temp] == '\t') + return; + else + { + line_error ("Cross-reference must be terminated with a period or a comma"); + return; + } + } + } + } +} + +cm_pxref (arg) + int arg; +{ + if (arg == START) + { + px_ref_flag++; + cm_xref (arg); + px_ref_flag--; + } + else + add_char ('.'); +} + +cm_inforef (arg) + int arg; +{ + if (arg == START) + { + char *node, *pname, *file; + + node = get_xref_token (); + pname = get_xref_token (); + file = get_xref_token (); + + execute_string ("*note %s: (%s)%s", pname, file, node); + } +} + +/* **************************************************************** */ +/* */ +/* Insertion Command Stubs */ +/* */ +/* **************************************************************** */ + +cm_quotation () +{ + begin_insertion (quotation); +} + +cm_example () +{ + begin_insertion (example); +} + +cm_smallexample () +{ + begin_insertion (smallexample); +} + +cm_lisp () +{ + begin_insertion (lisp); +} + +cm_smalllisp () +{ + begin_insertion (smalllisp); +} + +/* @cartouche/@end cartouche draws box with rounded corners in + TeX output. Right now, just a NOP insertion. */ +cm_cartouche () +{ + begin_insertion (cartouche); +} + +cm_format () +{ + begin_insertion (format); +} + +cm_display () +{ + begin_insertion (display); +} + +cm_itemize () +{ + begin_insertion (itemize); +} + +cm_enumerate () +{ + do_enumeration (enumerate, "1"); +} + +/* Start an enumeration insertion of type TYPE. If the user supplied + no argument on the line, then use DEFAULT_STRING as the initial string. */ +do_enumeration (type, default_string) + int type; + char *default_string; +{ + get_until_in_line (".", &enumeration_arg); + canon_white (enumeration_arg); + + if (!*enumeration_arg) + { + free (enumeration_arg); + enumeration_arg = savestring (default_string); + } + + if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg)) + { + warning ("%s requires a letter or a digit", insertion_type_pname (type)); + + switch (type) + { + case enumerate: + default_string = "1"; + break; + } + enumeration_arg = savestring (default_string); + } + begin_insertion (type); +} + +cm_table () +{ + begin_insertion (table); +} + +cm_ftable () +{ + begin_insertion (ftable); +} + +cm_vtable () +{ + begin_insertion (vtable); +} + +cm_group () +{ + begin_insertion (group); +} + +cm_ifinfo () +{ + begin_insertion (ifinfo); +} + +/* Begin an insertion where the lines are not filled or indented. */ +cm_flushleft () +{ + begin_insertion (flushleft); +} + +/* Begin an insertion where the lines are not filled, and each line is + forced to the right-hand side of the page. */ +cm_flushright () +{ + begin_insertion (flushright); +} + + +/* **************************************************************** */ +/* */ +/* Conditional Handling */ +/* */ +/* **************************************************************** */ + +/* A structure which contains `defined' variables. */ +typedef struct _defines { + struct _defines *next; + char *name; + char *value; +} DEFINE; + +/* The linked list of `set' defines. */ +DEFINE *defines = (DEFINE *)NULL; + +/* Add NAME to the list of `set' defines. */ +set (name, value) + char *name; + char *value; +{ + DEFINE *temp; + + for (temp = defines; temp; temp = temp->next) + if (strcmp (name, temp->name) == 0) + { + free (temp->value); + temp->value = savestring (value); + return; + } + + temp = (DEFINE *)xmalloc (sizeof (DEFINE)); + temp->next = defines; + temp->name = savestring (name); + temp->value = savestring (value); + defines = temp; +} + +/* Remove NAME from the list of `set' defines. */ +clear (name) + char *name; +{ + register DEFINE *temp, *last; + + last = (DEFINE *)NULL; + temp = defines; + + while (temp) + { + if (strcmp (temp->name, name) == 0) + { + if (last) + last->next = temp->next; + else + defines = temp->next; + + free (temp->name); + free (temp->value); + free (temp); + break; + } + last = temp; + temp = temp->next; + } +} + +/* Return the value of NAME. The return value is NULL if NAME is unset. */ +char * +set_p (name) + char *name; +{ + register DEFINE *temp; + + for (temp = defines; temp; temp = temp->next) + if (strcmp (temp->name, name) == 0) + return (temp->value); + + return ((char *)NULL); +} + +/* Conditionally parse based on the current command name. */ +command_name_condition () +{ + char *discarder; + + discarder = (char *)xmalloc (8 + strlen (command)); + + sprintf (discarder, "\n@end %s", command); + discard_until (discarder); + discard_until ("\n"); + + free (discarder); +} + +/* Create a variable whose name appears as the first word on this line. */ +cm_set () +{ + handle_variable (SET); +} + +/* Remove a variable whose name appears as the first word on this line. */ +cm_clear () +{ + handle_variable (CLEAR); +} + +cm_ifset () +{ + handle_variable (IFSET); +} + +cm_ifclear () +{ + handle_variable (IFCLEAR); +} + +cm_value (arg, start_pos, end_pos) + int arg, start_pos, end_pos; +{ + if (arg == END) + { + char *name, *value; + name = (char *)&output_paragraph[start_pos]; + output_paragraph[end_pos] = '\0'; + name = savestring (name); + value = set_p (name); + output_paragraph_offset = start_pos; + + if (value) + add_word_args ("%s", value); + else + add_word_args ("{No Value For \"%s\"}", name); + + free (name); + } +} + +/* Set, clear, or conditionalize based on ACTION. */ +handle_variable (action) + int action; +{ + char *name; + + get_rest_of_line (&name); + backup_input_pointer (); + canon_white (name); + handle_variable_internal (action, name); + free (name); +} + +handle_variable_internal (action, name) + int action; + char *name; +{ + char *value, *temp; + int delimiter; + + /* Only the first word of NAME is a valid tag. */ + temp = name; + delimiter = 0; + while (*temp && (delimiter || !whitespace (*temp))) + { + if (*temp == '"' || *temp == '\'') + { + if (*temp == delimiter) + delimiter = 0; + else + delimiter = *temp; + } + temp++; + } + *temp = '\0'; + + if (!*name) + line_error ("@%s requires a name", command); + else + { + switch (action) + { + case SET: + { + /* Allow a value to be saved along with a variable. The value is + the text following an `=' sign in NAME, if any is present. */ + char *value; + int delimiter; + + for (value = name; *value && *value != '='; value++); + + if (*value) + *value++ = '\0'; + + if (*value == '"' || *value == '\'') + { + value++; + value[strlen (value) - 1] = '\0'; + } + + set (name, value); + } + break; + + case CLEAR: + clear (name); + break; + + case IFSET: + case IFCLEAR: + /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set, + read lines from the the file until we reach a matching + "@end CONDITION". This means that we only take note of + "@ifset/clear" and "@end" commands. */ + { + char condition[8]; + int condition_len; + + if (action == IFSET) + strcpy (condition, "ifset"); + else + strcpy (condition, "ifclear"); + + condition_len = strlen (condition); + + if ((action == IFSET && !set_p (name)) || + (action == IFCLEAR && set_p (name))) + { + int level = 0, done = 0; + + while (!done) + { + char *freeable_line, *line; + + get_rest_of_line (&freeable_line); + + for (line = freeable_line; whitespace (*line); line++); + + if (*line == COMMAND_PREFIX && + (strncmp (line + 1, condition, condition_len) == 0)) + level++; + else if (strncmp (line, "@end", 4) == 0) + { + char *cname = line + 4; + char *temp; + + while (*cname && whitespace (*cname)) + cname++; + temp = cname; + + while (*temp && !whitespace (*temp)) + temp++; + *temp = '\0'; + + if (strcmp (cname, condition) == 0) + { + if (!level) + { + done = 1; + } + else + level--; + } + } + free (freeable_line); + } + break; + } + else + { + if (action == IFSET) + begin_insertion (ifset); + else + begin_insertion (ifclear); + } + } + break; + } + } +} + +/* **************************************************************** */ +/* */ +/* @itemx, @item */ +/* */ +/* **************************************************************** */ + +/* Non-zero means a string is in execution, as opposed to a file. */ +int executing_string = 0; + +/* Execute the string produced by formatting the ARGs with FORMAT. This + is like submitting a new file with @include. */ +execute_string (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + static char temp_string[4000]; + sprintf (temp_string, format, arg1, arg2, arg3, arg4, arg5); + strcat (temp_string, "@bye\n"); + pushfile (); + input_text_offset = 0; + input_text = temp_string; + input_filename = savestring (input_filename); +#ifdef TRACK_SRCFILE + src_filename = savestring (src_filename); +#endif /* TRACK_SRCFILE */ + size_of_input_text = strlen (temp_string); + + executing_string++; + reader_loop (); + + popfile (); + executing_string--; + + free_and_clear (&command); + command = savestring ("not bye"); +} + +int itemx_flag = 0; + +cm_itemx () +{ + itemx_flag++; + cm_item (); + itemx_flag--; +} + +cm_item () +{ + char *rest_of_line, *item_func; + + /* Can only hack "@item" while inside of an insertion. */ + if (insertion_level) + { + INSERTION_ELT *stack = insertion_stack; + int original_input_text_offset; + + skip_whitespace (); + original_input_text_offset = input_text_offset; + + get_rest_of_line (&rest_of_line); + canon_white (rest_of_line); + item_func = current_item_function (); + + /* Okay, do the right thing depending on which insertion function + is active. */ + + switch_top: + switch (stack->insertion) + { + case ifinfo: + case ifset: + case ifclear: + case cartouche: + stack = stack->next; + if (!stack) + goto no_insertion; + else + goto switch_top; + break; + + case menu: + case quotation: + case example: + case smallexample: + case lisp: + case format: + case display: + case group: + line_error ("The `@%s' command is meaningless within a `@%s' block", + command, + insertion_type_pname (current_insertion_type ())); + break; + + case itemize: + case enumerate: + if (itemx_flag) + { + line_error ("@itemx is not meaningful inside of a `%s' block", + insertion_type_pname (current_insertion_type ())); + } + else + { + start_paragraph (); + kill_self_indent (-1); + filling_enabled = indented_fill = 1; + + if (current_insertion_type () == itemize) + { + indent (output_column = current_indent - 2); + + /* I need some way to determine whether this command + takes braces or not. I believe the user can type + either "@bullet" or "@bullet{}". Of course, they + can also type "o" or "#" or whatever else they want. */ + if (item_func && *item_func) + { + if (*item_func == '@') + if (item_func[strlen (item_func) - 1] != '}') + execute_string ("%s{}", item_func); + else + execute_string ("%s", item_func); + else + execute_string ("%s", item_func); + } + insert (' '); + output_column++; + } + else + enumerate_item (); + + /* Special hack. This makes close paragraph ignore you until + the start_paragraph () function has been called. */ + must_start_paragraph = 1; + + /* Ultra special hack. It appears that some people incorrectly + place text directly after the @item, instead of on a new line + by itself. This happens to work in TeX, so I make it work + here. */ + if (*rest_of_line) + { + line_number--; + input_text_offset = original_input_text_offset; + } + } + break; + + case table: + case ftable: + case vtable: + { + /* Get rid of extra characters. */ + kill_self_indent (-1); + + /* close_paragraph () almost does what we want. The problem + is when paragraph_is_open, and last_char_was_newline, and + the last newline has been turned into a space, because + filling_enabled. I handle it here. */ + if (last_char_was_newline && filling_enabled && paragraph_is_open) + insert ('\n'); + close_paragraph (); + +#if defined (INDENT_PARAGRAPHS_IN_TABLE) + /* Indent on a new line, but back up one indentation level. */ + { + int t; + + t = inhibit_paragraph_indentation; + inhibit_paragraph_indentation = 1; + /* At this point, inserting any non-whitespace character will + force the existing indentation to be output. */ + add_char ('i'); + inhibit_paragraph_indentation = t; + } +#else /* !INDENT_PARAGRAPHS_IN_TABLE */ + add_char ('i'); +#endif /* !INDENT_PARAGRAPHS_IN_TABLE */ + + output_paragraph_offset--; + kill_self_indent (default_indentation_increment + 1); + + /* Add item's argument to the line. */ + filling_enabled = 0; + if (!item_func && !(*item_func)) + execute_string ("%s", rest_of_line); + else + execute_string ("%s{%s}", item_func, rest_of_line); + + if (current_insertion_type () == ftable) + execute_string ("@findex %s\n", rest_of_line); + + if (current_insertion_type () == vtable) + execute_string ("@vindex %s\n", rest_of_line); + + /* Start a new line, and let start_paragraph () + do the indenting of it for you. */ + close_single_paragraph (); + indented_fill = filling_enabled = 1; + } + } + free (rest_of_line); + } + else + { + no_insertion: + line_error ("@%s found outside of an insertion block", command); + } +} + + +/* **************************************************************** */ +/* */ +/* Defun and Friends */ +/* */ +/* **************************************************************** */ + +#define DEFUN_SELF_DELIMITING(c) \ + (((c) == '(') \ + || ((c) == ')') \ + || ((c) == '[') \ + || ((c) == ']')) + +struct token_accumulator +{ + unsigned int length; + unsigned int index; + char **tokens; +}; + +void +initialize_token_accumulator (accumulator) + struct token_accumulator *accumulator; +{ + (accumulator->length) = 0; + (accumulator->index) = 0; + (accumulator->tokens) = NULL; +} + +void +accumulate_token (accumulator, token) + struct token_accumulator *accumulator; + char *token; +{ + if ((accumulator->index) >= (accumulator->length)) + { + (accumulator->length) += 10; + (accumulator->tokens) = (char **) xrealloc + (accumulator->tokens, (accumulator->length * sizeof (char *))); + } + accumulator->tokens[accumulator->index] = token; + accumulator->index += 1; +} + +char * +copy_substring (start, end) + char *start; + char *end; +{ + char *result, *scan, *scan_result; + + result = (char *) xmalloc ((end - start) + 1); + scan_result = result; + scan = start; + + while (scan < end) + *scan_result++ = *scan++; + + *scan_result = '\0'; + return (result); +} + +/* Given `string' pointing at an open brace, skip forward and return a + pointer to just past the matching close brace. */ +int +scan_group_in_string (string_pointer) + char **string_pointer; +{ + register int c; + register char *scan_string; + register unsigned int level = 1; + + scan_string = (*string_pointer) + 1; + + while (1) + { + if (level == 0) + { + (*string_pointer) = scan_string; + return (1); + } + c = (*scan_string++); + if (c == '\0') + { + /* Tweak line_number to compensate for fact that + we gobbled the whole line before coming here. */ + line_number -= 1; + line_error ("Missing `}' in @def arg"); + line_number += 1; + (*string_pointer) = (scan_string - 1); + return (0); + } + if (c == '{') + level += 1; + if (c == '}') + level -= 1; + } +} + +/* Return a list of tokens from the contents of `string'. + Commands and brace-delimited groups count as single tokens. + Contiguous whitespace characters are converted to a token + consisting of a single space. */ +char ** +args_from_string (string) + char *string; +{ + struct token_accumulator accumulator; + register char *scan_string = string; + char *token_start, *token_end; + + initialize_token_accumulator (&accumulator); + + while ((*scan_string) != '\0') + { + /* Replace arbitrary whitespace by a single space. */ + if (whitespace (*scan_string)) + { + scan_string += 1; + while (whitespace (*scan_string)) + scan_string += 1; + accumulate_token ((&accumulator), (savestring (" "))); + continue; + } + + /* Commands count as single tokens. */ + if ((*scan_string) == COMMAND_PREFIX) + { + token_start = scan_string; + scan_string += 1; + if (self_delimiting (*scan_string)) + scan_string += 1; + else + { + register int c; + while (1) + { + c = *scan_string++; + + if ((c == '\0') || (c == '{') || (whitespace (c))) + { + scan_string -= 1; + break; + } + } + + if (*scan_string == '{') + { + char *s = scan_string; + (void) scan_group_in_string (&s); + scan_string = s; + } + } + token_end = scan_string; + } + + /* Parentheses and brackets are self-delimiting. */ + else if (DEFUN_SELF_DELIMITING (*scan_string)) + { + token_start = scan_string; + scan_string += 1; + token_end = scan_string; + } + + /* Open brace introduces a group that is a single token. */ + else if (*scan_string == '{') + { + char *s = scan_string; + int balanced = scan_group_in_string (&s); + + token_start = scan_string + 1; + scan_string = s; + token_end = balanced ? (scan_string - 1) : scan_string; + } + + /* Otherwise a token is delimited by whitespace, parentheses, + brackets, or braces. A token is also ended by a command. */ + else + { + token_start = scan_string; + + while (1) + { + register int c; + + c = *scan_string++; + + if (!c || + (whitespace (c) || DEFUN_SELF_DELIMITING (c) || + c == '{' || c == '}')) + { + scan_string--; + break; + } + + /* If we encounter a command imbedded within a token, + then end the token. */ + if (c == COMMAND_PREFIX) + { + scan_string--; + break; + } + } + token_end = scan_string; + } + + accumulate_token + (&accumulator, copy_substring (token_start, token_end)); + } + accumulate_token (&accumulator, NULL); + return (accumulator.tokens); +} + +void +process_defun_args (defun_args, auto_var_p) + char **defun_args; + int auto_var_p; +{ + int pending_space = 0; + + while (1) + { + char *defun_arg = *defun_args++; + + if (defun_arg == NULL) + break; + + if (defun_arg[0] == ' ') + { + pending_space = 1; + continue; + } + + if (pending_space) + { + add_char (' '); + pending_space = 0; + } + + if (DEFUN_SELF_DELIMITING (defun_arg[0])) + add_char (defun_arg[0]); + else if (defun_arg[0] == '&') + add_word (defun_arg); + else if (defun_arg[0] == COMMAND_PREFIX) + execute_string ("%s", defun_arg); + else if (auto_var_p) + execute_string ("@var{%s}", defun_arg); + else + add_word (defun_arg); + } +} + +char * +next_nonwhite_defun_arg (arg_pointer) + char ***arg_pointer; +{ + char **scan = (*arg_pointer); + char *arg = (*scan++); + + if ((arg != 0) && (*arg == ' ')) + arg = *scan++; + + if (arg == 0) + scan -= 1; + + *arg_pointer = scan; + + return ((arg == 0) ? "" : arg); +} + +/* Make the defun type insertion. + TYPE says which insertion this is. + X_P says not to start a new insertion if non-zero. */ +void +defun_internal (type, x_p) + enum insertion_type type; + int x_p; +{ + enum insertion_type base_type; + char **defun_args, **scan_args; + char *category, *defined_name, *type_name, *type_name2; + + { + char *line; + get_rest_of_line (&line); + defun_args = (args_from_string (line)); + free (line); + } + + scan_args = defun_args; + + switch (type) + { + case defun: + category = "Function"; + base_type = deffn; + break; + case defmac: + category = "Macro"; + base_type = deffn; + break; + case defspec: + category = "Special Form"; + base_type = deffn; + break; + case defvar: + category = "Variable"; + base_type = defvr; + break; + case defopt: + category = "User Option"; + base_type = defvr; + break; + case deftypefun: + category = "Function"; + base_type = deftypefn; + break; + case deftypevar: + category = "Variable"; + base_type = deftypevr; + break; + case defivar: + category = "Instance Variable"; + base_type = defcv; + break; + case defmethod: + category = "Method"; + base_type = defop; + break; + case deftypemethod: + category = "Method"; + base_type = deftypemethod; + break; + default: + category = next_nonwhite_defun_arg (&scan_args); + base_type = type; + break; + } + + if ((base_type == deftypefn) + || (base_type == deftypevr) + || (base_type == defcv) + || (base_type == defop) + || (base_type == deftypemethod)) + type_name = next_nonwhite_defun_arg (&scan_args); + + if (base_type == deftypemethod) + type_name2 = next_nonwhite_defun_arg (&scan_args); + + defined_name = next_nonwhite_defun_arg (&scan_args); + + /* This hack exists solely for the purposes of formatting the texinfo + manual. I couldn't think of a better way. The token might be + a simple @@ followed immediately by more text. If this is the case, + then the next defun arg is part of this one, and we should concatenate + them. */ + if (*scan_args && **scan_args && !whitespace (**scan_args) && + (strcmp (defined_name, "@@") == 0)) + { + char *tem = (char *)xmalloc (3 + strlen (scan_args[0])); + + sprintf (tem, "@@%s", scan_args[0]); + + free (scan_args[0]); + scan_args[0] = tem; + scan_args++; + defined_name = tem; + } + + if (!x_p) + begin_insertion (type); + + /* Write the definition header line. + This should start at the normal indentation. */ + current_indent -= default_indentation_increment; + start_paragraph (); + + switch (base_type) + { + case deffn: + case defvr: + case deftp: + execute_string (" -- %s: %s", category, defined_name); + break; + case deftypefn: + case deftypevr: + execute_string (" -- %s: %s %s", category, type_name, defined_name); + break; + case defcv: + execute_string (" -- %s of %s: %s", category, type_name, defined_name); + break; + case defop: + execute_string (" -- %s on %s: %s", category, type_name, defined_name); + break; + case deftypemethod: + execute_string (" -- %s on %s: %s %s", category, type_name, type_name2, + defined_name); + break; + } + current_indent += default_indentation_increment; + + /* Now process the function arguments, if any. + If these carry onto the next line, they should be indented by two + increments to distinguish them from the body of the definition, + which is indented by one increment. */ + current_indent += default_indentation_increment; + + switch (base_type) + { + case deffn: + case defop: + process_defun_args (scan_args, 1); + break; + case deftp: + case deftypefn: + case deftypemethod: + process_defun_args (scan_args, 0); + break; + } + current_indent -= default_indentation_increment; + close_single_paragraph (); + + /* Make an entry in the appropriate index. */ + switch (base_type) + { + case deffn: + case deftypefn: + execute_string ("@findex %s\n", defined_name); + break; + case defvr: + case deftypevr: + case defcv: + execute_string ("@vindex %s\n", defined_name); + break; + case defop: + case deftypemethod: + execute_string ("@findex %s on %s\n", defined_name, type_name); + break; + case deftp: + execute_string ("@tindex %s\n", defined_name); + break; + } + + /* Deallocate the token list. */ + scan_args = defun_args; + while (1) + { + char * arg = (*scan_args++); + if (arg == NULL) + break; + free (arg); + } + free (defun_args); +} + +/* Add an entry for a function, macro, special form, variable, or option. + If the name of the calling command ends in `x', then this is an extra + entry included in the body of an insertion of the same type. */ +cm_defun () +{ + int x_p; + enum insertion_type type; + char *temp = savestring (command); + + x_p = (command[strlen (command) - 1] == 'x'); + + if (x_p) + temp[strlen (temp) - 1] = '\0'; + + type = find_type_from_name (temp); + free (temp); + + /* If we are adding to an already existing insertion, then make sure + that we are already in an insertion of type TYPE. */ + if (x_p && + (!insertion_level || insertion_stack->insertion != type)) + { + line_error ("Must be in a `%s' insertion in order to use `%s'x", + command, command); + discard_until ("\n"); + return; + } + + defun_internal (type, x_p); +} + +/* End existing insertion block. */ +cm_end () +{ + char *temp; + enum insertion_type type; + + if (!insertion_level) + { + line_error ("Unmatched `@%s'", command); + return; + } + + get_rest_of_line (&temp); + canon_white (temp); + + if (strlen (temp) == 0) + line_error ("`@%s' needs something after it", command); + + type = find_type_from_name (temp); + + if (type == bad_type) + { + line_error ("Bad argument to `%s', `%s', using `%s'", + command, temp, insertion_type_pname (current_insertion_type ())); + } + end_insertion (type); + free (temp); +} + + +/* **************************************************************** */ +/* */ +/* Other Random Commands */ +/* */ +/* **************************************************************** */ + +/* This says to inhibit the indentation of the next paragraph, but + not of following paragraphs. */ +cm_noindent () +{ + if (!inhibit_paragraph_indentation) + inhibit_paragraph_indentation = -1; +} + +/* I don't know exactly what to do with this. Should I allow + someone to switch filenames in the middle of output? Since the + file could be partially written, this doesn't seem to make sense. + Another option: ignore it, since they don't *really* want to + switch files. Finally, complain, or at least warn. */ +cm_setfilename () +{ + char *filename; + get_rest_of_line (&filename); + /* warning ("`@%s %s' encountered and ignored", command, filename); */ + free (filename); +} + +cm_ignore_line () +{ + discard_until ("\n"); +} + +/* @br can be immediately followed by `{}', so we have to read those here. + It should simply close the paragraph. */ +cm_br () +{ + if (looking_at ("{}")) + input_text_offset += 2; + + if (curchar () == '\n') + { + input_text_offset++; + line_number++; + } + + close_paragraph (); +} + + /* Insert the number of blank lines passed as argument. */ +cm_sp () +{ + int lines; + char *line; + + get_rest_of_line (&line); + + sscanf (line, "%d", &lines); + while (lines--) + add_char ('\n'); + free (line); +} + +/* Start a new line with just this text on it. + Then center the line of text. + This always ends the current paragraph. */ +cm_center () +{ + register int i, start, length; + int fudge_factor = 1; + unsigned char *line; + + close_paragraph (); + filling_enabled = indented_fill = 0; + cm_noindent (); + start = output_paragraph_offset; + inhibit_output_flushing (); + get_rest_of_line ((char **)&line); + execute_string ((char *)line); + free (line); + uninhibit_output_flushing (); + + i = output_paragraph_offset - 1; + while (i > (start - 1) && output_paragraph[i] == '\n') + i--; + + output_paragraph_offset = ++i; + length = output_paragraph_offset - start; + + if (length < (fill_column - fudge_factor)) + { + line = (unsigned char *)xmalloc (1 + length); + bcopy (output_paragraph + start, line, length); + + i = (fill_column - fudge_factor - length) / 2; + output_paragraph_offset = start; + + while (i--) + insert (' '); + + for (i = 0; i < length; i++) + insert (line[i]); + + free (line); + } + + insert ('\n'); + close_paragraph (); + filling_enabled = 1; +} + +/* Show what an expression returns. */ +cm_result (arg) + int arg; +{ + if (arg == END) + add_word ("=>"); +} + +/* What an expression expands to. */ +cm_expansion (arg) + int arg; +{ + if (arg == END) + add_word ("==>"); +} + +/* Indicates two expressions are equivalent. */ +cm_equiv (arg) + int arg; +{ + if (arg == END) + add_word ("=="); +} + +/* What an expression may print. */ +cm_print (arg) + int arg; +{ + if (arg == END) + add_word ("-|"); +} + +/* An error signaled. */ +cm_error (arg) + int arg; +{ + if (arg == END) + add_word ("error-->"); +} + +/* The location of point in an example of a buffer. */ +cm_point (arg) + int arg; +{ + if (arg == END) + add_word ("-!-"); +} + +/* Start a new line with just this text on it. + The text is outdented one level if possible. */ +cm_exdent () +{ + char *line; + int i = current_indent; + + if (current_indent) + current_indent -= default_indentation_increment; + + get_rest_of_line (&line); + close_single_paragraph (); + execute_string (line); + current_indent = i; + free (line); + close_single_paragraph (); +} + +cm_include () +{ + cm_infoinclude (); +} + +/* Remember this file, and move onto the next. */ +cm_infoinclude () +{ + char *filename; + + close_paragraph (); + get_rest_of_line (&filename); + pushfile (); + + /* In verbose mode we print info about including another file. */ + if (verbose_mode) + { + register int i = 0; + register FSTACK *stack = filestack; + + for (i = 0, stack = filestack; stack; stack = stack->next, i++); + + i *= 2; + + printf ("%*s", i, ""); + printf ("%c%s %s\n", COMMAND_PREFIX, command, filename); + fflush (stdout); + } + + if (!find_and_load (filename)) + { + extern char *sys_errlist[]; + extern int errno, sys_nerr; + popfile (); + + /* Cannot "@include foo", in line 5 of "/wh/bar". */ + line_error ("`%c%s %s': %s", COMMAND_PREFIX, command, filename, + ((errno < sys_nerr) ? + sys_errlist[errno] : "Unknown file system error")); + } + free (filename); +} + +/* The other side of a malformed expression. */ +misplaced_brace () +{ +#ifdef ALLOW_JUNK + warning ("Misplaced `}'"); + add_word ("}"); +#else + line_error ("Misplaced `}'"); +#endif +} + +/* Don't let the filling algorithm insert extra whitespace here. */ +cm_force_abbreviated_whitespace () +{ +} + +/* Do not let this character signify the end of a sentence, though + if it was seen without the command prefix it normally would. We + do this by turning on the 8th bit of the character. */ +cm_ignore_sentence_ender () +{ + add_char (META ((*command))); +} + +/* Signals end of processing. Easy to make this happen. */ +cm_bye () +{ + input_text_offset = size_of_input_text; +} + +cm_asis () +{ +} + +cm_math () +{ +} + +#ifdef TRACK_SRCFILE +cm_srcfilename () +{ + get_rest_of_line (&src_filename); +} + +cm_srclineno () +{ + char *temp; + get_rest_of_line (&temp); + sscanf(temp, "%d", &src_lineno); + free (temp); +} +#endif /* TRACK_SRCFILE */ + +/* **************************************************************** */ +/* */ +/* Indexing Stuff */ +/* */ +/* **************************************************************** */ + + +/* An index element... */ +typedef struct index_elt +{ + struct index_elt *next; + char *entry; /* The index entry itself. */ + char *node; /* The node from whence it came. */ + int code; /* Non-zero means add `@code{...}' when + printing this element. */ + int defining_line; /* Line number where this entry was written. */ +} INDEX_ELT; + +/* A list of short-names for each index, and the index to that index in our + index array, the_indices. In addition, for each index, it is remembered + whether that index is a code index or not. Code indices have @code{} + inserted around the first word when they are printed with printindex. */ +typedef struct +{ + char *name; + int index; + int code; +} INDEX_ALIST; + +INDEX_ALIST **name_index_alist = (INDEX_ALIST **) NULL; + +/* An array of pointers. Each one is for a different index. The + "synindex" command changes which array slot is pointed to by a + given "index". */ +INDEX_ELT **the_indices = (INDEX_ELT **) NULL; + +/* The number of defined indices. */ +int defined_indices = 0; + +/* We predefine these. */ +#define program_index 0 +#define function_index 1 +#define concept_index 2 +#define variable_index 3 +#define datatype_index 4 +#define key_index 5 + +init_indices () +{ + int i; + + /* Create the default data structures. */ + + /* Initialize data space. */ + if (!the_indices) + { + the_indices = (INDEX_ELT **) xmalloc ((1 + defined_indices) * + sizeof (INDEX_ELT *)); + the_indices[defined_indices] = (INDEX_ELT *) NULL; + + name_index_alist = (INDEX_ALIST **) xmalloc ((1 + defined_indices) * + sizeof (INDEX_ALIST *)); + name_index_alist[defined_indices] = (INDEX_ALIST *) NULL; + } + + /* If there were existing indices, get rid of them now. */ + for (i = 0; i < defined_indices; i++) + undefindex (name_index_alist[i]->name); + + /* Add the default indices. */ + defindex ("pg", 0); + defindex ("fn", 1); /* "fn" is a code index. */ + defindex ("cp", 0); + defindex ("vr", 0); + defindex ("tp", 0); + defindex ("ky", 0); + +} + +/* Find which element in the known list of indices has this name. + Returns -1 if NAME isn't found. */ +int +find_index_offset (name) + char *name; +{ + register int i; + for (i = 0; i < defined_indices; i++) + if (name_index_alist[i] && + stricmp (name, name_index_alist[i]->name) == 0) + return (name_index_alist[i]->index); + return (-1); +} + +/* Return a pointer to the entry of (name . index) for this name. + Return NULL if the index doesn't exist. */ +INDEX_ALIST * +find_index (name) + char *name; +{ + int offset = find_index_offset (name); + if (offset > -1) + return (name_index_alist[offset]); + else + return ((INDEX_ALIST *) NULL); +} + +/* Given an index name, return the offset in the_indices of this index, + or -1 if there is no such index. */ +translate_index (name) + char *name; +{ + INDEX_ALIST *which = find_index (name); + + if (which) + return (which->index); + else + return (-1); +} + +/* Return the index list which belongs to NAME. */ +INDEX_ELT * +index_list (name) + char *name; +{ + int which = translate_index (name); + if (which < 0) + return ((INDEX_ELT *) - 1); + else + return (the_indices[which]); +} + +/* Please release me, let me go... */ +free_index (index) + INDEX_ELT *index; +{ + INDEX_ELT *temp; + + while ((temp = index) != (INDEX_ELT *) NULL) + { + free (temp->entry); + free (temp->node); + index = index->next; + free (temp); + } +} + +/* Flush an index by name. */ +undefindex (name) + char *name; +{ + int i; + int which = find_index_offset (name); + + if (which < 0) + return (which); + + i = name_index_alist[which]->index; + + + free_index (the_indices[i]); + the_indices[i] = (INDEX_ELT *) NULL; + + free (name_index_alist[which]->name); + free (name_index_alist[which]); + name_index_alist[which] = (INDEX_ALIST *) NULL; +} + +/* Define an index known as NAME. We assign the slot number. + CODE if non-zero says to make this a code index. */ +defindex (name, code) + char *name; + int code; +{ + register int i, slot; + + /* If it already exists, flush it. */ + undefindex (name); + + /* Try to find an empty slot. */ + slot = -1; + for (i = 0; i < defined_indices; i++) + if (!name_index_alist[i]) + { + slot = i; + break; + } + + if (slot < 0) + { + /* No such luck. Make space for another index. */ + slot = defined_indices; + defined_indices++; + + name_index_alist = (INDEX_ALIST **) + xrealloc ((char *)name_index_alist, + (1 + defined_indices) * sizeof (INDEX_ALIST *)); + the_indices = (INDEX_ELT **) + xrealloc ((char *)the_indices, + (1 + defined_indices) * sizeof (INDEX_ELT *)); + } + + /* We have a slot. Start assigning. */ + name_index_alist[slot] = (INDEX_ALIST *) xmalloc (sizeof (INDEX_ALIST)); + name_index_alist[slot]->name = savestring (name); + name_index_alist[slot]->index = slot; + name_index_alist[slot]->code = code; + + the_indices[slot] = (INDEX_ELT *) NULL; +} + +/* Add the arguments to the current index command to the index NAME. */ +index_add_arg (name) + char *name; +{ + int which; + char *index_entry; + INDEX_ALIST *tem; + + tem = find_index (name); + + which = tem ? tem->index : -1; + + get_rest_of_line (&index_entry); + ignore_blank_line (); + + if (which < 0) + { + line_error ("Unknown index reference `%s'", name); + free (index_entry); + } + else + { + INDEX_ELT *new = (INDEX_ELT *) xmalloc (sizeof (INDEX_ELT)); + new->next = the_indices[which]; + new->entry = index_entry; + new->node = current_node; + new->code = tem->code; + new->defining_line = line_number - 1; + the_indices[which] = new; + } +} + +#define INDEX_COMMAND_SUFFIX "index" + +/* The function which user defined index commands call. */ +gen_index () +{ + char *name = savestring (command); + if (strlen (name) >= strlen ("index")) + name[strlen (name) - strlen ("index")] = '\0'; + index_add_arg (name); + free (name); +} + +/* Define a new index command. Arg is name of index. */ +cm_defindex () +{ + gen_defindex (0); +} + +cm_defcodeindex () +{ + gen_defindex (1); +} + +gen_defindex (code) + int code; +{ + char *name; + get_rest_of_line (&name); + + if (find_index (name)) + { + line_error ("Index `%s' already exists", name); + free (name); + return; + } + else + { + char *temp = (char *) alloca (1 + strlen (name) + strlen ("index")); + sprintf (temp, "%sindex", name); + define_user_command (temp, gen_index, 0); + defindex (name, code); + free (name); + } +} + +/* Append LIST2 to LIST1. Return the head of the list. */ +INDEX_ELT * +index_append (head, tail) + INDEX_ELT *head, *tail; +{ + register INDEX_ELT *t_head = head; + + if (!t_head) + return (tail); + + while (t_head->next) + t_head = t_head->next; + t_head->next = tail; + return (head); +} + +/* Expects 2 args, on the same line. Both are index abbreviations. + Make the first one be a synonym for the second one, i.e. make the + first one have the same index as the second one. */ +cm_synindex () +{ + int redirector, redirectee; + char *temp; + + skip_whitespace (); + get_until_in_line (" ", &temp); + redirectee = find_index_offset (temp); + skip_whitespace (); + free_and_clear (&temp); + get_until_in_line (" ", &temp); + redirector = find_index_offset (temp); + free (temp); + if (redirector < 0 || redirectee < 0) + { + line_error ("Unknown index reference"); + } + else + { + /* I think that we should let the user make indices synonymous to + each other without any lossage of info. This means that one can + say @synindex cp dt anywhere in the file, and things that used to + be in cp will go into dt. */ + INDEX_ELT *i1 = the_indices[redirectee], *i2 = the_indices[redirector]; + + if (i1 || i2) + { + if (i1) + the_indices[redirectee] = index_append (i1, i2); + else + the_indices[redirectee] = index_append (i2, i1); + } + + name_index_alist[redirectee]->index = + name_index_alist[redirector]->index; + } +} + +cm_pindex () /* Pinhead index. */ +{ + index_add_arg ("pg"); +} + +cm_vindex () /* Variable index. */ +{ + index_add_arg ("vr"); +} + +cm_kindex () /* Key index. */ +{ + index_add_arg ("ky"); +} + +cm_cindex () /* Concept index. */ +{ + index_add_arg ("cp"); +} + +cm_findex () /* Function index. */ +{ + index_add_arg ("fn"); +} + +cm_tindex () /* Data Type index. */ +{ + index_add_arg ("tp"); +} + +/* Sorting the index. */ +/* partain: added 2nd test if entries are the same */ +index_element_compare (element1, element2) + INDEX_ELT **element1, **element2; +{ +/* old + return (strcmp ((*element1)->entry, (*element2)->entry)); +*/ + + int result; + /* This needs to ignore leading non-text characters. */ + result = strcmp ((*element1)->entry, (*element2)->entry); + + if (result != 0) + return(result); + else + return (strcmp ((*element1)->node, (*element2)->node)); +} + +/* Sort the index passed in INDEX, returning an array of + pointers to elements. The array is terminated with a NULL + pointer. We call qsort because it's supposed to be fast. + I think this looks bad. */ +INDEX_ELT ** +sort_index (index) + INDEX_ELT *index; +{ + INDEX_ELT *temp = index; + INDEX_ELT **array; + int count = 0; + + while (temp != (INDEX_ELT *) NULL) + { + count++; + temp = temp->next; + } + + /* We have the length. Make an array. */ + + array = (INDEX_ELT **) xmalloc ((count + 1) * sizeof (INDEX_ELT *)); + count = 0; + temp = index; + + while (temp != (INDEX_ELT *) NULL) + { + array[count++] = temp; + temp = temp->next; + } + array[count] = (INDEX_ELT *) NULL; /* terminate the array. */ + + /* Sort the array. */ + qsort (array, count, sizeof (INDEX_ELT *), index_element_compare); + + return (array); +} + +/* Non-zero means that we are in the middle of printing an index. */ +int printing_index = 0; + +/* Takes one arg, a short name of an index to print. + Outputs a menu of the sorted elements of the index. */ +cm_printindex () +{ + int item; + INDEX_ELT *index; + INDEX_ELT **array; + char *index_name; + int old_inhibitions = inhibit_paragraph_indentation; + int previous_filling_enabled_value = filling_enabled; + + close_paragraph (); + get_rest_of_line (&index_name); + + index = index_list (index_name); + if ((int) index == -1) + { + line_error ("Unknown index name `%s'", index_name); + free (index_name); + return; + } + else + free (index_name); + + array = sort_index (index); + + filling_enabled = 0; + inhibit_paragraph_indentation = 1; + close_paragraph (); + add_word ("* Menu:\n\n"); + + printing_index = 1; + for (item = 0; (index = array[item]); item++) + { + int real_line_number = line_number; + + /* Let errors generated while making the index entry point back + at the line which contains the entry. */ + line_number = index->defining_line; + + /* If this particular entry should be printed as a "code" index, + then wrap the entry with "@code{...}". */ + if (index->code) + execute_string ("* @code{%s}: ", index->entry); + else + execute_string ("* %s: ", index->entry); + + /* Pad the front of the destination nodename so that + the output looks nice. */ + if (fill_column > 40 && output_column < 40) + indent (40 - output_column); + + execute_string ("%s.\n", index->node); + + line_number = real_line_number; + flush_output (); + } + + printing_index = 0; + free (array); + close_single_paragraph (); + filling_enabled = previous_filling_enabled_value; + inhibit_paragraph_indentation = old_inhibitions; +} + + +/* **************************************************************** */ +/* */ +/* Making User Defined Commands */ +/* */ +/* **************************************************************** */ + +define_user_command (name, proc, needs_braces_p) + char *name; + FUNCTION *proc; + int needs_braces_p; +{ + int slot = user_command_array_len; + user_command_array_len++; + + if (!user_command_array) + user_command_array = (COMMAND **) xmalloc (1 * sizeof (COMMAND *)); + + user_command_array = (COMMAND **) xrealloc (user_command_array, + (1 + user_command_array_len) * + sizeof (COMMAND *)); + + user_command_array[slot] = (COMMAND *) xmalloc (sizeof (COMMAND)); + user_command_array[slot]->name = savestring (name); + user_command_array[slot]->proc = proc; + user_command_array[slot]->argument_in_braces = needs_braces_p; +} + +/* Make ALIAS run the named FUNCTION. Copies properties from FUNCTION. */ +define_alias (alias, function) + char *alias, *function; +{ +} + +/* Set the paragraph indentation variable to the value specified in STRING. + Values can be: + `asis': Don't change existing indentation. + `none': Remove existing indentation. + NUM: Indent NUM spaces at the starts of paragraphs. + Note that if NUM is zero, we assume `none'. + + Returns 0 if successful, or non-zero if STRING isn't one of the above. */ +int +set_paragraph_indent (string) + char *string; +{ + if (strcmp (string, "asis") == 0) + paragraph_start_indent = 0; + else if (strcmp (string, "none") == 0) + paragraph_start_indent = -1; + else + { + if (sscanf (string, "%d", ¶graph_start_indent) != 1) + return (-1); + else + { + if (paragraph_start_indent == 0) + paragraph_start_indent = -1; + } + } + return (0); +} + +cm_paragraphindent () +{ + char *arg; + + get_rest_of_line (&arg); + if (set_paragraph_indent (arg) != 0) + line_error ("Bad argument to @paragraphindent"); + + free (arg); +} + +/* Some support for footnotes. */ + +/* Footnotes are a new construct in Info. We don't know the best method + of implementing them for sure, so we present two possiblities. + + SeparateNode: + Make them look like followed references, with the reference + destinations in a makeinfo manufactured node or, + + EndNode: + Make them appear at the bottom of the node that they originally + appeared in. */ +#define SeparateNode 0 +#define EndNode 1 + +int footnote_style = EndNode; +int first_footnote_this_node = 1; +int footnote_count = 0; + +/* Set the footnote style based on he style identifier in STRING. */ +int +set_footnote_style (string) + char *string; +{ + if ((stricmp (string, "separate") == 0) || + (stricmp (string, "MN") == 0)) + footnote_style = SeparateNode; + else if ((stricmp (string, "end") == 0) || + (stricmp (string, "EN") == 0)) + footnote_style = EndNode; + else + return (-1); + + return (0); +} + +cm_footnotestyle () +{ + char *arg; + + get_rest_of_line (&arg); + + if (set_footnote_style (arg) != 0) + line_error ("Bad argument to @footnotestyle"); + + free (arg); +} + +typedef struct fn +{ + struct fn *next; + char *marker; + char *note; +} FN; + +FN *pending_notes = (FN *) NULL; + +/* A method for remembering footnotes. Note that this list gets output + at the end of the current node. */ +remember_note (marker, note) + char *marker, *note; +{ + FN *temp = (FN *) xmalloc (sizeof (FN)); + + temp->marker = savestring (marker); + temp->note = savestring (note); + temp->next = pending_notes; + pending_notes = temp; + footnote_count++; +} + +/* How to get rid of existing footnotes. */ +free_pending_notes () +{ + FN *temp; + + while ((temp = pending_notes) != (FN *) NULL) + { + free (temp->marker); + free (temp->note); + pending_notes = pending_notes->next; + free (temp); + } + first_footnote_this_node = 1; + footnote_count = 0; +} + +/* What to do when you see a @footnote construct. */ + + /* Handle a "footnote". + footnote *{this is a footnote} + where "*" is the marker character for this note. */ +cm_footnote () +{ + char *marker; + char *note; + + get_until ("{", &marker); + canon_white (marker); + + /* Read the argument in braces. */ + if (curchar () != '{') + { + line_error ("`@%s' expected more than just `%s'. It needs something in `{...}'", command, marker); + free (marker); + return; + } + else + { + int braces = 1; + int temp = ++input_text_offset; + int len; + + while (braces) + { + if (temp == size_of_input_text) + { + line_error ("No closing brace for footnote `%s'", marker); + return; + } + + if (input_text[temp] == '{') + braces++; + else if (input_text[temp] == '}') + braces--; + else if (input_text[temp] == '\n') + line_number ++; + + temp++; + } + + len = (temp - input_text_offset) - 1; + note = (char *)xmalloc (len + 1); + strncpy (note, &input_text[input_text_offset], len); + note[len] = '\0'; + input_text_offset = temp; + } + + if (!current_node || !*current_node) + { + line_error ("Footnote defined without parent node"); + free (marker); + free (note); + return; + } + + if (!*marker) + { + free (marker); + + if (number_footnotes) + { + marker = (char *)xmalloc (10); + sprintf (marker, "%d", current_footnote_number); + current_footnote_number++; + } + else + marker = savestring ("*"); + } + + remember_note (marker, note); + + /* Your method should at least insert MARKER. */ + switch (footnote_style) + { + case SeparateNode: + add_word_args ("(%s)", marker); + if (first_footnote_this_node) + { + char *temp_string; + + temp_string = (char *) + xmalloc ((strlen (current_node)) + (strlen ("-Footnotes")) + 1); + + add_word_args (" (*note %s-Footnotes::)", current_node); + strcpy (temp_string, current_node); + strcat (temp_string, "-Footnotes"); +#ifdef TRACK_SRCFILE + remember_node_reference (temp_string, line_number, src_lineno, followed_reference); +#else + remember_node_reference (temp_string, line_number, followed_reference); +#endif /* TRACK_SRCFILE */ + free (temp_string); + first_footnote_this_node = 0; + } + break; + + case EndNode: + add_word_args ("(%s)", marker); + break; + + default: + break; + } + free (marker); + free (note); +} + +/* Non-zero means that we are currently in the process of outputting + footnotes. */ +int already_outputting_pending_notes = 0; + +/* Output the footnotes. We are at the end of the current node. */ +output_pending_notes () +{ + FN *footnote = pending_notes; + + if (!pending_notes) + return; + + switch (footnote_style) + { + + case SeparateNode: + { + char *old_current_node = current_node; + char *old_command = savestring (command); + + already_outputting_pending_notes++; + execute_string ("@node %s-Footnotes,,,%s\n", current_node, current_node); + already_outputting_pending_notes--; + current_node = old_current_node; + free (command); + command = old_command; + } + break; + + case EndNode: + close_paragraph (); + in_fixed_width_font++; + execute_string ("---------- Footnotes ----------\n\n"); + in_fixed_width_font--; + break; + } + + /* Handle the footnotes in reverse order. */ + { + FN **array = (FN **) xmalloc ((footnote_count + 1) * sizeof (FN *)); + + array[footnote_count] = (FN *) NULL; + + while (--footnote_count > -1) + { + array[footnote_count] = footnote; + footnote = footnote->next; + } + + filling_enabled = 1; + indented_fill = 1; + + while (footnote = array[++footnote_count]) + { + + switch (footnote_style) + { + case SeparateNode: + case EndNode: + execute_string ("(%s) %s", footnote->marker, footnote->note); + close_paragraph (); + break; + } + } + close_paragraph (); + free (array); + } +} + + +/* **************************************************************** */ +/* */ +/* User definable Macros (text substitution) */ +/* */ +/* **************************************************************** */ + +#if defined (HAVE_MACROS) + +/* Array of macros and definitions. */ +MACRO_DEF **macro_list = (MACRO_DEF **)NULL; + +int macro_list_len = 0; /* Number of elements. */ +int macro_list_size = 0; /* Number of slots in total. */ + +/* Return the macro definition of NAME or NULL if NAME is not defined. */ +MACRO_DEF * +find_macro (name) + char *name; +{ + register int i; + register MACRO_DEF *def; + + def = (MACRO_DEF *)NULL; + for (i = 0; macro_list && (def = macro_list[i]); i++) + if (strcmp (def->name, name) == 0) + break; + + return (def); +} + +/* Add the macro NAME with DEFINITION to macro_list. FILENAME is + the name of the file where this definition can be found, and + LINENO is the line number within that file. If a macro already + exists with NAME, then a warning is produced, and that previous + definition is overwritten. */ +void +add_macro (name, definition, filename, lineno) + char *name, *definition; + char *filename; + int lineno; +{ + register MACRO_DEF *def; + + def = find_macro (name); + + if (!def) + { + if (macro_list_len + 2 >= macro_list_size) + macro_list = (MACRO_DEF **)xrealloc + (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *))); + + macro_list[macro_list_len] = (MACRO_DEF *)xmalloc (sizeof (MACRO_DEF)); + macro_list[macro_list_len + 1] = (MACRO_DEF *)NULL; + + def = macro_list[macro_list_len]; + macro_list_len += 1; + def->name = savestring (name); + } + else + { + char *temp_filename = input_filename; + int temp_line = line_number; + + warning ("The macro `%s' is previously defined.", name); + + input_filename = def->filename; + line_number = def->lineno; + + warning ("Here is the previous definition of `%s'.", name); + + input_filename = temp_filename; + line_number = temp_line; + + free (def->filename); + free (def->definition); + } + + def->filename = savestring (filename); + def->lineno = lineno; + def->definition = savestring (definition); +} + + +/* Delete the macro with name NAME. The macro is deleted from the list, + but it is also returned. If there was no macro defined, NULL is + returned. */ +MACRO_DEF * +delete_macro (name) + char *name; +{ + register int i; + register MACRO_DEF *def; + + def = (MACRO_DEF *)NULL; + for (i = 0; macro_list && (def = macro_list[i]); i++) + if (strcmp (def->name, name) == 0) + { + bcopy (macro_list + i + 1, macro_list + i, + ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *)); + break; + } + return (def); +} + +/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */ +void +execute_macro (def) + MACRO_DEF *def; +{ + + if (def != (MACRO_DEF *)NULL) + { + char *line, *string; + + get_until ("\n", &line); + + if (curchar () == '\n') /* as opposed to the end of the file... */ + { + line_number++; + input_text_offset++; + } + string = (char *)xmalloc (1 + strlen (def->definition) + strlen (line)); + strcpy (string, def->definition); + strcat (string, line); + free (line); + + execute_string ("%s\n", string); + free (string); + } +} + +int +cm_macro () +{ + register int i; + char *line, *name, *expansion; + + get_rest_of_line (&line); + canon_white (line); + + for (i = 0; line[i] && !whitespace (line[i]); i++); + name = (char *)xmalloc (i); + strncpy (name, line, i); + name[i] = '\0'; + + while (whitespace (line[i])) + i++; + + add_macro (name, line + i, input_filename, line_number - 1); + free (line); + free (name); +} + +int +cm_unmacro () +{ + register int i; + char *line, *name; + MACRO_DEF *def; + + get_rest_of_line (&line); + canon_white (line); + + for (i = 0; line[i] && !whitespace (line[i]); i++); + name = (char *)xmalloc (i); + strncpy (name, line, i); + name[i] = '\0'; + + def = delete_macro (name); + + if (def) + { + free (def->filename); + free (def->name); + free (def->definition); + free (def); + } + + free (line); + free (name); +} +#endif /* HAVE_MACROS */ + +/* **************************************************************** */ +/* */ +/* Looking For Include Files */ +/* */ +/* **************************************************************** */ + +/* Given a string containing units of information separated by colons, + return the next one pointed to by INDEX, or NULL if there are no more. + Advance INDEX to the character after the colon. */ +char * +extract_colon_unit (string, index) + char *string; + int *index; +{ + int i, start; + + i = *index; + + if (!string || (i >= strlen (string))) + return ((char *)NULL); + + /* Each call to this routine leaves the index pointing at a colon if + there is more to the path. If I is > 0, then increment past the + `:'. If I is 0, then the path has a leading colon. Trailing colons + are handled OK by the `else' part of the if statement; an empty + string is returned in that case. */ + if (i && string[i] == ':') + i++; + + start = i; + + while (string[i] && string[i] != ':') i++; + + *index = i; + + if (i == start) + { + if (string[i]) + (*index)++; + + /* Return "" in the case of a trailing `:'. */ + return (savestring ("")); + } + else + { + char *value; + + value = (char *)xmalloc (1 + (i - start)); + strncpy (value, &string[start], (i - start)); + value [i - start] = '\0'; + + return (value); + } +} + +/* Return the full pathname for FILENAME by searching along PATH. + When found, return the stat () info for FILENAME in FINFO. + If PATH is NULL, only the current directory is searched. + If the file could not be found, return a NULL pointer. */ +char * +get_file_info_in_path (filename, path, finfo) + char *filename, *path; + struct stat *finfo; +{ + char *dir; + int result, index = 0; + + if (path == (char *)NULL) + path = "."; + + /* Handle absolute pathnames. "./foo", "/foo", "../foo". */ + if (*filename == '/' || + (*filename == '.' && + (filename[1] == '/' || + (filename[1] == '.' && filename[2] == '/')))) + { + if (stat (filename, finfo) == 0) + return (savestring (filename)); + else + return ((char *)NULL); + } + + while (dir = extract_colon_unit (path, &index)) + { + char *fullpath; + + if (!*dir) + { + free (dir); + dir = savestring ("."); + } + + fullpath = (char *)xmalloc (2 + strlen (dir) + strlen (filename)); + sprintf (fullpath, "%s/%s", dir, filename); + free (dir); + + result = stat (fullpath, finfo); + + if (result == 0) + return (fullpath); + else + free (fullpath); + } + return ((char *)NULL); +} diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/makeinfo.texinfo b/web/glasgow/lit2x-0.16/literate/info-utils/makeinfo.texinfo new file mode 100644 index 0000000000..81f3796fb0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/makeinfo.texinfo @@ -0,0 +1,226 @@ +\include texinfo.tex @c -*- texinfo -*- + +@setfilename makeinfo.info + +@node Top +@chapter What is Makeinfo? + +Makeinfo is a program for converting @dfn{texinfo} files into @dfn{info} +files. Texinfo is a documentation language which allows a printed manual +and online documentation (an info file) to be produced from a single source +file. + +This text does not explain how to write a texinfo file. In order to +usefully use this documentation, you should be familiar with the texinfo +documentation language, and you should have used an info file reader to +read some info files. A good place to start is with @code{info}, a program +for reading online documentation. Just type @code{info} to get started. +Documentation on the texinfo language is available in the node Texinfo. +Type @code{info texinfo} to read it. + +@menu +* Formatting Control:: Controlling the appearance of the output file. +* Options:: Command line options. +* Validation:: What makes a `valid' info file. +* Node Defaulting:: How Makeinfo can fill in the node fields for you. +@end menu + +@node Formatting Control +@section Controlling Paragraph Formats + +In general, Makeinfo @dfn{fills} the paragraphs that it outputs to the info +file. Filling is the process of breaking up and connecting lines such that +the output is nearly justified. With Makeinfo, you can control: + +@itemize @bullet +@item +The width of the paragraph (the @dfn{fill-column}). +@item +The amount of indentation that the first line of the paragraph gets (the +@dfn{paragraph-indentation}). +@end itemize + + +@node Options +@section Command Line Options + +The following command line options are available for Makeinfo. + +@table @code + +@item +error-limit @var{num} +Sets the maximum number of errors that Makeinfo will print before exiting +(on the assumption that continuing would be useless). The default number +of errors that can be printed before Makeinfo gives up on processing the +input file is 100. + +@item +fill-column @var{num} +Specifies the maximum right-hand edge of a line. Paragraphs that are +filled will be filled to this width. The default value for fill-column +is 72. + +@item +footnote-style @var{style} + +Sets the footnote style to @var{style}. @var{style} should either be `MN' +for `make node', or `EN' for `bottom node'. When the footnote style is +`MN', Makeinfo makes a new node containing the footnotes found in the +current node. When the footnote style is `EN', Makeinfo places the +footnote references at the end of the current node. + +@item +no-split +Suppress the splitting stage of Makeinfo. In general, large output files +(where the size is greater than 70k bytes) are split into smaller subfiles, +each one apporximately 50k bytes. By specifying @code{+no-split}, Makeinfo +will not split up the output file. + +@item +no-validate +Suppress the validation phase of Makeinfo. Normally, after the file is +processed, some consistency checks are made to ensure that cross references +can be resolved, etc. @xref{Validation}. + +@item +no-warn +Suppress the output of warning messages. This does @emph{not} suppress the +output of error messages, simply warnings. You might want this if the file +you are creating has texinfo examples in it, and the nodes that are +referenced don't actually exist. + +@item +no-number-footnotes +Supress the automatic numbering of footnotes. The default is number +each footnote sequentially in a single node, resetting the current +footnote number to 1 at the start of each node. + +@item +paragraph-indent @var{num} +Sets the paragraph indentation to @var{num}. The value of @var{num} is +interpreted as follows: + +@itemize @bullet +@item +A value of 0 means don't change the existing indentation at the starts of +paragraphs. +@item +A value less than zero means indent paragraph starts to column zero by +deleting the existing indentation. +@item +A value greater than zero is the number of spaces to leave at the front of +each paragraph start. +@end itemize + +@item +verbose +Causes Makeinfo to inform you as to what it is doing. Normally Makeinfo +only outputs text if there are errors or warnings. + +@item +version +Prints outs the version number of Makeinfo. + +@end table + +@node Validation +@section What makes a valid Info file? + +If you have not suppressed validation (with the @code{+no-validate} +option), Makeinfo will check the validity of the final info file. Mostly, +this means ensuring that nodes you have referenced really exist. Here is a +complete list of what is checked: + +@enumerate +@item +If a node reference such as Prev, Next or Up is a reference to a node in +this file (i.e., not an external reference such as `(DIR)'), then the +referenced node must exist. + +@item +In a given node, if the node referenced by the Prev is different than the +node referenced by the Up, then the node referenced by the Prev must have a +Next which references this node. + +@item +Every node excepting @code{Top} must have an Up field. + +@item +The node referenced by Up must contain a reference to this node, other than +a Next reference. Obviously, this includes menu items and followed +references. + +@item +If the Next reference is not the same as the Next reference of the Up +reference, then the node referenced by Next must have a Prev reference +pointing back at this node. This rule still allows the last node in a +section to point to the first node of the next chapter. + +@end enumerate + +@node Node Defaulting +@section Defaulting the @code{Prev}, @code{Next}, and @code{Up} + +Although the definition of an info file allows a great deal of +flexibility, there are some conventions that you are urged to follow. +By letting Makeinfo default the Next, Prev, and Up pointers you can +follow these conventions with the minimum of effort. + +A common error ocurrs when adding a new node to a menu; often the nodes +which are referenced in the menu do not point to each other in the same +order as they appear in the menu. + +Makeinfo helps with this particular problem by defaulting Next, Prev, and +Up pointers in a @code{@@node} command if you leave off these pointers in +the command. + +The node to receive the defaulted pointers must be followed immediately by +a sectioning command, such as @code{@@chapter} or @code{@@section}, and +must appear in a menu that is one sectioning level or more above the +sectioning level that this node is to have. + +Here is an example of using this feature. + +@example +@@setfilename default-nodes-example.info +@@node Top +@@chapter Introduction +@@menu +* foo:: the foo node +* bar:: the bar node +@@end menu + +@@node foo +@@section foo +this is the foo node. + +@@node bar +@@section Bar +This is the Bar node. +@@bye + +@end example + +produces + +@example +Info file default-nodes-example.info, produced by Makeinfo, -*- Text -*- +from input file default-nodes.texinfo. + +File: default-nodes-example.info, Node: Top + +Introduction +************ + +* Menu: + +* foo:: the foo node +* bar:: the bar node + +File: default-nodes-example.info, Node: foo, Next: bar, Up: Top + +foo +=== + +this is the foo node. + +File: default-nodes-example.info, Node: bar, Prev: foo, Up: Top + +Bar +=== + +This is the Bar node. + +@end example +@bye diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/postmakeinfo.prl b/web/glasgow/lit2x-0.16/literate/info-utils/postmakeinfo.prl new file mode 100644 index 0000000000..81eaad12b0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/postmakeinfo.prl @@ -0,0 +1,81 @@ +# +die "must have exactly one argument\n" if $#ARGV != 0; +die "input file $ARGV[0] doesn't exist\n" if ! -f $ARGV[0]; +$Inputfile = $ARGV[0]; +$Bakfile = $ARGV[0].'.bak'; + +rename($Inputfile, $Bakfile) || + die "Can't rename $Inputfile to $Bakfile\n"; + +sub put_file_back { + print STDERR "doing mv $Bakfile $Inputfile...\n"; + rename($Bakfile, $Inputfile) || + die "Can't rename $Bakfile to $Inputfile\n"; + exit(1); +} +$SIG{'INT'} = 'put_file_back'; +$SIG{'QUIT'} = 'put_file_back'; + +open(OUTF,">$Inputfile") || die "Can't re-open $Inputfile for output\n"; +select(OUTF); + +$ARGV[0] = $Bakfile; # fiddle with, before first <> read + +# NB: eof() == 1 in perl means NEXT read will return end-of-file (urgh) + +$_ = <>; + +while ( $_ ) { # I don't dig this test ... + + # loop-'n-echo 'til we find a menu + while ( $_ && ! /^\* Menu:/) { + print $_; + $_ = <>; + } + next if ! /^\* Menu:/; + + # we found a menu, so munge it... + print $_; # the *Menu:... + + # snarf the entries (everything 'til node ends), rm'ing exact duplicates + # and uniquifying diff ones with the same + # entry part + # (they are sorted, right ?) + + $prev_entry = ''; + $prev_nodename = ''; + $uniquer = 2; + $_ = <>; + + while ( $_ && ! /^\037/) { + + if (/^\*(\s*)([^:]*)(:\s*)(.*)$/) { + $indent = $1; + $divider = $3; + $nodename = $4; + # fix the @_sep_@ stuff... + ($entry = $2) =~ s/(.+)\@_sep_\@//; + + next if $entry eq $prev_entry && $nodename eq $prev_nodename; + + if ($entry eq $prev_entry) { + print "\*${indent}${entry}_${uniquer}${divider}${nodename}\n"; + $uniquer++; + } else { + print "\*${indent}${entry}${divider}${nodename}\n"; + $uniquer = 2; # reset + } + + } else { # comment line + print $_; + } + } continue { + $_ = <>; # next... + $prev_entry = $entry; + $prev_nodename = $nodename; + } +} +close(OUTF); + +# once we're brave: +#unlink $Bakfile; diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/test-suite.texinfo b/web/glasgow/lit2x-0.16/literate/info-utils/test-suite.texinfo new file mode 100644 index 0000000000..cf0ea3256c --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/test-suite.texinfo @@ -0,0 +1,167 @@ +Info file: TEST-elisp-file, -*-Text-*- +produced by texinfo-format-buffer +from file: test.texinfo + +Examples of @def's +****************** + +* Command: revert-buffer &optional NO-AUTOSAVE-OFFER-P NOCONFIRM + + This command replaces the buffer text with the text of the + visited file on disk. This action undoes all changes since the + file was visited or saved. If the latest auto-save file is more + recent than the visited file, Emacs asks the user whether to use + that instead. + + When the value of the `no-autosave-offer-p' argument is + non-`nil', Emacs does not offer to use the auto-save file. This + argument is the prefix argument when the function is called + interactively. + + When the value of the `noconfirm' argument is non-`nil', emacs + does not ask for confirmation for the reversion action. This means + that the buffer is deleted and replaced by the text from the file + on the disk without asking the user if he or she really want that. + + If the value of the `revert-buffer-function' variable is + non-`nil', it is called as a function to do the work. + +* Function: cons OBJECT1 OBJECT2 + + This function is the primary function used to build new lists. + It creates a new cons cell, making OBJECT1 the `car', and OBJECT2 + the `cdr'. It then returns a pointer to the new cons cell. There + is no requirement for OBJECT2 to be of any particular type, + although it is normally a list. + + (cons 1 '(2)) + => (1 2) + (cons 1 '()) + => (1) + (cons 1 2) + => (1 . 2) + +* Function: list &rest OBJECTS + + This function creates a list with OBJECTS as its elements. The + resulting list is always `nil'-terminated. If no OBJECTS are + given, the empty list is returned. + + (list 1 2 3 4 5) + => (1 2 3 4 5) + (list) + => nil + + +* Special form: progn FORMS... + + This special form evaluates all of the FORMS, in textual order, + returning the result of the final form. + + (progn (print "The first form") + (print "The second form") + (print "The third form")) + -| "The first form" + -| "The second form" + -| "The third form" + => "The third form" + +* Variable: obarray + + This global variable is the standard obarray for use by `intern' + and `read'. It is a vector whose length ought to be prime for best + results (presently 511). Each element is an interned symbol whose + name hashes to that bucket. That symbol (if any) has an internal + link (invisible to the user) to the next symbol that hashes to that + bucket. The order of these is unimportant. + + +================================================================ + + +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename TEST-elisp-file +@settitle GNU Emacs Lisp TEST File +@c %**end of header + +@unnumbered Examples of @@def's + +@deffn Command revert-buffer &optional no-autosave-offer-p noconfirm + This command replaces the buffer text with the text of the visited +file on disk. This action undoes all changes since the file was +visited or saved. If the latest auto-save file is more recent than the +visited file, Emacs asks the user whether to use that instead. + + When the value of the @code{no-autosave-offer-p} argument is +non-@code{nil}, Emacs does not offer to use the auto-save file. This +argument is the prefix argument when the function is called +interactively. + + When the value of the @code{noconfirm} argument is non-@code{nil}, +emacs does not ask for confirmation for the reversion action. This +means that the buffer is deleted and replaced by the text from the +file on the disk without asking the user if he or she really want that. + + If the value of the @code{revert-buffer-function} variable is +non-@code{nil}, it is called as a function to do the work. +@end deffn + +@defun cons object1 object2 + This function is the primary function used to build new lists. It creates +a new cons cell, making @var{object1} the @code{car}, and @var{object2} the +@code{cdr}. It then returns a pointer to the new cons cell. There is no +requirement for @var{object2} to be of any particular type, although it is +normally a list. + +@example +(cons 1 '(2)) + @result{} (1 2) +(cons 1 '()) + @result{} (1) +(cons 1 2) + @result{} (1 . 2) +@end example +@end defun + +@defun list &rest objects + This function creates a list with @var{objects} as its elements. The +resulting list is always @code{nil}-terminated. If no @var{objects} +are given, the empty list is returned. + +@example +(list 1 2 3 4 5) + @result{} (1 2 3 4 5) +(list) + @result{} nil +@end example +@end defun + + +@defspec progn forms@dots{} +This special form evaluates all of the @var{forms}, in textual +order, returning the result of the final form. + +@example +(progn (print "The first form") + (print "The second form") + (print "The third form")) + @print{} "The first form" + @print{} "The second form" + @print{} "The third form" + @result{} "The third form" +@end example +@end defspec + +@defvar obarray + This global variable is the standard obarray for use by @code{intern} and +@code{read}. It is a vector whose length ought to be prime for best +results (presently 511). Each element is an interned symbol whose name +hashes to that bucket. That symbol (if any) has an internal link (invisible +to the user) to the next symbol that hashes to that bucket. The order of +these is unimportant. +@end defvar + + +@bye + diff --git a/web/glasgow/lit2x-0.16/literate/info-utils/testfile.texinfo b/web/glasgow/lit2x-0.16/literate/info-utils/testfile.texinfo new file mode 100644 index 0000000000..a7d924448f --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/info-utils/testfile.texinfo @@ -0,0 +1,130 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename format-test-file +@settitle Formatting Test File +@c %**end of header + + +@unnumberedsec Formatting Command Test File + +This file tests the following commands: + +@example +result +expansion +prints +equiv + +deffn +defun +defspec +defvar +@end example + +@c result +@c +The following example tests @code{@@result@{@}} + +@example +(car '(bow midships stern)) ; @r{This is a comment using @@r@{} +@result{} bow ; @r{This is an aligned comment using @@r@{} +@end example + +@c expansion +@c +The following example tests @code{@@expansion@{@}} and @code{@@result@{@}} + +@example +(third '(a b c)) ; @r{This is a comment using @@r@{} +@expansion{} (car (cdr (cdr '(a b c)))) ; @r{This is an aligned comment.} +@result{} c ; @r{This is an aligned comment.} +@end example + +@c print +@c +The following example tests @code{@@prints@{@}} + +@example +(message "Hello.") ; @r{This is a comment using @@r@{} +@print{} Hello. ; @r{This is an aligned comment using @@r@{} +@end example + +@c equiv +@c +The following example tests @code{@@equiv@{@}} + +@example +(make-sparse-keymap) @equiv{} (list 'keymap) +@end example + +@c error +@c +The following example tests @code{@@error@{@}} + +@example +(car) +@error{} Wrong number of arguments: #<subr car>, 0 +@end example + +@c indentedresult +@c +The following example tests @code{@@result@{@}} + +This command is an experiment designed to make it easy to change +indentation until we get it right. + +@example +(car '(bow midships stern)) + @result{} bow +@end example + +@c indentedexpansion, indendedresult +@c +The following example tests +@code{@@expansion@{@}} and @code{@@result@{@}} + +@example +(third '(a b c)) + @expansion{} (car (cdr (cdr '(a b c)))) + @result{} c +@end example + + +@subheading @@def commands + +@deffn Command make-variable-buffer-local symbol +This function marks @var{symbol} automatically buffer local, so that +any attempt to set it will make it local to the current buffer at the +time. + + I put this here twice on purpose: this function marks @var{symbol} +automatically buffer local, so that any attempt to set it will make it +local to the current buffer at the time. + +The value returned is @var{symbol}. +@end deffn + +@defun default-value symbol +Return @var{symbol}'s default value. This is the value that is seen +in buffers that do not have their own values for this variable. If +@var{symbol} is not buffer-local, than this is the same as +@code{symbol-value} (@pxref{Accessing Variables}). +@end defun + +@defspec setq-default symbol value +This function sets the default (global) value of @var{symbol} to +@var{value}. @var{symbol} is not evaluated, but @var{value} is. The +value of the @code{setq-default} form is @var{value}. + +@dots{} +@end defspec + +@defvar minibuffer-completion-table + The value of this variable is the alist or obarray used for +completion in the minibuffer. This is the global variable that +contains what @code{completing-read} passes to @code{read-minibuffer}. +It is used by all the minibuffer completion functions, such as +@code{minibuffer-complete-word}. +@end defvar + +@bye diff --git a/web/glasgow/lit2x-0.16/literate/leathrum_on_pgm_typesetting.tex b/web/glasgow/lit2x-0.16/literate/leathrum_on_pgm_typesetting.tex new file mode 100644 index 0000000000..fc99506efe --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/leathrum_on_pgm_typesetting.tex @@ -0,0 +1,59 @@ +% From: leathrum@dartmouth.edu (Thomas E. Leathrum) +% Newsgroups: comp.text.tex +% Subject: Re: WEB +% Date: 26 Feb 90 00:44:03 GMT +% Organization: Dartmouth College, Hanover, NH +% +% I haven't been paying a whole lot of attention to the messages about +% typesetting computer programs, but one I read had an interesting idea: reverse +% the typefaces, leaving reserved words in plain face and putting variable and +% procedure names in boldface instead. (The argument went something like this: +% reserved words are a computer language's fancy idea of punctuation, and besides +% not really as important as the variables and such, so why not turn things +% around?) Well, I tried this idea out by typesetting a little procedure from +% Jensen and Wirth's Pascal User Manual and Report, and I'm convinced -- it +% really looks better! So, for your perusal, I enclose below a little plainTeX +% file with a Pascal procedure to find and print the largest and smallest entries +% in an array of n integers. +% +% Regards, +% Tom Leathrum +% moth@dartmouth.edu +% +% --------------------------------------- +% +% >From Program 11.1 p.68 in 2nd edition +% +\+ procedure {\bf minmax};\cr +\+ var {\bf i}: 1..{\bf n};\cr +\+ \quad {\bf u}, {\bf v}, {\bf min}, {\bf max}: integer;\cr +\+ begin\cr +\+ \quad {\bf min}$:=${\bf a}[1];\cr +\+ \quad {\bf max}$:=${\bf min};\cr +\+ \quad while {\bf i}$<${\bf n} do\cr +\+ \quad begin\cr +\+ \quad \quad {\bf u}$:=${\bf a}[{\bf i}];\cr +\+ \quad \quad {\bf v}$:=${\bf a}[{\bf i}$+1$];\cr +\+ \quad \quad if {\bf u}$>${\bf v} then\cr +\+ \quad\quad begin\cr +\+ \quad \quad\quad if {\bf u}$>${\bf max} then {\bf max}$:=${\bf u};\cr +\+ \quad \quad\quad if {\bf v}$<${\bf min} then {\bf min}$:=${\bf u};\cr +\+ \quad\quad end;\cr +\+ \quad \quad else\cr +\+ \quad\quad begin\cr +\+ \quad \quad\quad if {\bf v}$>${\bf max} then {\bf max}$:=${\bf v};\cr +\+ \quad \quad\quad if {\bf u}$<${\bf min} then {\bf min}$:=${\bf u};\cr +\+ \quad\quad end;\cr +\+ \quad \quad {\bf i}$:=${\bf i}$+2$;\cr +\+ \quad end;\cr +\+ \quad if {\bf i}$=${\bf n} then\cr +\+ \quad \quad if {\bf a}[{\bf n}]$>${\bf max} then + {\bf max}$:=${\bf a}[{\bf n}];\cr +\+ \quad else\cr +\+ \quad \quad if {\bf a}[{\bf n}]$<${\bf min} then + {\bf min}$:=${\bf a}[{\bf n}];\cr +\+ \quad {\bf writeln}({\bf min}, {\bf max});\cr +\+ \quad {\bf writeln};\cr +\+ end;\cr + +\end diff --git a/web/glasgow/lit2x-0.16/literate/lit-2changes.lprl b/web/glasgow/lit2x-0.16/literate/lit-2changes.lprl new file mode 100644 index 0000000000..e2ba6ae7ab --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2changes.lprl @@ -0,0 +1,6 @@ +\section[lit2changelog_only]{Code used only in extracting changelogs} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2depend.lprl b/web/glasgow/lit2x-0.16/literate/lit-2depend.lprl new file mode 100644 index 0000000000..b6711cdb10 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2depend.lprl @@ -0,0 +1,56 @@ +\section[lit2depend_code]{Code used only in generating dependencies} + +\begin{code} +sub collect_dependencies { + local($file_seen) = @_; + + # assuming we're checking dependencies for Input_file "foo.lit" + # and we've just seen file "bar.lprl" (for example), we want a + # dependencies of the form: + # foo.texi: bar.itxi + # foo.tex : bar.itex + + local($file_seen_root,$file_seen_suff) = &root_and_suffix($file_seen); + + if ($Inputfile_root ne $file_seen_root) { + push(@Depend_lines, "$Inputfile_root.texi : $file_seen_root.itxi\n"); + push(@Depend_lines, "$Inputfile_root.tex : $file_seen_root.itex\n"); + } +} + +sub mangle_Makefile { # insert dependencies into Makefile + # this really should be made to work just like other mkdepend scripts + local($Makefile) = 'Makefile'; + local($begin_magic_str) = "# DO NOT DELETE: Beginning of literate-docs dependencies\n"; + local($end_magic_str) = "# DO NOT DELETE: End of literate-docs dependencies\n"; + + unlink("$Makefile.bak"); + rename($Makefile,"$Makefile.bak"); + # now copy Makefile.bak into Makefile, rm'ing old dependencies + # and adding the new + open(OMKF,"< $Makefile.bak") || die "$Pgm: can't open $Makefile.bak: $!\n"; + open(NMKF,"> $Makefile") || die "$Pgm: can't open $Makefile: $!\n"; + select(NMKF); + $_ = <OMKF>; + while ($_ && $_ ne $begin_magic_str) { # copy through, 'til begin_magic_str + print $_; + $_ = <OMKF>; + } + while ($_ && $_ ne $end_magic_str) { # delete 'til end_magic_str + $_ = <OMKF>; + } + # insert dependencies + print $begin_magic_str; + print @Depend_lines; + print $end_magic_str; + while (<OMKF>) { # copy the rest through + print $_; + } + close(NMKF); + close(OMKF); + chmod 0444, 'Makefile'; +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-c.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-c.lprl new file mode 100644 index 0000000000..c1bc9f6c6b --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-c.lprl @@ -0,0 +1,122 @@ +\section[lit2doc_for_c]{Document-processing code for language \tr{c}} + +\begin{code} +sub rm_embedded_stuff { # return clean code + index entries (\002 separated) + local($codetxt) = @_; + + ($codetxt, ''); +} + +sub add_code_interests { # DO NOTHING + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + local($defs_to_return) = ''; + local($uses_to_return) = ''; + + &setup_C_keywords(); + + $* = 1; # multi-line searches + s/^>//g; # de-Bird-ize + s/\/\*[^\/]*\*\///g;# de-commentize (necessarily fraught with peril) + s/\"[^\"\n]*\"//g; # de-string-ize and de-char-ize + s/\'[^\'\n]*\'//g; + + # OK, the "interesting" DEFS are #define'd things + # and things that might be subroutine defns. (3 chars long or more) + # The latter must begin in col 1! + + while (/^(\s*#define\s+)([A-Za-z_][A-Za-z0-9_]{2,})(\s*)/ || + /^([A-Z][a-z]+\s+)?([A-Za-z_][A-Za-z0-9_]{2,})(\([A-Za-z0-9_, ]*\))/) { + local($before) = $1; + local($interesting_thing) = $2; # see hacks below + local($after) = $3; + +#print STDERR "defs=>$before::$interesting_thing::$after::\n"; + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_defd[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_defd[$s] .= "$really_interesting_thing\001"; + } else { + $defs_to_return .= "$really_interesting_thing\001"; + } + } + # escaping all magic chars in before/interesting/after + # is v important for avoiding infinite loops! (also below) + $before =~ s/\s+/\\s\+/g; + $after =~ s/\s+/\\s\+/g; + $after =~ s/\(/\\\(/; + $after =~ s/\)/\\\)/; + + s/$before$interesting_thing$after//g; + } + + # I AM NOT INTERESTED IN USES AT THE MOMENT + if ( 0 ) { + # uses are the same sorts of things + while (/^(#if\s+|#elif\s+|#else\s+)([A-Za-z_][A-Za-z0-9_]{2,})(\s*)/ || # CPP-ery + /(\s*)([A-Za-z_][A-Za-z0-9_]{2,})(\s*)/) { + local($before) = $1; + local($interesting_thing) = $2; # more hacks below + local($after) = $3; + + #print STDERR "uses=>$before::$interesting_thing::$after::\n"; + + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_used[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_used[$s] .= "$really_interesting_thing\001"; + } else { + $uses_to_return .= "$really_interesting_thing\001"; + } + } + $before =~ s/\s+/\\s\+/g; + $interesting_thing =~ s/\$/\\\$/; + $interesting_thing =~ s/\@/\\\@/; + $interesting_thing =~ s/\%/\\\%/; + $after =~ s/\s+/\\s\+/g; + + s/$before$interesting_thing$after//g; + } + } + $* = 0; + + ($defs_to_return, $uses_to_return); +} + +sub setup_C_keywords { + $IGNORE_WD{'auto'} = 1; + $IGNORE_WD{'break'} = 1; + $IGNORE_WD{'case'} = 1; + $IGNORE_WD{'char'} = 1; + $IGNORE_WD{'continue'} = 1; + $IGNORE_WD{'default'} = 1; + $IGNORE_WD{'do'} = 1; + $IGNORE_WD{'double'} = 1; + $IGNORE_WD{'else'} = 1; + $IGNORE_WD{'entry'} = 1; + $IGNORE_WD{'extern'} = 1; + $IGNORE_WD{'float'} = 1; + $IGNORE_WD{'for'} = 1; + $IGNORE_WD{'goto'} = 1; + $IGNORE_WD{'if'} = 1; + $IGNORE_WD{'int'} = 1; + $IGNORE_WD{'long'} = 1; + $IGNORE_WD{'register'} = 1; + $IGNORE_WD{'return'} = 1; + $IGNORE_WD{'short'} = 1; + $IGNORE_WD{'sizeof'} = 1; + $IGNORE_WD{'static'} = 1; + $IGNORE_WD{'struct'} = 1; + $IGNORE_WD{'switch'} = 1; + $IGNORE_WD{'typedef'} = 1; + $IGNORE_WD{'union'} = 1; + $IGNORE_WD{'unsigned'} = 1; + $IGNORE_WD{'while'} = 1; +# $IGNORE_WD{''} = 1; +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-f.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-f.lprl new file mode 100644 index 0000000000..e49a32ab31 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-f.lprl @@ -0,0 +1,154 @@ +\section[lit2doc_for_f]{Document-processing code for language \tr{Fortran}} + +\begin{code} + +sub rm_embedded_stuff { # return clean code + index entries (\002 separated) + local($codetxt) = @_; + + ($codetxt, ''); +} + +\end{code} + +\begin{code} +sub add_code_interests { # DO NOTHING + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + local($defs_to_return) = ''; + local($uses_to_return) = ''; + + &setup_fortran_keywords(); + + $* = 1; # multi-line searches + s/^>//g; # de-Bird-ize + s/^C.*$//g; # de-commentize +# s/([^\\\n])!.*$/\1/g; Is this valid ????? ! comment + s/\"[^\"\n]*\"//g; # de-stringize + s/\'[^\'\n]*\'//g; + + # OK, the "interesting" DEFS are subroutines, functions and common blocks + # i.e + # SUBROUTINE <thing> <rubbish> + # <rubbish> FUNCTION <thing> <rubbish> + # COMMON /<thing>/ <rubbish> + # /^(\s*\S+\s+FUNCTION\s+)([A-Za-z0-9_]+)(\s*\()/ || + + while (/^(\s*SUBROUTINE\s+)([A-Za-z0-9_]+)(\s*\()/ || + /^(\s*[A-Za-z0-9\*]+\s+FUNCTION\s+)([A-Za-z0-9_]+)(\s*\()/ || + /^(\s*COMMON\s*)([A-Za-z0-9_]+)(\s*\/)/ ) { + + local($before) = $1; + local($interesting_thing) = $2; # see hacks below + local($after) = $3; + +# print STDERR "defs=>$before::$interesting_thing::$after::\n"; + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_defd[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_defd[$s] .= "$really_interesting_thing\001"; + } else { + $defs_to_return .= "$really_interesting_thing\001"; + } + } + $before =~ s/\s+/\\s\+/g; + $before =~ s/\*/\\*/g; + $after =~ s/\s+/\\s\+/g; + $after =~ s/\(/\\\(/; + $after =~ s/\)/\\\)/; + + s/$before$interesting_thing$after//g; +# print STDERR "repl=>$before::$interesting_thing::$after::\n"; + } + # uses are the same sorts of things + # CALL <thing> + # EXTERNAL <thing> + while (/^(\s*CALL\s*)([A-Za-z0-9_]+)(\s*)/ || + /^(\s*EXTERNAL\s*)([A-Za-z0-9_]+)(\s*)/) { + local($before) = $1; + local($interesting_thing) = $2; # more hacks below + local($after) = $3; + +# print STDERR "uses=>$before::$interesting_thing::$after::\n"; + + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_used[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_used[$s] .= "$really_interesting_thing\001"; + } else { + $uses_to_return .= "$really_interesting_thing\001"; + } + } + $before =~ s/\s+/\\s\+/g; + $after =~ s/\s+/\\s\+/g; + $after =~ s/\(/\\\(/; + $after =~ s/\)/\\\)/; + + s/$before$interesting_thing$after//g; + } + $* = 0; + + ($defs_to_return, $uses_to_return); +} + +sub setup_fortran_keywords { + $IGNORE_WD{'REAL*8'} = 1; + $IGNORE_WD{'REAL'} = 1; + $IGNORE_WD{'CHARACTER'} = 1; + $IGNORE_WD{'LOGICAL'} = 1; + $IGNORE_WD{'COMPLEX'} = 1; + $IGNORE_WD{'DOUBLE'} = 1; + $IGNORE_WD{'INTEGER'} = 1; + $IGNORE_WD{'FLOAT'} = 1; + $IGNORE_WD{'PROGRAM'} = 1; + $IGNORE_WD{'COMMON'} = 1; + $IGNORE_WD{'SUBROUTINE'} = 1; + $IGNORE_WD{'FUNCTION'} = 1; + $IGNORE_WD{'CONTINUE'} = 1; + $IGNORE_WD{'WHILE'} = 1; + $IGNORE_WD{'IF'} = 1; + $IGNORE_WD{'ENDIF'} = 1; + $IGNORE_WD{'THEN'} = 1; + $IGNORE_WD{'ELSE'} = 1; + $IGNORE_WD{'DO'} = 1; + $IGNORE_WD{'END'} = 1; + $IGNORE_WD{'DATA'} = 1; + $IGNORE_WD{'PARAMETER'} = 1; + $IGNORE_WD{'EXTERNAL'} = 1; + $IGNORE_WD{'RETURN'} = 1; + $IGNORE_WD{'FORMAT'} = 1; + $IGNORE_WD{'STOP'} = 1; + $IGNORE_WD{'CALL'} = 1; + $IGNORE_WD{'READ'} = 1; + $IGNORE_WD{'WRITE'} = 1; + $IGNORE_WD{'PRINT'} = 1; + $IGNORE_WD{'IOSTAT'} = 1; + $IGNORE_WD{'FILE'} = 1; + $IGNORE_WD{'STATUS'} = 1; + $IGNORE_WD{'ABS'} = 1; + $IGNORE_WD{'COS'} = 1; + $IGNORE_WD{'SQRT'} = 1; + $IGNORE_WD{'SQR'} = 1; + $IGNORE_WD{'SIN'} = 1; + $IGNORE_WD{'CMPLX'} = 1; + $IGNORE_WD{'CONJG'} = 1; + $IGNORE_WD{'IMAG'} = 1; + $IGNORE_WD{'DBLE'} = 1; + $IGNORE_WD{'INT'} = 1; + $IGNORE_WD{'EXP'} = 1; + $IGNORE_WD{'LOG'} = 1; + $IGNORE_WD{'LT'} = 1; + $IGNORE_WD{'LE'} = 1; + $IGNORE_WD{'EQ'} = 1; + $IGNORE_WD{'NE'} = 1; + $IGNORE_WD{'GE'} = 1; + $IGNORE_WD{'GT'} = 1; + $IGNORE_WD{'NOT'} = 1; + $IGNORE_WD{'AND'} = 1; + $IGNORE_WD{'OR'} = 1; +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-hs.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-hs.lprl new file mode 100644 index 0000000000..bef1d9a4ab --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-hs.lprl @@ -0,0 +1,304 @@ +\section[lit2doc_for_hs]{Document-processing code for language \tr{hs}} + +\begin{code} +sub rm_embedded_stuff { # return clean code + index entries (\002 separated) + local($_) = @_; + local($entries) = ''; + + $* = 1; + while (/^\s*--idx::(.*)$/) { + $entries .= "$1\002"; + s/^\s*--idx::(.*)$//; + } + + s/^\s*--\s*hide::.*$//g; # hidden comments + + $* = 0; + + chop($entries) if $entries ne ''; + + ($_, $entries); +} + +sub add_code_interests { + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + local($defs_to_return) = ''; + + &setup_haskell_keywords(); + + $* = 1; # multi-line searches + s/^>//g; # de-Bird-ize + s/--.*$//g; # de-commentize (simple ones only) + s/^\s*#.*\n//g; # de-CPPize + s/\"[^\"\n]*\"//g; # de-stringize + s/\'[^\'\n]+\'//g; # de-characterize + + # OK, the "interesting" DEFS are easy: + # functions with type sigs + # module definitions + # data <thing> = + # data ... = <thing> (NB: hack required) + # | <constructor> + # type <thing> + # + # CAN YOU SAY "HEURISTIC"??? + + while (/^(\s*)([A-Za-z0-9_']+)(\s*::)/ || + /^(\s*module\s+)([A-Za-z0-9_']+)(\s*)/ || + /^\s*data(\s*)([A-Z][A-Za-z0-9_']+)(\s*)=/ || + /^(\s*data\s*=\s*)([A-Z][A-Za-z0-9_']+)(\s*)/ || + /^(\s*type\s*)([A-Z][A-Za-z0-9_']+)(\s*=)/ || + /^(\s*\|\s*)([A-Z][A-Za-z0-9_']+)(\s*)/) { + local($before) = $1; + local($interesting_thing) = $2; + local($after) = $3; + $before =~ s/\|/\\\|/g; # oh dear + +#print STDERR "$before::$interesting_thing::$after:::$_\n"; + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_defd[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_defd[$s] .= "$really_interesting_thing\001"; + } else { + $defs_to_return .= "$really_interesting_thing\001"; + } + } + s/$before$interesting_thing$after//; + } + $* = 0; + + ($defs_to_return, &std_codething_uses_check($s, $b, $_)); +} + +sub setup_haskell_keywords { + $IGNORE_WD{'AppendChan'} = 1; + $IGNORE_WD{'Array'} = 1; + $IGNORE_WD{'Assoc'} = 1; + $IGNORE_WD{'Bin'} = 1; + $IGNORE_WD{'Binary'} = 1; + $IGNORE_WD{'Bool'} = 1; + $IGNORE_WD{'Char'} = 1; + $IGNORE_WD{'Complex'} = 1; + $IGNORE_WD{'Double'} = 1; + $IGNORE_WD{'Enum'} = 1; + $IGNORE_WD{'Eq'} = 1; + $IGNORE_WD{'False'} = 1; + $IGNORE_WD{'Float'} = 1; + $IGNORE_WD{'Fractional'} = 1; + $IGNORE_WD{'Int'} = 1; + $IGNORE_WD{'Integer'} = 1; + $IGNORE_WD{'Ix'} = 1; + $IGNORE_WD{'Num'} = 1; + $IGNORE_WD{'Ord'} = 1; + $IGNORE_WD{'Ratio'} = 1; + $IGNORE_WD{'Rational'} = 1; + $IGNORE_WD{'ReadS'} = 1; + $IGNORE_WD{'Real'} = 1; + $IGNORE_WD{'RealFloat'} = 1; + $IGNORE_WD{'RealFrac'} = 1; + $IGNORE_WD{'ShowS'} = 1; + $IGNORE_WD{'String'} = 1; + $IGNORE_WD{'Text'} = 1; + $IGNORE_WD{'Text'} = 1; + $IGNORE_WD{'True'} = 1; + $IGNORE_WD{'abs'} = 1; + $IGNORE_WD{'accum'} = 1; + $IGNORE_WD{'accumArray'} = 1; + $IGNORE_WD{'acos'} = 1; + $IGNORE_WD{'acosh'} = 1; + $IGNORE_WD{'amap'} = 1; + $IGNORE_WD{'and'} = 1; + $IGNORE_WD{'approxRational'} = 1; + $IGNORE_WD{'approximants'} = 1; + $IGNORE_WD{'array'} = 1; + $IGNORE_WD{'asTypeOf'} = 1; + $IGNORE_WD{'asin'} = 1; + $IGNORE_WD{'asinh'} = 1; + $IGNORE_WD{'assocs'} = 1; + $IGNORE_WD{'atan'} = 1; + $IGNORE_WD{'atan2'} = 1; + $IGNORE_WD{'atanh'} = 1; + $IGNORE_WD{'bounds'} = 1; + $IGNORE_WD{'break'} = 1; + $IGNORE_WD{'case'} = 1; + $IGNORE_WD{'ceiling'} = 1; + $IGNORE_WD{'chr'} = 1; + $IGNORE_WD{'cis'} = 1; + $IGNORE_WD{'class'} = 1; + $IGNORE_WD{'concat'} = 1; + $IGNORE_WD{'conjugate'} = 1; + $IGNORE_WD{'cos'} = 1; + $IGNORE_WD{'cosh'} = 1; + $IGNORE_WD{'cycle'} = 1; + $IGNORE_WD{'data'} = 1; + $IGNORE_WD{'decodeFloat'} = 1; + $IGNORE_WD{'default'} = 1; + $IGNORE_WD{'denominator'} = 1; + $IGNORE_WD{'deriving'} = 1; + $IGNORE_WD{'div'} = 1; + $IGNORE_WD{'divRem'} = 1; + $IGNORE_WD{'drop'} = 1; + $IGNORE_WD{'dropWhile'} = 1; + $IGNORE_WD{'elems'} = 1; + $IGNORE_WD{'else'} = 1; + $IGNORE_WD{'encodeFloat'} = 1; + $IGNORE_WD{'enumFrom'} = 1; + $IGNORE_WD{'enumFromThen'} = 1; + $IGNORE_WD{'enumFromThenTo'} = 1; + $IGNORE_WD{'enumFromTo'} = 1; + $IGNORE_WD{'error'} = 1; + $IGNORE_WD{'even'} = 1; + $IGNORE_WD{'exp'} = 1; + $IGNORE_WD{'exponent'} = 1; + $IGNORE_WD{'filter'} = 1; + $IGNORE_WD{'floatDigits'} = 1; + $IGNORE_WD{'floatRadix'} = 1; + $IGNORE_WD{'floatRange'} = 1; + $IGNORE_WD{'floor'} = 1; + $IGNORE_WD{'foldl'} = 1; + $IGNORE_WD{'foldl1'} = 1; + $IGNORE_WD{'foldr'} = 1; + $IGNORE_WD{'foldr1'} = 1; + $IGNORE_WD{'fromInteger'} = 1; + $IGNORE_WD{'fromIntegral'} = 1; + $IGNORE_WD{'fromRational'} = 1; + $IGNORE_WD{'fromRealFrac'} = 1; + $IGNORE_WD{'fst'} = 1; + $IGNORE_WD{'gcd'} = 1; + $IGNORE_WD{'head'} = 1; + $IGNORE_WD{'hiding'} = 1; + $IGNORE_WD{'if'} = 1; + $IGNORE_WD{'imagPart'} = 1; + $IGNORE_WD{'import'} = 1; + $IGNORE_WD{'in'} = 1; + $IGNORE_WD{'inRange'} = 1; + $IGNORE_WD{'index'} = 1; + $IGNORE_WD{'indices'} = 1; + $IGNORE_WD{'infix'} = 1; + $IGNORE_WD{'infixl'} = 1; + $IGNORE_WD{'infixr'} = 1; + $IGNORE_WD{'init'} = 1; + $IGNORE_WD{'instance'} = 1; + $IGNORE_WD{'interface'} = 1; + $IGNORE_WD{'isAlpha'} = 1; + $IGNORE_WD{'isAlphanum'} = 1; + $IGNORE_WD{'isAscii'} = 1; + $IGNORE_WD{'isControl'} = 1; + $IGNORE_WD{'isDigit'} = 1; + $IGNORE_WD{'isLower'} = 1; + $IGNORE_WD{'isNullBin'} = 1; + $IGNORE_WD{'isPrint'} = 1; + $IGNORE_WD{'isSpace'} = 1; + $IGNORE_WD{'isUpper'} = 1; + $IGNORE_WD{'iterate'} = 1; + $IGNORE_WD{'ixmap'} = 1; + $IGNORE_WD{'last'} = 1; + $IGNORE_WD{'lcm'} = 1; + $IGNORE_WD{'length'} = 1; + $IGNORE_WD{'lex'} = 1; + $IGNORE_WD{'lines'} = 1; + $IGNORE_WD{'listArray'} = 1; + $IGNORE_WD{'log'} = 1; + $IGNORE_WD{'logBase'} = 1; + $IGNORE_WD{'magnitude'} = 1; + $IGNORE_WD{'main'} = 1; + $IGNORE_WD{'map'} = 1; + $IGNORE_WD{'max'} = 1; + $IGNORE_WD{'maximum'} = 1; + $IGNORE_WD{'min'} = 1; + $IGNORE_WD{'minimum'} = 1; + $IGNORE_WD{'mkPolar'} = 1; + $IGNORE_WD{'mod'} = 1; + $IGNORE_WD{'module'} = 1; + $IGNORE_WD{'negate'} = 1; + $IGNORE_WD{'not'} = 1; + $IGNORE_WD{'nub'} = 1; + $IGNORE_WD{'null'} = 1; + $IGNORE_WD{'nullBin'} = 1; + $IGNORE_WD{'numerator'} = 1; + $IGNORE_WD{'odd'} = 1; + $IGNORE_WD{'of'} = 1; + $IGNORE_WD{'or'} = 1; + $IGNORE_WD{'ord'} = 1; + $IGNORE_WD{'otherwise'} = 1; + $IGNORE_WD{'partialQuotients'} = 1; + $IGNORE_WD{'partition'} = 1; + $IGNORE_WD{'phase'} = 1; + $IGNORE_WD{'pi'} = 1; + $IGNORE_WD{'polar'} = 1; + $IGNORE_WD{'product'} = 1; + $IGNORE_WD{'properFraction'} = 1; + $IGNORE_WD{'range'} = 1; + $IGNORE_WD{'read'} = 1; + $IGNORE_WD{'readBin'} = 1; + $IGNORE_WD{'readList'} = 1; + $IGNORE_WD{'readList'} = 1; + $IGNORE_WD{'readParen'} = 1; + $IGNORE_WD{'reads'} = 1; + $IGNORE_WD{'readsPrec'} = 1; + $IGNORE_WD{'readsPrec'} = 1; + $IGNORE_WD{'realPart'} = 1; + $IGNORE_WD{'rem'} = 1; + $IGNORE_WD{'remove'} = 1; + $IGNORE_WD{'renaming'} = 1; + $IGNORE_WD{'repeat'} = 1; + $IGNORE_WD{'reverse'} = 1; + $IGNORE_WD{'round'} = 1; + $IGNORE_WD{'scaleFloat'} = 1; + $IGNORE_WD{'scan'} = 1; + $IGNORE_WD{'show'} = 1; + $IGNORE_WD{'showBin'} = 1; + $IGNORE_WD{'showChar'} = 1; + $IGNORE_WD{'showList'} = 1; + $IGNORE_WD{'showList'} = 1; + $IGNORE_WD{'showParen'} = 1; + $IGNORE_WD{'showString'} = 1; + $IGNORE_WD{'shows'} = 1; + $IGNORE_WD{'showsPrec'} = 1; + $IGNORE_WD{'showsPrec'} = 1; + $IGNORE_WD{'significand'} = 1; + $IGNORE_WD{'signum'} = 1; + $IGNORE_WD{'sin'} = 1; + $IGNORE_WD{'sinh'} = 1; + $IGNORE_WD{'snd'} = 1; + $IGNORE_WD{'span'} = 1; + $IGNORE_WD{'sqrt'} = 1; + $IGNORE_WD{'sum'} = 1; + $IGNORE_WD{'tail'} = 1; + $IGNORE_WD{'take'} = 1; + $IGNORE_WD{'takeWhile'} = 1; + $IGNORE_WD{'tan'} = 1; + $IGNORE_WD{'tanh'} = 1; + $IGNORE_WD{'then'} = 1; + $IGNORE_WD{'to'} = 1; + $IGNORE_WD{'toInteger'} = 1; + $IGNORE_WD{'toLower'} = 1; + $IGNORE_WD{'toRational'} = 1; + $IGNORE_WD{'toUpper'} = 1; + $IGNORE_WD{'truncate'} = 1; + $IGNORE_WD{'type'} = 1; + $IGNORE_WD{'unlines'} = 1; + $IGNORE_WD{'until'} = 1; + $IGNORE_WD{'unwords'} = 1; + $IGNORE_WD{'where'} = 1; + $IGNORE_WD{'words'} = 1; + $IGNORE_WD{'zip'} = 1; + $IGNORE_WD{'zip3'} = 1; + $IGNORE_WD{'zip4'} = 1; + $IGNORE_WD{'zip5'} = 1; + $IGNORE_WD{'zip6'} = 1; + $IGNORE_WD{'zip7'} = 1; + $IGNORE_WD{'zipWith'} = 1; + $IGNORE_WD{'zipWith3'} = 1; + $IGNORE_WD{'zipWith4'} = 1; + $IGNORE_WD{'zipWith5'} = 1; + $IGNORE_WD{'zipWith6'} = 1; + $IGNORE_WD{'zipWith7'} = 1; +# $IGNORE_WD{''} = 1; +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-jm.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-jm.lprl new file mode 100644 index 0000000000..cddd5f2ab4 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-jm.lprl @@ -0,0 +1,64 @@ +\section[lit2doc_for_jm]{Document-processing code for language \tr{jm}} + +\begin{code} +sub rm_embedded_stuff { # return clean code + index entries (\002 separated) + local($codetxt) = @_; + + ($codetxt, ''); +} + +sub add_code_interests { # DO NOTHING + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + local($defs_to_return) = ''; + local($uses_to_return) = ''; + +# & setup_MkWorld_keywords(); + + $* = 1; # multi-line searches + s/^>//g; # de-Bird-ize + s/\/\*[^\/]*\*\///g;# de-commentize (necessarily fraught with peril) + s/\"[^\"\n]*\"//g; # de-string-ize and de-char-ize + s/\'[^\'\n]*\'//g; + + # OK, the "interesting" DEFS are #define'd things & defns of "make" vars + # The latter must begin in col 1! + + while (/^(\s*#define\s+)([A-Za-z_][A-Za-z0-9_]{2,})(\s*)/ || + /^(\s*)([A-Za-z_][A-Za-z0-9_]{2,})(\s*=)/) { + local($before) = $1; + local($interesting_thing) = $2; # see hacks below + local($after) = $3; + +#print STDERR "defs=>$before::$interesting_thing::$after::\n"; + + if ($interesting_thing) { + if ($s != -1) { + $Blk_codethings_defd[$b] .= "$interesting_thing\001"; + $Sec_codethings_defd[$s] .= "$interesting_thing\001"; + } else { + $defs_to_return .= "$interesting_thing\001"; + } + } + # escaping all magic chars in before/interesting/after + # is v important for avoiding infinite loops! (also below) + $before =~ s/\s+/\\s\+/g; + $after =~ s/\s+/\\s\+/g; + + s/$before$interesting_thing$after//g; + } + + # I AM NOT INTERESTED IN USES AT THE MOMENT + + $* = 0; +# ('', &std_codething_uses_check($s, $b, $incode)); + ($defs_to_return, $uses_to_return); +} + +#sub setup_MkWorld_keywords { +# $IGNORE_WD{''} = 1; +#} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-lex.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-lex.lprl new file mode 100644 index 0000000000..7b6c8246bb --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-lex.lprl @@ -0,0 +1,27 @@ +\section[lit2doc_for_lex]{Document-processing code for language \tr{lex}} + +\begin{code} +sub rm_embedded_stuff { # return clean code + entries (\002 separated) + local($codetxt) = @_; + + ($codetxt, ''); +} + +sub add_code_interests { # DO NOTHING + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + + # nothing special on uses; here's the lex IGNORE_WD table: + & setup_lex_keywords(); + + ('', &std_codething_uses_check($s, $b, $_)); +} + +sub setup_lex_keywords { + $IGNORE_WD{'while'} = 1; +# $IGNORE_WD{''} = 1; +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-none.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-none.lprl new file mode 100644 index 0000000000..c68e9a368c --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-none.lprl @@ -0,0 +1,21 @@ +\section[lit2doc_for_none]{Document-processing code for language \tr{none}} + +\begin{code} +# "none" is a really nice language + +sub rm_embedded_stuff { # return clean code + entries (\002 separated) + local($codetxt) = @_; + + ($codetxt, ''); +} + +sub add_code_interests { + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $in_code) = @_; + + ('', ''); # DO NOTHING +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc-prl.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc-prl.lprl new file mode 100644 index 0000000000..298bdb375e --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc-prl.lprl @@ -0,0 +1,111 @@ +\section[lit2doc_for_prl]{Document-processing code for language \tr{prl}} + +\begin{code} +sub rm_embedded_stuff { # return clean code + entries (\002 separated) + local($_) = @_; + local($entries) = ''; + + $* = 1; + while (/^\s*#idx::(.*)$/) { + $entries .= "$1\002"; + s/^\s*#idx::(.*)$//; + } + + s/^\s*#hide::.*$//g; # hidden comments + + $* = 0; + + chop($entries) if $entries ne ''; + + ($_, $entries); +} + +sub add_code_interests { # DO NOTHING + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + local($defs_to_return) = ''; + local($uses_to_return) = ''; + + &setup_perl_keywords(); + + $* = 1; # multi-line searches + s/^>//g; # de-Bird-ize + s/^#.*$//g; # de-commentize + s/([^\\\n])#.*$/\1/g; + s/\"[^\"\n]*\"//g; # de-stringize + s/\'[^\'\n]*\'//g; + s/s?\/.*\/.*\/g?//g;# de-regexp + + # OK, the "interesting" DEFS are subroutines and globals + # sub <thing> + # [@$%]<thing> (=|.=) + + while (/^(\s*sub\s+)([A-Za-z0-9_]+)(\s*\{)/ || + /^(\s*)([\@\$\%][A-Z][A-Za-z0-9_]+)(\s*=|\s*\.=)/) { + local($before) = $1; + local($interesting_thing) = $2; # see hacks below + local($after) = $3; + +#print STDERR "defs=>$before::$interesting_thing::$after::\n"; + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_defd[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_defd[$s] .= "$really_interesting_thing\001"; + } else { + $defs_to_return .= "$really_interesting_thing\001"; + } + } + # escaping all magic chars in before/interesting/after + # is v important for avoiding infinite loops! (also below) + $before =~ s/\s+/\\s\+/g; + $interesting_thing =~ s/\$/\\\$/; + $interesting_thing =~ s/\@/\\\@/; + $interesting_thing =~ s/\%/\\\%/; + $after =~ s/\s+/\\s\+/g; + $after =~ s/\{/\\\{/; + $after =~ s/\./\\\./; + + s/$before$interesting_thing$after//g; + } + + # uses are the same sorts of things + while (/(\&\s*)([A-Za-z0-9_]+)(\s*)/ || # subroutine calls + /(\s*)([\@\$\%][A-Z][A-Za-z0-9_]+)(\s*)/) { + local($before) = $1; + local($interesting_thing) = $2; # more hacks below + local($after) = $3; + +#print STDERR "uses=>$before::$interesting_thing::$after::\n"; + + local($really_interesting_thing) = (defined($IGNORE_WD{$interesting_thing})) ? '' : $interesting_thing; + if ($really_interesting_thing) { + if ($s != -1) { + $Blk_codethings_used[$b] .= "$really_interesting_thing\001"; + $Sec_codethings_used[$s] .= "$really_interesting_thing\001"; + } else { + $uses_to_return .= "$really_interesting_thing\001"; + } + } + $before =~ s/\s+/\\s\+/g; + $interesting_thing =~ s/\$/\\\$/; + $interesting_thing =~ s/\@/\\\@/; + $interesting_thing =~ s/\%/\\\%/; + $after =~ s/\s+/\\s\+/g; + + s/$before$interesting_thing$after//g; + } + $* = 0; + + ($defs_to_return, $uses_to_return); +} + +sub setup_perl_keywords { + $IGNORE_WD{'ARGV'} = 1; + $IGNORE_WD{'SIG'} = 1; + $IGNORE_WD{'ENV'} = 1; +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2doc.lprl b/web/glasgow/lit2x-0.16/literate/lit-2doc.lprl new file mode 100644 index 0000000000..1a57fecdc9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2doc.lprl @@ -0,0 +1,369 @@ +\section[lit2doc_code]{Code for processing documents (\tr{lit2texi} and \tr{lit2latex})} + +\subsection[Do_substitutions]{Doing \tr{\defines}s} + +Make a little \tr{perl} script from the collected substitution info +then throw each text block at it with @eval@. We love \tr{perl}! + +\begin{code} +sub do_text_substitutions { + # first, build up perl eval string + local($evalstring) = ''; + local($text,$replacement); + while (($text, $replacement) = each %Define) { + $replacement =~ s/\\/\\\\/g; # hide slashes, etc; need something more general + $replacement =~ s/\//\\\//g; + $replacement =~ s/\$/\\\$/g; # all regexp meta-chars; sigh + $replacement =~ s/\%/\\\%/g; + $replacement =~ s/\@/\\\@/g; + $replacement =~ s/\^/\\\^/g; + $replacement =~ s/\(/\\\(/g; + $replacement =~ s/\)/\\\)/g; + $replacement =~ s/\{/\\\{/g; + $replacement =~ s/\}/\\\}/g; + $replacement =~ s/\./\\\./g; + $evalstring .= "s/\\\\$text\\{\\}/$replacement/g;" + . "s/\\\\$text\\\\ /$replacement /g;" + . "s/\\\\$text\\b/$replacement/g;"; + } + + # now cycle through section titles and non-code/non-verbatim blocks + foreach ($S = 0; $S <= $#Sec_depth; $S++) { # titles... + local($_) = $Sec_title[$S]; + + eval($evalstring); + die "Subst eval failed: $@\neval_string=$eval_string\n" if $@; + $Sec_title[$S] = $_; + } + + foreach ($B = 0; $B <= $#Blk_type; $B++) { # blocks... + if ($Blk_type[$B] !~ /(code|verb)$/) { + local($_) = $Blk_txt[$B]; + + s/\%de[a-z][a-z]\%([^\n])/\1/g; + + eval($evalstring); + die "Subst eval failed: $@\neval_string=$eval_string\n" if $@; + $Blk_txt[$B] = $_; + } + } +} +\end{code} + +\subsection[Finding_codethings]{Finding interesting codethings} + +This code passes over the input looking for ``interesting'' +definitions and uses of things in the code (``interesting'' and +``things'' depending on @$Code_lang@, modified by @$Lang_xref@ cues). +It records this information in +@Sec_codethings_defd[$S]@, @Sec_codethings_used[$S]@ +@Blk_codethings_defd[$B]@, and @Blk_codethings_used[$B]@ +(long lists of names of codethings). +This info is used for indexing during processing and for +cross-referencing during linking. + +\begin{code} +sub find_interesting_codethings { + + foreach ($S = 0; $S <= $#Sec_depth; $S++) { + foreach ($B = $Sec_first_blk[$S]; $B <= $Sec_last_blk[$S]; $B++) { + if ($Blk_type[$B] eq 'code') { + + # language-specific... + &add_code_interests($S, $B, $Blk_txt[$B]); + + # for uses, rm duplicates + if ($Blk_codethings_used[$B]) { + $Blk_codethings_used[$B] = + &tidy_codething_list($Blk_codethings_used[$B]); + } + } + } + if ($Sec_codethings_used[$S]) { # tidy, as well + $Sec_codethings_used[$S] = + &tidy_codething_list($Sec_codethings_used[$S]); + } + } +} + +sub std_codething_uses_check { + + # section and blk to record in ($s == -1: don't update) + the code + local($s, $b, $_) = @_; + local($uses_to_return) = ''; + + # ANY identifier (> 2 chars) not in (presumably language-specific) + # IGNORE_WD table is recorded as being "used" + while (/([A-Za-z][A-Za-z0-9_']{2,})/) { + local($interesting_thing) = $1; + if ( ! defined($IGNORE_WD{$interesting_thing})) { + if ($s != -1) { + $Blk_codethings_used[$b] .= "$interesting_thing\001"; + $Sec_codethings_used[$s] .= "$interesting_thing\001"; + } else { + $uses_to_return .= "$interesting_thing\001"; + } + } + s/$interesting_thing//; + } + $uses_to_return; +} + +sub tidy_codething_list { + local($unsorted_list) = @_; + local(@sorted_list) = sort(split(/\001/,$unsorted_list)); + local($prev_thing) = ''; + local($s); + foreach $s (@sorted_list) { + if ($s eq $prev_thing) { + $prev_thing = $s; + $s = ''; + } else { + $prev_thing = $s; + } + } + local($outlist) = join("\001",@sorted_list); + $outlist =~ s/\001\001+/\001/g; + $outlist; +} +\end{code} + +\subsection[Generating_a_document]{Generating a Texinfo or \LaTeX{} document} + +Code for when producing a document (either Texinfo or \LaTeX{}). + +\begin{code} +sub print_intermed_document { + + foreach ($S = 0; $S <= $#Sec_depth; $S++) { + + &print_section_heading($S) if $Sec_nodename[$S]; + + foreach ($B = $Sec_first_blk[$S]; $B <= $Sec_last_blk[$S]; $B++) { + + # report where we are (lang specific) + print &mk_line_directive($Blk_srcfile_name[$B],$Blk_srcfile_lineno[$B]); + + if ($Blk_type[$B] eq 'txt') { + if ($Lit2texi) { + local($stuff,$idxstuff) = + &texinfoize_text($Blk_srcfile_name[$B], + $Blk_srcfile_lineno[$B], + $Blk_txt[$B] + ); + if ($stuff =~ /\n$/) { + print "$stuff$idxstuff"; + } else { + print "$stuff\n$idxstuff"; + } + } else { + local($stuff,$idxstuff) = + &latexize_text($Blk_srcfile_name[$B], + $Blk_srcfile_lineno[$B], + $Blk_txt[$B] + ); + print "$stuff$idxstuff"; # never a newline in between + } + + } elsif ($Blk_type[$B] =~ /^(code|pseudocode)$/) { + local($what) = $1; + if ($what eq 'code' && $Blk_magic[$B] ne 'main') { + print "CODE FOR ",(($Blk_magic[$B] =~ /,/) ? "RIBBONS" : "RIBBON"); + print ": ",$Blk_magic[$B],"\n\n" + if $Lit2texi; + print ": \\mbox\{\\tt\{\}",&verb2latex("\\tt",$Blk_magic[$B]),"\}\n\n" + if $Lit2latex; + } + + &print_code_blk($Blk_txt[$B]) if $Lit2latex; # lang specific + &std_print_code_blk($Blk_txt[$B]) if $Lit2texi; # _always_ + + &print_index_entries_for_code_blk($B) + if $Lang_xref !~ /noindex/; + + &print_latex_labels_for_code_blk_defs($B) if $Lit2latex; + +# print "\\par\n" if $Lit2latex; # doubtful long-term value + + } elsif ($Blk_type[$B] eq 'menu') { + if ($Lit2texi) { # menus only apply for Texinfo + print "\@menu\n"; + print $Blk_txt[$B]; + print "\@end menu\n"; + } + + } elsif ($Blk_type[$B] eq 'rawlatex') { + if ($Lit2latex) { + print "\001beginrawlatex\003\n"; + print $Blk_txt[$B]; + print "\001endrawlatex\003\n"; + } + + } elsif ($Blk_type[$B] eq 'tabular') { + if ($Lit2texi) { + local($text_stuff,$idx_stuff) = &texinfoize_table_body($Blk_txt[$B]); + print "\@example\n"; + print &texinfoize_tabular($text_stuff); + print "\@end example\n$idx_stuff"; + } else { + print "\\begin\{tabular\}",$Blk_magic[$B],"\n"; + local($text_stuff,$idx_stuff) = &latexize_text($Blk_srcfile_name[$B], + $Blk_srcfile_lineno[$B], + $Blk_txt[$B] + ); + print "$text_stuff\n\\end\{tabular\}\n$idx_stuff\n"; + } + } elsif ($Blk_type[$B] =~ /verb$/) { + if ($Lit2texi) { + print "\@example\n",&texinfoize_verb($Blk_txt[$B]),"\@end example\n" + if $Blk_type[$B] eq 'verb'; + print "\@format\n",&texinfoize_verb($Blk_txt[$B]),"\@end format\n" + if $Blk_type[$B] eq 'flushverb'; + } else { +#new: nothing for flushverb yet + print "\\begin\{verbtext\}"; + local($mangled_verb) = &verb2verbcode($Blk_txt[$B]); + if (($mangled_verb =~ s/\n/\n/g) >= 5) { # a terrible way to count lines + print "\\codeallowbreaks\{\}"; + } + print "\n"; + $mangled_verb =~ s/\n$//; # don't want newline before \end{verbtext} + print $mangled_verb; + print "\\end\{verbtext\}%\n"; +#old: +# print "\\BeginLitVerb\n" +# if $Blk_type[$B] eq 'verb'; +# print "\\BeginLitVerbNoIndent\n" +# if $Blk_type[$B] eq 'flushverb'; +# local($mangled_verb) = "\\mbox\{\\tt\{\}" . +# &verb2latex("\\tt",$Blk_txt[$B]) . +# "\}"; +# # chop junk off the end (nobody said life was easy) +# $mangled_verb =~ s/\\\\\n\\mbox\{\\tt\{\}\}$//; +# print $mangled_verb; +# print "\\EndLitVerb\n"; +# print "\\par\n"; + } + } elsif ($Blk_type ne '') { # let null ones through (?) + ¬_OK($Blk_srcfile_name[$B], $Blk_srcfile_lineno[$B], + "unknown or unimplemented blk type: $Blk_type[$B]\n"); + } + } + # end of section stuff would go here, e.g., where + # ref'd ribbons can be found (?) + } +} +\end{code} + +\subsection[Other_doc_only_code]{Other code for document generation} + +\begin{code} +sub print_section_heading { # dump the collected info for this section + local($s) = @_; + + # fix up section/node's owner if necessary (recorded in first blk, I hope...) + if ($Show_node_owner && ! $Sec_owner[$s]) { + local($srcfile) = $Blk_srcfile_name[$Sec_first_blk[$s]]; + if (! defined($srcfile) || ! -f $srcfile) { + ¬_OK("","","can't find source file: $srcfile\n"); + } else { + local(@srcfile_stats) = stat($srcfile); + local(@owner_stuff) = getpwuid($srcfile_stats[4]); + + $Sec_owner[$s] = $owner_stuff[0]; + } + } + + chop($Sec_aliases[$S]) if $Sec_aliases[$S]; + + local($guessname,$guessline) = ('',-1); + # try to guess where \section command is + if (($Sec_first_blk[$S] >= $Sec_last_blk[$S]) + && (! &empty_blk_p($Sec_first_blk[$S]) )) { + $guessname = $Blk_srcfile_name[$Sec_first_blk[$S]]; + $guessline = ($Blk_srcfile_lineno[$Sec_first_blk[$S]] - 1); + } + print "\001section\003",$Sec_depth[$s], + "\002",$Sec_nodename[$s], + "\002",$Sec_nodespec[$s], +# I doubt that texinfoize_text call... (idx_stuff?) + "\002",(($Lit2texi) ? &texinfoize_text('???','???',$Sec_owner[$s]) + : $Sec_owner[$s]), + "\002",&de_newlined($Sec_extra_menu_entries[$s]), + "\002",$Sec_codethings_defd[$S], + "\002",$Sec_aliases[$S], + "\002",$Sec_codethings_used[$S], + "\002",$guessname, + "#%%#",$guessline, + "#%%#"; + + local($fixed_title) = $Sec_title[$s]; + if ($Lit2latex) { + local($title,$idx_stuff) = &latexize_text("???","???",$fixed_title); + print "{$title}"; + # no label if funny chars found inside !!! + # (perhaps a warning?) + print "\\label{",$Sec_nodename[$s],"}" if $Sec_nodename[$s] !~ /[\\\{\}\$\%]/; + print "\n$idx_stuff"; + + } else { # $Lit2texi + local($title,$idxtitle) = &texinfoize_text('???','???',$fixed_title); + print " $title\n$idxtitle"; + } +} + +sub print_index_entries_for_code_blk { + # see also print_latex_labels_for_code_blk_defs + local($b) = @_; + + # print an index entry for each definition in this code blk + local($d); + foreach $d (split(/\001/, $Blk_codethings_defd[$b])) { + if ($d && $Lit2texi) { + print "\@cindex ".&mk_texi_index_entry("$d [def]")."\n"; + } elsif ($d) { + # thinking about a "\|ttunderline" in there, too... + print "\\index\{".&mk_latex_index_entry('tt',$d)."\|underline\}\%\n"; + } + } + + # print the uses that want indexing + # this cannot be done until linking time + print "\001index_uses\003",$Blk_codethings_used[$b],"\n" + if $Blk_codethings_used[$b]; + + # we want this for xrefs too -- but only those not def'd here + if ($Lit2latex && $Blk_codethings_used[$b]) { + local(@far_use) = split(/\001/,$Blk_codethings_used[$b]); + local($f); + + foreach $f (@far_use) { # a good enough check ? + if ( ($Blk_codethings_defd[$b] =~ /^$f/) + || ($Blk_codethings_defd[$b] =~ /$f$/) + || ($Blk_codethings_defd[$b] =~ /\001$f\001/)) { + $f = ''; + } + } + $f = join("\001join\003",@far_use); # join & tidy up + $f =~ s/(\001join\003){2,}/\001join\003/g; + $f =~ s/^\001join\003//; + $f =~ s/\001join\003$//; + $f =~ s/\001join\003/\001/g; + + print "\001xref_uses\003$f\n" if $f; + } +} + +sub fiddle_sectiontypes { + local($_) = @_; + + # \[Ss]ectiontype; rm shorthand first + s/\\([Ss])ectionref\{([^\}]+)\}/\\\1ectiontype\{\2\}~\\ref\{\2\}/g; + + # nothing else can be done until linking + $_; +} + +# a trailing 1 seems to be the habit for inc'd perl files +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-c.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-c.lprl new file mode 100644 index 0000000000..c50cbeed7f --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-c.lprl @@ -0,0 +1,22 @@ +\section[lit2latex_for_c]{Lit2latex-only code for language \tr{c}} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + &std_tgrind_code_blk('c', $codetxt); + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-f.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-f.lprl new file mode 100644 index 0000000000..955f9cf5c6 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-f.lprl @@ -0,0 +1,22 @@ +\section[lit2latex_for_f]{Lit2latex-only code for language \tr{Fortran}} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + &std_tgrind_code_blk('f', $codetxt); + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-hs.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-hs.lprl new file mode 100644 index 0000000000..01781123c2 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-hs.lprl @@ -0,0 +1,22 @@ +\section[lit2latex_for_hs]{Lit2latex-only code for language \tr{hs}} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + &std_tgrind_code_blk('hs', $codetxt); + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-jm.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-jm.lprl new file mode 100644 index 0000000000..ae544db187 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-jm.lprl @@ -0,0 +1,22 @@ +\section[lit2latex_for_jm]{Lit2latex-only code for language \tr{jm} (``make-world'' files)} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + &std_tgrind_code_blk('c', $codetxt); # pretend it's C + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-lex.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-lex.lprl new file mode 100644 index 0000000000..a0f17f6c33 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-lex.lprl @@ -0,0 +1,23 @@ +\section[lit2latex_for_lex]{Lit2latex-only code for language \tr{lex}} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + # 'yacc' is the nearest thing + &std_tgrind_code_blk('yacc', $codetxt); + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-none.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-none.lprl new file mode 100644 index 0000000000..582265632c --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-none.lprl @@ -0,0 +1,23 @@ +\section[lit2latex_for_none]{Lit2latex-only code for language \tr{none}} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + # 'src' is the generic tgrind thing + &std_tgrind_code_blk('src', $codetxt); + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex-prl.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex-prl.lprl new file mode 100644 index 0000000000..d1850cefd0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex-prl.lprl @@ -0,0 +1,22 @@ +\section[lit2latex_for_prl]{Lit2latex-only code for language \tr{prl}} + +\begin{code} +sub print_code_blk { # just use the std + local($codetxt) = @_; + + if ($Lang_typeset =~ /tgrind/) { + &std_tgrind_code_blk('perl', $codetxt); + } else { + &std_print_code_blk($codetxt); + } +} + +sub mk_code_frag { + local($codetxt) = @_; + + &std_mk_code_frag($codetxt); +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2latex.lprl b/web/glasgow/lit2x-0.16/literate/lit-2latex.lprl new file mode 100644 index 0000000000..9d45a1e3c8 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2latex.lprl @@ -0,0 +1,329 @@ +\section[lit2latex_only]{Code for generating \LaTeX{} files} + +\begin{code} +# I'm putting these two routines first, +# I think because perl has a bug in it +sub add_latex_literals { + local($_) = @_; + + s/\001lateXLitbackslash\003/\{\\char'134\}/g; + s/\001lateXLitlbrace\003/\{\\char'173\}/g; + s/\001lateXLitrbrace\003/\{\\char'175\}/g; + s/\001lateXLithash\003/\{\\char'43\}/g; + + $_; +} + +sub verb2latex { # takes a blob of text and produces a bunch of \mbox{$font...}'s + # if you ensure no newlines, then no \\mbox stuff will come out + # assumes \tt really; if you're doing something else, you may have to + # fiddle; see verb2rm, for example. + local($font, $_) = @_; + + study($_); + + s/\\/\001lateXLitbackslash\003/g; + s/\{/\001lateXLitlbrace\003/g; + s/\}/\001lateXLitrbrace\003/g; + + s/\n/\}\\\\\n\\mbox\{$font\{\}/g; + + s/\#/\\\#/g; + s/\&/\\\&/g; + s/ /\\ /g; + s/\!/\{\\char'41\}/g; + s/\"/\{\\char'42\}/g; + s/\$/\{\\char'44\}/g; + s/\%/\{\\char'45\}/g; + s/\*/\{\\char'52\}/g; + s/\</\{\\char'74\}/g; + s/\>/\{\\char'76\}/g; + s/\@/\{\\char'100\}/g; + s/\^/\{\\char'136\}/g; + s/\_/\{\\char'137\}/g; + s/\|/\{\\char'174\}/g; + s/\~/\{\\char'176\}/g; + + &add_latex_literals($_); +} + +sub verb2verbcode { # to go with Olin Shivers's (verb)code.sty + # need to escape: \ { } + local($_) = @_; + + s/\\/\\\\/g; + s/\{/\\\{/g; + s/\}/\\\}/g; + + $_; +} + +sub verb2rm { + local($_) = @_; + $_ = &verb2latex("\\ShouldNotBeUsed", $_); + # now undo some of it (because ain't no such chars in CMR roman font) + + s/\{\\char'74\}/\$\\langle\$/g; # < + s/\{\\char'76\}/\$\\rangle\$/g; # > + s/\{\\char'134\}/\$\\backslash\$/g; # \ + s/\{\\char'137\}/\\_/g; # _ + s/\{\\char'173\}/\\{/g; # { + s/\{\\char'174\}/\$\|\$/g; # | + s/\{\\char'175\}/\\}/g; # } + s/\{\\char'42\}/\{\\char'175\}/g; # " -- a nicer glyph + + $_; +} + +sub latexize_text { + # is given deatified text + # returns text and index entries + # + local($srcfilename,$srclineno,$_) = @_; + local($idx_real) = ''; + local($idx_maybe) = ''; + + # do \MathMode, \tr, and \codeInText first because they might be + # inside other things + + s/\\MathMode\{([^\}]*)\}/\$\1\$/g; + + while (/\\(pl|tr)\{([^\}]*)\}/) { + local($plain_or_typing) = $1; + local($guts) = &deatified2verb($2); + + $guts = "\\mbox\{" . &verb2rm($guts). "\}" + if $plain_or_typing eq 'pl'; + $guts = "\\mbox\{\\tt\{\}" . &verb2latex("\\tt",$guts). "\}" + if $plain_or_typing eq 'tr'; + + s/\\(pl|tr)\{[^\}]*\}/$guts/; + } + + + while (/\\codeInText\{([^\}]*)\}/) { + local($raw_code) = &deatified2verb($1); + local($indexing) = 1; + + $raw_code =~ s/\\@/@/g; # the one escaped thing + + if ($raw_code =~ /\001noindex\003/) { + $indexing = 0; + $raw_code =~ s/\001noindex\003//; + } + + local($munged_code) = &mk_code_frag($raw_code); + + if ($indexing) { + local($cdefs, $cuses) = &add_code_interests(-1,-1,$raw_code); + local($c); + # index all defs and uses + foreach $c (split(/\001/, $cdefs )) { + if ($c) { + # internally known indexing command + $idx_real .= "\\index\{".&mk_latex_index_entry('tt',$c)."\|underline\}\%\n"; + } + } + # uses are only indexed if the defined thing is known + # can't be done until link time + foreach $c (split(/\001/, $cuses)) { + if ($c) { + $idx_maybe .= "\001index_uses\003$c\n"; + } + } + } + s/\\codeInText\{[^\}]*\}/$munged_code$index_call/; + } + +# $_ .= $idx_real if $idx_real; +# $_ .= "\%\n$idx_maybe" if $idx_maybe; + + while (/\\index\{([^\}]+)\}/) { + local($guts) = &deatified2verb($1); + + $guts =~ s/\\@/\@/g; # de-escape them + $guts =~ s/\\!/\!/g; + $guts = &mk_latex_index_entry('rm',$guts); + + s/\\index\{([^\}]+)\}/\\index!_\{$guts\}/; #temp two + } + s/\\index!_\{/\\index\{/g; # fix temp two + + s/\\item\s*\n/\\item\{\}\n/g; + + s/(\\begin\{comment\})/\{\\small \1/g; + s/(\\end\{comment\})/\1\}/g; + + s/\\begin\{itemise\}/\\begin\{itemize\}/g; + s/\\end\{itemise\}/\\end\{itemize\}/g; + + s/\\@/\@/g; + + # the automagically supplied \makeindex... + s/(\\begin\{document\})/\\makeindex\n\1/; + + # check for unknown environments (only at beginning of lines; easier) + # mark good ones as \begin!_/\end!_ + # bad ones as \begin!!/\end!! + while (/^\\(begin|end)\{([A-Za-z]+)\}/) { + if ( $KNOWN_ENV{$2} ) { # good + s/\\(begin|end)\{([A-Za-z]+)\}/\\\1!_\{\2\}/; + } else { # bad + print STDERR "warning: unrecognised environment: $2\n"; + s/\\(begin|end)\{([A-Za-z]+)\}/\\\1!!\{\2\}/; + } + } + # unmark both good and bad ones + # (they were presumably put in for a reason) + s/\\(begin|end)!_\{([A-Za-z]+)\}/\\\1\{\2\}/g; + s/\\(begin|end)!!\{([A-Za-z]+)\}/\\\1\{\2\}/g; + + ( &deatified2verb_nl(&fiddle_sectiontypes($_)), + $idx_real . $idx_maybe + ); +} + +sub mk_latex_index_entry { # also used in linker + local($font, $raw_text) = @_; + local(@sub_entries) = split(/\001idxsubitem\003/, $raw_text); + local($sube,$sortstuff,$printstuff); + + foreach $sube (@sub_entries) { + if ($sube =~ /(.*[^\\])\001idxsort\003(.*)/) { + $sortstuff = $1; + $printstuff = $2; + } else { + $sortstuff = $sube; + $printstuff = $sube; + } + $sortstuff =~ s/"/""/g; + $sortstuff =~ s/!/"!/g; + $sortstuff =~ s/\\/"\\/g; + $sortstuff =~ s/\{/"\{/g; + $sortstuff =~ s/\}/"\}/g; + $sortstuff =~ s/\@/"\@/g; + $sortstuff =~ s/\|/"\|/g; + + if ($font eq 'tt') { + $sube = "$sortstuff\@\\protect\{\\tt\{\}" . &verb2latex("\\tt",$printstuff) . "\}"; + } elsif ($font eq 'rm') { + $sube = "$sortstuff\@\\protect\{" . &verb2rm($printstuff) . "\}"; + } else { + die "unknown font code: $font\n"; + } + } + + # stick it back together for makeindex + join('!',@sub_entries); +} + +sub print_latex_labels_for_code_blk_defs { + # see also print_index_entries_for_code_blk + local($b) = @_; + + # print a label for each definition in this code blk + local($d); + foreach $d (split(/\001/, $Blk_codethings_defd[$b])) { + # fiddling must match that in lit-linker + $d =~ s/\%/<percent>/g; # and other funny chars? + $d =~ s/\$/<dollar>/g; + $d =~ s/\\/<slash>/g; + print "\\label\{def::$d\}\%\n" if $d; + } + # see what is done with \001xref_uses\003 in linker +} + +sub mk_line_directive { + local($filename,$lineno) = @_; + + ( (! $filename) ? '' : "\%\% LINE $lineno \"$filename\"\n"); +} + +sub std_print_code_blk { # straight verbatim for those who want it + local($codetxt) = @_; + + # language specific + local($newtxt,$idx_list) = &rm_embedded_stuff($codetxt); + +#new + print "\\begin\{verbcode\}"; + print "\\hrule\{\}" if $Lang_typeset =~ /ruled/; + + local($mangled_code) = &verb2verbcode($newtxt); + if (($mangled_code =~ s/\n/\n/g) >= 5) { # a terrible way to count lines + print "\\codeallowbreaks\{\}"; + } + print "\n"; + $mangled_code =~ s/\n$//; # don't want newline before \end{verbcode} + print $mangled_code; + + print "\n\\hrule" if $Lang_typeset =~ /ruled/; + print "\\end\{verbcode\}%\n"; + +#old +# print "\\BeginLitCodeNoIndent\n"; +# print "\\hrule\n" if $Lang_typeset =~ /ruled/; +# +# local($mangled_code) = "\\mbox\{\\tt\{\}" . +# &verb2latex("\\tt",$newtxt) . +# "\}"; +# # chop junk off the end (nobody said life was easy) +# $mangled_code =~ s/\\\\\n\\mbox\{\\tt\{\}\}$//; +# print $mangled_code; +# +# print "\\hrule\n" if $Lang_typeset =~ /ruled/; +# +# print "\\EndLitCode\n"; + + if ($Lang_xref !~ /noindex/) { + local($i); + foreach $i (split(/\002/, $idx_list )) { + print "\\index\{".&mk_latex_index_entry('tt',$i)."\}\%\n" if $i; + } + } +} + +sub std_tgrind_code_blk { # push it through tgrind + local($lang, $codetxt) = @_; + + # language specific + local($newtxt,$idx_list) = &rm_embedded_stuff($codetxt); + + print "\\par\\addvspace\{0.1in\}\n"; + + print "\\hrule\n\\vskip .5\\baselineskip\n" if $Lang_typeset !~ /unruled/; + +# print "\\begin\{small\}\n\\begin\{tgrind\}\n"; + print "\\begin\{tgrind\}\n"; + local($mangled_code) = &filter_string("unexpand -a | $Tgrind_pgm -f -l $lang -", $newtxt); + + print $mangled_code; + print "\\end\{tgrind\}\n"; +# print "\\end\{tgrind\}\n\\end\{small\}\n"; + + print "\\vskip .5\\baselineskip\n\\hrule\n" if $Lang_typeset !~ /unruled/; + + print "\\addvspace\{0.1in\}\n"; + + if ($Lang_xref !~ /noindex/) { + local($i); + foreach $i (split(/\002/, $idx_list )) { + print "\\index\{".&mk_latex_index_entry('tt',$i)."\}\%\n" if $i; + } + } +} + +sub std_mk_code_frag { # straight verbatim for those who want it + local($codetxt) = @_; + + local($mangled_code) = "\\mbox\{\\tt\{\}" . + &verb2latex("\\tt",$codetxt) . + "\}"; + # chop junk off the end (nobody said life was easy) + $mangled_code =~ s/\\\\\n\\mbox\{\\tt\{\}\}$//; + $mangled_code; +} + +# a trailing 1 seems to be the habit for inc'd perl files +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-c.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-c.lprl new file mode 100644 index 0000000000..6bfb39e8c9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-c.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_c]{Lit2pgm-only code for language \tr{c}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + + "# line $lineno \"$filename\"\n"; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-f.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-f.lprl new file mode 100644 index 0000000000..c31ced58e2 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-f.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_f]{Lit2pgm-only code for language \tr{Fortran}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + + "# line $lineno \"$filename\"\n"; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-hs.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-hs.lprl new file mode 100644 index 0000000000..dedba6f47b --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-hs.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_hs]{Lit2pgm-only code for language \tr{hs}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + + "\{-# LINE $lineno \"$filename\" -\}\n"; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-jm.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-jm.lprl new file mode 100644 index 0000000000..14ccee2d95 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-jm.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_jm]{Lit2pgm-only code for language \tr{jm}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + + "# line $lineno \"$filename\"\n"; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-lex.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-lex.lprl new file mode 100644 index 0000000000..8c75337392 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-lex.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_lex]{Lit2pgm-only code for language \tr{lex}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + # toss it + ''; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-none.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-none.lprl new file mode 100644 index 0000000000..6f5e8218c7 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-none.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_none]{Lit2pgm-only code for language \tr{none}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + # toss it + ''; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm-prl.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm-prl.lprl new file mode 100644 index 0000000000..a8af7020cc --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm-prl.lprl @@ -0,0 +1,12 @@ +\section[lit2pgm_for_prl]{Lit2pgm-only code for language \tr{prl}} + +\begin{code} +sub mk_line_directive { + local($filename,$lineno) = @_; + # same as C + "# line $lineno \"$filename\"\n"; +} + +# so we get 'do'ne correctly +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2pgm.lprl b/web/glasgow/lit2x-0.16/literate/lit-2pgm.lprl new file mode 100644 index 0000000000..5ce12b7a04 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2pgm.lprl @@ -0,0 +1,53 @@ +\section[lit2pgm_only]{Code only for \tr{lit2pgm}} + +\begin{code} +sub spit_out_ribbons_code { + local(@Ribbons_to_get) = @_; + local($r); + print STDERR "spitting code for ribbons @Ribbons_to_get\n" if $Debugging; + + foreach $r (@Ribbons_to_get) { + local(@ribbon_blk_nos) = split(/,/,$Ribbon_blks{$r}); + local($b); + foreach $b (@ribbon_blk_nos) { + print &mk_line_directive($Blk_srcfile_name[$b],$Blk_srcfile_lineno[$b]); + + if ($Blk_txt[$b] !~ /\\insertribbon/) { + # safe to just go "dump"... + # de-Birdize the code block; urgh + $* = 1; # multiline matches... + $Blk_txt[$b] =~ s/^>//g; + $* = 0; # back to one-line matches... + print $Blk_txt[$b]; + + } else { # gotta look around... + local(@blk_txt_lns) = split(/\n/,$Blk_txt[$b]); + local($l, $called_ribbon); + + local($i) = 0; + foreach $l (@blk_txt_lns) { + if ($l =~ /^\s*\\insertribbon\{(.*)\}\s*$/) { # must be alone on line + $called_ribbon = $1; + if (! $Ribbon_blks{$called_ribbon}) { + ¬_OK($Blk_srcfile_name[$b],($Blk_srcfile_lineno[$b]+$i), + "no code found for ribbon: $called_ribbon\n"); + + } else { # recurse... + &spit_out_ribbons_code($called_ribbon); + } + } else { + # de-Birdize the code line... + $l =~ s/^>//; + print "$l\n"; + } + $i++; + } + } + } + } +} + +# a trailing 1 seems to be the habit for inc'd perl files +1; +\end{code} + diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-c.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-c.lprl new file mode 100644 index 0000000000..fcc41bb7c7 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-c.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_c]{Texinfo-only code for language \tr{c}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-f.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-f.lprl new file mode 100644 index 0000000000..e35eb33266 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-f.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_f]{Texinfo-only code for language \tr{Fortran}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-hs.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-hs.lprl new file mode 100644 index 0000000000..1144bd5d30 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-hs.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_hs]{Texinfo-only code for language \tr{hs}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-jm.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-jm.lprl new file mode 100644 index 0000000000..a9fa29e414 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-jm.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_jm]{Texinfo-only code for language \tr{jm}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-lex.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-lex.lprl new file mode 100644 index 0000000000..8cf9c49bcc --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-lex.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_lex]{Texinfo-only code for language \tr{lex}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-none.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-none.lprl new file mode 100644 index 0000000000..b04a327718 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-none.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_none]{Texinfo-only code for language \tr{none}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi-prl.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi-prl.lprl new file mode 100644 index 0000000000..f22e907ae9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi-prl.lprl @@ -0,0 +1,6 @@ +\section[texinfo_for_prl]{Texinfo-only code for language \tr{prl}} + +\begin{code} +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2texi.lprl b/web/glasgow/lit2x-0.16/literate/lit-2texi.lprl new file mode 100644 index 0000000000..d63c19c654 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2texi.lprl @@ -0,0 +1,434 @@ +\section[lit2texi_only]{Code for generating Texinfo files} + +\begin{code} +sub texinfoize_text { + # is given deatified text + # returns text and index entries + # + local($srcfilename,$srclineno,$_) = @_; + local($idx_real) = ''; + local($idx_maybe) = ''; + + # do \MathMode, \tr, and \codeInText first because they might be + # inside other things + + while (/\\MathMode\{([^\}]*)\}/) { # I like this easy stuff + local($guts) = $1; + + # arrows to start with... + $guts =~ s/\\leftarrow/->/g; + $guts =~ s/\\Leftarrow/=>/g; + $guts =~ s/\\rightarrow/<-/g; + $guts =~ s/\\Rightarrow/<=/g; + $guts =~ s/\\leftrightarrow/<->/g; + $guts =~ s/\\Leftrightarrow/<=>/g; + $guts =~ s/\\longleftarrow/-->/g; + $guts =~ s/\\Longleftarrow/==>/g; + $guts =~ s/\\longrightarrow/<--/g; + $guts =~ s/\\Longrightarrow/<==/g; + $guts =~ s/\\longleftrightarrow/<-->/g; + $guts =~ s/\\Longleftrightarrow/<==>/g; + + $guts =~ s/\\alpha/alpha/g; + $guts =~ s/\\beta/beta/g; + + s/\\MathMode\{([^\}]*)\}/$guts/; + } + + while (/\\(pl|tr)\{([^\}]*)\}/) { + local($plain_or_typing) = $1; + local($guts) = $2; + + $guts =~ s/\\/\001backslash\003/g; + $guts =~ s/\~/\001twiddle\003/g; + $guts =~ s/\@/\\\@/g; + $guts =~ s/\001lbrace\003/\\\001lbrace\003/g; + $guts =~ s/\001rbrace\003/\\\001rbrace\003/g; + # protect the following for now ... (see below) + $guts =~ s/\`\`/\001tex-open-double-quotes\003/g; + $guts =~ s/\'\'/\001tex-close-double-quotes\003/g; + + s/\\(pl|tr)\{[^\}]*\}/\\w\{$guts\}/ + if $plain_or_typing eq 'pl'; + s/\\(pl|tr)\{[^\}]*\}/\\w\{\\samp\{$guts\}\}/ + if $plain_or_typing eq 'tr'; + } + + while (/\\codeInText\{([^\}]*)\}/) { + local($raw_code) = $1; + local($indexing) = 1; + + $raw_code =~ s/\\\@/\@/g; # remove the one kind of escape + + if ($raw_code =~ /\001noindex\003/) { + $indexing = 0; + $raw_code =~ s/\001noindex\003//; + } + + $munged_code = $raw_code; + $munged_code =~ s/\\/\001backslash\003/g; + $munged_code =~ s/\~/\001twiddle\003/g; + $munged_code =~ s/\@/\\\@/g; # now put it back in + $munged_code =~ s/\001lbrace\003/\\\001lbrace\003/g; + $munged_code =~ s/\001rbrace\003/\\\001rbrace\003/g; + + if ($indexing) { + local($cdefs, $cuses) = &add_code_interests(-1,-1,&deatified2verb($raw_code)); + local($c); + # index all defs and uses + foreach $c (split(/\001/, $cdefs)) { + if ($c) { + $idx_real .= "\\cindex ".&mk_texi_index_entry("$c [def]")."\n"; + } + } + # uses are only indexed if the defined thing is known + # can't be done until link time + foreach $c (split(/\001/, $cuses)) { + if ($c) { + $idx_maybe .= "\001index_uses\003$c\n"; + } + } + } + # this really should use &mk_code_frag ... + + s/\\codeInText\{[^\}]*\}/\\w\{\\samp\{$munged_code\}\}/; + } + + if (/\\maketitle\n/) { + local($title_stuff) = ''; + $title_stuff .= "\\center $Doc_title\n" if $Doc_title; + $title_stuff .= "\n\\center $Doc_author\n" if $Doc_author; + $title_stuff .= "\n\\center $Doc_date\n" if $Doc_date; + $title_stuff .= "\n" if ($Doc_title || $Doc_author || $Doc_date); + if ($title_stuff ne '') { + print STDERR "$Pgm: warning: an unfixed perl 4.035 crashes here!\n"; + print STDERR "(a patch for perl is distributed with Glasgow Haskell)\n"; +# what happened to idx stuff ? + $title_stuff = &texinfoize_text($srcfilename, ($srclineno + $i), $title_stuff); + } + s/\\maketitle\n/$title_stuff/; + } + + while (/\\heading\{([^\}]+)\}\n/) { + local($title) = &deatified2verb($1); + s/\\heading\{([^\}]+)\}\n/\\heading $title\n/; + } + + while (/\\index\{([^\}]+)\}/) { + local($guts) = &deatified2verb($1); + + $guts =~ s/\\@/\@/g; # de-escape them + $guts =~ s/\\!/\!/g; + $guts = &mk_texi_index_entry($guts); + + $idx_real .= "\\cindex " . $guts . "\n"; + s/\\index\{([^\}]+)\}//; + } + + s/\\item\s+([^\[\n])/\\item\n\1/g; # must be first for \item + + # the following will get messed up if you do: + # \item [ ......... ] .......] + + while (/\\item\s*\[(.+)\]\s*\n/) { + local($item_tag) = &deatified2verb($1); + s/\\item\s*\[(.+)\]\s*\n/\\item $item_tag\n/; + } + while (/\\item\s*\[(.+)\]\s*(\S)/) { + local($item_tag) = &deatified2verb($1); + s/\\item\s*\[(.+)\]\s*(\S)/\\item $item_tag\n\2/; + } + + while (/\\centerline\{([^\}]+)\}\n/) { + local($center_text) = &deatified2verb($1); + s/\\centerline\{([^\}]+)\}\n/\\center $center_text\n/; + } + + while (/\\node\{([^\}]+)\}\n/) { + local($node_text) = &deatified2verb($1); + s/\\node\{([^\}]+)\}\n/\\node $node_text\n/; + } + + s/\\(begin|end)\{document\}\n//g; + s/\\begin\{description\}/\\table \\asis/g; + s/\\end\{description\}/\\end table/g; + s/\\begin\{enumerate\}/\\enumerate/g; + s/\\end\{enumerate\}/\\end enumerate/g; + s/\\begin\{itemi[sz]e\}/\\itemize \\bullet/g; + s/\\end\{itemi[sz]e\}/\\end itemize/g; + s/\\begin\{quotation\}/\\quotation/g; + s/\\end\{quotation\}/\\end quotation/g; + s/\\begin\{display\}/\n\\display/g; + s/\\end\{display\}/\\end display\n/g; + s/\\begin\{flushdisplay\}/\n\\format/g; + s/\\end\{flushdisplay\}/\\end format\n/g; + s/\\begin\{comment\}/\\quotation\nCOMMENT:-----------------------\n/g; # need more here? + s/\\end\{comment\}/-------------------------------\n\\end quotation/g; + + # check for unknown environments (only at beginning of lines; easier) + # mark good ones as \begin!_/\end!_ + # bad ones as \begin!!/\end!! + while (/^\\(begin|end)\{([A-Za-z]+)\}/) { + if ( $KNOWN_ENV{$2} ) { # good + s/\\(begin|end)\{([A-Za-z]+)\}/\\\1!_\{\2\}/; + } else { # bad + s/\\(begin|end)\{([A-Za-z]+)\}/\\\1!!\{\2\}/; + } + } + # put begin/end display around bad ones and escape magic chars + while (/\\(begin|end)!!\{([A-Za-z]+)\}/) { + local($begin_or_end) = $1; + local($env_name) = $2; + + local($new_stuff) = "\\display\n" if $begin_or_end eq 'begin'; + $new_stuff .= "\001backslash\003$begin_or_end\001lbrace\003$env_name\001rbrace\003\n"; + $new_stuff .= "\\end display\n" if $begin_or_end eq 'end'; + s/\\(begin|end)!!\{([A-Za-z]+)\}/$new_stuff/; + } + # unmark good ones + s/\\(begin|end)!_\{([A-Za-z]+)\}/\\\1\{\2\}/g; + + local($_) = &fiddle_sectiontypes($_); + + # comments were mainly handled in lit-deatify + s/\\\%/\%/g; # remaining percent signs needn't be escaped + + # now some easy ones + s/\\\&/\&/g; + s/\\\_/\_/g; + s/\\\#/\#/g; + s/\\\$/\$/g; + s/\\pounds\s*([0-9\?][0-9KkMm\.\,\?]*[0-9KkMm\?])/\1 pounds/g; + s/\{\\em\s*/@emph\{/g; + s/\\\///g; + s/\{\\tt\s*/@kbd\{/g; + s/\{\\sc\s*/@sc\{/g; + s/``/"/g; # except the ones in \tr and \pl (sigh) + s/''/"/g; + s/\001tex-open-double-quotes\003/``/g; + s/\001tex-close-double-quotes\003/''/g; + + s/([^\\ ])~/\1 /g; # I expect to be beaten by twiddles... + + s/([^-])---([^-])/\1 -- \2/g; # I don't like what makeinfo does + + # I prefer to go after specific cases, e.g., \ref's below + # accents + s/\\"\\i/i/g; # dotless i + s/\\"//g; + s/\\`//g; + s/\\'//g; + # \refs and \pagerefs + s/[ ~]\\ref\{/ \\xref\{/g; + s/^\\ref\{/\\xref\{/g; + s/[ ~]\\pageref\{/ \\xref\{/g; # good luck... + s/^\\pageref\{/\\xref\{/g; + + # \xref handling must be deferred to link time + + (&slashes2ats($_), (&slashes2ats($idx_real) . $idx_maybe)); +} + +sub slashes2ats { # and also the magic \001?\003 things put in by deatify; sigh + local($_) = @_; + + $_ = &deatified2verb_nl($_); + + s/\\/\@/g; + s/\001backslash\003/\\/g; # those meant to survive... + s/\001twiddle\003/\~/g; + + $_; +} + +sub texinfoize_verb { + local($_) = @_; + + s/\@/\@\@/g; + s/\{/\@\{/g; + s/\}/\@\}/g; + + $_; +} + +sub texinfoize_code { # same as verb for now + local($_) = @_; + + s/\@/\@\@/g; + s/\{/\@\{/g; + s/\}/\@\}/g; + + $_; +} + +sub texinfoize_table_body { + # is given deatified text + # returns text and index entries + local($_) = @_; + + # convert &'s and \\'s to something hidden + s/^\&/\\tabularAnd/; + s/([^\\])\&/\1\\tabularAnd/g; + s/\\\\/\\tabularNewline/g; + + local($ret_text,$ret_idxstuff) = &texinfoize_text('???','???',$_); + ($ret_text,$ret_idxstuff); +} + +sub texinfoize_tabular { + local($_) = @_; + + # newlines serve no purpose here + s/\n//g; + + # split into "rows" based on \\ + local(@row) = split(/\@tabularNewline/, $_); + local($r); + + # find maximum column widths + local(@col_width) = (); + foreach $r (@row) { +# $r =~ s/\\&/\001and\003/g; # avoid escaped ampersands + local(@row_col) = split(/\@tabularAnd/, $r); + local($rc_no); + for ($rc_no = 0; $rc_no <= $#row_col; $rc_no++) { + # strip leading/trailing whitespace + $row_col[$rc_no] =~ s/^\s+//; + $row_col[$rc_no] =~ s/\s+$//; + # \hline's throw the count off + $row_col[$rc_no] =~ s/\@hline//g; +# # convert funny ampersands +# $row_col[$rc_no] =~ s/\001and\003/&/g; + if (!defined($col_width[$rc_no]) + || length($row_col[$rc_no]) > $col_width[$rc_no]) { + $col_width[$rc_no] = length($row_col[$rc_no]); + } + } + } + # and the total width ... (2 each for intercolumn gaps) + local($total_width) = 0; + local($cw); + foreach $cw (@col_width) { + $total_width += $cw; + } + $total_width += ($#col_width * 2); + local($hline_text) = ('-' x $total_width)."\n"; + + # now we know widths, let's make new text accordingly + local($outtext) = ''; + foreach $r (@row) { + # escaped ampersands already under control + local(@row_col) = split(/\@tabularAnd/, $r); + local($rc_no); + for ($rc_no = 0; $rc_no <= $#row_col; $rc_no++) { + # strip leading/trailing whitespace + $row_col[$rc_no] =~ s/^\s+//; + $row_col[$rc_no] =~ s/\s+$//; + + # handle \hline's (AT BEGINNING OF LINE ONLY) + while ($row_col[$rc_no] =~ /^\@hline\s*/) { + $outtext .= $hline_text; + $row_col[$rc_no] =~ s/^\@hline\s*//; + } + # and now the rest of the line... +# # convert funny ampersands +# $row_col[$rc_no] =~ s/\001and\003/&/g; + + # only left justify for now + $outtext .= sprintf("%-".$col_width[$rc_no]."s ", $row_col[$rc_no]); + } + $outtext .= "\n"; + } + + &slashes2ats($outtext); +} + +sub mk_texi_index_entry { + local($raw_text) = @_; + local(@sub_entries) = split(/\001idxsubitem\003/, $raw_text); + local($sube,$sortstuff,$printstuff); + + foreach $sube (@sub_entries) { + if ($sube =~ /(.*[^\\])\001idxsort\003(.*)/) { + $sortstuff = $1; + $printstuff = $2; + } else { + $sortstuff = ''; + $printstuff = $sube; + } + $sortstuff =~ s/\\/\001backslash\003/g; + $sortstuff =~ s/\@/\@\@/g; + $sortstuff =~ s/\{/\\\001lbrace\003/g; + $sortstuff =~ s/\}/\\\001rbrace\003/g; + + $printstuff =~ s/\\/\001backslash\003/g; + $printstuff =~ s/\@/\@\@/g; + $printstuff =~ s/\{/\\\001lbrace\003/g; + $printstuff =~ s/\}/\\\001rbrace\003/g; + + if ($sortstuff) { + $sube = "$sortstuff\\@_sep_\\@$printstuff"; + } else { + $sube = $printstuff; + } + } + # stick it back together for makeindex + join(' -- ',@sub_entries); +} + +sub mk_line_directive { + local($filename,$lineno) = @_; + + ( (! $filename) ? '' : "\@srcfilename $filename\n\@srclineno $lineno\n"); +} + +sub std_print_code_blk { + local($codetxt) = @_; + + # language specific + local($newtxt,$idx_list) = &rm_embedded_stuff($codetxt); + + print "\@format\n"; + print '-' x 70, "\n"; # 70 lets us still fit in 80 cols, even w/ some indentation + print &texinfoize_code($newtxt); + print '-' x 70, "\n"; + print "\@end format\n"; + + local($i); + foreach $i (split(/\002/, $idx_list )) { + print "\@cindex ".&mk_texi_index_entry($i)."\n" if $i; + } +} + +sub std_mk_code_frag { + local($codetxt) = @_; + + "\@w\@samp\{" . &texinfoize_code($codetxt) . "\}\}"; +} + +sub gen_texinfo_table_of_contents_lines { # used by linker + push(@Menu_lines, "Detailed table of contents:\n\n"); + + local($s) = 0; + + while ($s <= $#Sec_depth) { + next if $Sec_abs_depth[$s] <= 0 || ! $Sec_nodename[$s]; + next if $Sec_title[$s] =~ /\001starred\003/; + + # take it's numstr, throw away all the 0 pieces + # use the length of what's left as how much to indent + # (pretty terrible, eh?) + local($magic_str) = $Sec_numstr[$s]; + $magic_str =~ s/^[0\.]+\.//; + $magic_str =~ s/\.[0\.]+$//; + + push(@Menu_lines, + '*'.(' ' x length($magic_str)).$Sec_nodename[$s].':: '.$Sec_title[$s]."\n"); + } continue { + $s++; + } +} + +# a trailing 1 makes this file's "do"ing a success +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-2text.lprl b/web/glasgow/lit2x-0.16/literate/lit-2text.lprl new file mode 100644 index 0000000000..54406e686c --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-2text.lprl @@ -0,0 +1,23 @@ +\section[lit2text_only]{Code used only in extracting text} + +Whereas \tr{lit2pgm} saves the code from a document (usually to feed +to a compiler), \tr{lit2text} saves the raw text from a document +(usually to feed to a spelling checker, or something similar). + +\begin{code} +# still probably too simplistic +sub spit_out_raw_text { + + foreach ($S = 0; $S <= $#Sec_depth; $S++) { + print "\\section$Sec_depth[$S]\[$Sec_nodespec[$S]\]\{$Sec_title[$S]\}\n"; + + foreach ($B = $Sec_first_blk[$S]; $B <= $Sec_last_blk[$S]; $B++) { + + print $Blk_txt[$B] if $Blk_type[$B] ne 'code'; + } + } +} + +# this keeps 'do'ing happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-deatify.c b/web/glasgow/lit2x-0.16/literate/lit-deatify.c new file mode 100644 index 0000000000..39386653a7 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-deatify.c @@ -0,0 +1,2084 @@ +/* A lexical scanner generated by flex */ + +/* scanner skeleton version: + * $Header: /usr/fsys/odin/a/vern/flex/RCS/flex.skel,v 2.16 90/08/03 14:09:36 vern Exp $ + */ + +#define FLEX_SCANNER + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <osfcn.h> + +/* use prototypes in function declarations */ +#define YY_USE_PROTOS + +/* the "const" storage-class-modifier is valid */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#ifdef __STDC__ + +#ifdef __GNUC__ +#include <stddef.h> +void *malloc( size_t ); +void free( void* ); +#else +#include <stdlib.h> +#endif /* __GNUC__ */ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + + +#ifdef __TURBOC__ +#define YY_USE_CONST +#endif + + +#ifndef YY_USE_CONST +#define const +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +/* we can't get here if it's an ANSI C compiler, or a C++ compiler, + * so it's got to be a K&R compiler, and therefore there's no standard + * place from which to include these definitions + */ +char *malloc(); +int free(); +int read(); +#endif + + +/* amount of stuff to slurp up with each read */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* returned upon end-of-file */ +#define YY_END_TOK 0 + +/* copy whatever the last rule matched to the standard output */ + +/* cast to (char *) is because for 8-bit chars, yytext is (unsigned char *) */ +/* this used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite() + */ +#define ECHO (void) fwrite( (char *) yytext, yyleng, 1, yyout ) + +/* gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#define YY_INPUT(buf,result,max_size) \ + if ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#define YY_NULL 0 + +/* no semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#define yyterminate() return ( YY_NULL ) + +/* report a fatal error */ + +/* The funky do-while is used to turn this macro definition into + * a single C statement (which needs a semi-colon terminator). + * This avoids problems with code like: + * + * if ( something_happens ) + * YY_FATAL_ERROR( "oops, the something happened" ); + * else + * everything_okay(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the YY_FATAL_ERROR() call. + */ + +#define YY_FATAL_ERROR(msg) \ + do \ + { \ + (void) fputs( msg, stderr ); \ + (void) putc( '\n', stderr ); \ + exit( 1 ); \ + } \ + while ( 0 ) + +/* default yywrap function - always treat EOF as an EOF */ +#define yywrap() 1 + +/* enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN + */ +#define BEGIN yy_start = 1 + 2 * + +/* action number for EOF rule of a given start state */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* special action meaning "start processing a new file" */ +#define YY_NEW_FILE \ + do \ + { \ + yy_init_buffer( yy_current_buffer, yyin ); \ + yy_load_buffer_state(); \ + } \ + while ( 0 ) + +/* default declaration of generated scanner - a define so the user can + * easily add parameters + */ +#define YY_DECL int yylex YY_PROTO(( void )) + +/* code executed at the end of each rule */ +#define YY_BREAK break; + +#define YY_END_OF_BUFFER_CHAR 0 + +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE (YY_READ_BUF_SIZE * 2) /* size of default input buffer */ +#endif + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +#define YY_CHAR char +# line 1 "lit-deatify.lex" +#define INITIAL 0 +# line 2 "lit-deatify.lex" +#define LEX_STK_SIZE 256 + +int lex_stk[LEX_STK_SIZE]; +int lex_stk_top = 0; + +#define PUSH(x) lex_stk[++lex_stk_top] = (x); BEGIN(x) +#define POP BEGIN(lex_stk[--lex_stk_top]) +#define LEX_STK_TOP lex_stk[lex_stk_top] +#define LEX_NEXT_TO_STK_TOP lex_stk[lex_stk_top - 1] +#define CHG_TOP(x) lex_stk[lex_stk_top] = (x); BEGIN(x) +#define CHG_NEXT_TO_TOP(x) lex_stk[lex_stk_top - 1] = (x) +/* not a lot in the old stack {over,under}flow dept, what? */ + +extern char *yytext; /* forward decl */ +void print_leading_whitespace(); + +void +print_lex_stk () /* just for debugging */ +{ + int i; + fprintf(stderr,"lex_stk:"); + for (i = lex_stk_top; i >= 0; i--) { + fprintf(stderr," %d",lex_stk[i]); + } + fprintf(stderr,"::%s\n",yytext); +} +int verbose; /* set from first argv */ +int follow_inputs; /* set from second argv */ + +#if defined (SYSV) || defined (SYSV) +#include <string.h> +#include <time.h> +#else +#include <strings.h> +#include <sys/time.h> +#endif + +#if defined (SYSV) +#define index(string, ch) strchr ((string), (ch)) +#endif + +#define INPUTFILE_STK_SIZE 20 +struct { + YY_BUFFER_STATE handle; /* flex-supplied magic */ + char* name; + int lineno; +} inputfile_stk[INPUTFILE_STK_SIZE]; +int inputfile_stk_top = 0; +void push_inputfile(); +void pop_inputfile(); +int i; /* temporary */ +char* rbrace; +int deatify_debug = 0; +int unmatched_lbraces = 0; +int unmatched_lbrackets = 0; + +/* like everything, must track srcfile name and lineno */ +char srcfile_name[1024]; /* too lazy to do this right */ +int lineno = 1; /* count \n's as they go by */ +int lineno_fiddled = 0; /* boolean: incr if newlines get trashed */ + +int exit_status = 0; +void not_OK (); /* prints an error msg and bumps exit_status */ +void warning (); /* same, but no exit-status fiddling */ + +int lit2what; /* set from ARGV */ + +#define IS_LIT2PGM_Q (lit2what == 1) +#define IS_LIT2PGM (lit2what == 2) +#define IS_LIT2TEXI (lit2what == 3) +#define IS_LIT2LATEX (lit2what == 4) +#define IS_LIT2DEPEND (lit2what == 5) +#define IS_LIT2CHANGELOG (lit2what== 6) + +/* the condition for printing to stdout */ +#define SHLD_PRINT (! IS_LIT2PGM_Q || (LEX_STK_TOP == Code || LEX_STK_TOP == Bird)) + +void myecho(); +#define MYECHO myecho() +void myprintstr(); + +#define YY_USER_ACTION if (deatify_debug) print_lex_stk(); /* debugging */ +#define Norm 1 +#define Verb 2 +#define Code 3 +#define Bird 4 +#define Atting 5 +#define Math 6 +#define Index 7 +#define Typing 8 +#define Linify_braces 9 +#define Linify_brackets 10 +# line 89 "lit-deatify.lex" + +/* done after the current pattern has been matched and before the + * corresponding action - sets up yytext + */ +#define YY_DO_BEFORE_ACTION \ + yytext = yy_bp; \ + yyleng = yy_cp - yy_bp; \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* return all but the first 'n' matched characters back to the input stream */ +#define yyless(n) \ + do \ + { \ + /* undo effects of setting up yytext */ \ + *yy_cp = yy_hold_char; \ + yy_c_buf_p = yy_cp = yy_bp + n; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext ) + + +struct yy_buffer_state + { + FILE *yy_input_file; + + YY_CHAR *yy_ch_buf; /* input buffer */ + YY_CHAR *yy_buf_pos; /* current position in input buffer */ + + /* size of input buffer in bytes, not including room for EOB characters*/ + int yy_buf_size; + + /* number of characters read into yy_ch_buf, not including EOB characters */ + int yy_n_chars; + + int yy_eof_status; /* whether we've seen an EOF on this buffer */ +#define EOF_NOT_SEEN 0 + /* "pending" happens when the EOF has been seen but there's still + * some text process + */ +#define EOF_PENDING 1 +#define EOF_DONE 2 + }; + +static YY_BUFFER_STATE yy_current_buffer; + +/* we provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state" + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed */ +static YY_CHAR yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + + +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +#ifndef YY_USER_INIT +#define YY_USER_INIT +#endif + +extern YY_CHAR *yytext; +extern int yyleng; +extern FILE *yyin, *yyout; + +YY_CHAR *yytext; +int yyleng; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +#define YY_END_OF_BUFFER 111 +typedef int yy_state_type; +static const short int yy_accept[398] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 111, 1, 110, 40, 39, 41, 32, 40, + 30, 40, 40, 40, 39, 47, 48, 47, 47, 47, + 53, 53, 52, 51, 63, 62, 60, 57, 58, 59, + 71, 70, 68, 65, 71, 71, 66, 67, 105, 104, + 103, 102, 89, 93, 100, 74, 78, 83, 86, 74, + 88, 105, 85, 74, 76, 81, 95, 74, 98, 77, + 82, 39, 0, 0, 0, 0, 38, 31, 36, 29, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 34, 35, 0, 12, 0, 0, 39, + 0, 46, 0, 0, 0, 52, 0, 0, 50, 51, + 51, 62, 54, 0, 70, 64, 104, 101, 87, 90, + 84, 73, 84, 0, 92, 0, 0, 75, 79, 80, + 94, 96, 97, 0, 0, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, + 0, 50, 50, 0, 0, 0, 0, 9, 0, 10, + 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 27, 0, 0, 0, 0, 0, 39, + + 0, 0, 0, 91, 72, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 39, 0, 0, 0, 0, 0, 0, 16, + 0, 0, 0, 28, 0, 0, 21, 0, 0, 0, + 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 19, 0, 22, 0, 0, + 26, 0, 0, 39, 0, 0, 0, 0, 0, 13, + 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, + 18, 0, 0, 24, 23, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 45, 0, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 55, 15, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 44, 25, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 2, 43, 0, 0, 0, 6, 0 + + } ; + +static const YY_CHAR yy_ec[128] = + { 0, + 1, 1, 1, 2, 2, 2, 2, 2, 3, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 5, 2, 2, 6, 7, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 2, 2, 2, + 2, 9, 2, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 12, 13, 14, 2, 15, 2, 16, 17, 18, 19, + + 20, 21, 22, 23, 24, 11, 11, 25, 26, 27, + 28, 29, 11, 30, 31, 32, 33, 34, 35, 36, + 37, 11, 38, 2, 39, 2, 2 + } ; + +static const YY_CHAR yy_meta[40] = + { 0, + 1, 1, 2, 3, 1, 1, 1, 2, 1, 1, + 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 4 + } ; + +static const short int yy_base[425] = + { 0, + 609, 608, 0, 39, 604, 4, 603, 7, 15, 18, + 78, 117, 156, 195, 234, 273, 18, 19, 308, 343, + 378, 0, 606, 611, 611, 611, 0, 33, 611, 601, + 611, 412, 600, 9, 573, 611, 611, 598, 581, 580, + 611, 31, 52, 595, 611, 0, 611, 37, 611, 611, + 611, 0, 611, 611, 594, 51, 611, 611, 611, 0, + 611, 611, 611, 611, 611, 58, 611, 611, 611, 88, + 611, 593, 611, 446, 611, 558, 611, 48, 557, 611, + 611, 0, 63, 585, 589, 588, 69, 611, 611, 611, + 558, 69, 83, 88, 570, 42, 573, 568, 559, 551, + + 560, 108, 51, 611, 611, 580, 611, 116, 78, 565, + 578, 611, 554, 553, 93, 103, 110, 134, 575, 574, + 611, 0, 611, 550, 0, 611, 0, 611, 611, 611, + 611, 611, 611, 572, 131, 533, 453, 611, 611, 611, + 611, 611, 611, 473, 477, 476, 611, 141, 470, 445, + 147, 447, 447, 441, 451, 455, 451, 449, 451, 440, + 447, 438, 426, 445, 446, 429, 438, 123, 437, 438, + 436, 450, 611, 421, 147, 439, 409, 611, 442, 611, + 611, 419, 402, 401, 412, 403, 407, 405, 398, 403, + 388, 400, 395, 611, 382, 386, 387, 387, 377, 385, + + 370, 369, 382, 611, 611, 377, 380, 383, 364, 374, + 376, 363, 386, 372, 376, 357, 364, 369, 370, 367, + 359, 348, 354, 125, 360, 350, 346, 347, 344, 611, + 353, 345, 333, 611, 332, 342, 611, 330, 339, 350, + 327, 326, 325, 342, 336, 329, 339, 330, 338, 317, + 327, 327, 313, 323, 611, 611, 312, 611, 316, 317, + 611, 154, 0, 336, 307, 319, 308, 318, 316, 611, + 297, 310, 611, 295, 302, 165, 303, 302, 304, 297, + 307, 287, 310, 293, 290, 305, 300, 283, 611, 290, + 611, 279, 173, 611, 611, 283, 290, 275, 287, 276, + + 301, 299, 280, 283, 285, 261, 261, 278, 259, 276, + 275, 263, 260, 275, 287, 611, 0, 256, 261, 252, + 611, 242, 238, 611, 243, 231, 246, 249, 251, 261, + 245, 246, 239, 611, 611, 232, 257, 226, 231, 226, + 169, 227, 228, 229, 227, 249, 611, 232, 233, 226, + 240, 225, 218, 193, 203, 200, 201, 202, 171, 211, + 206, 611, 193, 207, 203, 182, 182, 188, 180, 180, + 201, 195, 210, 177, 182, 611, 611, 166, 154, 187, + 611, 184, 127, 124, 116, 208, 76, 85, 105, 611, + 611, 611, 50, 72, 55, 611, 611, 485, 489, 493, + + 497, 501, 505, 509, 513, 28, 517, 521, 525, 529, + 23, 14, 1, 533, 537, 541, 545, 549, 551, 555, + 559, 563, 567, 571 + } ; + +static const short int yy_def[425] = + { 0, + 398, 398, 399, 399, 400, 401, 400, 401, 402, 402, + 403, 403, 404, 404, 405, 405, 16, 16, 16, 16, + 16, 21, 397, 397, 397, 397, 406, 397, 397, 407, + 397, 397, 408, 32, 406, 397, 397, 409, 397, 397, + 397, 397, 397, 410, 397, 411, 397, 397, 397, 397, + 397, 412, 397, 397, 407, 397, 397, 397, 397, 413, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 414, 397, 397, 397, 397, 397, 74, 397, 397, + 397, 406, 397, 397, 415, 407, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + + 397, 397, 397, 397, 397, 408, 397, 397, 397, 406, + 409, 397, 397, 397, 397, 397, 397, 397, 416, 410, + 397, 411, 397, 397, 412, 397, 413, 397, 397, 397, + 397, 397, 397, 414, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 417, 415, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 406, 397, + 397, 416, 397, 397, 397, 397, 397, 397, 417, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 406, + + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 406, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 406, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 418, 406, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 418, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + + 419, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 419, 397, 420, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 420, + 397, 397, 397, 397, 397, 397, 421, 397, 397, 397, + 420, 397, 397, 397, 397, 421, 397, 397, 397, 397, + 420, 397, 397, 397, 397, 397, 397, 397, 420, 397, + 397, 397, 397, 397, 397, 397, 420, 397, 397, 397, + 397, 397, 422, 420, 397, 397, 397, 397, 397, 422, + 397, 420, 397, 397, 423, 420, 397, 397, 423, 397, + 397, 397, 397, 424, 424, 397, 0, 397, 397, 397, + + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397 + } ; + +static const short int yy_nxt[651] = + { 0, + 26, 26, 127, 28, 26, 29, 30, 37, 26, 31, + 37, 26, 32, 26, 26, 125, 39, 42, 43, 40, + 42, 43, 59, 59, 122, 108, 44, 69, 69, 82, + 70, 70, 109, 115, 116, 83, 84, 26, 26, 26, + 26, 85, 28, 26, 29, 30, 123, 33, 31, 124, + 26, 34, 26, 26, 117, 118, 126, 89, 396, 141, + 119, 142, 128, 129, 130, 83, 144, 131, 157, 35, + 132, 148, 149, 158, 166, 396, 26, 26, 45, 45, + 163, 47, 45, 45, 45, 92, 45, 48, 394, 45, + 45, 45, 45, 129, 130, 115, 116, 133, 152, 151, + + 132, 92, 153, 154, 168, 117, 118, 155, 390, 158, + 393, 119, 117, 118, 392, 49, 50, 45, 45, 390, + 47, 45, 45, 45, 92, 45, 48, 164, 45, 45, + 45, 45, 92, 175, 176, 167, 117, 118, 151, 165, + 92, 188, 119, 148, 149, 245, 151, 388, 92, 175, + 176, 199, 387, 246, 49, 50, 51, 51, 247, 53, + 51, 54, 55, 92, 51, 51, 164, 51, 56, 51, + 51, 278, 293, 341, 279, 341, 294, 151, 367, 92, + 293, 341, 280, 351, 294, 351, 374, 281, 386, 367, + 381, 382, 385, 57, 58, 51, 51, 384, 53, 51, + + 54, 55, 295, 51, 51, 383, 51, 56, 51, 51, + 295, 391, 341, 381, 379, 367, 378, 377, 376, 375, + 373, 372, 351, 371, 370, 369, 368, 366, 365, 364, + 363, 362, 57, 58, 59, 59, 361, 61, 62, 63, + 64, 360, 59, 65, 359, 59, 66, 59, 59, 358, + 357, 356, 347, 355, 354, 353, 352, 350, 349, 348, + 347, 345, 344, 343, 342, 341, 340, 339, 338, 337, + 336, 67, 68, 59, 59, 335, 61, 62, 63, 64, + 334, 59, 65, 333, 59, 66, 59, 59, 332, 331, + 316, 329, 328, 327, 326, 325, 324, 323, 322, 321, + + 320, 319, 318, 317, 316, 314, 313, 312, 311, 310, + 67, 68, 59, 71, 72, 309, 308, 73, 307, 306, + 74, 305, 304, 303, 302, 301, 300, 299, 298, 297, + 296, 292, 291, 290, 289, 288, 287, 286, 285, 284, + 283, 277, 276, 275, 274, 75, 76, 59, 71, 72, + 273, 272, 73, 271, 270, 74, 269, 268, 267, 266, + 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, + 255, 254, 253, 252, 251, 250, 249, 248, 244, 243, + 75, 76, 59, 71, 72, 242, 241, 73, 240, 77, + 78, 79, 239, 238, 237, 236, 235, 234, 233, 232, + + 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, + 221, 220, 219, 218, 217, 80, 81, 88, 89, 216, + 215, 90, 214, 213, 212, 211, 210, 91, 92, 93, + 94, 209, 208, 207, 95, 96, 97, 98, 99, 100, + 101, 206, 102, 103, 92, 180, 205, 204, 203, 104, + 105, 129, 130, 173, 202, 133, 201, 200, 132, 198, + 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, + 187, 186, 185, 184, 136, 183, 182, 137, 181, 147, + 180, 178, 177, 138, 139, 25, 25, 25, 25, 27, + 27, 27, 27, 36, 36, 36, 36, 38, 38, 38, + + 38, 41, 41, 41, 41, 46, 46, 46, 46, 52, + 52, 52, 52, 60, 60, 60, 60, 86, 86, 86, + 86, 106, 106, 106, 106, 111, 111, 111, 111, 120, + 120, 120, 120, 134, 134, 134, 134, 146, 146, 146, + 146, 172, 172, 172, 172, 179, 179, 179, 179, 282, + 282, 315, 315, 315, 315, 330, 330, 177, 330, 346, + 346, 346, 346, 380, 380, 380, 380, 389, 389, 389, + 389, 395, 395, 395, 395, 135, 174, 121, 173, 171, + 170, 112, 169, 107, 163, 162, 161, 160, 159, 156, + 150, 87, 147, 145, 143, 140, 135, 87, 121, 114, + + 113, 112, 110, 107, 87, 397, 37, 37, 24, 24, + 23, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397 + } ; + +static const short int yy_chk[651] = + { 0, + 3, 3, 413, 3, 3, 3, 3, 6, 3, 3, + 8, 3, 3, 3, 3, 412, 6, 9, 9, 8, + 10, 10, 17, 18, 411, 34, 10, 17, 18, 406, + 17, 18, 34, 42, 42, 28, 28, 3, 3, 4, + 4, 28, 4, 4, 4, 4, 48, 4, 4, 48, + 4, 4, 4, 4, 43, 43, 56, 56, 395, 78, + 43, 78, 66, 66, 66, 83, 83, 66, 96, 4, + 66, 87, 87, 96, 103, 394, 4, 4, 11, 11, + 103, 11, 11, 11, 11, 92, 11, 11, 393, 11, + 11, 11, 11, 70, 70, 115, 115, 70, 93, 92, + + 70, 92, 93, 94, 109, 116, 116, 94, 389, 109, + 388, 116, 117, 117, 387, 11, 11, 12, 12, 385, + 12, 12, 12, 12, 102, 12, 12, 102, 12, 12, + 12, 12, 108, 135, 135, 108, 118, 118, 102, 102, + 102, 168, 118, 148, 148, 224, 108, 384, 108, 175, + 175, 168, 383, 224, 12, 12, 13, 13, 224, 13, + 13, 13, 13, 151, 13, 13, 151, 13, 13, 13, + 13, 262, 276, 341, 262, 359, 276, 151, 359, 151, + 293, 374, 262, 341, 293, 359, 367, 262, 382, 367, + 380, 374, 379, 13, 13, 14, 14, 378, 14, 14, + + 14, 14, 276, 14, 14, 375, 14, 14, 14, 14, + 293, 386, 386, 373, 372, 386, 371, 370, 369, 368, + 366, 365, 386, 364, 363, 361, 360, 358, 357, 356, + 355, 354, 14, 14, 15, 15, 353, 15, 15, 15, + 15, 352, 15, 15, 351, 15, 15, 15, 15, 350, + 349, 348, 346, 345, 344, 343, 342, 340, 339, 338, + 337, 336, 333, 332, 331, 330, 329, 328, 327, 326, + 325, 15, 15, 16, 16, 323, 16, 16, 16, 16, + 322, 16, 16, 320, 16, 16, 16, 16, 319, 318, + 315, 314, 313, 312, 311, 310, 309, 308, 307, 306, + + 305, 304, 303, 302, 301, 300, 299, 298, 297, 296, + 16, 16, 19, 19, 19, 292, 290, 19, 288, 287, + 19, 286, 285, 284, 283, 282, 281, 280, 279, 278, + 277, 275, 274, 272, 271, 269, 268, 267, 266, 265, + 264, 260, 259, 257, 254, 19, 19, 20, 20, 20, + 253, 252, 20, 251, 250, 20, 249, 248, 247, 246, + 245, 244, 243, 242, 241, 240, 239, 238, 236, 235, + 233, 232, 231, 229, 228, 227, 226, 225, 223, 222, + 20, 20, 21, 21, 21, 221, 220, 21, 219, 21, + 21, 21, 218, 217, 216, 215, 214, 213, 212, 211, + + 210, 209, 208, 207, 206, 203, 202, 201, 200, 199, + 198, 197, 196, 195, 193, 21, 21, 32, 32, 192, + 191, 32, 190, 189, 188, 187, 186, 32, 32, 32, + 32, 185, 184, 183, 32, 32, 32, 32, 32, 32, + 32, 182, 32, 32, 32, 179, 177, 176, 174, 32, + 32, 74, 74, 172, 171, 74, 170, 169, 74, 167, + 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, + 156, 155, 154, 153, 74, 152, 150, 74, 149, 146, + 145, 144, 137, 74, 74, 398, 398, 398, 398, 399, + 399, 399, 399, 400, 400, 400, 400, 401, 401, 401, + + 401, 402, 402, 402, 402, 403, 403, 403, 403, 404, + 404, 404, 404, 405, 405, 405, 405, 407, 407, 407, + 407, 408, 408, 408, 408, 409, 409, 409, 409, 410, + 410, 410, 410, 414, 414, 414, 414, 415, 415, 415, + 415, 416, 416, 416, 416, 417, 417, 417, 417, 418, + 418, 419, 419, 419, 419, 420, 420, 136, 420, 421, + 421, 421, 421, 422, 422, 422, 422, 423, 423, 423, + 423, 424, 424, 424, 424, 134, 124, 120, 119, 114, + 113, 111, 110, 106, 101, 100, 99, 98, 97, 95, + 91, 86, 85, 84, 79, 76, 72, 55, 44, 40, + + 39, 38, 35, 33, 30, 23, 7, 5, 2, 1, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 397, 397, 397, 397, 397, 397, 397, 397 + } ; + +static yy_state_type yy_last_accepting_state; +static YY_CHAR *yy_last_accepting_cpos; + +/* the intent behind this definition is that it'll catch + * any uses of REJECT which flex missed + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 + +/* these variables are all declared out here so that section 3 code can + * manipulate them + */ +/* points to current character in buffer */ +static YY_CHAR *yy_c_buf_p = (YY_CHAR *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yyunput YY_PROTO(( YY_CHAR c, YY_CHAR *buf_ptr )); +void yyrestart YY_PROTO(( FILE *input_file )); +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); + +#define yy_new_buffer yy_create_buffer + +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif + +YY_DECL + { + register yy_state_type yy_current_state; + register YY_CHAR *yy_cp, *yy_bp; + register int yy_act; + + + CHG_TOP(Norm); /* that's where we start */ + + if ( yy_init ) + { + YY_USER_INIT; + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( yy_current_buffer ) + yy_init_buffer( yy_current_buffer, yyin ); + else + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + + yy_init = 0; + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* support of yytext */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of the + * current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; + if ( yy_bp[-1] == '\n' ) + ++yy_current_state; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[*yy_cp]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 398 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 397 ); + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + YY_USER_ACTION; + +do_action: /* this label is used only to access EOF actions */ + + + switch ( yy_act ) + { + case 0: /* must backtrack */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +# line 91 "lit-deatify.lex" +{ not_OK("ASCII chars \001, \002, \003 may not appear in literate files\n"); + exit(1); + } + YY_BREAK +case 2: +# line 94 "lit-deatify.lex" +{ + sscanf(yytext+10,"%[^!]!_!%d", srcfile_name, &lineno); + if (lineno > 0) { + ECHO; + } + } + YY_BREAK +case 3: +# line 100 "lit-deatify.lex" +{ lineno++; + if (follow_inputs) { + /* nullify first right brace */ + rbrace = index(yytext+7,'}'); + *rbrace = '\0'; + push_inputfile(yytext+7); + } else { + MYECHO; + } + } + YY_BREAK +case YY_STATE_EOF(Norm): +case YY_STATE_EOF(Bird): +# line 110 "lit-deatify.lex" +{ if ( inputfile_stk_top <= 0 ) { + yyterminate(); + } else { + pop_inputfile(); + } + CHG_TOP(Norm); /* revert */ + } + YY_BREAK +case 5: +# line 118 "lit-deatify.lex" +case 6: +# line 119 "lit-deatify.lex" +case 7: +# line 119 "lit-deatify.lex" +{ lineno++; MYECHO; PUSH(Verb); /* some may have opt arg */ } + YY_BREAK +case 8: +# line 120 "lit-deatify.lex" +{ lineno++; + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + } + MYECHO; + PUSH(Code); + } + YY_BREAK +case 9: +# line 127 "lit-deatify.lex" +{ /* convert to something less weird & try again */ + unput('>'); unput('\n'); unput('\n'); + } + YY_BREAK +case 10: +# line 130 "lit-deatify.lex" +{ lineno += 3; + /* NB: init > converted to space */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+3); + } else { + ECHO; + } + PUSH(Bird); + } + YY_BREAK +case 11: +# line 140 "lit-deatify.lex" +{ lineno++; /* so msg will have right line # */ + if (lineno > 2) /* I feel guilty about this hack */ + /* to avoid: file is: blank lines, then code */ + not_OK("Bird-style code not preceded by a blank line\n"); + lineno++; /* account for other \n */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+2); + } else { + ECHO; + } + PUSH(Bird); + } + YY_BREAK +case 12: +# line 153 "lit-deatify.lex" +{ lineno++; /* first line of file */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+1); + } else { + ECHO; + } + PUSH(Bird); + } + YY_BREAK +case 13: +# line 162 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 14: +# line 163 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 15: +# line 164 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 16: +# line 165 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 17: +# line 166 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 18: +# line 167 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 19: +# line 168 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 20: +# line 169 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 21: +# line 170 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 22: +# line 171 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 23: +# line 172 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 24: +# line 173 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_brackets); } + YY_BREAK +case 25: +# line 174 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 26: +# line 175 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 27: +# line 176 "lit-deatify.lex" +{ MYECHO; unmatched_lbraces = 1; PUSH(Typing); + /* \tr has braces as literals */ + } + YY_BREAK +case 28: +# line 179 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_brackets); } + YY_BREAK +case 29: +# line 180 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 30: +# line 181 "lit-deatify.lex" +{ myprintstr("\\codeInText{"); PUSH(Atting); } + YY_BREAK +case 31: +# line 182 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 32: +# line 183 "lit-deatify.lex" +{ myprintstr("\\MathMode{"); PUSH(Math); } + YY_BREAK +case 33: +# line 184 "lit-deatify.lex" +{ MYECHO; + unmatched_lbraces = 1; + PUSH(Index); + } + YY_BREAK +case 34: +# line 188 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 35: +# line 189 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 36: +# line 190 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 37: +# line 191 "lit-deatify.lex" +{ /* technically this Bird-style code is wrong + (no blank line in front of it, but that's + not intuitively obvious to the casual observer). + Solution? A hack! + */ + unput('>'); unput('\n'); unput('\n'); + } + YY_BREAK +case 38: +# line 198 "lit-deatify.lex" +{ /* throw away */ lineno++; + if (! IS_LIT2PGM_Q) + printf("\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + } + YY_BREAK +case 39: +# line 202 "lit-deatify.lex" +{ MYECHO; /* slight efficiency */ } + YY_BREAK +case 40: +# line 203 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 41: +# line 204 "lit-deatify.lex" +{ /* handle line-number fiddling */ + MYECHO; + lineno++; + if (lineno_fiddled) { + if (! IS_LIT2PGM_Q) + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + lineno_fiddled = 0; + } + } + YY_BREAK +case 42: +# line 214 "lit-deatify.lex" +case 43: +# line 215 "lit-deatify.lex" +case 44: +# line 215 "lit-deatify.lex" +{ MYECHO; POP; } + YY_BREAK +case 45: +# line 216 "lit-deatify.lex" +{ if (! IS_LIT2PGM_Q) ECHO; POP; } + YY_BREAK +case 46: +# line 217 "lit-deatify.lex" +{ lineno++; MYECHO; /* a line not started by \ */} + YY_BREAK +case 47: +# line 218 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 48: +# line 219 "lit-deatify.lex" +{ lineno++; MYECHO; } + YY_BREAK +case YY_STATE_EOF(Verb): +case YY_STATE_EOF(Code): +# line 220 "lit-deatify.lex" +{ not_OK("unexpected end-of-file in verbatim text or (pseudo)code\n"); + exit(1); + } + YY_BREAK +case 50: +# line 223 "lit-deatify.lex" +{ /* whitespace/blank-lines do not matter */ + /* count lines... */ + for (i = 0; i < strlen(yytext); i++) { + if (yytext[i] == '\n') + lineno++; + } + if (! IS_LIT2PGM_Q) { + ECHO; + } else { /* don't print leading whitestuff */ + for (i = 0; i < strlen(yytext) && yytext[i] != '>'; i++) + ; /* no-op */ + /* report where this got us...*/ + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name, + ((yytext[yyleng-1] == '\n') ? (lineno-1) : lineno)); + /* putchar(' '); convert leading > to space */ + for ( i++ ; i < strlen(yytext); i++) + putchar(yytext[i]); + } + } + YY_BREAK +case 51: +# line 242 "lit-deatify.lex" +{ if (yytext[yyleng-1] == '\n') { lineno++; } + if (IS_LIT2PGM_Q) printf("%s",yytext+1); else ECHO; + } + YY_BREAK +case 52: +# line 245 "lit-deatify.lex" +{ lineno++; + if ( ! IS_LIT2PGM_Q) ECHO; + POP; + } + YY_BREAK +case 53: +# line 249 "lit-deatify.lex" +{ lineno--; /* to get right # on msg */ + not_OK("Bird-style code not followed by a blank line\n"); + lineno++; /* put it back */ + unput(yytext[0]); + POP; + } + YY_BREAK +case 54: +# line 255 "lit-deatify.lex" +{ myprintstr("@"); } + YY_BREAK +case 55: +# line 257 "lit-deatify.lex" +case 56: +# line 257 "lit-deatify.lex" +{ myprintstr("\001noindex\003}"); + POP; + } + YY_BREAK +case 57: +# line 260 "lit-deatify.lex" +{ myprintstr("}"); + POP; + } + YY_BREAK +case 58: +# line 263 "lit-deatify.lex" +{ myprintstr("\001lbrace\003"); } + YY_BREAK +case 59: +# line 264 "lit-deatify.lex" +{ myprintstr("\001rbrace\003"); } + YY_BREAK +case 60: +# line 265 "lit-deatify.lex" +{ warning("I'm turning a newline inside a @...@ into a space\n"); + myprintstr(" "); + lineno++; + } + YY_BREAK +case YY_STATE_EOF(Atting): +# line 270 "lit-deatify.lex" +{ not_OK("unexpected end-of-file inside an @ ... @\n"); + exit(1); + } + YY_BREAK +case 62: +# line 273 "lit-deatify.lex" +{ MYECHO; /* tiny efficiency */ } + YY_BREAK +case 63: +# line 274 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 64: +# line 275 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 65: +# line 276 "lit-deatify.lex" +{ myprintstr("}"); + POP; + } + YY_BREAK +case 66: +# line 279 "lit-deatify.lex" +{ myprintstr("\001lbrace\003"); } + YY_BREAK +case 67: +# line 280 "lit-deatify.lex" +{ myprintstr("\001rbrace\003"); } + YY_BREAK +case 68: +# line 281 "lit-deatify.lex" +{ myprintstr("\001newline\003"); + lineno++; + } + YY_BREAK +case YY_STATE_EOF(Math): +# line 285 "lit-deatify.lex" +{ not_OK("unexpected end-of-file inside $ ... $ (math mode)\n"); + exit(1); + } + YY_BREAK +case 70: +# line 288 "lit-deatify.lex" +{ MYECHO; /* tiny efficiency */ } + YY_BREAK +case 71: +# line 289 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 72: +# line 290 "lit-deatify.lex" +{ + MYECHO; + unmatched_lbraces = 1; + PUSH(Typing); + } + YY_BREAK +case 73: +# line 296 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 74: +# line 299 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 75: +# line 302 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 76: +# line 306 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_braces); } + YY_BREAK +case 77: +# line 307 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 78: +# line 309 "lit-deatify.lex" +{ unmatched_lbraces++; myprintstr("\001lbrace\003"); } + YY_BREAK +case 79: +# line 311 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 80: +# line 314 "lit-deatify.lex" +{ /* next arg */ MYECHO; } + YY_BREAK +case 81: +# line 316 "lit-deatify.lex" +{ MYECHO; POP; } + YY_BREAK +case 82: +# line 317 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 83: +# line 319 "lit-deatify.lex" +{ if (--unmatched_lbraces == 0) { + MYECHO; + POP; + } else { + myprintstr("\001rbrace\003"); + } + } + YY_BREAK +case 84: +# line 327 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 85: +# line 330 "lit-deatify.lex" +{ + myprintstr("\\codeInText{"); /* no newline */ + PUSH(Atting); + } + YY_BREAK +case 86: +# line 334 "lit-deatify.lex" +{ MYECHO; /* NB: magic <Index> chars below */ } + YY_BREAK +case 87: +# line 336 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 88: +# line 339 "lit-deatify.lex" +{ + myprintstr("\\MathMode{"); /* no newline */ + PUSH(Math); + } + YY_BREAK +case 89: +# line 343 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 90: +# line 345 "lit-deatify.lex" +{ + MYECHO; + } + YY_BREAK +case 91: +# line 348 "lit-deatify.lex" +{ + /* see earlier comments about crimes against humanity */ + unput('>'); unput('\n'); unput('\n'); + } + YY_BREAK +case 92: +# line 352 "lit-deatify.lex" +{ /* throw away */ + lineno++; + lineno_fiddled++; + } + YY_BREAK +case 93: +# line 356 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 94: +# line 358 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 95: +# line 359 "lit-deatify.lex" +{ MYECHO; PUSH(Linify_brackets); } + YY_BREAK +case 96: +# line 361 "lit-deatify.lex" +{ myprintstr("\\\001rbracket\003"); /* cannot have these in the way */ } + YY_BREAK +case 97: +# line 362 "lit-deatify.lex" +{ if (LEX_NEXT_TO_STK_TOP == Norm) { + MYECHO; + } else { + myprintstr("\001rbracket\003\{"); + not_OK("WHAT'S GOING ON? ]{\n"); + print_lex_stk(); + } + CHG_TOP(Linify_braces); + } + YY_BREAK +case 98: +# line 371 "lit-deatify.lex" +{ if (LEX_NEXT_TO_STK_TOP == Norm) { + MYECHO; + } else { + myprintstr("\001rbracket\003"); + } + POP; + } + YY_BREAK +case 99: +# line 379 "lit-deatify.lex" +{ MYECHO; /* my pseudo-makeindex has two magic chars */ } + YY_BREAK +case 100: +# line 380 "lit-deatify.lex" +{ myprintstr("\001idxsort\003"); } + YY_BREAK +case 101: +# line 381 "lit-deatify.lex" +{ MYECHO; } + YY_BREAK +case 102: +# line 382 "lit-deatify.lex" +{ myprintstr("\001idxsubitem\003"); } + YY_BREAK +case 103: +# line 384 "lit-deatify.lex" +{ + lineno++; + lineno_fiddled++; + if (LEX_STK_TOP == Index) { + warning("I'm turning a newline inside an \\index{...} into a space\n"); + myprintstr(" "); + } else if (LEX_STK_TOP == Typing) { + warning("I'm turning a newline inside a \\tr{...} or \\pl{...} into a space\n"); + myprintstr(" "); + } else { + myprintstr("\001newline\003"); + } + } + YY_BREAK +case 104: +# line 398 "lit-deatify.lex" +{ + MYECHO; /* tiny efficiency */ + } + YY_BREAK +case 105: +# line 402 "lit-deatify.lex" +{ MYECHO; /* catch all */ } + YY_BREAK +case YY_STATE_EOF(Index): +# line 404 "lit-deatify.lex" +{ not_OK("unexpected end-of-file inside an \\index{...}\n"); + exit(1); + } + YY_BREAK +case YY_STATE_EOF(Linify_braces): +# line 407 "lit-deatify.lex" +{ not_OK("unexpected end-of-file inside a macro argument\n"); + exit(1); + } + YY_BREAK +case YY_STATE_EOF(Linify_brackets): +# line 410 "lit-deatify.lex" +{not_OK("unexpected end-of-file inside a macro optional argument\n"); + exit(1); + } + YY_BREAK +case YY_STATE_EOF(Typing): +# line 413 "lit-deatify.lex" +{ not_OK("unexpected end-of-file inside a \\tr{...}\n"); + exit(1); + } + YY_BREAK +case 110: +# line 416 "lit-deatify.lex" +ECHO; + YY_BREAK +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* amount of text matched not including the EOB char */ + int yy_amount_of_matched_text = yy_cp - yytext - 1; + + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + + /* note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the end- + * of-buffer state). Contrast this with the test in yyinput(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* this was really a NUL */ + { + yy_state_type yy_next_state; + + yy_c_buf_p = yytext + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* okay, we're now positioned to make the + * NUL transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we + * don't want to build jamming into it because + * then it will run more slowly) + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* consume the NUL */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* note: because we've taken care in + * yy_get_next_buffer() to have set up yytext, + * we can now set up yy_c_buf_p so that if some + * total hoser (like flex itself) wants + * to call the scanner after we return the + * YY_NULL, it'll still work - another YY_NULL + * will get returned. + */ + yy_c_buf_p = yytext + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF((yy_start - 1) / 2); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + } + break; + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: +#ifdef FLEX_DEBUG + printf( "action # %d\n", yy_act ); +#endif + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } + } + } + + +/* yy_get_next_buffer - try to read in a new buffer + * + * synopsis + * int yy_get_next_buffer(); + * + * returns a code representing an action + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + + { + register YY_CHAR *dest = yy_current_buffer->yy_ch_buf; + register YY_CHAR *source = yytext - 1; /* copy prev. char, too */ + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + /* try to read more data */ + + /* first move last chars to start of buffer */ + number_to_move = yy_c_buf_p - yytext; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_eof_status != EOF_NOT_SEEN ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_n_chars = 0; + + else + { + int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + else if ( num_to_read <= 0 ) + YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); + + /* read in more data */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == 1 ) + { + ret_val = EOB_ACT_END_OF_FILE; + yy_current_buffer->yy_eof_status = EOF_DONE; + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_eof_status = EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + /* yytext begins at the second character in yy_ch_buf; the first + * character is the one which preceded it before reading in the latest + * buffer; it needs to be kept around in case it's a newline, so + * yy_get_previous_state() will have with '^' rules active + */ + + yytext = &yy_current_buffer->yy_ch_buf[1]; + + return ( ret_val ); + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached + * + * synopsis + * yy_state_type yy_get_previous_state(); + */ + +static yy_state_type yy_get_previous_state() + + { + register yy_state_type yy_current_state; + register YY_CHAR *yy_cp; + + register YY_CHAR *yy_bp = yytext; + + yy_current_state = yy_start; + if ( yy_bp[-1] == '\n' ) + ++yy_current_state; + + for ( yy_cp = yytext + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[*yy_cp] : 2); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 398 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return ( yy_current_state ); + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( register yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +register yy_state_type yy_current_state; +#endif + + { + register int yy_is_jam; + register YY_CHAR *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 2; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 398 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 397); + + return ( yy_is_jam ? 0 : yy_current_state ); + } + + +#ifdef YY_USE_PROTOS +static void yyunput( YY_CHAR c, register YY_CHAR *yy_bp ) +#else +static void yyunput( c, yy_bp ) +YY_CHAR c; +register YY_CHAR *yy_bp; +#endif + + { + register YY_CHAR *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + register int number_to_move = yy_n_chars + 2; /* +2 for EOB chars */ + register YY_CHAR *dest = + &yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size + 2]; + register YY_CHAR *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += dest - source; + yy_bp += dest - source; + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + if ( yy_cp > yy_bp && yy_cp[-1] == '\n' ) + yy_cp[-2] = '\n'; + + *--yy_cp = c; + + /* note: the formal parameter *must* be called "yy_bp" for this + * macro to now work correctly + */ + YY_DO_BEFORE_ACTION; /* set up yytext again */ + } + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + + { + int c; + YY_CHAR *yy_cp = yy_c_buf_p; + + *yy_cp = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* this was really a NUL */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + yytext = yy_c_buf_p; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + { + yy_c_buf_p = yytext + YY_MORE_ADJ; + return ( EOF ); + } + + YY_NEW_FILE; + +#ifdef __cplusplus + return ( yyinput() ); +#else + return ( input() ); +#endif + } + break; + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext + YY_MORE_ADJ; + break; + + case EOB_ACT_LAST_MATCH: +#ifdef __cplusplus + YY_FATAL_ERROR( "unexpected last match in yyinput()" ); +#else + YY_FATAL_ERROR( "unexpected last match in input()" ); +#endif + } + } + } + + c = *yy_c_buf_p; + yy_hold_char = *++yy_c_buf_p; + + return ( c ); + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + + { + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* flush out information for old buffer */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* we don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) malloc( sizeof( struct yy_buffer_state ) ); + + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (YY_CHAR *) malloc( (unsigned) (b->yy_buf_size + 2) ); + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + yy_init_buffer( b, file ); + + return ( b ); + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + free( (char *) b->yy_ch_buf ); + free( (char *) b ); + } + + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + { + b->yy_input_file = file; + + /* we put in the '\n' and start reading from [1] so that an + * initial match-at-newline will be true. + */ + + b->yy_ch_buf[0] = '\n'; + b->yy_n_chars = 1; + + /* we always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[1]; + + b->yy_eof_status = EOF_NOT_SEEN; + } +# line 416 "lit-deatify.lex" + + +main(argc, argv) +int argc; +char **argv; +{ + if (argc != 5) { + fprintf(stderr,"Sorry, %s must have exactly 4 arguments\n", argv[0]); + exit(1); + } + verbose = argv[1][0] - '0'; /* hacks */ + follow_inputs = argv[2][0] - '0'; + lit2what = argv[3][0] - '0'; /* used in IS_LIT2xxx tests */ + if (strcmp(argv[4], "-") == 0) { + yyin = stdin; + } else if ((yyin = fopen(argv[4], "r")) == NULL) { + fprintf(stderr,"%s: can't open file %s\n", argv[0], argv[4]); + exit(1); + } + strcpy(srcfile_name, argv[4]); + inputfile_stk[ inputfile_stk_top /* 0 */ ].name = argv[4]; + if ( ! IS_LIT2PGM_Q ) printf("srcfile!_!%s!_!1!_!\n",argv[4]); + yylex(); + exit(exit_status); +} + +void +push_inputfile (fname) +char* fname; +{ + if ( inputfile_stk_top >= INPUTFILE_STK_SIZE ) { + fprintf(stderr,"\\input's too deeply nested\n"); + exit(1); + } + + /* record where we are in current file */ + inputfile_stk[ inputfile_stk_top ].lineno = lineno; + inputfile_stk[ inputfile_stk_top ].handle = YY_CURRENT_BUFFER; + /* actual push */ + inputfile_stk_top++; + + /* open new file fname */ + if ((yyin = fopen(fname, "r")) == NULL) { + fprintf(stderr,"%s:%d: can't open \\input file %s\n", srcfile_name, lineno, fname); + exit(1); + } + yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); + + /* report that's where we are */ + if (! IS_LIT2PGM_Q) printf("srcfile!_!%s!_!1!_!\n",fname); + /* set srcfile_name and lineno for new file */ + + strcpy(srcfile_name, fname); /* for my own tracking */ + lineno = 1; + + /* push/record everything for new file */ + inputfile_stk[ inputfile_stk_top ].name = srcfile_name; + inputfile_stk[ inputfile_stk_top ].lineno = lineno; +} + +void +pop_inputfile () +{ + inputfile_stk_top--; /* actual pop */ + + /* remind where we were */ + strcpy(srcfile_name, inputfile_stk[inputfile_stk_top].name); + lineno = inputfile_stk[inputfile_stk_top].lineno; + /* put in an extra newline or two before the next file; + otherwise, the cat'ting of files gives things like: + + > last line of code + \section{Next section} + + which happens to be very bad for lit2stuff. + */ + if (! IS_LIT2PGM_Q) printf("\n\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + + /* return to prev inputfile */ + yy_switch_to_buffer( inputfile_stk[inputfile_stk_top].handle ); +} + +void +myecho () +{ + myprintstr(yytext); +} + +void +myprintstr (str) +char *str; +{ + if (SHLD_PRINT) { + printf("%s",str); + } +} + +void +print_leading_whitespace () +{ + int i; + + for (i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++) { + putchar(yytext[i]); + } +} + +void +not_OK(msg) +char *msg; +{ + /* a good old emacsable error msg */ + fprintf(stderr,"%s:%d: %s", srcfile_name, lineno, msg); + exit_status++; +} + +void +warning(msg) /* exit_status not fiddled */ +char *msg; +{ + /* a good old emacsable warning msg */ + fprintf(stderr,"%s:%d: [warning] %s", srcfile_name, lineno, msg); +} diff --git a/web/glasgow/lit2x-0.16/literate/lit-deatify.lex b/web/glasgow/lit2x-0.16/literate/lit-deatify.lex new file mode 100644 index 0000000000..8f4079fedc --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-deatify.lex @@ -0,0 +1,538 @@ +%{ +#define LEX_STK_SIZE 256 + +int lex_stk[LEX_STK_SIZE]; +int lex_stk_top = 0; + +#define PUSH(x) lex_stk[++lex_stk_top] = (x); BEGIN(x) +#define POP BEGIN(lex_stk[--lex_stk_top]) +#define LEX_STK_TOP lex_stk[lex_stk_top] +#define LEX_NEXT_TO_STK_TOP lex_stk[lex_stk_top - 1] +#define CHG_TOP(x) lex_stk[lex_stk_top] = (x); BEGIN(x) +#define CHG_NEXT_TO_TOP(x) lex_stk[lex_stk_top - 1] = (x) +/* not a lot in the old stack {over,under}flow dept, what? */ + +extern char *yytext; /* forward decl */ +void print_leading_whitespace(); + +void +print_lex_stk () /* just for debugging */ +{ + int i; + fprintf(stderr,"lex_stk:"); + for (i = lex_stk_top; i >= 0; i--) { + fprintf(stderr," %d",lex_stk[i]); + } + fprintf(stderr,"::%s\n",yytext); +} +int verbose; /* set from first argv */ +int follow_inputs; /* set from second argv */ + +#if defined (SYSV) || defined (SYSV) +#include <string.h> +#include <time.h> +#else +#include <strings.h> +#include <sys/time.h> +#endif + +#if defined (SYSV) +#define index(string, ch) strchr ((string), (ch)) +#endif + +#define INPUTFILE_STK_SIZE 20 +struct { + YY_BUFFER_STATE handle; /* flex-supplied magic */ + char* name; + int lineno; +} inputfile_stk[INPUTFILE_STK_SIZE]; +int inputfile_stk_top = 0; +void push_inputfile(); +void pop_inputfile(); +int i; /* temporary */ +char* rbrace; +int deatify_debug = 0; +int unmatched_lbraces = 0; +int unmatched_lbrackets = 0; + +/* like everything, must track srcfile name and lineno */ +char srcfile_name[1024]; /* too lazy to do this right */ +int lineno = 1; /* count \n's as they go by */ +int lineno_fiddled = 0; /* boolean: incr if newlines get trashed */ + +int exit_status = 0; +void not_OK (); /* prints an error msg and bumps exit_status */ +void warning (); /* same, but no exit-status fiddling */ + +int lit2what; /* set from ARGV */ + +#define IS_LIT2PGM_Q (lit2what == 1) +#define IS_LIT2PGM (lit2what == 2) +#define IS_LIT2TEXI (lit2what == 3) +#define IS_LIT2LATEX (lit2what == 4) +#define IS_LIT2DEPEND (lit2what == 5) +#define IS_LIT2CHANGELOG (lit2what== 6) + +/* the condition for printing to stdout */ +#define SHLD_PRINT (! IS_LIT2PGM_Q || (LEX_STK_TOP == Code || LEX_STK_TOP == Bird)) + +void myecho(); +#define MYECHO myecho() +void myprintstr(); + +#define YY_USER_ACTION if (deatify_debug) print_lex_stk(); /* debugging */ +%} +D [0-9]+ +END_WORD [-~/!\?(),\.'`A-Za-z0-9]*[ \t]* + +%x Norm Verb Code Bird Atting Math Index Typing Linify_braces Linify_brackets +%% + CHG_TOP(Norm); /* that's where we start */ +[\001\002\003] { not_OK("ASCII chars \001, \002, \003 may not appear in literate files\n"); + exit(1); + } +<Norm>^"srcfile!_!"(.+)"!_!"([0-9]+)"!_!"\n { + sscanf(yytext+10,"%[^!]!_!%d", srcfile_name, &lineno); + if (lineno > 0) { + ECHO; + } + } +<Norm>^\\input\{[^\}\n]+\}.*\n { lineno++; + if (follow_inputs) { + /* nullify first right brace */ + rbrace = index(yytext+7,'}'); + *rbrace = '\0'; + push_inputfile(yytext+7); + } else { + MYECHO; + } + } +<Norm,Bird><<EOF>> { if ( inputfile_stk_top <= 0 ) { + yyterminate(); + } else { + pop_inputfile(); + } + CHG_TOP(Norm); /* revert */ + } +<Norm>^\\begin\{verbatim\}.*\n | +<Norm>^\\begin\{flushverbatim\}.*\n | +<Norm>^\\begin\{pseudocode\}.*\n { lineno++; MYECHO; PUSH(Verb); /* some may have opt arg */ } +<Norm>^\\begin\{code\}.*\n { lineno++; + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + } + MYECHO; + PUSH(Code); + } +<Norm>\n[ \t]+\n\> { /* convert to something less weird & try again */ + unput('>'); unput('\n'); unput('\n'); + } +<Norm>\n\n\>.*\n { lineno += 3; + /* NB: init > converted to space */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+3); + } else { + ECHO; + } + PUSH(Bird); + } +<Norm>\n\>.*\n { lineno++; /* so msg will have right line # */ + if (lineno > 2) /* I feel guilty about this hack */ + /* to avoid: file is: blank lines, then code */ + not_OK("Bird-style code not preceded by a blank line\n"); + lineno++; /* account for other \n */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+2); + } else { + ECHO; + } + PUSH(Bird); + } +<Norm>^\>.*\n { lineno++; /* first line of file */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+1); + } else { + ECHO; + } + PUSH(Bird); + } +<Norm>\\author\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\caption\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\centerline\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\date\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\define\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\heading\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\label\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\menuentry\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\node\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\owner\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\[sub]*section{D}?\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\[sub]*section{D}?\[ { MYECHO; PUSH(Linify_brackets); } +<Norm>\\standaloneornot\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\title\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\(tr|pl)\{ { MYECHO; unmatched_lbraces = 1; PUSH(Typing); + /* \tr has braces as literals */ + } +<Norm>\\item\[ { MYECHO; PUSH(Linify_brackets); } +<Norm>\\@ { MYECHO; } +<Norm>@ { myprintstr("\\codeInText{"); PUSH(Atting); } +<Norm>\\\$ { MYECHO; } +<Norm>\$ { myprintstr("\\MathMode{"); PUSH(Math); } +<Norm>\\index\{ { MYECHO; + unmatched_lbraces = 1; + PUSH(Index); + } +<Norm>\\\{ { MYECHO; } +<Norm>\\\} { MYECHO; } +<Norm,Math>\\% { MYECHO; } +<Norm,Math>\%.*\n[ \t]*\n> { /* technically this Bird-style code is wrong + (no blank line in front of it, but that's + not intuitively obvious to the casual observer). + Solution? A hack! + */ + unput('>'); unput('\n'); unput('\n'); + } +<Norm,Math>\%.*\n { /* throw away */ lineno++; + if (! IS_LIT2PGM_Q) + printf("\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + } +<Norm>[A-Za-z0-9 \t]+ { MYECHO; /* slight efficiency */ } +<Norm>. { MYECHO; } +<Norm>\n { /* handle line-number fiddling */ + MYECHO; + lineno++; + if (lineno_fiddled) { + if (! IS_LIT2PGM_Q) + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + lineno_fiddled = 0; + } + } +<Verb>^\\end\{verbatim\} | +<Verb>^\\end\{flushverbatim\} | +<Verb>^\\end\{pseudocode\} { MYECHO; POP; } +<Code>^\\end\{code\} { if (! IS_LIT2PGM_Q) ECHO; POP; } +<Verb,Code>^[^\\\n].*\n { lineno++; MYECHO; /* a line not started by \ */} +<Verb,Code>. { MYECHO; } +<Verb,Code>\n { lineno++; MYECHO; } +<Verb,Code><<EOF>> { not_OK("unexpected end-of-file in verbatim text or (pseudo)code\n"); + exit(1); + } +<Bird>[ \t\n]*\n\>.*\n? { /* whitespace/blank-lines do not matter */ + /* count lines... */ + for (i = 0; i < strlen(yytext); i++) { + if (yytext[i] == '\n') + lineno++; + } + if (! IS_LIT2PGM_Q) { + ECHO; + } else { /* don't print leading whitestuff */ + for (i = 0; i < strlen(yytext) && yytext[i] != '>'; i++) + ; /* no-op */ + /* report where this got us...*/ + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name, + ((yytext[yyleng-1] == '\n') ? (lineno-1) : lineno)); + /* putchar(' '); convert leading > to space */ + for ( i++ ; i < strlen(yytext); i++) + putchar(yytext[i]); + } + } +<Bird>^\>.*\n? { if (yytext[yyleng-1] == '\n') { lineno++; } + if (IS_LIT2PGM_Q) printf("%s",yytext+1); else ECHO; + } +<Bird>[ \t]*\n { lineno++; + if ( ! IS_LIT2PGM_Q) ECHO; + POP; + } +<Bird>. { lineno--; /* to get right # on msg */ + not_OK("Bird-style code not followed by a blank line\n"); + lineno++; /* put it back */ + unput(yytext[0]); + POP; + } +<Atting>@@ { myprintstr("@"); } +<Atting>@\\noindex\{\} | +<Atting>@\\noindex { myprintstr("\001noindex\003}"); + POP; + } +<Atting>@ { myprintstr("}"); + POP; + } +<Atting>\{ { myprintstr("\001lbrace\003"); } +<Atting>\} { myprintstr("\001rbrace\003"); } +<Atting>\n { warning("I'm turning a newline inside a @...@ into a space\n"); + myprintstr(" "); + lineno++; + } + +<Atting><<EOF>> { not_OK("unexpected end-of-file inside an @ ... @\n"); + exit(1); + } +<Atting>[A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } +<Atting>. { MYECHO; } +<Math>\\\$ { MYECHO; } +<Math>\$ { myprintstr("}"); + POP; + } +<Math>\{ { myprintstr("\001lbrace\003"); } +<Math>\} { myprintstr("\001rbrace\003"); } +<Math>\n { myprintstr("\001newline\003"); + lineno++; + } + +<Math><<EOF>> { not_OK("unexpected end-of-file inside $ ... $ (math mode)\n"); + exit(1); + } +<Math>[A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } +<Math>. { MYECHO; } +<Linify_braces,Linify_brackets>\\(tr|pl)\{ { + MYECHO; + unmatched_lbraces = 1; + PUSH(Typing); + } + +<Index,Linify_braces,Linify_brackets,Typing>\\\\ { + MYECHO; + } +<Index,Linify_braces,Linify_brackets,Typing>\\ { + MYECHO; + } +<Linify_braces,Linify_brackets>\\\{ { + MYECHO; + } + +<Linify_braces>\{ { MYECHO; PUSH(Linify_braces); } +<Linify_brackets>\{ { MYECHO; } + +<Index,Typing>\{ { unmatched_lbraces++; myprintstr("\001lbrace\003"); } + +<Linify_braces,Linify_brackets>\\\} { + MYECHO; + } +<Linify_braces>\}\{ { /* next arg */ MYECHO; } + +<Linify_braces>\} { MYECHO; POP; } +<Linify_brackets>\} { MYECHO; } + +<Index,Typing>\} { if (--unmatched_lbraces == 0) { + MYECHO; + POP; + } else { + myprintstr("\001rbrace\003"); + } + } + +<Index,Linify_braces,Linify_brackets,Typing>\\@ { + MYECHO; + } +<Linify_braces,Linify_brackets>@ { + myprintstr("\\codeInText{"); /* no newline */ + PUSH(Atting); + } +<Typing>@ { MYECHO; /* NB: magic <Index> chars below */ } + +<Index,Linify_braces,Linify_brackets,Typing>\\\$ { + MYECHO; + } +<Linify_braces,Linify_brackets>\$ { + myprintstr("\\MathMode{"); /* no newline */ + PUSH(Math); + } +<Index,Typing>\$ { MYECHO; } + +<Index,Linify_braces,Linify_brackets,Typing>\\% { + MYECHO; + } +<Linify_braces,Linify_brackets>\%.*\n[ \t]*\n> { + /* see earlier comments about crimes against humanity */ + unput('>'); unput('\n'); unput('\n'); + } +<Linify_braces,Linify_brackets>\%.*\n { /* throw away */ + lineno++; + lineno_fiddled++; + } +<Index,Typing>% { MYECHO; } + +<Linify_brackets>\\\[ { MYECHO; } +<Linify_brackets>\[ { MYECHO; PUSH(Linify_brackets); } + +<Linify_brackets>\\\] { myprintstr("\\\001rbracket\003"); /* cannot have these in the way */ } +<Linify_brackets>\]\{ { if (LEX_NEXT_TO_STK_TOP == Norm) { + MYECHO; + } else { + myprintstr("\001rbracket\003\{"); + not_OK("WHAT'S GOING ON? ]{\n"); + print_lex_stk(); + } + CHG_TOP(Linify_braces); + } +<Linify_brackets>\] { if (LEX_NEXT_TO_STK_TOP == Norm) { + MYECHO; + } else { + myprintstr("\001rbracket\003"); + } + POP; + } + +<Index>\\\@ { MYECHO; /* my pseudo-makeindex has two magic chars */ } +<Index>\@ { myprintstr("\001idxsort\003"); } +<Index>\\! { MYECHO; } +<Index>\! { myprintstr("\001idxsubitem\003"); } + +<Index,Linify_braces,Linify_brackets,Typing>\n { + lineno++; + lineno_fiddled++; + if (LEX_STK_TOP == Index) { + warning("I'm turning a newline inside an \\index{...} into a space\n"); + myprintstr(" "); + } else if (LEX_STK_TOP == Typing) { + warning("I'm turning a newline inside a \\tr{...} or \\pl{...} into a space\n"); + myprintstr(" "); + } else { + myprintstr("\001newline\003"); + } + } + +<Index,Linify_braces,Linify_brackets,Typing>[A-Za-z0-9 \t]+ { + MYECHO; /* tiny efficiency */ + } + +<Index,Linify_braces,Linify_brackets,Typing>. { MYECHO; /* catch all */ } + +<Index><<EOF>> { not_OK("unexpected end-of-file inside an \\index{...}\n"); + exit(1); + } +<Linify_braces><<EOF>> { not_OK("unexpected end-of-file inside a macro argument\n"); + exit(1); + } +<Linify_brackets><<EOF>> {not_OK("unexpected end-of-file inside a macro optional argument\n"); + exit(1); + } +<Typing><<EOF>> { not_OK("unexpected end-of-file inside a \\tr{...}\n"); + exit(1); + } +%% + +main(argc, argv) +int argc; +char **argv; +{ + if (argc != 5) { + fprintf(stderr,"Sorry, %s must have exactly 4 arguments\n", argv[0]); + exit(1); + } + verbose = argv[1][0] - '0'; /* hacks */ + follow_inputs = argv[2][0] - '0'; + lit2what = argv[3][0] - '0'; /* used in IS_LIT2xxx tests */ + if (strcmp(argv[4], "-") == 0) { + yyin = stdin; + } else if ((yyin = fopen(argv[4], "r")) == NULL) { + fprintf(stderr,"%s: can't open file %s\n", argv[0], argv[4]); + exit(1); + } + strcpy(srcfile_name, argv[4]); + inputfile_stk[ inputfile_stk_top /* 0 */ ].name = argv[4]; + if ( ! IS_LIT2PGM_Q ) printf("srcfile!_!%s!_!1!_!\n",argv[4]); + yylex(); + exit(exit_status); +} + +void +push_inputfile (fname) +char* fname; +{ + if ( inputfile_stk_top >= INPUTFILE_STK_SIZE ) { + fprintf(stderr,"\\input's too deeply nested\n"); + exit(1); + } + + /* record where we are in current file */ + inputfile_stk[ inputfile_stk_top ].lineno = lineno; + inputfile_stk[ inputfile_stk_top ].handle = YY_CURRENT_BUFFER; + /* actual push */ + inputfile_stk_top++; + + /* open new file fname */ + if ((yyin = fopen(fname, "r")) == NULL) { + fprintf(stderr,"%s:%d: can't open \\input file %s\n", srcfile_name, lineno, fname); + exit(1); + } + yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); + + /* report that's where we are */ + if (! IS_LIT2PGM_Q) printf("srcfile!_!%s!_!1!_!\n",fname); + /* set srcfile_name and lineno for new file */ + + strcpy(srcfile_name, fname); /* for my own tracking */ + lineno = 1; + + /* push/record everything for new file */ + inputfile_stk[ inputfile_stk_top ].name = srcfile_name; + inputfile_stk[ inputfile_stk_top ].lineno = lineno; +} + +void +pop_inputfile () +{ + inputfile_stk_top--; /* actual pop */ + + /* remind where we were */ + strcpy(srcfile_name, inputfile_stk[inputfile_stk_top].name); + lineno = inputfile_stk[inputfile_stk_top].lineno; + /* put in an extra newline or two before the next file; + otherwise, the cat'ting of files gives things like: + + > last line of code + \section{Next section} + + which happens to be very bad for lit2stuff. + */ + if (! IS_LIT2PGM_Q) printf("\n\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + + /* return to prev inputfile */ + yy_switch_to_buffer( inputfile_stk[inputfile_stk_top].handle ); +} + +void +myecho () +{ + myprintstr(yytext); +} + +void +myprintstr (str) +char *str; +{ + if (SHLD_PRINT) { + printf("%s",str); + } +} + +void +print_leading_whitespace () +{ + int i; + + for (i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++) { + putchar(yytext[i]); + } +} + +void +not_OK(msg) +char *msg; +{ + /* a good old emacsable error msg */ + fprintf(stderr,"%s:%d: %s", srcfile_name, lineno, msg); + exit_status++; +} + +void +warning(msg) /* exit_status not fiddled */ +char *msg; +{ + /* a good old emacsable warning msg */ + fprintf(stderr,"%s:%d: [warning] %s", srcfile_name, lineno, msg); +} diff --git a/web/glasgow/lit2x-0.16/literate/lit-deatify.llex b/web/glasgow/lit2x-0.16/literate/lit-deatify.llex new file mode 100644 index 0000000000..45c43efb12 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-deatify.llex @@ -0,0 +1,669 @@ +\section[De-at-ifier]{Handles `at' and `tr' shorthands} + +[Taking over from lit-inputter, minus the LITINPUTS stuff] + +Has to know whether \tr{lit2pgm}, \tr{lit2latex} or \tr{lit2texi} +(grabbed from deviously-passed command-line argument). + +And makes index entries appear well-behaved (same as \tr{\tr}, really). + +And nukes [most] comments (sigh). + +\subsection[deatify_Definitions]{Lex definitions} + +Here, we use \tr{lex} ``start conditions'' a lot; we keep a stack of +them and manipulate them in a fairly obvious way. Using start +conditions like this gives you ``mini-lexers'' within the overall +lexer. +\begin{code} +%{ +#define LEX_STK_SIZE 256 + +int lex_stk[LEX_STK_SIZE]; +int lex_stk_top = 0; + +#define PUSH(x) lex_stk[++lex_stk_top] = (x); BEGIN(x) +#define POP BEGIN(lex_stk[--lex_stk_top]) +#define LEX_STK_TOP lex_stk[lex_stk_top] +#define LEX_NEXT_TO_STK_TOP lex_stk[lex_stk_top - 1] +#define CHG_TOP(x) lex_stk[lex_stk_top] = (x); BEGIN(x) +#define CHG_NEXT_TO_TOP(x) lex_stk[lex_stk_top - 1] = (x) +/* not a lot in the old stack {over,under}flow dept, what? */ + +extern char *yytext; /* forward decl */ +void print_leading_whitespace(); + +void +print_lex_stk () /* just for debugging */ +{ + int i; + fprintf(stderr,"lex_stk:"); + for (i = lex_stk_top; i >= 0; i--) { + fprintf(stderr," %d",lex_stk[i]); + } + fprintf(stderr,"::%s\n",yytext); +} +\end{code} + +Things related to handling \tr{\input} commands (not doing this at the +moment): +\begin{code} +int verbose; /* set from first argv */ +int follow_inputs; /* set from second argv */ + +#if defined (SYSV) || defined (SYSV) +#include <string.h> +#include <time.h> +#else +#include <strings.h> +#include <sys/time.h> +#endif + +#if defined (SYSV) +#define index(string, ch) strchr ((string), (ch)) +#endif + +#define INPUTFILE_STK_SIZE 20 +struct { + YY_BUFFER_STATE handle; /* flex-supplied magic */ + char* name; + int lineno; +} inputfile_stk[INPUTFILE_STK_SIZE]; +int inputfile_stk_top = 0; +void push_inputfile(); +void pop_inputfile(); +int i; /* temporary */ +char* rbrace; +\end{code} + +\begin{code} +int deatify_debug = 0; +int unmatched_lbraces = 0; +int unmatched_lbrackets = 0; + +/* like everything, must track srcfile name and lineno */ +char srcfile_name[1024]; /* too lazy to do this right */ +int lineno = 1; /* count \n's as they go by */ +int lineno_fiddled = 0; /* boolean: incr if newlines get trashed */ + +int exit_status = 0; +void not_OK (); /* prints an error msg and bumps exit_status */ +void warning (); /* same, but no exit-status fiddling */ + +int lit2what; /* set from ARGV */ + +#define IS_LIT2PGM_Q (lit2what == 1) +#define IS_LIT2PGM (lit2what == 2) +#define IS_LIT2TEXI (lit2what == 3) +#define IS_LIT2LATEX (lit2what == 4) +#define IS_LIT2DEPEND (lit2what == 5) +#define IS_LIT2CHANGELOG (lit2what== 6) + +/* the condition for printing to stdout */ +#define SHLD_PRINT (! IS_LIT2PGM_Q || (LEX_STK_TOP == Code || LEX_STK_TOP == Bird)) + +void myecho(); +#define MYECHO myecho() +void myprintstr(); + +#define YY_USER_ACTION if (deatify_debug) print_lex_stk(); /* debugging */ +%} +D [0-9]+ +END_WORD [-~/!\?(),\.'`A-Za-z0-9]*[ \t]* + +%x Norm Verb Code Bird Atting Math Index Typing Linify_braces Linify_brackets +%% + CHG_TOP(Norm); /* that's where we start */ +\end{code} + +\subsection[deatify_Rules]{Lex rules} + +We start as @<Norm>@ and branch off to one of the other +``mini-scanners'' when we see certain things. + +First: some magic characters absolutely verboten in the input: +\begin{code} +[\001\002\003] { not_OK("ASCII chars \001, \002, \003 may not appear in literate files\n"); + exit(1); + } +\end{code} + + +% um... we're generating these here now... +% (sorry, wrongo, buddy) +First thing is the magic source-file tracking lines (only in +\tr{<Norm>}, I think): +\begin{code} +<Norm>^"srcfile!_!"(.+)"!_!"([0-9]+)"!_!"\n { + sscanf(yytext+10,"%[^!]!_!%d", srcfile_name, &lineno); + if (lineno > 0) { + ECHO; + } + } +\end{code} + +Now a bit of stuff to handle \tr{\input} lines: +\begin{code} +<Norm>^\\input\{[^\}\n]+\}.*\n { lineno++; + if (follow_inputs) { + /* nullify first right brace */ + rbrace = index(yytext+7,'}'); + *rbrace = '\0'; + push_inputfile(yytext+7); + } else { + MYECHO; + } + } +<Norm,Bird><<EOF>> { if ( inputfile_stk_top <= 0 ) { + yyterminate(); + } else { + pop_inputfile(); + } + CHG_TOP(Norm); /* revert */ + } +\end{code} + + +Code and verbatim stuff gets copied through absolutely unmangled, +using the @<Verb>@ (or almost equivalently @<Code>@) mini-scanner. +\begin{code} +<Norm>^\\begin\{verbatim\}.*\n | +<Norm>^\\begin\{flushverbatim\}.*\n | +<Norm>^\\begin\{pseudocode\}.*\n { lineno++; MYECHO; PUSH(Verb); /* some may have opt arg */ } +<Norm>^\\begin\{code\}.*\n { lineno++; + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + } + MYECHO; + PUSH(Code); + } +\end{code} + +Then there's the \tr{>} business; the ugliest way ever invented for +writing programs. You can only get there from \tr{<Norm>}, because I +said so. + +\begin{code} +<Norm>\n[ \t]+\n\> { /* convert to something less weird & try again */ + unput('>'); unput('\n'); unput('\n'); + } +<Norm>\n\n\>.*\n { lineno += 3; + /* NB: init > converted to space */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+3); + } else { + ECHO; + } + PUSH(Bird); + } +<Norm>\n\>.*\n { lineno++; /* so msg will have right line # */ + if (lineno > 2) /* I feel guilty about this hack */ + /* to avoid: file is: blank lines, then code */ + not_OK("Bird-style code not preceded by a blank line\n"); + lineno++; /* account for other \n */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+2); + } else { + ECHO; + } + PUSH(Bird); + } +<Norm>^\>.*\n { lineno++; /* first line of file */ + if (IS_LIT2PGM_Q) { + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); + printf("%s",yytext+1); + } else { + ECHO; + } + PUSH(Bird); + } +\end{code} + +There are a few macros (\tr{\section}, \tr{\author}, and the others +below) that may have funny \tr{@...@}'s, etc., in them (meaning +newlines would be inserted normally); these newlines must be +suppressed! These macros send us off to \tr{<Linify_braces>} or +\tr{<Linify_brackets>}, which are like \tr{<Norm>} except that the +\tr{unput} newlines (below) get munched. (This is getting really +horrible...) + +\begin{code} +<Norm>\\author\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\caption\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\centerline\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\date\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\define\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\heading\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\label\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\menuentry\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\node\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\owner\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\[sub]*section{D}?\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\[sub]*section{D}?\[ { MYECHO; PUSH(Linify_brackets); } +<Norm>\\standaloneornot\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\title\{ { MYECHO; PUSH(Linify_braces); } +<Norm>\\(tr|pl)\{ { MYECHO; unmatched_lbraces = 1; PUSH(Typing); + /* \tr has braces as literals */ + } +<Norm>\\item\[ { MYECHO; PUSH(Linify_brackets); } +\end{code} + +Similarly, an \tr{@} sends us off to @<Atting>@. Of course, a \tr{\@} doesn't. +\begin{code} +<Norm>\\@ { MYECHO; } +<Norm>@ { myprintstr("\\codeInText{"); PUSH(Atting); } +\end{code} + +Simple math mode stuff. + +\begin{code} +<Norm>\\\$ { MYECHO; } +<Norm>\$ { myprintstr("\\MathMode{"); PUSH(Math); } +\end{code} + +For index commands, we want them to be at the beginning of a line (we do?); +hence the @printf@'s here. The internal magic is done by +@<Index>@. +\begin{code} +<Norm>\\index\{ { MYECHO; + unmatched_lbraces = 1; + PUSH(Index); + } +\end{code} + +The rest of the @<Norm>@ mini-scanner handles comments and echoes +everything else. +\begin{code} +<Norm>\\\{ { MYECHO; } +<Norm>\\\} { MYECHO; } +<Norm,Math>\\% { MYECHO; } +<Norm,Math>\%.*\n[ \t]*\n> { /* technically this Bird-style code is wrong + (no blank line in front of it, but that's + not intuitively obvious to the casual observer). + Solution? A hack! + */ + unput('>'); unput('\n'); unput('\n'); + } +<Norm,Math>\%.*\n { /* throw away */ lineno++; + if (! IS_LIT2PGM_Q) + printf("\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + } +<Norm>[A-Za-z0-9 \t]+ { MYECHO; /* slight efficiency */ } +<Norm>. { MYECHO; } +<Norm>\n { /* handle line-number fiddling */ + MYECHO; + lineno++; + if (lineno_fiddled) { + if (! IS_LIT2PGM_Q) + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + lineno_fiddled = 0; + } + } +\end{code} + +The \tr{<Verb>} and \tr{<Code>} mini-scanners pass everything through until it sees an +\tr{\end <something>}. As it stands, the \tr{<something>} doesn't +have to be what was \tr{\begun} (bug). +\begin{code} +<Verb>^\\end\{verbatim\} | +<Verb>^\\end\{flushverbatim\} | +<Verb>^\\end\{pseudocode\} { MYECHO; POP; } +<Code>^\\end\{code\} { if (! IS_LIT2PGM_Q) ECHO; POP; } +<Verb,Code>^[^\\\n].*\n { lineno++; MYECHO; /* a line not started by \ */} +<Verb,Code>. { MYECHO; } +<Verb,Code>\n { lineno++; MYECHO; } +<Verb,Code><<EOF>> { not_OK("unexpected end-of-file in verbatim text or (pseudo)code\n"); + exit(1); + } +\end{code} + +The \tr{<Bird>} mini-scanner is here only to check for +no-blank-line-after errors in uglyly-written code. +\begin{code} +<Bird>[ \t\n]*\n\>.*\n? { /* whitespace/blank-lines do not matter */ + /* count lines... */ + for (i = 0; i < strlen(yytext); i++) { + if (yytext[i] == '\n') + lineno++; + } + if (! IS_LIT2PGM_Q) { + ECHO; + } else { /* don't print leading whitestuff */ + for (i = 0; i < strlen(yytext) && yytext[i] != '>'; i++) + ; /* no-op */ + /* report where this got us...*/ + printf("srcfile!_!%s!_!%d!_!\n",srcfile_name, + ((yytext[yyleng-1] == '\n') ? (lineno-1) : lineno)); + /* putchar(' '); convert leading > to space */ + for ( i++ ; i < strlen(yytext); i++) + putchar(yytext[i]); + } + } +<Bird>^\>.*\n? { if (yytext[yyleng-1] == '\n') { lineno++; } + if (IS_LIT2PGM_Q) printf("%s",yytext+1); else ECHO; + } +<Bird>[ \t]*\n { lineno++; + if ( ! IS_LIT2PGM_Q) ECHO; + POP; + } +<Bird>. { lineno--; /* to get right # on msg */ + not_OK("Bird-style code not followed by a blank line\n"); + lineno++; /* put it back */ + unput(yytext[0]); + POP; + } +\end{code} + +\tr{<Typing>} and \tr{<Index>} deal with braces the same way: these +rules must come before the default rules for \tr{<Typing>.} and +\tr{<Index>.}. + +The rule of the @<Atting>@ game is to send everything through except +right braces and newlines (which break the use of @/[^\}]+/@ regexps). +No longer worry about one per line. + +\begin{code} +<Atting>@@ { myprintstr("@"); } +<Atting>@\\noindex\{\} | +<Atting>@\\noindex { myprintstr("\001noindex\003}"); + POP; + } +<Atting>@ { myprintstr("}"); + POP; + } +<Atting>\{ { myprintstr("\001lbrace\003"); } +<Atting>\} { myprintstr("\001rbrace\003"); } +<Atting>\n { warning("I'm turning a newline inside a @...@ into a space\n"); + myprintstr(" "); + lineno++; + } + +<Atting><<EOF>> { not_OK("unexpected end-of-file inside an @ ... @\n"); + exit(1); + } +<Atting>[A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } +<Atting>. { MYECHO; } +\end{code} + +Math mode stuff. At present, only extra work is to replace some +control sequences with plain text---for \tr{lit2texi} only. + +\begin{code} +<Math>\\\$ { MYECHO; } +<Math>\$ { myprintstr("}"); + POP; + } +<Math>\{ { myprintstr("\001lbrace\003"); } +<Math>\} { myprintstr("\001rbrace\003"); } +<Math>\n { myprintstr("\001newline\003"); + lineno++; + } + +<Math><<EOF>> { not_OK("unexpected end-of-file inside $ ... $ (math mode)\n"); + exit(1); + } +<Math>[A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } +<Math>. { MYECHO; } +\end{code} + +The braces/brackets stuff isn't too bad. Well, there's the stuff for +\tr{\tr} and \tr{@..@}'s (no \tr{\index}'s now...) ... +\begin{code} +<Linify_braces,Linify_brackets>\\(tr|pl)\{ { + MYECHO; + unmatched_lbraces = 1; + PUSH(Typing); + } + +<Index,Linify_braces,Linify_brackets,Typing>\\\\ { + MYECHO; + } +<Index,Linify_braces,Linify_brackets,Typing>\\ { + MYECHO; + } +<Linify_braces,Linify_brackets>\\\{ { + MYECHO; + } + +<Linify_braces>\{ { MYECHO; PUSH(Linify_braces); } +<Linify_brackets>\{ { MYECHO; } + +<Index,Typing>\{ { unmatched_lbraces++; myprintstr("\001lbrace\003"); } + +<Linify_braces,Linify_brackets>\\\} { + MYECHO; + } +<Linify_braces>\}\{ { /* next arg */ MYECHO; } + +<Linify_braces>\} { MYECHO; POP; } +<Linify_brackets>\} { MYECHO; } + +<Index,Typing>\} { if (--unmatched_lbraces == 0) { + MYECHO; + POP; + } else { + myprintstr("\001rbrace\003"); + } + } + +<Index,Linify_braces,Linify_brackets,Typing>\\@ { + MYECHO; + } +<Linify_braces,Linify_brackets>@ { + myprintstr("\\codeInText{"); /* no newline */ + PUSH(Atting); + } +<Typing>@ { MYECHO; /* NB: magic <Index> chars below */ } + +<Index,Linify_braces,Linify_brackets,Typing>\\\$ { + MYECHO; + } +<Linify_braces,Linify_brackets>\$ { + myprintstr("\\MathMode{"); /* no newline */ + PUSH(Math); + } +<Index,Typing>\$ { MYECHO; } + +<Index,Linify_braces,Linify_brackets,Typing>\\% { + MYECHO; + } +<Linify_braces,Linify_brackets>\%.*\n[ \t]*\n> { + /* see earlier comments about crimes against humanity */ + unput('>'); unput('\n'); unput('\n'); + } +<Linify_braces,Linify_brackets>\%.*\n { /* throw away */ + lineno++; + lineno_fiddled++; + } +<Index,Typing>% { MYECHO; } + +<Linify_brackets>\\\[ { MYECHO; } +<Linify_brackets>\[ { MYECHO; PUSH(Linify_brackets); } + +<Linify_brackets>\\\] { myprintstr("\\\001rbracket\003"); /* cannot have these in the way */ } +<Linify_brackets>\]\{ { if (LEX_NEXT_TO_STK_TOP == Norm) { + MYECHO; + } else { + myprintstr("\001rbracket\003\{"); + not_OK("WHAT'S GOING ON? ]{\n"); + print_lex_stk(); + } + CHG_TOP(Linify_braces); + } +<Linify_brackets>\] { if (LEX_NEXT_TO_STK_TOP == Norm) { + MYECHO; + } else { + myprintstr("\001rbracket\003"); + } + POP; + } + +<Index>\\\@ { MYECHO; /* my pseudo-makeindex has two magic chars */ } +<Index>\@ { myprintstr("\001idxsort\003"); } +<Index>\\! { MYECHO; } +<Index>\! { myprintstr("\001idxsubitem\003"); } + +<Index,Linify_braces,Linify_brackets,Typing>\n { + lineno++; + lineno_fiddled++; + if (LEX_STK_TOP == Index) { + warning("I'm turning a newline inside an \\index{...} into a space\n"); + myprintstr(" "); + } else if (LEX_STK_TOP == Typing) { + warning("I'm turning a newline inside a \\tr{...} or \\pl{...} into a space\n"); + myprintstr(" "); + } else { + myprintstr("\001newline\003"); + } + } + +<Index,Linify_braces,Linify_brackets,Typing>[A-Za-z0-9 \t]+ { + MYECHO; /* tiny efficiency */ + } + +<Index,Linify_braces,Linify_brackets,Typing>. { MYECHO; /* catch all */ } + +<Index><<EOF>> { not_OK("unexpected end-of-file inside an \\index{...}\n"); + exit(1); + } +<Linify_braces><<EOF>> { not_OK("unexpected end-of-file inside a macro argument\n"); + exit(1); + } +<Linify_brackets><<EOF>> {not_OK("unexpected end-of-file inside a macro optional argument\n"); + exit(1); + } +<Typing><<EOF>> { not_OK("unexpected end-of-file inside a \\tr{...}\n"); + exit(1); + } +\end{code} + +Finally, we have a non-default @main@ routine because we need to pick +up the (mandatory) argument that says if we're doing pre-processing +for \tr{lit2pgm}, \tr{lit2latex}, or \tr{lit2texi}. +\begin{code} +%% + +main(argc, argv) +int argc; +char **argv; +{ + if (argc != 5) { + fprintf(stderr,"Sorry, %s must have exactly 4 arguments\n", argv[0]); + exit(1); + } + verbose = argv[1][0] - '0'; /* hacks */ + follow_inputs = argv[2][0] - '0'; + lit2what = argv[3][0] - '0'; /* used in IS_LIT2xxx tests */ + if (strcmp(argv[4], "-") == 0) { + yyin = stdin; + } else if ((yyin = fopen(argv[4], "r")) == NULL) { + fprintf(stderr,"%s: can't open file %s\n", argv[0], argv[4]); + exit(1); + } + strcpy(srcfile_name, argv[4]); + inputfile_stk[ inputfile_stk_top /* 0 */ ].name = argv[4]; + if ( ! IS_LIT2PGM_Q ) printf("srcfile!_!%s!_!1!_!\n",argv[4]); + yylex(); + exit(exit_status); +} + +void +push_inputfile (fname) +char* fname; +{ + if ( inputfile_stk_top >= INPUTFILE_STK_SIZE ) { + fprintf(stderr,"\\input's too deeply nested\n"); + exit(1); + } + + /* record where we are in current file */ + inputfile_stk[ inputfile_stk_top ].lineno = lineno; + inputfile_stk[ inputfile_stk_top ].handle = YY_CURRENT_BUFFER; + /* actual push */ + inputfile_stk_top++; + + /* open new file fname */ + if ((yyin = fopen(fname, "r")) == NULL) { + fprintf(stderr,"%s:%d: can't open \\input file %s\n", srcfile_name, lineno, fname); + exit(1); + } + yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); + + /* report that's where we are */ + if (! IS_LIT2PGM_Q) printf("srcfile!_!%s!_!1!_!\n",fname); + /* set srcfile_name and lineno for new file */ + + strcpy(srcfile_name, fname); /* for my own tracking */ + lineno = 1; + + /* push/record everything for new file */ + inputfile_stk[ inputfile_stk_top ].name = srcfile_name; + inputfile_stk[ inputfile_stk_top ].lineno = lineno; +} + +void +pop_inputfile () +{ + inputfile_stk_top--; /* actual pop */ + + /* remind where we were */ + strcpy(srcfile_name, inputfile_stk[inputfile_stk_top].name); + lineno = inputfile_stk[inputfile_stk_top].lineno; + /* put in an extra newline or two before the next file; + otherwise, the cat'ting of files gives things like: + + > last line of code + \section{Next section} + + which happens to be very bad for lit2stuff. + */ + if (! IS_LIT2PGM_Q) printf("\n\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); + + /* return to prev inputfile */ + yy_switch_to_buffer( inputfile_stk[inputfile_stk_top].handle ); +} + +void +myecho () +{ + myprintstr(yytext); +} + +void +myprintstr (str) +char *str; +{ + if (SHLD_PRINT) { + printf("%s",str); + } +} + +void +print_leading_whitespace () +{ + int i; + + for (i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++) { + putchar(yytext[i]); + } +} + +void +not_OK(msg) +char *msg; +{ + /* a good old emacsable error msg */ + fprintf(stderr,"%s:%d: %s", srcfile_name, lineno, msg); + exit_status++; +} + +void +warning(msg) /* exit_status not fiddled */ +char *msg; +{ + /* a good old emacsable warning msg */ + fprintf(stderr,"%s:%d: [warning] %s", srcfile_name, lineno, msg); +} +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-globals.lprl b/web/glasgow/lit2x-0.16/literate/lit-globals.lprl new file mode 100644 index 0000000000..3ab4edde1b --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-globals.lprl @@ -0,0 +1,381 @@ +\section[Global_data]{Global data structures for processing} + +The main stuff is kept in global structures; to improve quality of +life, global things' names start with Capital Letters. If it ain't +described here, it ain't supposed to be global! (Well, except for +some command-line option variables...) + +The document being processed is taken to be a sequence of {\em +sections}\index{sections}, each made of zero or more {\em +blocks}\index{blocks} (see next section) of stuff-of-one-kind. Important: +whereas the ``sections'' the user sees may be nested within each other +(e.g., sections within a chapter), a ``section'' here just the +sequence of blocks between one sectioning command (\tr{\section<n>}) +and the next (\tr{\section<m>}, for any \tr{<n>} and \tr{<m>}. For +example, the stuff before the first sectioning command is the root +``section'' (number~0.0.0...), the stuff between (e.g.) a +\tr{\section1} command and an ensuing \tr{\section2} command is a +``section,'' etc. Confusing, but only to us hackers... + +\subsection[Data_about_sections]{Global data about sections} + +\begin{code} +&init_section_data_structures(); + +sub init_section_data_structures { # also used in the linker +\end{code} + +Things we want to keep track of about ``sections'' (values for the root +section are provided): +\begin{description} +\item[@Sec_depth@:] +the sectioning depth provided by the user; 0 is a special depth only +for the root section (pre-amble) [sparked by seeing +\tr{\documentstyle}] and the \tr{\end{document}} section; -1 means no +depth has been assigned. +\begin{code} + @Sec_depth = (-1); +\end{code} + +\item[@Sec_abs_depth@:] +the absolute sectioning depth; it is calculated. +\begin{code} + @Sec_abs_depth = (-1); +\end{code} + +\item[@Sec_nodename@:] +the default node-name for that section; to go from a +nodename to a section number, we have the auxiliary associative array +@%Nodename_sec@. The array @Sec_alias@ contains {\em extra} +names for this section, introduced by \tr{\label}s. +\begin{code} + @Sec_nodename = (''); # 'Top' (set by \documentstyle) + %Nodename_sec = (); # ('Top', 0); + @Sec_aliases = (''); +\end{code} + +\item[@Sec_nodespec@:] +a specification (a string) for how each node is wired up (\tr{lit2texi}). +\begin{code} + @Sec_nodespec = (''); # Top,,,(dir) +\end{code} + +\item[@Sec_title@] +gives the text of the title for a +section. +\begin{code} + @Sec_title = (''); +\end{code} + +\item[@Sec_numstr@:] +the section number as a string, +full-stop/period-separated; the associative array @%Sec_numstr_exists@ +(indexed by @Sec_numstr@'s) is used to help find (e.g.) a +\tr{\section<n>}'s \tr{\section<n+1>}'s, and such like. +@Sec_vec@, a sort-of counter, is very much related; in turn, the routine +@incr_Sec_vec@ is very much related to it. +\begin{code} + @Sec_numstr = (''); # (0.0.0.0.0.0.0.0.0.0.0.0') + %Sec_numstr_exists = (); # ('0.0.0.0.0.0.0.0.0.0.0.0', 0) + + # 12 sectioning levels for the user; level 0 is magic and extra + # that -1 will be bumped first thing (we hope) + @Sec_vec = (-1,0,0,0,0,0,0,0,0,0,0,0,0); # curr Sec_numstr in non-string form +\end{code} + +\item[@Sec_first_blk@ and @Sec_last_blk@:] +these point the way to a section's blocks (see next section). +\begin{code} + @Sec_first_blk = (0); # to find their blocks + @Sec_last_blk = (-1); +\end{code} + +\item[@Sec_owner@:] +who should be listed as the owner of this section when a \tr{-O} flag +given; set from \tr{\owner} command; otherwise, from who actually owns +the source-file of the section's first block. +\begin{code} + @Sec_owner = (''); +\end{code} + +\item[@Sec_extra_menu_entries@:] +a string giving extra menu entries (from user's \tr{\menuentry} +requests). +\begin{code} + @Sec_extra_menu_entries = (''); +\end{code} + +\item[@Sec_codethings_defd@ and @Sec_codethings_used@:] +a comma-separated string of ``interesting'' things found by +@find_interesting_codethings@ in this section. + +\begin{code} + @Sec_codethings_defd = (''); + @Sec_codethings_used = (''); + %Codething_defd_sec = (); # only used in the linker + +} # end of subroutine init_section_data_structures +\end{code} +\end{description} + +\begin{code} +sub tidy_numstr { + local($numstr) = @_; + + $numstr =~ s/^-1\.//; # strip leading -1 (I don't like this...) + $numstr =~ s/^[0\.]+\.//; # strip leading zeros + $numstr =~ s/\.[0\.]+$//; # strip trailing zeros + $numstr; +} + +$S = 0; # reserved scalar for walking through sections + +# constants; full LaTeX hierarchy +# all subparagraphs (LaTeX) or subsubsections (Texinfo) below +# a certain level -- for now +$MAX_SEC_DEPTH = 12; + +sub incr_Sec_vec { + local($i) = @_; # the section-depth to increment + +# print STDERR "entering incr_Sec_vec: $i\n" if $Debugging; + + $Sec_vec[$i] = $Sec_vec[$i] + 1; + $i++; + while ($i <= $#Sec_vec) { # zero out subsections + $Sec_vec[$i] = 0; + $i++; + } +} + +#operations on Secs + +sub start_new_section { # wind up curr section, make ready for next + +# print STDERR "entering start_new_section\n" if $Debugging; + + $S++; + if (! &empty_blk_p($B)) { + $Sec_last_blk[$S - 1] = $B; + &incr_blk_ctr(); # new section -> new block + } else { + $Sec_last_blk[$S - 1] = $B - 1; + $Blk_sec[$B] = $S; + } + + $Sec_depth[$S] = -1; # means: unknown" + $Sec_abs_depth[$S] = -1; + $Sec_nodename[$S] = ''; + $Sec_aliases[$S] = ''; + $Sec_nodespec[$S] = ''; + $Sec_title[$S] = ''; + $Sec_numstr[$S] = ''; + $Sec_first_blk[$S] = $B; + $Sec_last_blk[$S] = -1; + + $Sec_owner[$S] = ''; + $Sec_extra_menu_entries[$S] = ''; + $Sec_codethings_defd[$S] = ''; + $Sec_codethings_used[$S] = ''; +} + +\end{code} + +\subsection[Data_about_blocks]{Global data about blocks} + +Each ``section'' is a sequence of ``blocks'' of stuff: each block +has a type (text, code, etc.) and some text, plus some other +miscellaneous information. The presumption is that, though blocks may +change internally (number of lines, etc.), the number/order/etc.~of +blocks won't change. + +\begin{code} +@Blk_type = (''); +@Blk_sec = (''); # backpointer to what section it's in +@Blk_magic = (''); # mainly ribbon names, for "code" +@Blk_txt = (''); +@Blk_srcfile_name = (''); +@Blk_srcfile_lineno = (1); + +# list of codethings defined/used in this block (if code) +@Blk_codethings_defd = (); +@Blk_codethings_used = (); + +$B = 0; # reserved for walking through blocks + +# operations thereon + +sub empty_blk_p { # empty if it has no text + local($blk_no) = @_; + + ($Blk_txt[$B] eq '') ? 1 : 0; +} + +sub incr_blk_ctr { +# print STDERR "entering incr_blk_ctr\n" if $Debugging; + + $B++; + $Blk_type[$B] = ''; + $Blk_sec[$B] = $S; # that's where we are + $Blk_txt[$B] = ''; + $Blk_magic[$B] = ''; + $Blk_srcfile_name[$B] = ''; + $Blk_srcfile_lineno[$B] = -1; + $Blk_codethings_defd[$B]= ''; + $Blk_codethings_used[$B]= ''; +} + +sub set_blk_magic_info { # for special info about specific types of blks + local($b_info) = @_; + + $Blk_magic[$B] = $b_info; +} + +sub append_to_curr_blk { + local($b_type, $b_txt) = @_; + + if (&empty_blk_p($B)) { # first use + ¬_OK($Srcfile_name, $Srcfile_lineno, # I hope that's right... + "non-matching type on empty blk with type already set\n") + if ($Blk_type[$B] && $Blk_type[$B] ne $b_type); + + $Blk_type[$B] = $b_type; + $Blk_txt[$B] = $b_txt; + $Blk_srcfile_name[$B] = $Srcfile_name; + $Blk_srcfile_lineno[$B] = $Srcfile_lineno; + + } elsif ($Blk_type[$B] ne $b_type) { # ??? + ¬_OK($Srcfile_name, $Srcfile_lineno, # I hope that's right... + "unexpected blk type change in append_to_curr_blk: $Blk_type[$B], $b_type; $b_txt\n"); + $Blk_type[$B] = $b_type; + $Blk_txt[$B] = $b_txt; + $Blk_srcfile_name[$B] = $Srcfile_name; + $Blk_srcfile_lineno[$B] = $Srcfile_lineno; + + } else { + $Blk_txt[$B] .= $b_txt; + } +} +\end{code} + +Executable/compilable code (inside \tr{\begin{code} ... \end{code}}) is +associated with one or more code {\em ribbons}; by default, code is +appended onto ribbon \tr{main}. During @read_and_categorize_input@, the +numbers for all the blocks holding code for ribbon \tr{foo} are +accumulated into @$Ribbon_blks{'foo'}@. + +\begin{code} +%Ribbon_blks = (); +\end{code} + +\subsection[Other_global_data]{Other global data} + +Miscellaneous global things. + +\begin{code} +$Srcfile_name = ''; # source file current line came from +$Srcfile_lineno = 0; # line number of current line + +$Doc_title = ''; +$Doc_author = ''; +$Doc_date = ''; + +$Only_latex = 0; +$Only_info = 0; + +# for \define{<foo>}{<bar>} things; some built-in for lit2texi +%Define = (); +if ($Lit2texi) { + $Define{'LaTeX'} = 'LaTeX'; + $Define{'Haskell'} = 'Haskell'; + $Define{'TeX'} = 'TeX'; + $Define{'ldots'} = '...'; +} + +%SECCMD_DEPTH = ('RESERVED_A_bug_if_you_see_it', 0, + 'part', 1, 'chapter', 2, 'section', 3, + 'subsection', 4, 'subsubsection', 5, 'paragraph', 6, + 'subparagraph', 7,'subparagraph', 8, 'subparagraph', 9, + 'subparagraph',10,'subparagraph', 11, 'subparagraph', 12 + ); +# LaTeX (used for \section(ref|type)s for Texinfo as well) +@SECDEPTH_LCMD =('RESERVED_A_bug_if_you_see_it', + 'part', 'chapter', 'section', + 'subsection', 'subsubsection', 'paragraph', + 'subparagraph','subparagraph', 'subparagraph', + 'subparagraph','subparagraph', 'subparagraph' + ); +# Texinfo -- really need something like 'part' +@SECDEPTH_TCMD =('RESERVED_A_bug_if_you_see_it', + 'chapter', 'chapter', 'section', + 'subsection', 'subsubsection', 'subsubsection', + 'subsubsection','subsubsection','subsubsection', + 'subsubsection','subsubsection','subsubsection' + ); + +# a table of \begin/end environments we known what to do with +# this is so lit2texi can turn the others into something sensible +$KNOWN_ENV{'change'} = 1; +$KNOWN_ENV{'comment'} = 1; +$KNOWN_ENV{'description'} = 1; +$KNOWN_ENV{'display'} = 1; +$KNOWN_ENV{'document'} = 1; +$KNOWN_ENV{'enumerate'} = 1; +$KNOWN_ENV{'figure'} = 1; +$KNOWN_ENV{'flushdisplay'} = 1; +$KNOWN_ENV{'flushverbatim'} = 1; +$KNOWN_ENV{'itemise'} = 1; +$KNOWN_ENV{'itemize'} = 1; +$KNOWN_ENV{'menu'} = 1; +# onlylatex/info/etc should never get far enough to be seen +# so they aren't in this table. +$KNOWN_ENV{'quotation'} = 1; +$KNOWN_ENV{'table'} = 1; +$KNOWN_ENV{'tabular'} = 1; +$KNOWN_ENV{'test'} = 1; +$KNOWN_ENV{'verbatim'} = 1; +\end{code} + +\subsection[Debugging_global_data]{Debugging global data} + +\begin{code} +sub dump_sections_and_blocks { + local(@ln, $l); # for blk text lines + local($temp); + +# print STDERR "entering dump_sections_and_blocks\n" if $Debugging; +# this may not be printing the latest and greatest stuff + + foreach ($S = 0; $S <= $#Sec_depth; $S++) { + print STDERR "Section $S ($Sec_numstr[$S]):: depth: $Sec_depth[$S]; abs_depth: $Sec_abs_depth[$S]; nodename: $Sec_nodename[$S]; nodespec: $Sec_nodespec[$S]; blks: $Sec_first_blk[$S]:$Sec_last_blk[$S]; title: $Sec_title[$S]\n"; + foreach ($B = $Sec_first_blk[$S]; $B <= $Sec_last_blk[$S]; $B++) { + print STDERR " Block $B; sec $Blk_sec[$B]; srcfile: $Blk_srcfile_name[$B]/$Blk_srcfile_lineno[$B]; type: $Blk_type[$B]; magic: $Blk_magic[$B]\n"; + + ¬_OK($Blk_srcfile_name[$B], $Blk_srcfile_lineno[$B], + "!!! Hey blk_sec ne sec: $Blk_sec[$B] != $S\n") if $Blk_sec[$B] != $S; + $temp = $Blk_txt[$B]; + $temp =~ s/\n/\\n\n/g; + @ln = split(/\n/,$temp); + for $l (@ln) { + print STDERR "\t$l\n"; + } + if ($Blk_type[$B] eq 'code') { + print STDERR "codethings defd: $Blk_codethings_defd[$B]\n" + if $Blk_codethings_defd[$B]; + print STDERR "codethings used: $Blk_codethings_used[$B]\n" + if $Blk_codethings_used[$B]; + } + } + print STDERR "sec codethings defd: $Sec_codethings_defd[$S]\n" + if $Sec_codethings_defd[$S]; + print STDERR "sec codethings used: $Sec_codethings_used[$S]\n" + if $Sec_codethings_used[$S]; + print STDERR "\n"; + } + print STDERR "Ribbons:\n"; + local($ribbon,$blk_list); + while (($ribbon, $blk_list) = each %Ribbon_blks) { + print STDERR "\t$ribbon: $blk_list\n"; + } +} +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-inputter.lprl b/web/glasgow/lit2x-0.16/literate/lit-inputter.lprl new file mode 100644 index 0000000000..fac6ecd3db --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-inputter.lprl @@ -0,0 +1,121 @@ +\section[Inputter]{Read files, follow \tr{\input}'s, do definitions} + +At the beginning and end of each \tr{\input}'d file, the source file +name and line number is reported, in lines of the form (separate for +reasons of C-hacking convenience): +% first space makes it invisible to itself +\begin{verbatim} + srcfile!_!filename!_!line-number!_! +\end{verbatim} + +At this point, I expect the filename specified in the +\tr{\input} to be exactly the desired name (no implied suffix, +etc.), somewhere along the \tr{LITINPUTS} path (specified by that +environment variable). + +\begin{code} +($Pgm = $0) =~ s/.*\/([^\/]+)$/\1/; +$Verbose = shift(@ARGV); # they had better be there! +$Follow_inputs = shift(@ARGV); +$Litinputs = shift(@ARGV); +@Litinput = split(/:/,$Litinputs); +$Exit_status = 0; # everything OK + +# read STDIN ("-") if no files specified +# +unshift(@ARGV, '-') if $#ARGV < $[; +while ($ARGV = shift) { + &send_file($ARGV, 'fh00'); +} +exit $Exit_status; + +sub send_file { # follows an example in the `open' item in perl man page + + local($fname,$fhandle) = @_; + local($l_no) = 1; + local($follow_file); + $fhandle++; # a string increment + + local($last_seen_dir) = $fname; + $last_seen_dir =~ s/\/[^\/]+$//; # strip to dir name + $last_seen_dir = '.' if ($last_seen_dir eq $fname); + + unless (open($fhandle, $fname)) { + print STDERR "$Pgm: Can't open $fname: $!\n"; + $Exit_status++; + return; + } + + local($is_intermed_file) = ($fname =~ /\.(itxi|itex)$/) ? 1 : 0; + + while (<$fhandle>) { + if ($l_no == 1 && ! $is_intermed_file) { # beginning + print "srcfile!_!$fname!_!1!_!\n"; + } + + # we do *nothing* to rawlatex environments + if ( /^\\begin\{rawlatex\}/ || /\001beginrawlatex\003/ ) { + while ($_ ne '' && ! (/^\\end\{rawlatex\}/ || /\001endrawlatex\003/ )) { + print $_; + $_ = <$fhandle>; + } + } + + if (/^\\inputnow\{(.*)\}\s*(%.*)?$/ # dubious ... + || ($Follow_inputs + && (/^\\input\s*\{(.*)\}\s*(%.*)?$/ + || /^\@input\s*\{(.*\.itxi)\}\s*$/))) { + $follow_file = &find_on_Litinputs($1, $last_seen_dir); + + if ($follow_file) { # it found something + print STDERR "reading $follow_file ...\n" if $Verbose; + &send_file($follow_file,$fhandle); + # add a couple of blank lines in case + # the last thing was some Miranda-style code + print "\n\n\n"; + print "srcfile!_!$fname!_!".($l_no+1)."!_!\n" if ! $is_intermed_file; + } else { + print STDERR "$fname:$l_no: Couldn't handle: $_"; + $Exit_status++; + } + } else { + print $_; + } + } continue { $l_no++; } + close($fhandle); +} + +sub find_on_Litinputs { + local($name, $last_seen_dir) = @_; + local($lit); + + if ($name =~ /^\//) { # absolute pathname + print STDERR "trying $name...\n" if $Verbose; + if (-f $name) { # exists + return($name); + } else { + print STDERR " file `$name' doesn't exist\n"; + $Exit_status++; + return(''); + } + } else { # hop along $Litinputs + foreach $lit (@Litinput) { + # handle . magically + if ($lit eq '.') { # SPECIAL try for a file in last_seen_dir + + print STDERR "trying $last_seen_dir/$name...\n" if $Verbose; + if (-f "$last_seen_dir/$name") { + return("$last_seen_dir/$name"); + } + } + print STDERR "trying $lit/$name...\n" if $Verbose; + if (-f "$lit/$name") { + return("$lit/$name"); + } + } + $Exit_status++; + print STDERR "No file `$name' along LITINPUTS path `$Litinputs'\n"; + return (''); # sigh + } +} +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-inputter.prl b/web/glasgow/lit2x-0.16/literate/lit-inputter.prl new file mode 100644 index 0000000000..9f3e1deca0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-inputter.prl @@ -0,0 +1,104 @@ +($Pgm = $0) =~ s/.*\/([^\/]+)$/\1/; +$Verbose = shift(@ARGV); # they had better be there! +$Follow_inputs = shift(@ARGV); +$Litinputs = shift(@ARGV); +@Litinput = split(/:/,$Litinputs); +$Exit_status = 0; # everything OK + +# read STDIN ("-") if no files specified +# +unshift(@ARGV, '-') if $#ARGV < $[; +while ($ARGV = shift) { + &send_file($ARGV, 'fh00'); +} +exit $Exit_status; + +sub send_file { # follows an example in the `open' item in perl man page + + local($fname,$fhandle) = @_; + local($l_no) = 1; + local($follow_file); + $fhandle++; # a string increment + + local($last_seen_dir) = $fname; + $last_seen_dir =~ s/\/[^\/]+$//; # strip to dir name + $last_seen_dir = '.' if ($last_seen_dir eq $fname); + + unless (open($fhandle, $fname)) { + print STDERR "$Pgm: Can't open $fname: $!\n"; + $Exit_status++; + return; + } + + local($is_intermed_file) = ($fname =~ /\.(itxi|itex)$/) ? 1 : 0; + + while (<$fhandle>) { + if ($l_no == 1 && ! $is_intermed_file) { # beginning + print "srcfile!_!$fname!_!1!_!\n"; + } + + # we do *nothing* to rawlatex environments + if ( /^\\begin\{rawlatex\}/ || /\001beginrawlatex\003/ ) { + while ($_ ne '' && ! (/^\\end\{rawlatex\}/ || /\001endrawlatex\003/ )) { + print $_; + $_ = <$fhandle>; + } + } + + if (/^\\inputnow\{(.*)\}\s*(%.*)?$/ # dubious ... + || ($Follow_inputs + && (/^\\input\s*\{(.*)\}\s*(%.*)?$/ + || /^\@input\s*\{(.*\.itxi)\}\s*$/))) { + $follow_file = &find_on_Litinputs($1, $last_seen_dir); + + if ($follow_file) { # it found something + print STDERR "reading $follow_file ...\n" if $Verbose; + &send_file($follow_file,$fhandle); + # add a couple of blank lines in case + # the last thing was some Miranda-style code + print "\n\n\n"; + print "srcfile!_!$fname!_!".($l_no+1)."!_!\n" if ! $is_intermed_file; + } else { + print STDERR "$fname:$l_no: Couldn't handle: $_"; + $Exit_status++; + } + } else { + print $_; + } + } continue { $l_no++; } + close($fhandle); +} + +sub find_on_Litinputs { + local($name, $last_seen_dir) = @_; + local($lit); + + if ($name =~ /^\//) { # absolute pathname + print STDERR "trying $name...\n" if $Verbose; + if (-f $name) { # exists + return($name); + } else { + print STDERR " file `$name' doesn't exist\n"; + $Exit_status++; + return(''); + } + } else { # hop along $Litinputs + foreach $lit (@Litinput) { + # handle . magically + if ($lit eq '.') { # SPECIAL try for a file in last_seen_dir + + print STDERR "trying $last_seen_dir/$name...\n" if $Verbose; + if (-f "$last_seen_dir/$name") { + return("$last_seen_dir/$name"); + } + } + print STDERR "trying $lit/$name...\n" if $Verbose; + if (-f "$lit/$name") { + return("$lit/$name"); + } + } + $Exit_status++; + print STDERR "No file `$name' along LITINPUTS path `$Litinputs'\n"; + return (''); # sigh + } +} diff --git a/web/glasgow/lit2x-0.16/literate/lit-link-globals.lprl b/web/glasgow/lit2x-0.16/literate/lit-link-globals.lprl new file mode 100644 index 0000000000..eb081d8fef --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-link-globals.lprl @@ -0,0 +1,9 @@ +\section[Link_globals]{Global data needed only for linking} + +\begin{code} +$Base_sec_depth = 0; # changed by \{up,down}section commands +$Sec_depth_offset=1; # changed by \documentstyle, \rootsectiontype commands + +# a trailing 1 seems to be the habit for inc'd perl files +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-linker.lprl b/web/glasgow/lit2x-0.16/literate/lit-linker.lprl new file mode 100644 index 0000000000..b9ee25a1ce --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-linker.lprl @@ -0,0 +1,525 @@ +\begin{code} +sub first_link_pass { # just collecting information + &init_section_data_structures(); + $S = -1; # section counter; should be bumped before use!!! + + $pipe_string = "$Lit_inputter $Verbose 1 $Litinputs $Input_file"; + print STDERR "link(1):in=$pipe_string\n" if $Verbose; + print STDERR " out=/dev/null\n" if $Verbose; + # NB: not supposed to have any output... + &do_std_opens($pipe_string,'/dev/null'); + + while (<INPIPE>) { + if (/^\001(down|up)section\003$/) { + $Base_sec_depth++ if $1 eq 'down'; + $Base_sec_depth-- if $1 eq 'up'; + + } elsif (/^\001rootsectiontype\003(\d+)\002$/) { + $Sec_depth_offset = $1; + + } elsif (/^\001section\003(.+)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)/) { + local($sec_depth) = $1; + local($nodename) = $2; + local($nodespec) = $3; + local($owner) = $4; + local($xtra_menu) = &deatified2verb_nl($5); # restore newlines + local($codethings_defd) = $6; + local($aliases) = $7; + local($codethings_used) = $8; + local($restofline) = $9; # restore newlines + # restofline has srcfile on the front... + local($srcfilename,$srcfilelineno); + $restofline =~ /^(.*)#%%#(.+)#%%#(.*)/; + $srcfilename = $1; $srcfilelineno = $2; + $restofline = &deatified2verb_nl($3); + + $S++; # new "section" + + $Sec_depth[$S] = $sec_depth; + if ($sec_depth == 0) { # this is a magical depth + $Sec_abs_depth[$S] = 0; + } else { + $Sec_abs_depth[$S] = $Base_sec_depth + $Sec_depth_offset + $sec_depth - 1; + } + if ($Sec_abs_depth[$S] < 0) { + ¬_OK('???', '???', "section depth not positive: $_"); + $Sec_abs_depth[$S] = 1; + } elsif ($Sec_abs_depth[$S] > $MAX_SEC_DEPTH) { + ¬_OK('???', '???', "section depth more than $MAX_SEC_DEPTH: $_"); + $Sec_abs_depth[$S] = $MAX_SEC_DEPTH; + } + &incr_Sec_vec($Sec_abs_depth[$S]); + $Sec_numstr[$S] = join('.',@Sec_vec); + $Sec_numstr_exists{$Sec_numstr[$S]} = $S; + $Sec_nodename[$S] = $nodename; + $Nodename_sec{$nodename} = $S; + $Sec_aliases[$S] = $aliases; + local($a); + foreach $a (split(/,/,$aliases)) { # aliases too + $Nodename_sec{$a} = $S if $a; + } + $Sec_nodespec[$S] = $nodespec; + $Sec_title[$S] = $restofline; # this will only be right for lit2texi +#out $Sec_title[$S] =~ s/\001starred\003//; # will pick up on 2nd pass + # maybe should leave it in so \tableofcontents works as expected... + $Sec_owner[$S] = $owner; + $Sec_extra_menu_entries[$S] = $xtra_menu; + $Sec_codethings_used[$S] = $codethings_used; + $Sec_codethings_defd[$S] = $codethings_defd; + local($d); + foreach $d (split(/\001/,$codethings_defd)) { + $Codething_defd_sec{$d} = $S if $d; + } + $Sec_first_blk[$S] = 0; $Sec_last_blk[$S] = -1; # dummies + } + } + &do_std_closes(); +} + +sub second_link_pass { + $S = -1; # section counter; should be bumped before use!!! + + $Table_of_contents_please = 0; + + # may be only grabbing (-g <node>) a subtree of nodes rooted at + # node; so first figure out what sections these are. + # NB: the first (pre-amble) and last (\end{document}) sections are + # ALWAYS printed. + ($First_sec_to_grab, $Last_sec_to_grab) = &calc_grab_range(); + print STDERR "grab range: $First_sec_to_grab--$Last_sec_to_grab\n" if $Debugging; + + $pipe_string = "$Lit_inputter $Verbose 1 $Litinputs $Input_file"; + print STDERR "link(2):in=$pipe_string\n" if $Verbose; + print STDERR " out=$Link_outfile\n" if $Verbose; + &do_std_opens($pipe_string,$Link_outfile); + + &print_setfilename() if $Lit2texi; + + while (<INPIPE>) { + if (/^srcfile!_!.*!_!\d+!_!$/) { + next; # junk from lit-inputter + + } elsif (/^\001(down|up)section\003$/) { + next; + + } elsif (/\001rootsectiontype\003(\d+)\002/) { + next; + + } elsif (/\001beginrawlatex\003/) { + $_ = <INPIPE>; + while ($_ ne '' && ! /\001endrawlatex\003/) { + print $_; + $_ = <INPIPE>; + } + next; + + } elsif (/^\001section\003(.+)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)\002(.*)/) { + local($sec_depth) = $1; + local($nodename) = $2; + local($nodespec) = $3; + local($owner) = $4; + local($xtra_menu) = &deatified2verb_nl($5); # restore newlines + local($codethings_defd) = $6; + local($aliases) = $7; + local($codethings_used) = $8; + local($restofline) = $9; # restore newlines + # restofline has srcfile on the front... + local($srcfilename,$srcfilelineno); + $restofline =~ /^(.*)#%%#(.+)#%%#(.*)/; + $srcfilename = $1; $srcfilelineno = $2; + $restofline = &deatified2verb_nl($3); + + $S++; # new "section" + + # we take sections in the grab range, plus any at + # the magic absolute-depth 0 (pre-amble and \end{document}, + # presumably) + # + # first an unfortunate hack so that grabbed things start + # out on a page of their own + print "\\pagebreak\n" if $S == 1 && $Grab_node ne 'Top'; + + next if ! ($Sec_abs_depth[$S] == 0 + || ($S >= $First_sec_to_grab && $S <= $Last_sec_to_grab)); + + if ($Lit2texi) { + &end_of_section_stuff($S-1) if $S > 0; # end previous section + + print &mk_line_directive($srcfilename,($srcfilelineno - 3)) + if $srcfilename && $srcfilelineno >= 4; + # guessed how much extra junk got put in... + + &print_node_header($S) if $Sec_nodespec[$S]; + + if ($Sec_abs_depth[$S] > 0 && $restofline !~ /\001starred\003/) { + print "\@",$SECDEPTH_TCMD[$Sec_abs_depth[$S]]," "; + print $Sec_title[$S],"\n"; + print "\n[The `owner' of this section is $owner.]\n\n" if $owner; + } elsif ($Sec_abs_depth[$S] > 0) { + local($temp_title) = $Sec_title[$S]; + $temp_title =~ s/\001starred\003//; + print "\n$temp_title\n\n"; + } + } elsif ($Lit2latex) { + print &mk_line_directive($srcfilename,$srcfilelineno) + if $srcfilename && $srcfilelineno >= 1; + + if ($Sec_abs_depth[$S] > 0) { + print "\\",$SECDEPTH_LCMD[$Sec_abs_depth[$S]]; + print "\*" if $restofline =~ /\001starred\003/; + local($temp_title) = $Sec_title[$S]; + $temp_title =~ s/\001starred\003//; + print "$temp_title\n"; + print "\n[The `owner' of this section is $owner.]\n\n" if $owner; + } + } + + } else { + next if ! ($Sec_abs_depth[$S] == 0 + || ($S >= $First_sec_to_grab && $S <= $Last_sec_to_grab)); + + if (/^\001index_uses\003(.*)/ && $Lang_xref !~ /noindex/) { + &print_index_entries_for_uses($1); + + } elsif (/^\001xref_uses\003(.*)/) { + &print_xrefs_for_uses($1); + + } elsif (/\\[Ss]ectiontype/ || ($Lit2texi && /\@[Ss]ectiontype/)) { + s/\@([Ss])ectiontype/\\\1ectiontype/g; # sigh + print &subst_sectiontypes('???','???',$_); + + } elsif ($Lit2texi && /\@tableofcontents/) { + $Table_of_contents_please = 1; + + } else { + if ($Lit2texi) { + # some of our xrefs may be to aliases (labels), not to nodenames proper. + # sigh + while (/\@xref\{([^\}]+)\}/) { + local($label) = $1; # assume the guts are clean + + if ( ! defined($Nodename_sec{$label})) { + ¬_OK('???','???',"I can't dig the \\ref to: $label (no such node?)\n"); + } else { # canonicalize to real node name + $label = $Sec_nodename[$Nodename_sec{$label}]; + } + s/\@xref\{([^\}]+)\}/\@xref!_\{$label\}/; #temp + } + s/\@xref!_\{/\@xref\{/g; # fix temps + } + print $_; + } + } + } + &do_std_closes(); +} + +sub print_setfilename { # make up @setfilename command for Texinfo + if ($Infofilename) { + print "\@setfilename $Infofilename\n"; + + } elsif ($Inputfile_root && $Inputfile_root ne '???') { # it's something reasonable + $Infofilename = "$Inputfile_root\.info"; + print "\@setfilename $Infofilename\n"; + + } else { + ¬_OK("","","can't generate Info file name from inputfile root:$Inputfile_root\n"); + } +} + +sub print_node_header { + local($s) = @_; + + local($this, $next, $prev, $up) = split(/,/, $Sec_nodespec[$s]); + local($depth) = $Sec_abs_depth[$s]; + local($numstr_this) = $Sec_numstr[$s]; + local(@numstr_this) = split(/\./, $numstr_this); + +# print STDERR "this:\t",join('.',@numstr_this),"\n" if $Debugging; + + if ($next eq '?') { + # default 'next' node is NEXT one at same depth (-L: or plain NEXT) or NONE + local(@numstr_next) = @numstr_this; + $numstr_next[$depth] = $numstr_this[$depth] + 1; +# print STDERR "next:\t",join('.',@numstr_next),"\n" if $Debugging; + + $next = $Sec_numstr_exists{join('.',@numstr_next)}; + if (defined($next)) { + $next = $Sec_nodename[$next]; + } elsif ($Opt_node_links && defined($Sec_nodename[$s + 1])) { + $next = $Sec_nodename[$s + 1]; + } else { + $next = ' '; + } + } + + if ($prev eq '?') { + # default 'prev' node is PREVIOUS one at same depth (-L: or plain PREVIOUS) or NONE + # prev will be same as up-node if first section at a level + local(@numstr_prev) = @numstr_this; + $numstr_prev[$depth] = $numstr_this[$depth] - 1; +# print STDERR "prev:\t",join('.',@numstr_prev),"\n" if $Debugging; + + $prev = $Sec_numstr_exists{join('.',@numstr_prev)}; + if (defined($prev)) { + $prev = $Sec_nodename[$prev]; + } elsif ($Opt_node_links && defined($Sec_nodename[$s - 1])) { + $prev = $Sec_nodename[$s - 1]; + } else { + $prev = ' '; + } + } + + if ($up eq '?') { + # default 'up' node is same numstr w/ this depth zeroed out + # it should always exist, because of default node `Top' + local(@numstr_up) = @numstr_this; + $numstr_up[$depth] = 0; +# print STDERR "up:\t",join('.',@numstr_up),"\n" if $Debugging; + + $up = $Sec_numstr_exists{join('.',@numstr_up)}; + if (! defined($up)) { + ¬_OK('???','???', + "couldn't make up-node from numstr:".join('.',@numstr_up)."\n"); + $up = 'Top'; + } else { + $up = $Sec_nodename[$up]; + } + } + + print "\n\@node $this, $next, $prev, $up\n"; + print "\@comment node, next, previous, up\n"; +} + +sub calc_grab_range { + if ($Grab_node eq 'Top') { + return (0, $#Sec_depth); # that is, all sections + + } elsif (! defined($Nodename_sec{$Grab_node})) { # a little error-checking... + ¬_OK('???','???',"No such node to grab: $Grab_node\n"); + if ($#Files_to_tidy >= 0) { + print STDERR "rm -f @Files_to_tidy\n" if $Verbose; + unlink ( @Files_to_tidy ); + } + exit $Status; + + } else { + local($first_sec) = $Nodename_sec{$Grab_node}; # that's easy + # we now look for the next sec at the same depth; + # the sec preceding it will be the last one + local($depth) = $Sec_abs_depth[$first_sec]; + local($first_sec_numstr) = $Sec_numstr[$first_sec]; + local(@first_sec_numstr) = split(/\./, $first_sec_numstr); + local(@next_sec_numstr) = @first_sec_numstr; + $next_sec_numstr[$depth] = $first_sec_numstr[$depth] + 1; + + while ($depth >= 1) { +# print STDERR "next guess=@next_sec_numstr\n"; + + if (defined($Sec_numstr_exists{join('.',@next_sec_numstr)})) { + return($first_sec, + $Sec_numstr_exists{join('.',@next_sec_numstr)} - 1); + + } else { # try next higher level + $next_sec_numstr[$depth] = 0; + $depth--; + $next_sec_numstr[$depth] = $first_sec_numstr[$depth] + 1; + } + } + return ($first_sec, $#Sec_depth); + } +} + +sub subst_sectiontypes { + local($srcfilename, $srclineno, $_) = @_; + local($type); + + while (/\\([Ss])ectiontype\{([^\}]+)\}/) { + local($capped) = $1; + local($nodename) = $2; + if (! defined($Nodename_sec{$nodename})) { + ¬_OK($srcfilename,$srclineno,"\\sectiontype/ref of unknown node: $nodename (very approx line no)\n"); + $type = '???failed sectiontype???'; + } else { + local($depth) = $Sec_abs_depth[$Nodename_sec{$nodename}]; + if (! defined($Sec_abs_depth[$Nodename_sec{$nodename}])) { + ¬_OK($srcfilename,$srclineno,"failed to do \\sectiontype/ref\n"); + $type = '???failed sectiontype???'; + } elsif ($depth >= 3) { + $type = 'section'; + } else { + # we use the LaTeX table here ... + $type = $SECDEPTH_LCMD[$depth]; + } + if ($capped eq 'S') { + local($first) = $type; + $first =~ s/^(.).*/\1/; + $first =~ y/a-z/A-Z/; + local($rest) = $type; + $rest =~ s/^.(.*)/\1/; + $type = $first . $rest; + } + } + s/\\[Ss]ectiontype\{([^\}]+)\}/$type/g; + } + $_; +} + +sub end_of_section_stuff { # lit2texi only + local($s) = @_; + + @Menu_lines = (); + &gen_endofsection_menu_lines($s); +#print STDERR "1::",@Menu_lines; + if ($Sec_extra_menu_entries[$s]) { + push(@Menu_lines, "\n"); + push(@Menu_lines, split(/\n/, $Sec_extra_menu_entries[$s])); + } +#print STDERR "2::",@Menu_lines; + push(@Menu_lines, "\n"); + &gen_codething_menu_lines($s); +#print STDERR "3::",@Menu_lines; + if ($s == 0 && $Table_of_contents_please == 1) { + &gen_texinfo_table_of_contents_lines(); + } +#print STDERR "4::",@Menu_lines; + + if ( $#Menu_lines >= 1 ) { # more than just what I put there + if ($Menu_lines[0] eq "\n") { # nuke a leading blank line + shift(@Menu_lines); + } + print "\n\@menu\n"; + &format_and_print_menu_lines(); + print "\@end menu\n"; + } +} + +sub format_and_print_menu_lines { + # just to be beautiful, let's find the longest menu item + # (for printing purposes) + local($longest_item) = 0; + local($ml); + + foreach $ml (@Menu_lines) { + if ( $ml =~ /^\*(\s+[^:\n]+):/ ) { + local($mi_length) = length( $1 ); + if ( $mi_length > $longest_item) { + $longest_item = $mi_length; + } + } + } + # add two to "longest_item" for "::" + $longest_item += 2; + + $* = 1; + foreach $ml (@Menu_lines) { + if ( $ml =~ /^\*(\s+[^:\n]+)(:+)\s*(.*)/ ) { + local($m_item) = $1; + local($m_sep) = $2; + local($m_descr)= $3; + + printf "*%-${longest_item}s %s\n", $m_item.$m_sep, $m_descr; + } else { + print $ml; + } + } + $* = 0; +} + +sub gen_endofsection_menu_lines { + local($s) = @_; + + local($depth) = -1; + if ($Sec_abs_depth[$s] > 0) { + $depth = $Sec_abs_depth[$s] + 1; + } elsif ($Sec_abs_depth[$s] == 0) { + $depth = $Sec_depth_offset; # where rootsectiontype takes us + } + die "got depth $depth when doing print_endofsection_menu\n" if $depth < 0; + + local(@numstr_subsec) = split(/\./, $Sec_numstr[$s]); + $numstr_subsec[$depth] = 1; # 1st subsection, if it exists + + $n = $Sec_numstr_exists{join('.',@numstr_subsec)}; + + while (defined($n) && $n > 0) { + + local($temp_title) = $Sec_title[$n]; + $temp_title =~ s/\001starred\003//; + + push(@Menu_lines, "* $Sec_nodename[$n]:: $temp_title.\n"); + + $numstr_subsec[$depth] = $numstr_subsec[$depth] + 1; + $n = $Sec_numstr_exists{join('.',@numstr_subsec)}; + } +} + +sub gen_codething_menu_lines { + local($s) = @_; + # generate menu entries for (defined) codethings that have been used + # in this section. (don't print if definition is merely elsewhere in + # this section). + + local($u); + foreach $u (split(/\001/, $Sec_codethings_used[$s])) { + if (defined($Codething_defd_sec{$u})) { + local($item_name) = $u; + $item_name =~ s/\@/\@\@/g; + local($sec_defd_in) = $Codething_defd_sec{$u}; + local($node_defd_in) = $Sec_nodename[$sec_defd_in]; + push(@Menu_lines, "\* $item_name: $node_defd_in.\n") if $sec_defd_in != $s; + } + } +} + +sub print_index_entries_for_uses { + local($uses) = @_; + +#no # print entries for the used things that HAVE definitions + local($u); + foreach $u (split(/\001/, $uses)) { +# if (defined($Codething_defd_sec{$u})) { + if ($Lit2texi) { + print "\@cindex ".&mk_texi_index_entry($u)."\n"; + } else { + # thinking about a "\|ttize" in there, too + print "\\index\{".&mk_latex_index_entry('tt',$u)."\}\%\n"; + } +# } + } +} + +sub print_xrefs_for_uses { # latex only + local($uses) = @_; + + return if ! $Codedef_blurbs; # some people don't want them + + # print entries for the used things that HAVE definitions + local(@use) = split(/\001/, $uses); + local($u); + local($i) = 0; + while ( $i <= $#use ) { + $u = $use[$i]; + if (defined($Codething_defd_sec{$u})) { + # fiddling must match that in lit-2latex + local($fiddled_u); + ($fiddled_u = $u) =~ s/\%/<percent>/g; # and other funny chars? + $fiddled_u =~ s/\$/<dollar>/g; + $fiddled_u =~ s/\\/<slash>/g; + + $use[$i] = &std_mk_code_frag($u) . ": p.~\\pageref\{def::$fiddled_u\}\%\n"; + # really should use lang-specific "mk_code_frag" but at + # link time we don't necessarily know what language is + # called for... and it could vary through a big document + $i++; + } else { # not defined -- remove it + splice(@use, $i, 1); + } + } + $u = join('; ',@use); # join up + print "\n\n\{\\small \[Definitions: $u\]\}\n\n" if $u; +} + +# a trailing 1 seems to be the habit for inc'd perl files +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-reader.lprl b/web/glasgow/lit2x-0.16/literate/lit-reader.lprl new file mode 100644 index 0000000000..58d7f179c7 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-reader.lprl @@ -0,0 +1,588 @@ +This code involves looking at the input and stuffing it in the +right global data structure. You may wish to consult the description +of said structures (\sectionref{Global_data}). + +\begin{code} +sub read_and_categorize_input { + + local($gobbling) = ''; # more on this below + + $S = $B = 0; # initialise section and block counters + + line: while (<INPIPE>) { + $Srcfile_lineno++; + + study; # to speed up regexp matching ??? + + # first, deal with magic "srcfile" lines from `lit-inputter' + # (lest they be "gobbled") + if (/^srcfile!_!(.*)!_!(.*)!_!$/) { + $Srcfile_name = $1; + $Srcfile_lineno = $2 - 1; # will be incr next time thru + # + # kick over to a new blk + # if not empty, start another block of same type + # otherwise, kick curr one again to insert the srcfilename/lineno + # (No: this doesn't work -- we can, e.g., get lots of little + # "tabular" envs, which is junk.) + # +# &incr_blk_ctr() if ! &empty_blk_p($B); +# &append_to_curr_blk($Blk_type[$B],''); + + next line; + } + + # Next, we worry about the \begin/\end's that serve only to + # include/exclude code. These are "onlylatex", "onlyinfo", + # "onlypartofdoc", "onlystandalone". + # + # this is a dull-witted implementation and things can go badly wrong + # if the input has errors + # + if (/^\\(begin|end)\{(onlylatex|onlyinfo|onlypartofdoc|onlystandalone)\}/) { + local($begin_or_end) = $1; + local($b_or_e_what) = $2; + + $Only_latex = (($begin_or_end eq 'begin') ? 1 : 0) if $b_or_e_what eq 'onlylatex'; + $Only_info = (($begin_or_end eq 'begin') ? 1 : 0) if $b_or_e_what eq 'onlyinfo'; + $Only_partofdoc = (($begin_or_end eq 'begin') ? 1 : 0) if $b_or_e_what eq 'onlypartofdoc'; + $Only_standalone = (($begin_or_end eq 'begin') ? 1 : 0) if $b_or_e_what eq 'onlystandalone'; + + next line; # finished with this line + } + next line if $Only_latex && ! $Lit2latex; + next line if $Only_info && ! $Lit2texi; + next line if $Only_partofdoc && $Standalone_doc; + next line if $Only_standalone && (! $Standalone_doc); + + # Now, we worry about "gobbling": that is, once we've seen a + # \begin{somethingInteresting}, we want to gobble everything up to + # the \end{somethingInteresting} -- no ifs, ands, buts or nesting! + # these are \begin/\end's that suggest _categories_ of stuff + # (text, code, etc.) + + # the two arguments to std_gobbling_stuff says how to categorize + # an ordinary line and an \end{somethingInteresting} line. + + if ($gobbling) { + + if ($gobbling eq 'change') { # not really implemented + $gobbling = &std_gobbling_stuff('TOSS IT','TOSS IT'); + + } elsif ($gobbling eq 'test') { # ditto + $gobbling = &std_gobbling_stuff('TOSS IT','TOSS IT'); + + } elsif ($gobbling eq 'verbatim') { + $gobbling = &std_gobbling_stuff('verb','NEW BLK ONLY'); + } elsif ($gobbling eq 'flushverbatim') { + $gobbling = &std_gobbling_stuff('flushverb','NEW BLK ONLY'); + + } elsif ($gobbling eq 'display') { + $gobbling = &std_gobbling_stuff('txt','txt'); + } elsif ($gobbling eq 'flushdisplay') { + $gobbling = &std_gobbling_stuff('txt','txt'); + + } elsif ($gobbling eq 'pseudocode') { + $gobbling = &std_gobbling_stuff('pseudocode','NEW BLK ONLY'); + + } elsif ($gobbling eq 'tabular') { + $gobbling = &std_gobbling_stuff('tabular','NEW BLK ONLY'); + + } elsif ($gobbling eq 'menu') { + $gobbling = &std_gobbling_stuff( + ($Lit2texi) ? 'menu' : 'TOSS IT', + ($Lit2texi) ? 'NEW BLK ONLY' : 'TOSS IT'); + + } elsif ($gobbling eq 'rawlatex') { + $gobbling = &std_gobbling_stuff( + ($Lit2latex) ? 'rawlatex' : 'TOSS IT', + ($Lit2latex) ? 'NEW BLK ONLY' : 'TOSS IT'); + + # rawtexinfo is too hard (and not that useful?) + + } elsif ($gobbling eq 'code') { + $gobbling = &std_gobbling_stuff('code','NEW BLK ONLY'); + + } elsif ($gobbling eq 'bird-code') { # > Bird-track code lines + if (/^>.*/) { # append... + s/^>// if $Lang_typeset =~ /nobird/; # coerce to non-Bird + &append_to_curr_blk('code', $_); + } else { # it's over... (in trouble if this is \begin...) + &incr_blk_ctr(); + &append_to_curr_blk('txt',$_); + $gobbling = ''; # finished + } + } + next line; # outta here... + } + + # now let's do all the stuff that gets us gobbling + # + + # change/test: not implemented + if (/^\\begin\{(change|test)\}/) { # not implemented + $gobbling = $1; + # just a warning + print STDERR "$Srcfile_name:$Srcfile_lineno: \\begin/\\end\{$1\} not implemented yet [warning]\n"; + + } elsif (/^\\begin\{verbatim\}/) { + $gobbling = 'verbatim'; + &incr_blk_ctr(); + } elsif (/^\\begin\{flushverbatim\}/) { + $gobbling = 'flushverbatim'; + &incr_blk_ctr(); + + # special handling of display so we can put \hfil\break onto each + # line (for lit2latex) + } elsif (/^\\begin\{display\}/) { # no new block here + $gobbling = 'display'; + &append_to_curr_blk('txt',$_); + } elsif (/^\\begin\{flushdisplay\}/) { + $gobbling = 'flushdisplay'; + &append_to_curr_blk('txt',$_); + + } elsif (/^\\begin\{pseudocode\}/) { + $gobbling = 'pseudocode'; + &incr_blk_ctr(); + + } elsif (/^\\begin\{tabular\}(.*)/) { + $gobbling = 'tabular'; + &incr_blk_ctr(); # for new tabular blk + &set_blk_magic_info($1); # the main thing! + + } elsif (/^\\begin\{menu\}/) { + $gobbling = 'menu'; + &incr_blk_ctr() if $Lit2texi; # for new menu blk + + } elsif (/^\\begin\{rawlatex\}/) { + $gobbling = 'rawlatex'; + &incr_blk_ctr() if $Lit2latex; # for new blk + + } elsif (/^\\begin\{code\}/) { + $gobbling = 'code'; + if (/\\begin\{code\}\[(.+)\]/) { # named ribbons... + $ribbon_names = $1; + $ribbon_names =~ s/\s*,\s*/,/g; # rm spaces around commas + } else { # implicitly more of code ribbon <<main>> + $ribbon_names = 'main'; + } + &incr_blk_ctr(); # for new code blk + &set_blk_magic_info($ribbon_names); # the main thing! + + # record this block's number in %Ribbon_blks + local(@ribbons) = split(/,/,$ribbon_names); + local($r); + foreach $r (@ribbons) { + if ($Ribbon_blks{$r}) { + $Ribbon_blks{$r} .= ",$B"; + } else { # first block + $Ribbon_blks{$r} = $B; + } + } + + } elsif (/^>.*/) { + $gobbling = 'bird-code'; + &incr_blk_ctr(); # for new code blk + + s/^>// if $Lang_typeset =~ /nobird/; # coerce to non-Bird + &append_to_curr_blk('code', $_); + + # incr srclineno, because it may later be fiddled downwards + $Blk_srcfile_lineno[$B]++ if ! $Lit2pgm; + &set_blk_magic_info('main'); + + if ($Ribbon_blks{'main'}) { + $Ribbon_blks{'main'} .= ",$B"; + } else { # first block + $Ribbon_blks{'main'} = $B; + } + } + + next line if $gobbling; # now set... + + # in alphabetical order, magical things to look for while categorizing + + if (/\\author\{(.+)\}/) { + if ($Lit2texi) { + $Doc_author = &deatified2verb($1); + $Doc_author =~ s/\\\\/\n\\center /g; + } else { + &append_to_curr_blk('txt',$_); + } + next line; # to help perl + + } elsif ($Lit2texi && /^\\appendix/) { + # tossed + next line; # to help perl + + } elsif ($Lit2texi && /^\\caption\{(.*)\}/) { + &append_to_curr_blk('txt',"CAPTION: $1\n"); + next line; # to help perl + + } elsif (/\\date\{(.+)\}/) { + if ($Lit2texi) { + $Doc_date = &deatified2verb($1); + $Doc_date =~ s/\\\\/\n\\center /g; + } else { + &append_to_curr_blk('txt',$_); + } + next line; # to help perl + + } elsif (/^\\define\{\\(.*)\}\s*\{(.*)\}/) { + $Define{$1} = $2; + # text not saved + next line; # to help perl + + } elsif (/^\\end\{document\}/) { # a magic section all its own! + &start_new_section(); + &incr_Sec_vec(0); # magical depth + $Sec_numstr[$S] = join('.',@Sec_vec); + + $Sec_depth[$S] = 0; # magic value for \begin/\end{document} + $Sec_nodename[$S]=''; # so a \001section\003 line will not be dumped for it + + $Sec_nodename[$S] = 'Bottom'; + # $Nodename_sec{'Bottom'} = $S; # no need for this + + &append_to_curr_blk('txt',$_) if $Lit2latex; + &append_to_curr_blk('txt','') if ! $Lit2latex; # need something there + next line; # to help perl + + } elsif (/^\\documentstyle(.*)\{(\w+)\}$/) { # says what top-level section should be + local($style_options) = $1; + local($document_type) = $2; + + $Standalone_doc = 1; + + $Sec_depth[0] = 0; + # makes node 'Top' start to exist (?) + &incr_Sec_vec(0); # magical depth + $Sec_numstr[0] = join('.',@Sec_vec); + + $Sec_nodename[0] = 'Top'; + $Nodename_sec{'Top'} = 0; + $Sec_nodespec[0] = 'Top,,,(dir)'; + + # depths are set so that top-level menu of sections can be constructed + if ($document_type eq 'report' || $document_type eq 'book') { + # \section1 is a "chapter" + # save info in weird form + &append_to_curr_blk('txt',"\001rootsectiontype\0032\002\n"); + } elsif ($document_type eq 'article') { + # \section1 is a "section" + &append_to_curr_blk('txt',"\001rootsectiontype\0033\002\n"); + } else { + ¬_OK($Srcfile_name, $Srcfile_lineno, + "don't recognise document type: $document_type\n"); + } + + # strip the literate style option and put in an explicit \input + # this ensures we get the version we want + $style_options =~ s/\bliterate\b//; + $style_options =~ s/,,/,/; # tidy any mess + $style_options =~ s/^\[,/\[/; + $style_options =~ s/,\]$/\]/; + $style_options =~ s/^\[\]$//; + if ($Lit2latex) { + &append_to_curr_blk('txt',"\\documentstyle$style_options\{$document_type\}\n"); + # \input is split over two lines so lit-inputter won't recognize it but LaTeX will + &append_to_curr_blk('txt',"\\input%\n"); + &append_to_curr_blk('txt',"\{$LIB_DIR/lit-style.tex\}\n"); + } + next line; # to help perl + + } + # split here to help perl + if (/^\\downsection/) { # save in weird form + &append_to_curr_blk('txt',"\001downsection\003\n"); + next line; # to help perl + + } elsif ($Lit2texi && /^\\(begin|end)\{figure\}/) { + #tossed + next line; # to help perl + + } elsif (! $Lit2pgm && /^\\input\{(.*)\}/) { + local($iname) = $1; + local($newsuff) = ($Lit2texi) ? 'itxi' : 'itex'; + + # change name to the expected suffix or add it if it doesn't have it + # cf setting Inputfile_root, etc. in lit2stuff driver + if ($iname =~ /\.lit\.[^\.\/]+$/) { # a .lit.<xx> suffix + $iname =~ s/\.lit\.[^\.\/]+$/\.$newsuff/; + } elsif ($iname =~ /\.[^\.\/]+$/) { + $iname =~ s/[^\.\/]+$/$newsuff/; + } else { + $iname .= ".$newsuff"; + } + &append_to_curr_blk('txt',"\\input\{$iname\}\n"); + next line; # to help perl + + } elsif (/^\\clear(doublepage|page)/) { + &append_to_curr_blk('txt',$_) if $Lit2latex; + next line; # to help perl + + } elsif (/^\\listof(figures|tables)/) { + &append_to_curr_blk('txt',$_) if $Lit2latex; + next line; # to help perl + + } elsif ($Lit2texi && /^\\infocommand\{\\(.*)\}\s*\{(.*)\}/) { + ¬_OK($Srcfile_name, $Srcfile_lineno, "\\infocommand is obsolete; pls use \\define\n"); + # text not saved + next line; # to help perl + + # \label's require a bit of extra stuff; see below + + } elsif (/^\\makeindex/) { +#ignored &append_to_curr_blk('txt',$_) if $Lit2latex; + next line; # to help perl + + } elsif (/\\menuentry\{(.+)\}\{(.+)\}/) { + if ($Lit2texi) { + local($tag) = $1; + local($descr) = $2; + $Sec_extra_menu_entries[$S] .= "\* $tag::\t$descr\n"; + } + next line; # to help perl + + } elsif (! $Lit2texi && /\\node\{.*\}/) { + # toss it + next line; # to help perl + + } elsif (/\\owner\{([^\}]+)\}/) { + local($owner_name) = &deatified2verb($1); + + $Sec_owner[$S] = $owner_name; + next line; # to help perl + } + + # split here to help perl + if (/^\\printindex/) { # sectioning-like things need doing for Texinfo + + if ($Lit2latex) { # hmm... means index might get tacked on when -g used +# &append_to_curr_blk('txt',$_); + + # manufacture a top-level section [very carefully] + # otherwise you can get index entries pinned on after the + # \printindex + &start_new_section(); + $Sec_depth[$S] = 1 ; + $Sec_title[$S] = ''; # no title + &incr_Sec_vec( 1 ); + $Sec_numstr[$S] = join('.',@Sec_vec); + $Sec_numstr_exists{$Sec_numstr[$S]} = $S; + $Sec_nodename[$S] = ''; # no nodename + $Nodename_sec{'Index'} = $S; + $Sec_nodespec[$S] = ''; + + &append_to_curr_blk('txt',$_); + + } elsif ($Lit2texi) { + # manufacture a top-level section + # (gaze in handle_sectioning_line, for enlightenment...) + &start_new_section(); + $Sec_depth[$S] = 1 ; + $Sec_title[$S] = 'Index'; + &incr_Sec_vec( 1 ); + $Sec_numstr[$S] = join('.',@Sec_vec); + $Sec_numstr_exists{$Sec_numstr[$S]} = $S; + $Sec_nodename[$S] = 'Index'; + $Nodename_sec{'Index'} = $S; + $Sec_nodespec[$S] = 'Index,?,?,?'; + + &append_to_curr_blk('txt',"\\printindex cp\n"); + } + next line; # to help perl + } elsif (/^\\rootsectiontype\{\\(\w+)\}/ || /^\\rootsectiontype\{(\w+)\}/) { + if ( ! defined($SECCMD_DEPTH{$1})) { + ¬_OK($Srcfile_name, $Srcfile_lineno, "bogus \\rootsectiontype: $1\n"); + } + # saved in weird form + &append_to_curr_blk('txt',"\001rootsectiontype\003$SECCMD_DEPTH{$1}\002\n"); + next line; # to help perl + + } elsif ( ! /^\\section(type|ref)/ + && (/^\\section[^A-Za-z]/ || /^\\(sub){1,3}section/)) { + # quick, zap the synonyms... + s/^\\section([^\d])/\\section1\1/; + s/^\\subsubsubsection/\\section4/; + s/^\\subsubsection/\\section3/; + s/^\\subsection/\\section2/; + + # now the real work + &start_new_section(); + &handle_sectioning_line(); + next line; # to help perl + + } elsif (/(.*)\\standaloneornot\{(.*)\}\{(.*)\}(.*\n)/) { + local($before) = $1; + local($ifso_text) = &deatified2verb_nl($2); + local($ifnot_text) = &deatified2verb_nl($3); + local($after) = $4; + + &append_to_curr_blk('txt',"$before$ifso_text$after") if $Standalone_doc; + &append_to_curr_blk('txt',"$before$ifnot_text$after") if ! $Standalone_doc; + next line; # to help perl + + } elsif (/^\\suppresscomments/) { + &append_to_curr_blk('txt',$_) if $Lit2latex; + ¬_OK($Srcfile_name,$Srcfile_lineno,"can't \\suppresscomments in Info files (warning)\n") if $Lit2texi; + next line; # to help perl + + } elsif (/^\\suppressmenu/) { + ¬_OK($Srcfile_name,$Srcfile_lineno,"\\suppressmenu not implemented\n"); + next line; # to help perl + + } elsif ($Lit2texi && /^\\(begin|end)\{table\}/) { + # tossed + next line; # to help perl + + } elsif (/^\\tableofcontents/) { + &append_to_curr_blk('txt',$_); + next line; # to help perl + + } elsif (/\\title\{(.+)\}/) { + if ($Lit2texi) { + $Doc_title = &deatified2verb($1); + $Doc_title =~ s/\\\\/\n\\center /g; + } else { + &append_to_curr_blk('txt',$_); + } + next line; # to help perl + + } elsif (/^\\upsection/) { # save in weird form + &append_to_curr_blk('txt',"\001upsection\003\n"); + next line; # to help perl + + } else { # just some random line of text + + # go after \label's + while ( ! $Lit2pgm && /\\label\{([^\}]+)\}/) { + local($label_name) = &deatified2verb($1); + + if (defined($Nodename_sec{$label_name})) { + ¬_OK($Srcfile_name,$Srcfile_lineno,"$label_name already used as a label or nodename\n"); + } else { + $Nodename_sec{$label_name} = $S; # new alias for this section + $Sec_aliases[$S] .= "$label_name,"; + } + s/\\label\{([^\}]+)\}// if $Lit2texi; + s/\\label\{/\\label!_\{/ if $Lit2latex; # temp + } + s/\\label!_\{/\\label\{/g if $Lit2latex; # untemp + + &append_to_curr_blk('txt',$_); + } + } + # wind up last section + $Sec_last_blk[$S] = $B; +} + +sub std_gobbling_stuff { # looks at $_ + # args say what to do with ordinary line ($curr_type) + # and what to do if \end{$gobbling} seen + local($curr_type, $end_type) = @_; + + if (/^\\end\{$gobbling\}/) { # it's over... + + if ($end_type eq 'NEW BLK ONLY') { + &incr_blk_ctr(); + + } elsif ($end_type ne 'TOSS IT') { + &incr_blk_ctr(); + &append_to_curr_blk($end_type, $_); + } + + $gobbling = ''; # finished + + } elsif ($curr_type ne 'TOSS IT') { # just append... + + # magic stuff for code and (flush)display + $_ = '>'.$_ if $gobbling eq 'code' && $Lang_typeset =~ /\bbird/; + s/\n$/\\hfil\\break\n/ if $Lit2latex && $gobbling =~ /display$/; + + &append_to_curr_blk($curr_type, $_); + } + # new $gobbling value returned + $gobbling; +} + +sub handle_sectioning_line { # part of categorizing input + local($sec_depth,$title,$node_spec) = ('', '', ''); + + if (/^\\section(\d+)\*\[([^\]]+)\]\{(.*)\}\s*\n/) { # given title, node-spec (STARRED) + $sec_depth = $1; $node_spec = $2; $title = "\001starred\003$3"; + $node_spec .= ',?,?,?' unless $node_spec =~ /,/; + + } elsif (/^\\section(\d+)\[([^\]]+)\]\{(.*)\}\s*\n/) { # given title, node-spec + $sec_depth = $1; $node_spec = $2; $title = $3; + $node_spec .= ',?,?,?' unless $node_spec =~ /,/; + + } elsif (/^\\section(\d+)\*\{(.*)\}\s*\n/) { # given title, default node-spec (STARRED) + $sec_depth = $1; $node_spec = '?,?,?,?'; $title = "\001starred\003$2"; + + } elsif (/^\\section(\d+)\{(.*)\}\s*\n/) { # given title, default node-spec + $sec_depth = $1; $title = $2; $node_spec = '?,?,?,?'; + + } else { + ¬_OK($Srcfile_name, $Srcfile_lineno, "hey, sectioning command has me confused: $_"); + } + if ($sec_depth <= 0) { + ¬_OK($Srcfile_name, $Srcfile_lineno, "section depth not positive: $_"); + $sec_depth = 1; + } elsif ($sec_depth > $MAX_SEC_DEPTH) { + ¬_OK($Srcfile_name, $Srcfile_lineno, "section depth more than $MAX_SEC_DEPTH: $_"); + $sec_depth = $MAX_SEC_DEPTH; + } + + $Sec_title[$S] = $title; # stored as deatified ... + $Sec_title[$S] =~ s/\001newline\003/ /g; # but the newlines go + $Sec_depth[$S] = $sec_depth; + &incr_Sec_vec($Sec_depth[$S]); + + $Sec_numstr[$S] = join('.',@Sec_vec); + $Sec_numstr_exists{$Sec_numstr[$S]} = $S; + + $node_spec =~ s/^\s+//; # tidy up + $node_spec =~ s/\s+$//; # no leading/trailing spaces + $node_spec =~ s/\s*,\s*/,/g; # no spaces around commas + + if ($node_spec =~ /^\?(,.*)/) { + local($rest_of_nodespec) = $1; + # default node name is root of input filename + section number + $Sec_nodename[$S] = $Inputfile_root + . '_' . &tidy_numstr($Sec_numstr[$S]) + . $Nodename_suffix; + $Sec_nodespec[$S] = $Sec_nodename[$S] . $rest_of_nodespec; + } elsif ($node_spec =~ /^([^,\?]+)(,.*)/) { + $Sec_nodename[$S] = $1 . $Nodename_suffix; + local($rest_of_nodespec) = $2; + $Sec_nodespec[$S] = $Sec_nodename[$S] . $rest_of_nodespec; + } else { + ¬_OK($Srcfile_name, $Srcfile_lineno, "node_spec has me confused: $node_spec\n"); + } + $Nodename_sec{$Sec_nodename[$S]} = $S; +} + +sub fiddle_line_numbers { + # there are some off-by-one errors in line numbers, because of the + # way things are recorded in read_and_categorize_input. try to fix. + local($S, $B); + + foreach ($S = 0; $S <= $#Sec_depth; $S++) { + foreach ($B = $Sec_first_blk[$S]; $B <= $Sec_last_blk[$S]; $B++) { + + # all the things where the \begin{something}/\end{something} + # isn't kept + + $Blk_srcfile_lineno[$B]-- + if ($Blk_type[$B] =~ /^(code|pseudocode)$/) + || ($Blk_type[$B] eq 'menu') + || ($Blk_type[$B] eq 'tabular') + || ($Blk_type[$B] =~ /verb$/); + } + } +} + +# keeps the including 'do' happy +1; +\end{code} diff --git a/web/glasgow/lit2x-0.16/literate/lit-style.tex b/web/glasgow/lit2x-0.16/literate/lit-style.tex new file mode 100644 index 0000000000..7ffd7603a0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit-style.tex @@ -0,0 +1,1152 @@ +% THIS FILE IS AUTOMATICALLY INPUT INTO GLASGOW LITERATE DOCUMENTS +% +% support for "literate programming" with Haskell (and other things) +% contact: Will Partain (partain@dcs.glasgow.ac.uk) +% +% most of it is copies of semi-std .sty files; +% done this way so we don't have to rely on others having them + +\newcommand{\ToDo}[1]{$\spadesuit$~{\bf ToDo:} {\em #1} $\spadesuit$} +\newcommand{\srcloc}[1]{\marginpar{\footnotesize\tt #1}} +\newcommand{\smiley}{% +\hbox{$\bigcirc\mskip-13.3mu{}^{..} +\mskip-11mu\scriptscriptstyle\smile\ $}} + +\makeatletter + +%% basic format, for better or worse, is "Simon's format" +%% intended for 11pt work +%% +%=================================================================== +%\input{a4wide.sty} +%NAME: a4wide.sty +% "moretext" document style option. +% Jean-Francois Lamy, July 86 +% +% Redefines the margins so that they are more in line with +% what we are used to see. +% + +%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%\input a4.sty +%% +%% This file was generated with `docstrip.tex' version v1.0b <89/11/05> +%% +%% The original source file was `a4.doc'. +%% +%% IMPORTANT NOTICE: +%% You are not allowed to distribute this file. +%% For distribution of the original source see +%% the copyright notice in the file `a4.doc'. +%% +\def\fileversion{1.2} +\def\filedate{26 Feb 90} +\def\docdate {26 Feb 90} +%% \CheckSum{134} +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%% +%%\typeout{Style option `A4' \fileversion\space<\filedate> (NP and JLB)} +%%\typeout{English documentation\space\space\space<\docdate> (JLB)} +\topmargin 0pt +\ifcase \@ptsize + \textheight 53\baselineskip +\or + \textheight 46\baselineskip +\or + \textheight 42\baselineskip +\fi +\advance\textheight by \topskip +\ifcase \@ptsize + \textwidth 5.00in + \marginparwidth 1.00in + \if@twoside + \oddsidemargin 0.55in + \evensidemargin 0.75in + \else + \oddsidemargin 0.55in + \evensidemargin 0.55in + \fi +\or + \textwidth 5.20in + \marginparwidth 1.00in + \if@twoside + \oddsidemargin 0.45in + \evensidemargin 0.65in + \else + \oddsidemargin 0.45in + \evensidemargin 0.45in + \fi +\or + \textwidth 5.70in + \marginparwidth 0.80in + \if@twoside + \oddsidemargin 0.20in + \evensidemargin 0.40in + \else + \oddsidemargin 0.20in + \evensidemargin 0.20in + \fi +\fi +\def\WideMargins{% + \newdimen\ExtraWidth + \ifcase \@ptsize + \ExtraWidth = 0.5in + \@widemargins + \or + \ExtraWidth = 0.5in + \@widemargins + \or + \ExtraWidth = 0.7in + \@widemargins + \fi\let\WideMargins\relax\let\@widemargins\relax} +{\def\do{\noexpand\do\noexpand} + \xdef\@preamblecmds{\@preamblecmds \do\WideMargins} +} +\def\@widemargins{% + \global\advance\textwidth by -\ExtraWidth + \global\advance\marginparwidth by \ExtraWidth + \if@twoside + \tw@sidedwidemargins + \else + \@nesidedwidemargins + \fi} +\def\tw@sidedwidemargins{% + \if@reversemargin + \@tempdima=\evensidemargin + \advance\@tempdima by -\oddsidemargin + \advance\oddsidemargin by \ExtraWidth + \advance\oddsidemargin by \@tempdima + \advance\evensidemargin by -\@tempdima + \else + \advance\evensidemargin by \ExtraWidth + \fi} +\def\@nesidedwidemargins{% + \if@reversemargin + \advance\oddsidemargin by \ExtraWidth + \advance\evensidemargin by \ExtraWidth + \fi} +%\endinput +% end of a4.sty +%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +\ifcase \@ptsize + % mods for 10 pt + \oddsidemargin 0.15 in % Left margin on odd-numbered pages. + \evensidemargin 0.35 in % Left margin on even-numbered pages. + \marginparwidth 1 in % Width of marginal notes. + \oddsidemargin 0.25 in % Note that \oddsidemargin = \evensidemargin + \evensidemargin 0.25 in + \marginparwidth 0.75 in + \textwidth 5.875 in % Width of text line. +\or % mods for 11 pt + \oddsidemargin 0.1 in % Left margin on odd-numbered pages. + \evensidemargin 0.15 in % Left margin on even-numbered pages. + \marginparwidth 1 in % Width of marginal notes. + \oddsidemargin 0.125 in % Note that \oddsidemargin = \evensidemargin + \evensidemargin 0.125 in + \marginparwidth 0.75 in + \textwidth 6.125 in % Width of text line. +\or % mods for 12 pt + \oddsidemargin -10 pt % Left margin on odd-numbered pages. + \evensidemargin 10 pt % Left margin on even-numbered pages. + \marginparwidth 1 in % Width of marginal notes. + \oddsidemargin 0 in % Note that \oddsidemargin = \evensidemargin + \evensidemargin 0 in + \marginparwidth 0.75 in + \textwidth 6.375 true in % Width of text line. +\fi +% end of a4wide.sty +%=================================================================== + +% Block paragraphs +% NOTE: comment out these four lines if you want more +% standard LaTeX-looking paragraphs. +\setlength{\parskip}{0.25cm} +% partain: save the parindent value, for indenting code +\newlength{\litcodeindent} +\setlength{\litcodeindent}{\z@} +%\setlength{\litcodeindent}{\parindent} +% comment out this one line if you want std para indentation: +\setlength{\parindent}{0cm} +%\renewcommand{\textfraction}{0.2} +%\renewcommand{\floatpagefraction}{0.7} + +% display environment: same as "quotation" +\def\display{\list{}{\listparindent \z@ + \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\enddisplay=\endlist + +% flushdisplay environment: same as "display" but without indent +\def\flushdisplay{\list{}{\listparindent \z@ + \itemindent\listparindent + \leftmargin\z@ \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endflushdisplay=\endlist + +% unflushverbatim environment: "verbatim" is naturally "flush" +% so this simply arranges "unflushness". It presumes things are written as... +% \begin{unflushverbatim} +% \begin{verbatim} +% <stuff> +% \end{verbatim} +% \end{unflushverbatim} +% +\def\unflushverbatim{\list{}{\listparindent \z@ + \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endunflushverbatim=\endlist + +%\newcommand{\BeginLitCode}{\par\noindent\begin{tabular}{@{\hspace*{1.2em}}l@{}}} +%\newcommand{\BeginLitCodeNoIndent}{\par\noindent\begin{tabular}{@{}l@{}}} +%\newcommand{\EndLitCode}{\end{tabular}} + +% same, for now +%\newcommand{\BeginLitVerb}{\par\noindent\begin{tabular}{@{\hspace*{1.2em}}l@{}}} +%\newcommand{\BeginLitVerbNoIndent}{\par\noindent\begin{tabular}{@{}l@{}}} +%\newcommand{\EndLitVerb}{\end{tabular}} + +% and some internal variants that set the page numbers differently +\newcommand{\indexttit}[1]{\index{#1@{\tt #1}|itindexpage}} +\newcommand{\itindexpage}[1]{{\it #1}} +%\newcommand{\indexPageUL}[1]{\index{#1|underline}} +\newcommand{\ttize}[1]{{\tt #1}} +\newcommand{\ttunderline}[1]{\underline{\tt #1}} + +\newcommand{\heading}[1]{\par\vspace{2\baselineskip}\noindent #1\par} + +\newcommand{\Haskell}{Haskell} + +% slightly hacked... +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% File "comment.sty" (by Tom Hofmann, E-mail: wtho@cgch.UUCP) +% 1989-10-30 +% +% This File contains the definition of a LaTeX environment "comment" +% which allows to alternatively print or suppress parts of the document. +% +% +% Usage: +% +% - Declare "comment" as documentstyle option or include this file +% by "\input{comment.sty}" +% - Embed comments in "\begin{comment}" and "\end{comment}" +% - To print the document including the comments write "\printcomments" +% before the first comment. Alternatively, write "\suppresscomments" +% to print without comments. +% - The default setting is "\printcomments". +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% (1) Definition of the environment "comment" when notes are +% to be printed. + +% hack here +% orig: \def\printcomments{\def\comment{}} % "\endcomment" can be missing + +\def\printcomments{\def\comment{\par \small {\em Comment:}}} % "\endcomment" can be missing + +% (2) Definition of the environment "comment" when notes are not +% to be printed. + +% Make '{' and '}' "other characters" and make '(' and ')' +% "begingroup" and "endgroup" resp. Thus make it possible +% to have "\end{comment}" as part of a macro definition. + +\begingroup\makeatletter % since the catcodes of '{' and '}' +\catcode`{=12\relax\catcode`}=12\relax % will change, use \begingroup and +\catcode`(=1\relax \catcode`)=2\relax % \endgroup instead. + +\gdef\suppresscomments(% + +% Make '{' and '}' searchable when expanding the macro by giving them +% the same catcode in the subsequent text as in the macro definition. + + \gdef\comment(\catcode`{=12\relax\catcode`}=12\relax\@NOTE) + +% Skip text between "\begin{comment}" and "\end{comment}" +% (inclusive), but return an "\end{comment}" command to LaTeX for +% the correct environment handling (see below). + + \long\gdef\@NOTE##1\end{comment}(\@ENDNOTE)) + + +\endgroup % End of the enchantment. + +% Generate an environment-end command conformable to LaTeX. + +{\makeatletter\gdef\@ENDNOTE{\end{comment}}} + +\printcomments % This is the default setting. + +%======================================================================== +% saves having to put this in all the time +%\input{makeidx.sty} +% makeidx.sty 20-Jan-87 + +\def\see#1#2{{\em see\/} #1} +\def\printindex{\@input{\jobname.ind}} +% end of makeidx.sty +\makeatother +%======================================================================== + +%======================================================================== +\makeatletter +% file tgrind.sty +% NB: nuke line numbering +%%%%%%%%%%% +%NAME: tgrind.sty +% LaTeX tgrind environment + +% Based on Van Jacobson's ``tgrindmac'', a macro package for TeX grinding +% Our job here is to simplify it quite a bit and make it conform to LaTeX + +\newif\ifcomment\newif\ifstring +\newcount\linecount\newcount\linenext +\newbox\linesofar +\newdimen\TBwid +\newdimen\ts +\newbox\tbox + +\def\tgrind{% +% Stuff we ignore for right now. +\let\Head=\@gobble +\def\File##1,##2,##3{} +\let\Proc=\@gobble +\let\ProcCont=\@gobble +% +% Each formfeed in the input is replaced by a "\NewPage" macro. If +% you really want a page break here, define this as "\vfill\eject". +\def\NewPage{\filbreak\bigskip} +% +% Each line of the program text is enclosed by a "\L{...}". We turn +% each line into an hbox of size hsize. If we saw a procedure name somewhere +% in the line (i.e., "procbox" is not null), we right justify "procbox" +% on the line. Every 10 lines we output a small, right justified line number. +\def\L##1{\par\hbox to\hsize{\CF\strut\global\advance\linecount by1 +##1\hss\linebox}} +% +\linecount=0 +\linenext=9 +\def\linebox{\ifnum\linecount>\linenext\global\advance\linenext by10 +% partain: \hbox{\sevrm\the\linecount}\fi} +% partain2: \hbox{\rm\tiny\the\linecount}\fi} +\hbox{}\fi} +% +% The following weirdness is to deal with tabs. "Pieces" of a line +% between tabs are output as "\LB{...}". E.g., a line with a tab at +% column 16 would be output as "\LB{xxx}\Tab{16}\LB{yyy}". (Actually, to +% reduce the number of characters in the .tex file the \Tab macro +% supplies the 2nd & subsequent \LB's.) We accumulate the LB stuff in an +% hbox. When we see a Tab, we grab this hbox (using "\lastbox") and turn +% it into a box that extends to the tab position. We stash this box in +% "\linesofar" & use "\everyhbox" to get \linesofar concatenated onto the +% front of the next piece of the line. (There must be a better way of +% doing tabs [cf., the Plain.tex tab macros] but I'm not not enough of a +% TeX wizard to come up with it. Suggestions would be appreciated.) +\def\LB{\CF\hbox} +\setbox\linesofar=\null +\everyhbox={\box\linesofar} +\def\Tab##1{\setbox\tbox=\lastbox\TBwid=1\wd\tbox\advance\TBwid by 1\ts +\ifdim\TBwid>##1\ts +\setbox\linesofar=\hbox{\box\tbox\space}\else +\setbox\linesofar=\hbox to ##1\ts{\box\tbox\hfil}\fi\LB} +% +% A normal space is too thin for code listings. We make spaces & tabs +% be in "\ts" units (which are the width of a "0" in the current font). +\setbox\tbox=\hbox{0} \ts=1\wd\tbox \setbox\tbox=\hbox{\hskip 1\ts} +\def\space{\hskip 1\ts\relax} +% +% Font changing stuff for keywords, comments & strings. We put keywords +% in boldface, comments in text-italic & strings in typewriter. Since +% we're usually changing the font inside of a \LB macro, we remember the +% current font in \CF & stick a \CF at the start of each new box. +% Also, the characters " and ' behave differently in comments than in +% code, and others behave differently in strings than in code. +\let\CF=\rm +\def\K##1{{\bf ##1}} % Keyword +\def\C{\it\global\let\CF=\it\global\commenttrue\relax} % Comment Start +\def\CE{\rm\global\let\CF=\rm\global\commentfalse\relax}% Comment End +\def\S{\tt\global\let\CF=\tt\global\stringtrue\relax} % String Start +\def\SE{\rm\global\let\CF=\rm\global\stringfalse\relax} % String End +% +% Special characters. +\def\{{\ifmmode\lbrace\else\ifstring{\char'173}\else$\lbrace$\fi\fi} +\def\}{\ifmmode\rbrace\else\ifstring{\char'175}\else$\rbrace$\fi\fi} +\def\!{\ifmmode\backslash\else\ifstring{\char'134}\else$\backslash$\fi\fi} +\def\|{\ifmmode|\else\ifstring{\char'174}\else$|$\fi\fi} +\def\<{\ifmmode<\else\ifstring<\else$<$\fi\fi} +\def\>{\ifmmode>\else\ifstring>\else$>$\fi\fi} +\def\/{\ifmmode/\else\ifstring/\else$/$\fi\fi} +\def\-{\ifmmode-\else\ifstring-\else$-$\fi\fi} +\def\_{\ifstring{\char'137}\else\underbar{\ }\fi} +\def\&{{\char'046}} +\def\#{{\char'043}} +\def\%{{\char'045}} +\def\~{{\char'176}} +\def\"{\ifcomment''\else{\tt\char'042}\fi} +\def\'{\ifcomment'\else{\tt\char'047}\fi} +\def\^{{\char'136}} +\def\${{\rm\char'044}} +% +\raggedright\obeyspaces%\let =\space% +} + +% \tagrind*[FLOAT]{FILE}{CAPTION}{LABEL} +% * optional +% FLOAT float options +% FILE reads LaTeXgrind input in file FILE +% CAPTION for list of figures +% LABEL for \ref and \pageref +\def\tagrind{\@ifstar{\@stagrind}{\@tagrind}} + +\def\@tagrind{\@ifnextchar[{\@@tagrind}{\@@tagrind[t]}} +\def\@stagrind{\@ifnextchar[{\@@stagrind}{\@@stagrind[t]}} + +\def\@@tagrind[#1]#2#3#4{% + \begin{figure}[#1] + \hrule + \vskip .5\baselineskip + \begin{minipage}\columnwidth\small + \begin{tgrind} + \input #2\relax + \end{tgrind} + \end{minipage} + \vskip .5\baselineskip plus .5\baselineskip + \begingroup + \setbox\z@=\hbox{#4}% + \ifdim\wd\z@>\z@ + \caption{#3}% + \label{#4}% + \else + \captcont{#3}% + \fi + \endgroup + \vskip 2pt + \hrule + \end{figure} +} + +\def\@@stagrind[#1]#2#3#4{% + \begin{figure*}[#1] + \hrule + \vskip .5\baselineskip + \begin{minipage}\textwidth\small + \begin{tgrind} + \input #2\relax + \end{tgrind} + \end{minipage} + \vskip .5\baselineskip plus .5\baselineskip + \begingroup + \setbox\z@=\hbox{#4}% + \ifdim\wd\z@>\z@ + \caption{#3}% + \label{#4}% + \else + \captcont{#3}% + \fi + \endgroup + \vskip 2pt + \hrule + \end{figure*} +} + + +\def\tgrindfile#1{% + \par\addvspace{0.1in} + \hrule + \vskip .5\baselineskip + \begin{footnotesize} + \begin{tgrind} + \input #1\relax + \end{tgrind} + \end{footnotesize} + \vskip .5\baselineskip + \hrule + \addvspace{0.1in} +} +% end of tgrind.sty +\makeatother +%======================================================================== + +%======================================================================== +% changebar.sty +\makeatletter + +%% This is file `changebar.sty' generated +%% on <1992/1/6> with the docstrip utility (v1.1k). +%% +%% The original source file was `changebar.doc'. +%% Included modules: `changebar'. +%% +%% IMPORTANT NOTICE: +%% You are not allowed to distribute this file. +%% For distribution of the original source see +%% the copyright notice in the file `changebar.doc'. +%% +\def\fileversion{v3.0-test} +\def\filedate{6 Nov 91} +\def\docdate{6 Nov 91} +%% \CheckSum{798} +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\wlog{Document style option `changebar', \fileversion\space<\filedate>} +\chardef\atcatcode=\catcode`\@ +\catcode`\@=11\relax +\def\cb@maxpoint{80} +\def\cb@minpoint{1} +\def\cb@nil{0} +\newcount\cb@nextpoint +\cb@nextpoint=\cb@minpoint +\newcount\cb@currentpoint +\newcount\cb@page +\newcount\cb@pagecount +\cb@pagecount=0 +\newif\ifouterbars \outerbarsfalse +\newdimen\cb@odd +\newdimen\cb@even +\def\cb@positions{% + \global\cb@odd =\hoffset + \global\advance\cb@odd by \oddsidemargin + \ifouterbars + \global\advance\cb@odd by \textwidth + \global\advance\cb@odd by \changebarsep + \else + \global\advance\cb@odd by -\changebarsep + \fi + \global\cb@even =\hoffset + \global\advance\cb@even by \evensidemargin + \if@twoside + \ifouterbars + \global\advance\cb@even by -\changebarsep + \else + \global\advance\cb@even by \textwidth + \global\advance\cb@even by \changebarsep + \fi + \else + \ifouterbars + \global\advance\cb@even by \textwidth + \global\advance\cb@even by \changebarsep + \else + \fi + \global\advance\cb@even by -\changebarsep + \fi} +{\catcode`\p=12\catcode`\t=12 \gdef\cb@removedim#1pt{#1}} +\def\driver#1{% + \bgroup\edef\next{\def\noexpand\tempa{#1}}% + \uppercase\expandafter{\next}% + \def\LN{DVITOLN03}% + \def\DVItoPS{DVITOPS}% + \def\DVIPS{DVIPS}% + \def\emTeX{EMTEX}% + \global\chardef\cb@driver@setup=0 + \ifx\tempa\LN \global\chardef\cb@driver@setup=0\fi + \ifx\tempa\DVItoPS \global\chardef\cb@driver@setup=1\fi + \ifx\tempa\DVIPS \global\chardef\cb@driver@setup=2\fi + \ifx\tempa\emTeX \global\chardef\cb@driver@setup=3\fi + \egroup} +{\def\do{\noexpand\do\noexpand} + \xdef\@preamblecmds{\@preamblecmds \do\driver} +} +\def\cb@setup@specials{% +\ifcase\cb@driver@setup + \def\cb@defpoint##1##2{\special{ln03:defpoint \the##1(\the##2,)}} + \def\cb@connect##1##2##3{% + \special{ln03:connect \the##1\space\space \the##2\space \the##3}} + \def\cb@resetpoints{% + \special{ln03:resetpoints \cb@minpoint \space\cb@maxpoint}} +\or + \def\cb@defpoint##1##2{% + \special{dvitops: inline + \expandafter\cb@removedim\the##2\space 6.5536 mul\space + /CBarX\the##1\space exch def currentpoint exch pop + /CBarY\the##1\space exch def}} + \def\cb@connect##1##2##3{% + \special{dvitops: inline + gsave \thechangebargrey\space 100 div setgray + \expandafter\cb@removedim\the##3\space 6.5536 mul\space + CBarX\the##1\space\space CBarY\the##1\space\space moveto + CBarX\the##2\space\space CBarY\the##2\space\space lineto + stroke grestore}} + \let\cb@resetpoints\relax +\or + \def\cb@defpoint##1##2{% + \special{ps: + \expandafter\cb@removedim\the##2\space 4.096 mul\space + Resolution\space mul\space 300\space div\space + /CBarX\the##1\space exch def currentpoint exch pop + /CBarY\the##1\space exch def}} + \def\cb@connect##1##2##3{% + \special{ps: + gsave \thechangebargrey\space 100 div setgray + \expandafter\cb@removedim\the##3\space 4.096 mul\space + Resolution\space mul\space 300\space div\space + setlinewidth + CBarX\the##1\space\space CBarY\the##1\space\space moveto + CBarX\the##2\space\space CBarY\the##2\space\space lineto + stroke grestore}} + \let\cb@resetpoints\relax +\or + \typeout{Changebar Warning: changebars only supported for v1.5+ of dvidrv}% + \def\cb@defpoint##1##2{\special{em:point \the##1,\the##2}} + \def\cb@connect##1##2##3{\special{em:line \the##1,\the##2,\the##3}} + \let\cb@resetpoints\relax +\else + \typeout{Changebar Warning: changebars not supported in unknown setup} + \def\cb@defpoint##1##2{} + \def\cb@connect##1##2##3{} + \let\cb@resetpoints\relax +\fi +\global\let\cb@setup@specials\relax} +\def\cbstart{\@ifnextchar [{\cb@start}{\cb@start[\changebarwidth]}} +\def\cbend{\cb@end} +\def\cbdelete{\@ifnextchar [{\cb@delete}{\cb@delete[\deletebarwidth]}} +\def\cb@delete[#1]{\vbox to 0pt{\vss\cb@start[#1]\vskip #1\cb@end}} +\def\changebar{\@ifnextchar [{\cb@start}{\cb@start[\changebarwidth]}}% +\def\endchangebar{\cb@end} +\def\nochangebars{\def\cb@start[##1]{}% + \def\cb@delete[##1]{}% + \let\cb@end\relax} +\newlength{\changebarwidth} +\setlength{\changebarwidth}{2pt} +\newlength{\deletebarwidth} +\setlength{\deletebarwidth}{4pt} +\newlength{\changebarsep} +\setlength{\changebarsep}{30pt} +\newcounter{changebargrey} +\setcounter{changebargrey}{65} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\def\cb@start[#1]{\cb@currentpoint=\cb@nextpoint + \@tempdima=#1\relax % for \cb@push + \cb@push\cb@currentlist + \ifvmode \cb@setBeginPoint\cb@currentpoint + \else \vbox to 0pt{\vskip -\ht\strutbox %jump up a line to + \cb@setBeginPoint\cb@currentpoint %set point + \vskip \ht\strutbox}\fi + \cb@writeAux\cb@advancePoint} +\def\cb@advancePoint{% + \global\advance\cb@nextpoint by 2\relax + \ifnum\cb@nextpoint>\cb@maxpoint + \global\cb@nextpoint=\cb@minpoint\relax + \fi} +\def\cb@end{% + \cb@pop\cb@currentlist + \ifnum\cb@currentpoint=\cb@nil + \typeout{Changebar Warning: Badly nested changebars; + Expect erroneous results}% + \else + \cb@setEndPoint\cb@currentpoint + \advance\cb@currentpoint by1\cb@writeAux + \fi} +\def\cb@setBeginPoint#1{% + \ifodd\cb@pagecount + \cb@defpoint{#1}{\cb@even}% + \else + \cb@defpoint{#1}{\cb@odd}% + \fi} +\def\cb@setEndPoint#1{% + \@tempcnta=#1\advance\@tempcnta by1\relax + \ifodd\cb@pagecount + \cb@defpoint{\@tempcnta}{\cb@even}% + \else + \cb@defpoint{\@tempcnta}{\cb@odd}% + \fi + \cb@connect{#1}{\@tempcnta}{\@tempdima}}% +\def\cb@writeAux{% + \if@filesw + \begingroup + \edef\point{\the\cb@currentpoint}% + \edef\level{\the\@tempdima}% + \let\the=0% + \edef\cb@temp{\write\@auxout + {\string\cb@barpoint{\point}{\the\cb@pagecount}{\level}}}% + \cb@temp + \endgroup + \fi} +\let\cb@makecol=\@makecol +\def\@makecol{% + \setbox\@cclv=\vbox{\cb@resetpoints\cb@beginSaves\unvbox\@cclv}% + \gdef\cb@beginSaves{} + \global\advance\cb@pagecount by 1% + \cb@buildActive\cb@processActive + \cb@makecol} +\def\cb@processActive{% + \cb@pop\cb@spanlist + \ifnum\cb@currentpoint=\cb@nil + \else + \setbox\@cclv=\vbox{\unvbox\@cclv\advance\cb@pagecount by -1% + \cb@setEndPoint\cb@currentpoint}% + \cb@saveBeginPoint\cb@currentpoint + \cb@push\cb@history + \cb@processActive + \fi} +\def\cb@saveBeginPoint#1{% + \ifodd\cb@pagecount + \xdef\cb@beginSaves{\cb@defpoint{#1}{\cb@even}\cb@beginSaves}% + \else + \xdef\cb@beginSaves{\cb@defpoint{#1}{\cb@odd}\cb@beginSaves}% + \fi} +\def\cb@beginSaves{} % initially empty +\def\cb@buildActive{\cb@initlist\cb@spanlist\cb@pushNextActive} +\def\cb@pushNextActive{% + \cb@pop\cb@history + \ifnum\cb@currentpoint=\cb@nil + \else + \ifnum\cb@page>\cb@pagecount + \cb@push\cb@history + \else + \ifodd\cb@currentpoint + \cb@push\cb@spanlist + \else + \cb@pop\cb@spanlist + \fi + \cb@pushNextActive + \fi + \fi} +\def\cb@initlist#1{\xdef#1{}} +\cb@initlist\cb@history % the history list; initially empty +\cb@initlist\cb@spanlist % list of bars spanning current page +\cb@initlist\cb@currentlist % used to implement nesting without using + +\newwrite\cb@write % file for history list +\newread\cb@read +\immediate\openout\cb@write=\jobname.cb % open for building of history list +\def\cb@pop#1{% + \ifx #1\cb@history + \ifeof\cb@read + \else + {\endlinechar=-1\read\cb@read to\@temp + \xdef\cb@history{\cb@history\@temp}% + }% + \fi + \fi + \ifx#1\@empty + \cb@currentpoint=\cb@nil\cb@page=0% + \else + \expandafter\cb@carcdr#1e#1% + \fi} +\def\cb@carcdr#1n#2p#3l#4e#5{% + \cb@currentpoint=#1\cb@page=#2\@tempdima=#3\xdef#5{#4}} +\def\cb@push#1{% + \xdef#1{\the\cb@currentpoint n\the\cb@page p\the\@tempdima l#1}} +\def\cb@barpoint#1#2#3{\immediate\write\cb@write{#1n#2p#3l}} +\let\cb@document=\document +\def\document{\cb@document + \cb@setup@specials + \cb@positions + \immediate\closeout\cb@write + \immediate\openin\cb@read=\jobname.cb} +\let\cb@enddocument\enddocument +\def\enddocument{\clearpage\cb@initlist\cb@history + \immediate\closein\cb@read\immediate\openin\cb@read=\jobname.cb% + \let\cb@barpoint=\cb@checkHistory\cb@enddocument} +\def\cb@checkHistory#1#2#3{\cb@pop\cb@history + \ifnum #1=\cb@currentpoint + \ifnum #2=\cb@page % do nothing + \else \cb@error % page numbers mismatched + \fi + \else \cb@error % point numbers mismatched + \fi} +\def\cb@error{% + \message{Changebar Warning: Changebar info has changed. % + Rerun to get right.} + \gdef\cb@checkHistory##1##2##3{}% + \let\cb@barpoint=\cb@checkHistory} +\let\cb@endfloat=\end@float +\def\end@float{% + \cb@pop\cb@currentlist + \ifnum\cb@currentpoint=\cb@nil + \else + \cb@push\cb@currentlist + \global\@tempdima=\@tempdima + \egroup + \global\setbox\@currbox=% + \vbox\bgroup\cb@start[\@tempdima]\unvbox\@currbox\cb@end + \fi + \cb@endfloat} +\let\endfigure=\end@float % need to rebind these to new def +\let\endtable=\end@float +\let\cb@footnote=\@footnotetext +\long\def\@footnotetext#1{% + \cb@pop\cb@currentlist + \ifnum\cb@currentpoint=\cb@nil + \cb@footnote{#1} + \else + \cb@push\cb@currentlist + \edef\cb@temp{\the\@tempdima}% + \cb@footnote{\cb@start[\cb@temp]#1\cb@end}% + \fi} +\let\cb@mpfootnote=\@mpfootnotetext +\long\def\@mpfootnotetext#1{% + \cb@pop\cb@currentlist + \ifnum\cb@currentpoint=\cb@nil + \cb@mpfootnote{#1} + \else + \cb@push\cb@currentlist + \edef\cb@temp{\the\@tempdima}% + \cb@mpfootnote{\cb@start[\cb@temp]#1\cb@end}% + \fi} +\catcode`\@=\atcatcode \let\atcatcode\relax +%\endinput +%% +%% End of file `changebar.sty'. +% +% end of changebar.sty; now we configure it: +% +% partain: +\driver{DVIPS} +% want black, thin lines +\setlength{\changebarwidth}{0.2pt} +\setcounter{changebargrey}{0} +% +\makeatother +%======================================================================== + +%======================================================================== +\makeatletter + +% Olin Shiver's code.sty +% partain: the stuff actually used is defined immediately afterwards +%-------- +% code.sty: -*- latex -*- +% Latex macros for a "weak" verbatim mode. +% -- like verbatim, except \, {, and } have their usual meanings. + +% Environments: code, tightcode, codeaux, codebox, centercode +% Commands: \dcd, \cddollar, \cdmath, \cd, \codeallowbreaks, \codeskip, \^ +% Already defined in LaTeX, but of some relevance: \#, \$, \%, \&, \_, \{, \} + +% Changelog at the end of the file. + +% These commands give you an environment, code, that is like verbatim +% except that you can still insert commands in the middle of the environment: +% \begin{code} +% for(x=1; x<loop_bound; x++) +% y += x^3; /* {\em Add in {\tt x} cubed} */ +% \end{code} +% +% All characters are ordinary except \{}. To get \{} in your text, +% you use the commands \\, \{, and \}. + +% These macros mess with the definition of the special chars (e.g., ^_~%). +% The characters \{} are left alone, so you can still have embedded commands: +% \begin{code} f(a,b,\ldots,y,z) \end{code} +% However, if your embedded commands use the formerly-special chars, as in +% \begin{code} x := x+1 /* \mbox{\em This is $y^3$} */ \end{code} +% then you lose. The $ and ^ chars are scanned in as non-specials, +% so they don't work. If the chars are scanned *outside* the code env, +% then you have no problem: +% \def\ycube{$y^3$} +% \begin{code} x := x+1 /* {\em This is \ycube} */ \end{code} +% If you must put special chars inside the code env, you do it by +% prefixing them with the special \dcd ("decode") command, that +% reverts the chars to back to special status: +% \begin{code} x := x+1 /* {\dcd\em This is $y^3$} */ \end{code} +% \dcd's scope is bounded by its enclosing braces. It is only defined within +% the code env. You can also turn on just $ with the \cddollar command; +% you can turn on just $^_ with the \cdmath command. See below. +% +% Alternatively, just use \(...\) for $...$, \sp for ^, and \sb for _. + +% WARNING: +% Like \verb, you cannot put a \cd{...} inside an argument to a macro +% or a command. If you try, for example, +% \mbox{\cd{$x^y$}} +% you will lose. That is because the text "\cd{$x^y$}" gets read in +% as \mbox's argument before the \cd executes. But the \cd has to +% have a chance to run before LaTeX ever reads the $x^y$ so it can +% turn off the specialness of $ and ^. So, \cd has to appear at +% top level, not inside an argument. Similarly, you can't have +% a \cd or a \code inside a macro (Although you could use \gdef to +% define a macro *inside* a \cd, which you could then use outside. +% Don't worry about this if you don't understand it.) + +% BUG: In the codebox env, the effect of a \dcd, \cddollar, or \cdmath +% command is reset at the end of each line. This can be hacked by +% messing with the \halign's preamble, if you feel up to it. + +% Useage note: the initial newline after the \begin{code} or +% \begin{codebox} is eaten, but the last newline is not. +% So, +% \begin{code} +% foo +% bar +% \end{code} +% leaves one more blank line after bar than does +% \begin{code} +% foo +% bar\end{code} +% Moral: get in the habit of terminating code envs without a newline +% (as in the second example). +% + +% All this stuff tweaks the meaning of space, tab, and newline. +%=============================================================================== +% \cd@obeyspaces +% Turns all spaces into non-breakable spaces. +% Note: this is like \@vobeyspaces except without spurious space in defn. +% @xobeysp is basically a space; it's defined in latex.tex. +% +{\catcode`\ =\active\gdef\cd@obeyspaces{\catcode`\ =\active\let =\@xobeysp}} + + + +% \cd@obeytabs +% Turns all tabs into 8 non-breakable spaces (which is bogus). +% +{\catcode`\^^I=\active % + \gdef\cd@obeytabs{\catcode`\^^I=\active\let^^I=\cd@tab}} + +\def\cd@tab{\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp} + + + +% \cd@obeylines +% Turns all cr's into linebreaks. Pagebreaks are not permitted between lines. +% This is copied from lplain.tex's \obeylines, with the cr def'n changed. +% +{\catcode`\^^M=\active % these lines must end with % + \gdef\cd@obeylines{\catcode`\^^M=\active\let^^M=\cd@cr}} + +% What ^M turns into. This def'n keeps blank lines from being compressed out. +\def\cd@cr{\par\penalty10000\leavevmode} % TeX magicness +%\def\cd@cr{\par\penalty10000\mbox{}} % LaTeX + + +% \codeallowbreaks +% Same as \cd@obeylines, except pagebreaks are allowed. +% Put this command inside a code env to allow pagebreaks. + +{\catcode`\^^M=\active % these lines must end with % + \gdef\codeallowbreaks{\catcode`\^^M\active\let^^M\cd@crbr}} + +%\def\cd@crbr{\leavevmode\endgraf} % What ^M turns into. +%partain: +\def\cd@crbr{\par\leavevmode} % What ^M turns into. + + +% \cd@obeycrsp +% Turns cr's into non-breakable spaces. Used by \cd. + +{\catcode`\^^M=\active % these lines must end with % + \gdef\cd@obeycrsp{\catcode`\^^M=\active\let^^M=\@xobeysp}} + +% ============================================================================= + +% Set up code environment, in which most of the common special characters +% appearing in code are treated verbatim, namely: $&#^_~% +% \ { } are still enabled so that macros can be called in this +% environment. Use \\, \{, and \} to use these characters verbatim +% in this environment. +% +% Inside a group, you can make +% all the hacked chars special with the \dcd command +% $ special with the \cddollar command +% $^_ special with the \cdmath command. +% If you have a bunch of math $..$'s in your code env, then a global \cddollar +% or \cdmath at the beginning of the env can save a lot of trouble. +% When chars are special (e.g., after a \dcd), you can still get #$%&_{} with +% \#, \$, \%, \&, \_, \{, and \} -- this is standard LaTeX. +% Additionally, \\ gives \ inside the code env, and when \cdmath +% makes ^ special, it also defines \^ to give ^. + +%The hacked characters can be made special again +% within a group by using the \dcd command. + +% Note: this environment allows no breaking of lines whatsoever; not +% at spaces or hypens. To arrange for a break use the standard \- command, +% or a \discretionary{}{}{} which breaks, but inserts nothing. This is useful, +% for example for allowing hypenated identifiers to be broken, e.g. +% \def\={\discretionary{}{}{}} %optional break +% FOO-\=BAR. + +\def\setupcode{\parsep=0pt\parindent=0pt% + \tt\frenchspacing\catcode``=13\@noligs% + \def\\{\char`\\}% + \let\dcd=\cd@dcd\let\cddollar=\cd@dollarspecial\let\cdmath=\cd@mathspecial% + \@makeother\$\@makeother\&\@makeother\#% + \@makeother\^\@makeother\_\@makeother\~% + \@makeother\%\cd@obeytabs\cd@obeyspaces} +% other: $&#^_~% +% left special: \{} +% unnecessary: @`'" + + +%% codebox, centercode +%%============================================================================= +%% The codebox env makes a box exactly as wide as it needs to be +%% (i.e., as wide as the longest line of code is). This is useful +%% if you want to center a chunk of code, or flush it right, or +%% something like that. The optional argument to the environment, +%% [t], [c], or [b], specifies how to vertically align the codebox, +%% just as with arrays or other boxes. Default is [c]. + +%% Must be a newline immediately after "\begin{codebox}[t]"! + +{\catcode`\^^M=\active % these lines must end with % + \gdef\cd@obeycr{\catcode`\^^M=\active\let^^M=\cr}} + +% If there is a [<letter>] option, then the following newline will +% be read *after* ^M is bound to \cr, so we're cool. If there isn't +% an option given (i.e., default to [c]), then the @\ifnextchar will +% gobble up the newline as it gobbles whitespace. So we insert the +% \cr explicitly. Isn't TeX fun? +\def\codebox{\leavevmode\@ifnextchar[{\@codebox}{\@codebox[c]\cr}} %] + +\def\@codebox[#1]% + {\hbox\bgroup$\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi\bgroup% + \tabskip\z@\setupcode\cd@obeycr% just before cd@obey + \halign\bgroup##\hfil\span} + +\def\endcodebox{\crcr\egroup\egroup\m@th$\egroup} + +% Center the box on the page: +\newenvironment{centercode}% + {\begin{center}\begin{codebox}[c]}% + {\end{codebox}\end{center}} + + +%% code, codeaux, tightcode +%%============================================================================= +%% Code environment as described above. Lines are kept on one page. +%% This actually works by setting a huge penalty for breaking +%% between lines of code. Code is indented same as other displayed paras. +%% Note: to increase left margin, use \begin{codeaux}{\leftmargin=1in}. + +% To allow pagebreaks, say \codeallowbreaks immediately inside the env. +% You can allow breaks at specific lines with a \pagebreak form. + +%% N.B.: The \global\@ignoretrue command must be performed just inside +%% the *last* \end{...} before the following text. If not, you will +%% get an extra space on the following line. Blech. + +%% This environment takes two arguments. +%% The second, required argument is the \list parameters to override the +%% \@listi... defaults. +%% - Usefully set by clients: \topsep \leftmargin +%% - Possible, but less useful: \partopsep +%% The first, optional argument is the extra \parskip glue that you get around +%% \list environments. It defaults to the value of \parskip. +\def\codeaux{\@ifnextchar[{\@codeaux}{\@codeaux[\parskip]}} %] +\def\@codeaux[#1]#2{% + \bgroup\parskip#1% + \begin{list}{}% + {\parsep\z@\rightskip\z@\listparindent\z@\itemindent\z@#2}% + \item[]\setupcode\cd@obeylines}% +\def\endcodeaux{\end{list}\leavevmode\egroup\ignorespaces\global\@ignoretrue} + +%% Code env is codeaux with the default margin and spacing \list params: +\def\code{\codeaux{}} \let\endcode=\endcodeaux + +%% Like code, but with no extra vertical space above and below. +\def\tightcode{\codeaux[=0pt]{\topsep\z@}}% +\let\endtightcode\endcodeaux +% {\vspace{-1\parskip}\begin{codeaux}{\partopsep\z@\topsep\z@}}% +% {\end{codeaux}\vspace{-1\parskip}} + + + +% Reasonable separation between lines of code +\newcommand{\codeskip}{\penalty0\vspace{2ex}} + + +% \cd is used to build a code environment in the middle of text. +% Note: only difference from display code is that cr's are taken +% as unbreakable spaces instead of linebreaks. + +\def\cd{\leavevmode\begingroup\ifmmode\let\startcode=\startmcode\else% + \let\startcode\starttcode\fi% + \setupcode\cd@obeycrsp\startcode} + +\def\starttcode#1{#1\endgroup} +\def\startmcode#1{\hbox{#1}\endgroup} + + +% Restore $&#^_~% to their normal catcodes +% Define \^ to give the ^ char. +% \dcd points to this guy inside a code env. +\def\cd@dcd{\catcode`\$=3\catcode`\&=4\catcode`\#=6\catcode`\^=7% + \catcode`\_=8\catcode`\~=13\catcode`\%=14\def\^{\char`\^}} + +% Selectively enable $, and $^_ as special. +% \cd@mathspecial also defines \^ give the ^ char. +% \cddollar and \cdmath point to these guys inside a code env. +\def\cd@dollarspecial{\catcode`\$=3} +\def\cd@mathspecial{\catcode`\$=3\catcode`\^=7\catcode`\_=8% + \def\^{\char`\^}} + + +% Change log: +% Started off as some macros found in C. Rich's library. +% Olin 1/90: +% Removed \makeatletter, \makeatother's -- they shouldn't be there, +% because style option files are read with makeatletter. The terminal +% makeatother screwed things up for the following style options. +% Olin 3/91: +% Rewritten. +% - Changed things so blank lines don't get compressed out (the \leavevmove +% in \cd@cr and \cd@crwb). +% - Changed names to somewhat less horrible choices. +% - Added lots of doc, so casual hackers can more easily mess with all this. +% - Removed `'"@ from the set of hacked chars, since they are already +% non-special. +% - Removed the bigcode env, which effect can be had with the \codeallowbreaks +% command. +% - Removed the \@noligs command, since it's already defined in latex.tex. +% - Win big with the new \dcd, \cddollar, and \cdmath commands. +% - Now, *only* the chars \{} are special inside the code env. If you need +% more, use the \dcd command inside a group. +% - \cd now works inside math mode. (But if you use it in a superscript, +% it still comes out full size. You must explicitly put a \scriptsize\tt +% inside the \cd: $x^{\cd{\scriptsize\tt...}}$. A \leavevmode was added +% so that if you begin a paragraph with a \cd{...}, TeX realises you +% are starting a paragraph. +% - Added the codebox env. Tricky bit involving the first line hacked +% with help from David Long. + +% end of code.sty +% +% partain: things actually used +%% verbcode env is like tightcode: +%\def\verbcode{\codeaux[=0pt]{\topsep\z@\parskip\z@\leftmargin\litcodeindent}} \let\endverbcode=\endcodeaux +%\def\verbcode{\codeaux{\leftmargin\litcodeindent\cbstart}}% +\def\verbcode{% + \bgroup\parskip\parskip% + \begin{list}{}% + {\parsep\z@\rightskip\z@\listparindent\z@\itemindent\z@\leftmargin\litcodeindent}% + \item[]\setupcode\cd@obeylines\cbstart}% +\def\endverbcode{\cbend\end{list}\leavevmode\egroup\ignorespaces\global\@ignoretrue} +% +\def\verbtext{\codeaux{\leftmargin\litcodeindent}} \let\endverbtext=\endcodeaux +% +\makeatother +%======================================================================== diff --git a/web/glasgow/lit2x-0.16/literate/lit2pgm.BOOT b/web/glasgow/lit2x-0.16/literate/lit2pgm.BOOT new file mode 100644 index 0000000000..b2dea81d65 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit2pgm.BOOT @@ -0,0 +1,385 @@ +eval "exec perl -S $0 $*" + if $running_under_some_random_shell; +# +############# +# magic version for booting... +########### +# line 27 "lit2stuff.lprl" +$Pgm = $0; $Pgm =~ s/.*\/([^\/]+)$/\1/; + +# an initial -A<name> option overrides the name +if ($#ARGV >= 0 && $ARGV[0] =~ /^-A(lit2)(pgm|texi|latex)$/) { + $Pgm = $1.$2; + shift(@ARGV); +} +$Lit2pgm = ($Pgm eq 'lit2pgm') ? 1 : 0; +$Lit2latex = ($Pgm eq 'lit2latex') ? 1 : 0; +$Lit2texi = ($Pgm eq 'lit2texi') ? 1 : 0; +$Lit2depend = ($Pgm eq 'mkdependlit') ? 1 : 0; +$Lit2changelog = ($Pgm eq 'lit2changelog') ? 1 : 0; +die "$Pgm: must be invoked as lit2pgm, lit2texi, lit2latex, mkdependlit, or lit2changelog (or use -A<name>)\n" + if (!($Lit2pgm || $Lit2latex || $Lit2texi || $Lit2depend || $Lit2changelog)); + +# $Lit2what will be set after we know $Quick_lit2pgm + +$Status = 0; # just used for exit() status +# line 53 "lit2stuff.lprl" +do 'getopts.pl' || die "Giant error 'do'ing getopts.pl: $@"; +$Usage = "usage: $Pgm ". + '[-i input-file] '. + '[-I LITINPUTS-path-additions] '. + '[-o output-file] '; +$Usage .= '[-cdnqv] '. + '[-r ribbons] '. + "[input-file]\n" if $Lit2pgm; +$Usage .= '[-cdLnOSv] '. + '[-N infofilename] '. + '[-[lx] language] '. + '[-s stop-list-file] '. + "[input-file]\n" if $Lit2texi; +$Usage .= '[-cdnOSv] '. + '[-g node-name] '. + '[-[lptx] language] '. + '[-s stop-list-file] '. + "[input-file]\n" if $Lit2latex; +$Usage .= '[-dv] '. + "[input-file]\n" if $Lit2depend; +$Usage .= '[-dnv] '. + "[input-file]\n" if $Lit2changelog; + +if ( ($Lit2pgm && ! &Getopts('cdH:I:i:no:qr:v')) + || ($Lit2texi && ! &Getopts('cdH:I:i:Ll:nN:Oo:Ss:vx:')) + || ($Lit2latex && ! &Getopts('cdg:H:I:i:l:no:Op:Ss:t:vx:')) + || ($Lit2depend && ! &Getopts('dH:I:i:o:v')) + || ($Lit2changelog && ! &Getopts('dH:I:i:no:v'))) { + print STDERR $Usage; + exit 1; +} elsif ($#ARGV > 0) { + print STDERR "$Pgm: cannot have more than one input file: @ARGV \n"; + print STDERR $Usage; + exit 1; +} +# SHARED OPTIONS +$Debugging = ($opt_d) ? 1 : 0; +$Verbose = ($Debugging | $opt_v) ? 1 : 0; +$Input_file = ($opt_i) ? $opt_i : ''; +# -o <output file> handled after deciding if linking + +$Litinputs = '.'; +$Litinputs_adds = ($opt_I) ? $opt_I : ''; +$Litinputs = "$Litinputs_adds:$Litinputs" if $Litinputs && $Litinputs_adds; + +# where all the assisting code is found (HARDWIRED) +if ($opt_H) { + # no error checking; you get what you deserve + ($LIB_ARCH_DIR,$LIB_DIR) = split(/:/,$opt_H); +} else { +# boot changes... + $LIB_ARCH_DIR = '.'; + $LIB_DIR = '.'; +} +unshift(@INC, $LIB_DIR); # adding to; for .prl libraries sucked in at runtime +# +# now the (derived) names of all the helpers +$Lit_inputter = "$LIB_DIR/lit-inputter"; +$Lit_deatify = "$LIB_ARCH_DIR/lit-deatify"; +$Lit_verb2latex = "$LIB_ARCH_DIR/lit-verb2latex"; + +# finish knowing myself; must agree with lit-deatify.llex +# boot change +$Quick_lit2pgm = 1; # ($opt_q) ? 1 : 0; +$Lit2what = 1; # if $Quick_lit2pgm; + +# LESS SHARED OPTIONS +$Grab_node = ($opt_g) ? $opt_g : 'Top'; +$Infofilename = ($opt_N) ? $opt_N : ''; # see do_setfilename +$Follow_inputs = ($opt_n) ? 1 : 0; +$Show_node_owner= ($opt_O) ? 1 : 0; +$Opt_node_links = ($opt_L) ? 1 : 0; +$Standalone_doc = ($opt_S) ? 1 : 0; + +$Stoplist_file = ($opt_s) ? $opt_s : ''; +# for now, stop lists are simply words to be ignored +if ($Stoplist_file) { + if ( ! -f $Stoplist_file) { + ¬_OK('','',"stop-list file does not exist: $Stoplist_file\n"); + } else { + open(STOPF,"<$Stoplist_file") || die "Can't open file: $Stoplist_file\n"; + while (<STOPF>) { + chop; + $IGNORE_WD{$_} = 1; # no questions asked... + } + close(STOPF); + } +} + +$Ribbons_to_get = ($opt_r) ? $opt_r : 'main'; +$Ribbons_to_get =~ s/\s*,\s*/,/g; # remove spaces around commas + +# figure out what we're doing and the input and output files... +if ( ! $Input_file ) { + if ($#ARGV == 0) { + $Input_file = $ARGV[0]; + } else { + $Input_file = '-'; # stdin; hmm... + } +} + +($Inputfile_root,$Inputfile_suff) = &root_and_suffix($Input_file); + +# are we "processing" and/or "linking" ? +if ( ! ($Lit2texi || $Lit2latex)) { # that's easy... + $Processing = 1; + $Linking = 0; +} else { + $Processing = 1 if $Inputfile_suff !~ /^(itxi|itex|texi|tex)$/; + $Linking = ($opt_c) ? 0 : 1; +} + +# table of input-suffixes -> output-suffixes (for "processing"); +# cf. tables in &check_language_stuff +$ISUFF2OSUFF{'lit'} = ''; +$ISUFF2OSUFF{'lhs'} = 'hs'; +$ISUFF2OSUFF{'lit.hs'} = 'hs'; +$ISUFF2OSUFF{'lprl'} = 'prl'; +$ISUFF2OSUFF{'llex'} = 'lex'; + +# guess the output filenames (for "processing" and "linking") +if ( $opt_o ) { + if ( $Linking ) { + $Link_outfile = $opt_o; + } else { + $Proc_outfile = $opt_o; + } +} +if ( !defined($Proc_outfile) ) { + if ($Linking) { # got to put it _somewhere_ + $Proc_outfile = "/usr/tmp/lit2stuff-po.$$"; + + } elsif ($Lit2pgm) { # try to be clever + if (defined($ISUFF2OSUFF{$Inputfile_suff})) { + $Proc_outfile = $Inputfile_root; + $Proc_outfile .= '.'.$ISUFF2OSUFF{$Inputfile_suff} + if $ISUFF2OSUFF{$Inputfile_suff}; + } else { + print STDERR "$Pgm: don't know the file suffix: $Inputfile_suff\n"; + $Proc_outfile = '-'; # stdout will do + } + + } elsif ($Lit2texi) { + $Proc_outfile = $Inputfile_root . '.itxi'; + + } elsif ($Lit2latex) { + $Proc_outfile = $Inputfile_root . '.itex'; + + } else { + $Proc_outfile = '-'; # stdout + } +} +# messing with Link_outfile deferred to later... + +&check_language_stuff(); +exit $Status if $Status; # don't proceed if errors + +print STDERR "Language info: code=$Code_lang, xref=$Lang_xref, ", + "typeset=$Lang_typeset, pagebreak=$Lang_pagebreak\n" + if $Verbose; + +# now we know the program, the options, and the language info, we load +# the other (non-language-related) pieces of perl code (roll-your-own +# dynamic linking...) +# if ( ! $Quick_lit2pgm) { +# do 'lit-globals.prl' || die "Giant error 'do'ing lit-globals.prl: $@"; +# do 'lit-reader.prl' || die "Giant error 'do'ing lit-reader.prl: $@"; +#} +#if ($Lit2pgm) { +# if (! $Quick_lit2pgm) { # i.e., the slow one +# do 'lit-2pgm.prl' || die "Giant error 'do'ing lit-2pgm.prl: $@"; +# } +# boot changes +# # we _always_ need something for line directives +# do "lit-2pgm-$Code_lang.prl" +# || die "Giant error 'do'ing lit-2pgm-$Code_lang.prl: $@"; +# +#} else { +# die "can't use lit2pgm.BOOT except for lit2pgm'ming" +#} + +# NOW WE START DRIVING... + +# first: we handle "quick" lit2pgm +if ($Quick_lit2pgm) { + + # check that no incompatible lit2pgm options were used + die "Can only get ribbon 'main' with lit2pgm -q option\n" + if ($Ribbons_to_get ne 'main'); + die "Can't follow \\input{}s with lit2pgm -q option\n" + if ($Follow_inputs); + + $pipe_string = "$Lit_deatify $Verbose 0 $Lit2what $Input_file | expand"; + print STDERR "QUICK LIT2PGM:in=$pipe_string\n" if $Verbose; + print STDERR " out=$Proc_outfile\n" if $Verbose; + &do_std_opens($pipe_string,$Proc_outfile); + + # this "quick" loop does as little as possible + while (<INPIPE>) { + if ( /^srcfile!_!(.*)!_!(.*)!_!/) { +# boot change: +# print &mk_line_directive($1,$2); +; + } else { + print $_ ; + } + } + &do_std_closes(); + exit $Status; +} + +# continue with various kinds of "processing" ... + +if ($Lit2pgm) { + print STDERR "LIT2PGM:out=$Proc_outfile\n" if $Verbose; + &spit_out_ribbons_code(split(/,/, $Ribbons_to_get)); + &do_std_closes(); + exit $Status; +} + +# line 418 "lit2stuff.lprl" +sub check_language_stuff { + + # fixed tables of "language"-related info + + $ISUFF2LANG{'lit'} = 'none'; + $ISUFF2LANG{'lc'} = 'c'; + $ISUFF2LANG{'lhs'} = 'hs'; + $ISUFF2LANG{'lit.hs'}='hs'; + $ISUFF2LANG{'lprl'} = 'prl'; + $ISUFF2LANG{'llex'} = 'lex'; + + $STD_LANGS = 'none,c,hs,prl,lex'; # fully supported (?) + + $XREF_HINTS = ''; # could have more... + $PAGEBREAK_HINTS = ''; + $TYPESET_HINTS = ''; + + $Code_lang = + ($opt_l) ? $opt_l + : (defined($ISUFF2LANG{$Inputfile_suff})) ? $ISUFF2LANG{$Inputfile_suff} + : 'none'; + $Lang_pagebreak = ($opt_p) ? $opt_p : ''; + $Lang_typeset = ($opt_t) ? $opt_t : ''; + $Lang_xref = ($opt_x) ? $opt_x : ''; + + ¬_OK("","","xref hints unknown: $Lang_xref\n") + if $Lang_xref && index( $XREF_HINTS, $Lang_xref ) < 0; + ¬_OK("","","pagebreak hints unknown: $Lang_pagebreak\n") + if $Lang_pagebreak && index( $PAGEBREAK_HINTS, $Lang_pagebreak ) < 0; + ¬_OK("","","typeset hints unknown: $Lang_typeset\n") + if $Lang_typeset && index( $TYPESET_HINTS, $Lang_typeset ) < 0; +} +# line 472 "lit2stuff.lprl" +sub do_std_opens { # opens INPIPE, and OUTF; selects the latter + + local($pipe_string,$output_file) = @_; + + # check it output is to a pipe + $output_file = ">$output_file" if $output_file !~ /^\|/; + + open(INPIPE, "$pipe_string |") + || die "$Pgm: can't start prefilter pipe: $pipe_string\n"; + open(OUTF, "$output_file") + || die "$Pgm: can't open output file: $output_file\n"; + select(OUTF); +} + +sub do_std_closes { # closes INPIPE and OUTF; re-selects STDOUT + + close(INPIPE); + # most regrettably, this only tells if the _last_ thing + # in the pipeline croaked... + if ($? >> 8) { + print STDERR "$Pgm: error(s) from prefilter pipe\n"; + unlink("/usr/tmp/lit2stuff-po.$$"); # this might exist... + exit 1; + } + close(OUTF); + if ($? >> 8) { + print STDERR "$Pgm: error in closing output file: $?\n"; + unlink("/usr/tmp/lit2stuff-po.$$"); # this might exist... + exit 1; + } + select(STDOUT); +} + +sub not_OK { # report error, increment $Status, but keep going + local($srcfilename, $srclineno, $msg) = @_; + if ($srcfilename) { # not always there + print STDERR "$srcfilename:$srclineno: $msg"; + } else { + print STDERR "$Pgm: $msg"; + } + $Status++; +} + +sub filter_string { + local($filter, $string) = @_; + + open(FILT, "| $filter > /tmp/lit$$") || die "Can't open in filter_string\n"; + print FILT $string; + close(FILT); + if ($? >> 8) { # something went wrong in the pipe ??? + print STDERR "$Pgm: error(s) in/from filter: $filter\n"; + } + local($filtered_string) = `cat /tmp/lit$$`; + unlink("/tmp/lit$$"); + $filtered_string; +} + +sub deatified2verb_nl { # lit-deatify put 'em in; now we take 'em out + local($_) = @_; + + s/\001newline\003/\n/g; # _WITH_ newlines + s/\001lbrace\003/\{/g; + s/\001rbrace\003/\}/g; + s/\001rbracket\003/\]/g; + + $_; +} + +sub deatified2verb { # without newlines + local($_) = @_; + + $_ = &deatified2verb_nl($_); + + s/\n/ /g; # the difference; to SPACES + $_; +} + +sub de_newlined { + local($_) = @_; + + s/\n/\001newline\003/g; + $_; +} + +sub root_and_suffix { + local($filename) = @_; + local($root,$suffix); + + # find the file's "suffix" (NB: *.lit.hs has a 6-letter suffix) + if ($filename =~ /\.(lit\.[^\.\/]+)$/) { # cf \input handling in reader + $suffix = $1; + ($root = $filename) =~ s/\.(lit\.[^\.\/]+)$//; + + } elsif ($filename =~ /\.([^\.\/]+)$/) { + $suffix = $1; + ($root = $filename) =~ s/\.([^\.\/]+)$//; + + } else { + # should there be a warning or something here? + $root = '???'; + $suffix = '???'; + } + ($root, $suffix); +} + diff --git a/web/glasgow/lit2x-0.16/literate/lit2stuff.lprl b/web/glasgow/lit2x-0.16/literate/lit2stuff.lprl new file mode 100644 index 0000000000..cacb4422fe --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/lit2stuff.lprl @@ -0,0 +1,775 @@ +% *** MSUB does some substitutions here *** +% *** grep for $( *** +% +\begin{onlystandalone} +\documentstyle[11pt,literate]{article} +\begin{document} +\title{Source for the Glasgow literate programming system} +\author{(A sheepish) Will Partain} +\maketitle +\begin{rawlatex} +\tableofcontents +\end{rawlatex} +\end{onlystandalone} + +\section[Source_Introduction]{Source: introduction and overall structure} + +This \tr{perl} script is a driver that converts literate scripts into other +useful forms. Because the various tasks +\tr{lit2pgm},\index{lit2pgm} \tr{lit2latex},\index{lit2latex} +etc., are so similar, there's just one script (which I call +\tr{lit2stuff}),\index{lit2stuff} with some parts conditionally +included/executed, depending on how +the script was invoked (exactly one of the variables @$Lit2pgm@, +@$Lit2latex@, and @$Lit2texi@ will be @1@, the others @0@). + +\tr{lit2stuff} is written in \tr{perl}, so some tasks are not as +conveniently expressed as one might wish. For example, \tr{perl} is +line-oriented so, for example, chasing down the contents of a multi-line +\tr{\title{...}} is, in the general case, unpleasant. +\tr{lit2stuff} uses helper programs to cope with such things. You'll +see 'em along the way. + +\section[Naming_and_background]{Naming conventions, perl hackery, etc.} + +[How I use names, and so on.] + +\section[Global_data_structures]{Global data structures} +\downsection +\input{lit-globals.lprl} +\input{lit-link-globals.lprl} +\upsection + +\section[Lit_initialization]{Initialization and command-line argument checking} + +First, the program must have been invoked with an approved name: +\begin{code} +($Pgm = $0) =~ s/.*\/([^\/]+)$/\1/; +$LIT_VERSION = '0.16'; + +# an initial -A<name> option overrides the name +if ($#ARGV >= 0 && $ARGV[0] =~ /^-A(lit2)(pgm|texi|latex)$/) { + $Pgm = $1.$2; + shift(@ARGV); +} +$Lit2pgm = ($Pgm eq 'lit2pgm') ? 1 : 0; +$Lit2latex = ($Pgm eq 'lit2latex') ? 1 : 0; +$Lit2texi = ($Pgm eq 'lit2texi') ? 1 : 0; +$Lit2depend = ($Pgm eq 'mkdependlit') ? 1 : 0; +$Lit2changelog = ($Pgm eq 'lit2changelog') ? 1 : 0; +$Lit2text = ($Pgm eq 'lit2text') ? 1 : 0; +die "$Pgm: must be invoked as lit2pgm, lit2texi, lit2latex, mkdependlit, lit2changelog, or lit2text (or use -A<name>)\n" + if (!($Lit2pgm || $Lit2latex || $Lit2texi || $Lit2depend || $Lit2changelog || $Lit2text)); + +# $Lit2what will be set after we know $Quick_lit2pgm + +$Status = 0; # just used for exit() status +\end{code} + +Unravel the command-line options with one of the perl-library @getopt@ +routines, then transfer that information to more pleasantly-named +global variables (see the User Guide +\standaloneornot{}{[Section~\ref{Literate_guide}]} +for what passes as good command-line arguments): + +\begin{code} +# really only needed if perl is misinstalled. (and can't find getopts.pl) +if ( $(INSTALLING) ) { + unshift(@INC, '$(INSTDATADIR_LITERATE)'); +} else { + unshift(@INC, '$(TOP_PWD)/$(CURRENT_DIR)'); # absolutize the paths +} + +do 'getopts.pl' || die "Giant error 'do'ing getopts.pl: $@"; + +$Usage = "usage: $Pgm ". + '[-i input-file] '. + '[-I LITINPUTS-path-additions] '. + '[-o output-file] '; +$Usage .= '[-cdnqv] '. + '[-r ribbons] '. + "[input-file]\n" if $Lit2pgm; +$Usage .= '[-cdLnOSv] '. + '[-f nodename-suffix] '. + '[-N infofilename] '. + '[-[lx] language] '. + '[-s stop-list-file] '. + "[input-file]\n" if $Lit2texi; +$Usage .= '[-cdDnOSv] '. + '[-g node-name] '. + '[-[lptx] language] '. + '[-s stop-list-file] '. + "[input-file]\n" if $Lit2latex; +$Usage .= '[-dv] '. + "[input-file]\n" if $Lit2depend; +$Usage .= '[-dnv] '. + "[input-file]\n" if $Lit2changelog; +$Usage .= '[-dnv] '. + "[input-file]\n" if $Lit2text; + +if ( ($Lit2pgm && ! &Getopts('cdH:I:i:no:qr:v')) + || ($Lit2texi && ! &Getopts('cdf:H:I:i:Ll:nN:Oo:Ss:vx:')) + || ($Lit2latex && ! &Getopts('cdDg:H:I:i:l:no:Op:Ss:t:vx:')) + || ($Lit2depend && ! &Getopts('dH:I:i:o:v')) + || ($Lit2text && ! &Getopts('dH:I:i:no:v')) + || ($Lit2changelog && ! &Getopts('dH:I:i:no:v'))) { + print STDERR $Usage; + exit 1; +} elsif ($#ARGV > 0) { + print STDERR "$Pgm: cannot have more than one input file: @ARGV \n"; + print STDERR $Usage; + exit 1; +} +# SHARED OPTIONS +$Debugging = ($opt_d) ? 1 : 0; +$Verbose = ($Debugging | $opt_v) ? 1 : 0; +print STDERR "Glasgow literate programming system, version $LIT_VERSION\n" if $Verbose; +$Input_file = ($opt_i) ? $opt_i : ''; +# -o <output file> handled after deciding if linking + +$Litinputs = '.'; +$Litinputs_adds = ($opt_I) ? $opt_I : ''; +$Litinputs = "$Litinputs_adds:$Litinputs" if $Litinputs && $Litinputs_adds; + +# where all the assisting code is found (HARDWIRED) +if ($opt_H) { + # no error checking; you get what you deserve + ($LIB_ARCH_DIR,$LIB_DIR) = split(/:/,$opt_H); +} elsif ( $(INSTALLING) ) { + $LIB_ARCH_DIR = '$(INSTLIBDIR_LITERATE)'; + $LIB_DIR = '$(INSTDATADIR_LITERATE)'; +} else { + $LIB_ARCH_DIR = '$(TOP_PWD)/$(CURRENT_DIR)'; # absolutize the paths + $LIB_DIR = '$(TOP_PWD)/$(CURRENT_DIR)'; +} +unshift(@INC, $LIB_DIR); # adding to; for .prl libraries sucked in at runtime +# +# now the (derived) names of all the helpers +$Lit_inputter = "$LIB_ARCH_DIR/lit-inputter"; +$Lit_deatify = "$LIB_ARCH_DIR/lit-deatify"; +$Lit_verb2latex = "$LIB_ARCH_DIR/lit-verb2latex"; + +# this should be done a better way... +$Tgrind_pgm = '$(TGRIND_HELPER)'; + +# finish knowing myself; must agree with lit-deatify.llex +$Quick_lit2pgm = ($opt_q) ? 1 : 0; +$Lit2what = 1 if $Quick_lit2pgm; +$Lit2what = 2 if $Lit2pgm && ! $Quick_lit2pgm; +$Lit2what = 3 if $Lit2texi; +$Lit2what = 4 if $Lit2latex; +$Lit2what = 5 if $Lit2depend; +$Lit2what = 6 if $Lit2changelog; +$Lit2what = 7 if $Lit2text; + +# LESS SHARED OPTIONS +$Codedef_blurbs = ($opt_D) ? 1 : 0; +$Grab_node = ($opt_g) ? $opt_g : 'Top'; +$Infofilename = ($opt_N) ? $opt_N : ''; # see do_setfilename +$Follow_inputs = ($opt_n) ? 1 : 0; +$Show_node_owner= ($opt_O) ? 1 : 0; +$Nodename_suffix= ($opt_f) ? $opt_f : ''; +$Opt_node_links = ($opt_L) ? 1 : 0; +$Standalone_doc = ($opt_S) ? 1 : 0; + +$Stoplist_file = ($opt_s) ? $opt_s : ''; +# for now, stop lists are simply words to be ignored +if ($Stoplist_file) { + if ( ! -f $Stoplist_file) { + ¬_OK('','',"stop-list file does not exist: $Stoplist_file\n"); + } else { + open(STOPF,"<$Stoplist_file") || die "Can't open file: $Stoplist_file\n"; + while (<STOPF>) { + chop; + $IGNORE_WD{$_} = 1; # no questions asked... + } + close(STOPF); + } +} + +$Ribbons_to_get = ($opt_r) ? $opt_r : 'main'; +$Ribbons_to_get =~ s/\s*,\s*/,/g; # remove spaces around commas + +# figure out what we're doing and the input and output files... +if ( ! $Input_file ) { + if ($#ARGV == 0) { + $Input_file = $ARGV[0]; + } else { + $Input_file = '-'; # stdin; hmm... + } +} + +($Inputfile_root,$Inputfile_suff) = &root_and_suffix($Input_file); +@Files_to_tidy = (); + +# are we "processing" and/or "linking" ? +if ( ! ($Lit2texi || $Lit2latex)) { # that's easy... + $Processing = 1; + $Linking = 0; +} else { + $Processing = 1 if $Inputfile_suff !~ /^(itxi|itex|texi|tex)$/; + $Linking = ($opt_c) ? 0 : 1; +} + +# table of input-suffixes -> output-suffixes (for "processing"); +# cf. tables in &check_language_stuff +$ISUFF2OSUFF{'lit'} = ''; +$ISUFF2OSUFF{'lhs'} = 'hs'; +$ISUFF2OSUFF{'lit.hs'} = 'hs'; +$ISUFF2OSUFF{'lprl'} = 'prl'; +$ISUFF2OSUFF{'llex'} = 'lex'; +$ISUFF2OSUFF{'lhc'} = 'hc'; +$ISUFF2OSUFF{'lc'} = 'c'; +$ISUFF2OSUFF{'lh'} = 'h'; +$ISUFF2OSUFF{'ltex'} = 'tex'; +$ISUFF2OSUFF{'lit.tex'} = 'tex'; +$ISUFF2OSUFF{'ljm'} = 'jm'; # mkworld-ery +$ISUFF2OSUFF{'lf'} = 'f'; # Literate Fortran (adriaan@dcs.qmw.ac.uk) + +# guess the output filenames (for "processing" and "linking") +if ( $opt_o ) { + @Files_to_tidy = ( $opt_o ); + if ( $Linking ) { + $Link_outfile = $opt_o; + } else { + $Proc_outfile = $opt_o; + } +} +if ( !defined($Proc_outfile) ) { + if ($Linking) { # got to put it _somewhere_ + $Proc_outfile = "$(TMPDIR)/lit2stuff-po.$$"; + + } elsif ($Lit2pgm) { # try to be clever + if (defined($ISUFF2OSUFF{$Inputfile_suff})) { + $Proc_outfile = $Inputfile_root; + $Proc_outfile .= '.'.$ISUFF2OSUFF{$Inputfile_suff} + if $ISUFF2OSUFF{$Inputfile_suff}; + } else { + print STDERR "$Pgm: don't know the file suffix: $Inputfile_suff\n"; + $Proc_outfile = '-'; # stdout will do + } + + } elsif ($Lit2texi) { + $Proc_outfile = $Inputfile_root . '.itxi'; + + } elsif ($Lit2latex) { + $Proc_outfile = $Inputfile_root . '.itex'; + + } else { + $Proc_outfile = '-'; # stdout + } + @Files_to_tidy = ( $Proc_outfile ) if $Proc_outfile ne '-'; +} +# messing with Link_outfile deferred to later... + +&check_language_stuff(); +exit $Status if $Status; # don't proceed if errors + +# here we go: set up signal handler +sub quit_upon_signal { + # delete any files to tidy + print STDERR "deleting... @Files_to_tidy\n" if $Verbose && $#Files_to_tidy >= 0; + unlink @Files_to_tidy if $#Files_to_tidy >= 0; + exit 1; +} +$SIG{'INT'} = 'quit_upon_signal'; +$SIG{'QUIT'} = 'quit_upon_signal'; + +print STDERR "Language info: code=$Code_lang, xref=$Lang_xref, ", + "typeset=$Lang_typeset, pagebreak=$Lang_pagebreak\n" + if $Verbose; + +# now we know the program, the options, and the language info, we load +# the other (non-language-related) pieces of perl code (roll-your-own +# dynamic linking...) +if ( ! $Quick_lit2pgm) { + do 'lit-globals.prl' || die "Giant error 'do'ing lit-globals.prl: $@"; + do 'lit-reader.prl' || die "Giant error 'do'ing lit-reader.prl: $@"; +} +if ($Lit2pgm) { + if (! $Quick_lit2pgm) { # i.e., the slow one + do 'lit-2pgm.prl' || die "Giant error 'do'ing lit-2pgm.prl: $@"; + } + # we _always_ need something for line directives + do "lit-2pgm-$Code_lang.prl" + || die "Giant error 'do'ing lit-2pgm-$Code_lang.prl: $@"; + +} elsif ($Lit2depend) { + do 'lit-2depend.prl' || die "Giant error 'do'ing lit-2depend.prl: $@"; + +} elsif ($Lit2changelog) { + do 'lit-2changes.prl' || die "Giant error 'do'ing lit-2changes.prl: $@"; + +} elsif ($Lit2text) { + do 'lit-2text.prl' || die "Giant error 'do'ing lit-2text.prl: $@"; + +} else { + # creating a document... + do 'lit-2doc.prl' || die "Giant error 'do'ing lit-2doc.prl: $@"; + # language-specific stuff (most of it) + do "lit-2doc-$Code_lang.prl" + || die "Giant error 'do'ing lit-2doc-$Code_lang.prl: $@"; + if ( $Lit2texi ) { + do 'lit-2texi.prl' || die "Giant error 'do'ing lit-2texi.prl: $@"; + if ($Processing) { + do "lit-2texi-$Code_lang.prl" + || die "Giant error 'do'ing lit-2texi-$Code_lang.prl: $@"; + # non-Code_lang xref/typeset/pagebreak code would be slurped here + # [not implemented] + } + } + if ( $Lit2latex ) { + do 'lit-2latex.prl' || die "Giant error 'do'ing lit-2latex.prl: $@"; + if ($Processing) { + do "lit-2latex-$Code_lang.prl" + || die "Giant error 'do'ing lit-2latex-$Code_lang.prl: $@"; + # non-Code_lang xref/typeset/pagebreak code would be slurped here + # [not implemented] + } + } + if ( $Linking ) { + do 'lit-link-globals.prl' || die "Giant error 'do'ing lit-link-globals.prl: $@"; + do 'lit-linker.prl' || die "Giant error 'do'ing lit-linker.prl: $@"; + } +} + +# NOW WE START DRIVING... + +# first: we handle "quick" lit2pgm +if ($Quick_lit2pgm) { + + # check that no incompatible lit2pgm options were used + die "Can only get ribbon 'main' with lit2pgm -q option\n" + if ($Ribbons_to_get ne 'main'); + die "Can't follow \\input{}s with lit2pgm -q option\n" + if ($Follow_inputs); + + $Input_file = '' if $Input_file eq '-'; + $pipe_string = "(echo \"srcfile!_!$Input_file!_!1!_!\" ; expand $Input_file) | " . + "$Lit_deatify $Verbose 0 $Lit2what -"; + print STDERR "QUICK LIT2PGM:in=$pipe_string\n" if $Verbose; + print STDERR " out=$Proc_outfile\n" if $Verbose; + &do_std_opens($pipe_string,$Proc_outfile); + + # this "quick" loop does as little as possible + while (<INPIPE>) { + if ( /^srcfile!_!(.*)!_!(.*)!_!/) { + print &mk_line_directive($1,$2); + } else { + print $_ ; + } + } + &do_std_closes(); + exit $Status; +} + +# second: we handle lit2depend +if ($Lit2depend) { + $Follow_inputs = 1; # that's the whole point + # just using lit-inputter to follow \input's + + $pipe_string = "$Lit_inputter $Verbose $Follow_inputs $Litinputs $Input_file"; + print STDERR "MKDEPENDLIT:in=$pipe_string\n" if $Verbose; + print STDERR " out=$Proc_outfile\n" if $Verbose; + &do_std_opens($pipe_string,$Proc_outfile); + + # lineno 1 means we just started the file + # look for these and deduce dependency info (a hack) + @Depend_lines = (); + while (<INPIPE>) { + if ( /^srcfile!_!(.*)!_!1!_!/) { + &collect_dependencies($1); + } + } + &do_std_closes(); + &mangle_Makefile(); + exit $Status; +} + +# all other invocations of "processing" (slow lit2pgm, lit2latex, +# lit2texi, lit2changelog) need the input "parsed" and stuffed into +# the global data structures, so we do that now. + +if ($Processing) { + # (would really like to get \input'ing over to deatify...) + + $pipe_string = "$Lit_inputter $Verbose $Follow_inputs $Litinputs $Input_file | ". + "expand | ". + "$Lit_deatify $Verbose 0 $Lit2what -"; + # lit-deatify last so we get its error report + print STDERR "PARSING:in=$pipe_string\n" if $Verbose; + print STDERR " out=$Proc_outfile\n" if $Verbose; + + &do_std_opens($pipe_string,$Proc_outfile); + + &read_and_categorize_input(); # reads <INPIPE> + &fiddle_line_numbers() if ! $Lit2pgm; + + if ($Lit2texi || $Lit2latex) { # want this before dumping... + &find_interesting_codethings(); + } + + if ($Debugging) { + print STDERR "AFTER \"PARSING\" :-\n"; + &dump_sections_and_blocks(); + } +} + +# continue with various kinds of "processing" ... + +if ($Lit2pgm) { + print STDERR "LIT2PGM:out=$Proc_outfile\n" if $Verbose; + &spit_out_ribbons_code(split(/,/, $Ribbons_to_get)); + &do_std_closes(); + exit $Status; +} + +if ($Lit2changelog) { + print STDERR "LIT2CHANGELOG:out=$Proc_outfile\n" if $Verbose; + &spit_out_change_info(); + &do_std_closes(); + exit $Status; +} + +if ($Lit2text) { + print STDERR "LIT2TEXT:out=$Proc_outfile\n" if $Verbose; + &spit_out_raw_text(); + &do_std_closes(); + exit $Status; +} + +if ($Processing) { + # now either lit2latex or lit2texi... + print STDERR "LIT2DOC:out=$Proc_outfile\n" if $Verbose; + + &do_text_substitutions(); # \defines + + &print_intermed_document(); + + &do_std_closes(); +} + +## (I'd rather keep going... ) +## close up and unlink temp outfile file if we are about to die +#unlink("$(TMPDIR)/lit2stuff-po.$$") if $Status; +#exit $Status if $Status || ! $Linking; +exit $Status if ! $Linking; + +# NOW WE'RE TO "linking" ... (lit2texi and lit2latex only) + +# make sure we know where to put the output (_before_ redefining Input_file) +if ( !defined($Link_outfile) ) { + $Link_outfile = $Inputfile_root . '.texi' if $Lit2texi; + $Link_outfile = $Inputfile_root . '.tex' if $Lit2latex; + @Files_to_tidy = ( $Link_outfile ); +} +# readjust notions of "input" file if just processed +if ( $Processing ) { + $Input_file = $Proc_outfile; +} + +# $Input_file is the root of a bunch of i{tex,texi} files to be glued +# together; the sectioning needs to be fixed and unresolved node refs +# need to be fixed. +# each file has a table of relevant info at the beginning +# 1st pass: go \inputting down through them, reading those tables +# 2nd pass: go \inputting down through them, fixing things and writing + +&first_link_pass(); # GO!!! + +if ($Debugging) { + print STDERR "AFTER LINKER FIRST PASS :-\n"; + &dump_sections_and_blocks(); +} + +# # (I'd rather keep going) +# # unlink temp outfile file if we are about to die +# unlink("$(TMPDIR)/lit2stuff-po.$$") if $Status; +# exit $Status if $Status; + +&second_link_pass(); + +# unlink temp outfile no matter what +unlink("$(TMPDIR)/lit2stuff-po.$$"); +exit $Status; +\end{code} + +\begin{code} +sub check_language_stuff { + + # fixed tables of "language"-related info + + $ISUFF2LANG{'lit'} = 'none'; + $ISUFF2LANG{'lhc'} = 'c'; + $ISUFF2LANG{'lc'} = 'c'; + $ISUFF2LANG{'lh'} = 'c'; + $ISUFF2LANG{'lhs'} = 'hs'; + $ISUFF2LANG{'lit.hs'}='hs'; + $ISUFF2LANG{'lprl'} = 'prl'; + $ISUFF2LANG{'llex'} = 'lex'; + $ISUFF2LANG{'ljm'} = 'jm'; # mkworld-ery + $ISUFF2LANG{'lf'} = 'f'; # Literate Fortran (adriaan@dcs.qmw.ac.uk) + + $STD_LANGS = 'none,c,hs,prl,lex,jm,f'; # fully supported (?) + + $XREF_HINTS = 'noindex'; # could have more... + $PAGEBREAK_HINTS = ''; + $TYPESET_HINTS = 'tgrind,ruled,unruled,bird,nobird'; + + $Code_lang = + ($opt_l) ? $opt_l + : (defined($ISUFF2LANG{$Inputfile_suff})) ? $ISUFF2LANG{$Inputfile_suff} + : 'none'; + $Lang_pagebreak = ($opt_p) ? $opt_p : ''; + $Lang_typeset = ($opt_t) ? $opt_t : ''; + $Lang_xref = ($opt_x) ? $opt_x : ''; + + ¬_OK("","","xref hint(s) unknown: $Lang_xref\n") + if $Lang_xref && &hints_not_OK( $XREF_HINTS, $Lang_xref ); + ¬_OK("","","pagebreak hint(s) unknown: $Lang_pagebreak\n") + if $Lang_pagebreak && &hints_not_OK( $PAGEBREAK_HINTS, $Lang_pagebreak ); + ¬_OK("","","typeset hint(s) unknown: $Lang_typeset\n") + if $Lang_typeset && &hints_not_OK( $TYPESET_HINTS, $Lang_typeset ); +} +\end{code} + +\section[Misc_routines]{Miscellaneous subroutines} + +\begin{code} +sub do_std_opens { # opens INPIPE, and OUTF; selects the latter + + local($pipe_string,$output_file) = @_; + + # check it output is to a pipe + $output_file = ">$output_file" if $output_file !~ /^\|/; + + open(INPIPE, "$pipe_string |") + || die "$Pgm: can't start prefilter pipe: $pipe_string\n"; + open(OUTF, "$output_file") + || die "$Pgm: can't open output file: $output_file\n"; + select(OUTF); +} + +sub do_std_closes { # closes INPIPE and OUTF; re-selects STDOUT + + close(INPIPE); + # most regrettably, this only tells if the _last_ thing + # in the pipeline croaked... + if ($? >> 8) { + print STDERR "$Pgm: error(s) from prefilter pipe\n"; + unlink("$(TMPDIR)/lit2stuff-po.$$"); # this might exist... + if ($#Files_to_tidy >= 0) { + print STDERR "rm -f @Files_to_tidy\n" if $Verbose; + unlink ( @Files_to_tidy ); + } + exit 1; + } + close(OUTF); + if ($? >> 8) { + print STDERR "$Pgm: error in closing output file: $?\n"; + unlink("$(TMPDIR)/lit2stuff-po.$$"); # this might exist... + exit 1; + } + select(STDOUT); +} + +sub not_OK { # report error, increment $Status, but keep going + local($srcfilename, $srclineno, $msg) = @_; + if ($srcfilename) { # not always there + print STDERR "$srcfilename:$srclineno: $msg"; + } else { + print STDERR "$Pgm: $msg"; + } + $Status++; +} + +sub hints_not_OK { # return 1 or '' depending on if all hints are in valid list or not + local($valid_hints,$given_hints) = @_; + local($h); + + foreach $h (split(/,/,$given_hints)) { + return(1) if index($valid_hints,$h) < 0; + } + ''; +} + +sub filter_string { + local($filter, $string) = @_; + + open(FILT, "| $filter > /tmp/lit$$") || die "Can't open in filter_string\n"; + print FILT $string; + close(FILT); + if ($? >> 8) { # something went wrong in the pipe ??? + print STDERR "$Pgm: error(s) in/from filter: $filter\n"; + } +# local($filtered_string) = `cat /tmp/lit$$`; # perl bug + $filtered_string = `cat /tmp/lit$$`; + unlink("/tmp/lit$$"); + $filtered_string; +} + +sub deatified2verb_nl { # lit-deatify put 'em in; now we take 'em out + local($_) = @_; + + s/\001newline\003/\n/g; # _WITH_ newlines + s/\001lbrace\003/\{/g; + s/\001rbrace\003/\}/g; + s/\001rbracket\003/\]/g; + + $_; +} + +sub deatified2verb { # without newlines + local($_) = @_; + + $_ = &deatified2verb_nl($_); + + s/\n/ /g; # the difference; to SPACES + $_; +} + +sub de_newlined { + local($_) = @_; + + s/\n/\001newline\003/g; + $_; +} + +sub root_and_suffix { + local($filename) = @_; + local($root,$suffix); + + # find the file's "suffix" (NB: *.lit.hs has a 6-letter suffix) + if ($filename =~ /\.(lit\.[^\.\/]+)$/) { # cf \input handling in reader + $suffix = $1; + ($root = $filename) =~ s/\.(lit\.[^\.\/]+)$//; + + } elsif ($filename =~ /\.([^\.\/]+)$/) { + $suffix = $1; + ($root = $filename) =~ s/\.([^\.\/]+)$//; + + } else { + # should there be a warning or something here? + $root = '???'; + $suffix = '???'; + } + ($root, $suffix); +} + +\end{code} + +\section[Reader_feeding]{Pre-processing programs that feed the reader} +\downsection +% the inputter that we hope will go away +\input{lit-inputter.lprl} + +% the pre-processing filter, a lex script +\input{lit-deatify.llex} +\upsection + +\section[Reader]{The input reader and categorizer} +\downsection +\input{lit-reader.lprl} +\upsection + +\section[Language_independent_processing]{Language-independent processing code} + +``Language''-specific code is described after the linker. + +\downsection +\input{lit-2pgm.lprl} +% for both lit2texi and lit2latex +\input{lit-2doc.lprl} +\input{lit-2texi.lprl} +\input{lit-2latex.lprl} +\input{lit-2depend.lprl} +\input{lit-2changes.lprl} +\upsection + +\section[Linking_code]{Language-independent code for linking} +\downsection +\input{lit-linker.lprl} +\upsection + +\section[Language_specific_processing]{Code-language-specific processing} + +This code only applies for \tr{lit2texi} and \tr{lit2latex}. + +\downsection +\section[Language_none]{Special stuff for language \tr{none}} +\downsection +\input{lit-2pgm-none.lprl} +\input{lit-2doc-none.lprl} +\input{lit-2texi-none.lprl} +\input{lit-2latex-none.lprl} +\upsection +\upsection + +\downsection +\section[Language_hs]{Special stuff for language \tr{hs} (Haskell)} +\downsection +\input{lit-2pgm-hs.lprl} +\input{lit-2doc-hs.lprl} +\input{lit-2texi-hs.lprl} +\input{lit-2latex-hs.lprl} +\upsection +\upsection + +\downsection +\section[Language_prl]{Special stuff for language \tr{prl} (Perl)} +\downsection +\input{lit-2pgm-prl.lprl} +\input{lit-2doc-prl.lprl} +\input{lit-2texi-prl.lprl} +\input{lit-2latex-prl.lprl} +\upsection +\upsection + +\downsection +\section[Language_C]{Special stuff for language \tr{c} (C)} +\downsection +\input{lit-2pgm-c.lprl} +\input{lit-2doc-c.lprl} +\input{lit-2texi-c.lprl} +\input{lit-2latex-c.lprl} +\upsection +\upsection + +\downsection +\section[Language_lex]{Special stuff for language \tr{lex}} +\downsection +\input{lit-2pgm-lex.lprl} +\input{lit-2doc-lex.lprl} +\input{lit-2texi-lex.lprl} +\input{lit-2latex-lex.lprl} +\upsection +\upsection + +\downsection +\section[Language_Fortran]{Special stuff for language \tr{f}} +\downsection +\input{lit-2pgm-f.lprl} +\input{lit-2doc-f.lprl} +\input{lit-2texi-f.lprl} +\input{lit-2latex-f.lprl} +\upsection +\upsection + +\downsection +\section[Language_jm]{Special stuff for language \tr{jm} (``make world'' stuff)} + +This type of input file is a mixture of C-pre-processor stuff and +\tr{make} stuff. + +\downsection +\input{lit-2pgm-jm.lprl} +\input{lit-2doc-jm.lprl} +\input{lit-2texi-jm.lprl} +\input{lit-2latex-jm.lprl} +\upsection +\upsection + +\begin{onlystandalone} +\printindex +\end{document} +\end{onlystandalone} diff --git a/web/glasgow/lit2x-0.16/literate/typesetting-code b/web/glasgow/lit2x-0.16/literate/typesetting-code new file mode 100644 index 0000000000..7553426a07 --- /dev/null +++ b/web/glasgow/lit2x-0.16/literate/typesetting-code @@ -0,0 +1,1061 @@ +From piet@cs.ruu.nl Thu Oct 10 20:05:48 1991 +From: piet@cs.ruu.nl (Piet van Oostrum) +Newsgroups: comp.text.tex +Subject: Typesetting programs with (La)TeX (update) +Date: 9 Oct 91 14:38:42 GMT +Reply-To: piet@cs.ruu.nl (Piet van Oostrum) +Organization: Dept of Computer Science, Utrecht University, The Netherlands + +Typesetting program texts with TeX and LaTeX. + +This is a survey of methods to typeset program texts with TeX +and/or LaTeX, usually mixed with other text. The description consists +mostly of (edited) parts of the documentation of the packages, or messages +from their authors. I post this to get responses from people that know +other packages, or updated versions of these. Also I would like to receive +input about the availability (e.g. by FTP or mail server) of these +packages, other than the ones mentioned here. + +PLEASE MAIL remarks to me, do not post them on the net. After two or three +weeks I will post an updated version. I might also submit it for +publication in TUGboat, but then I will have to TeXify it first. + +---------------------------------------------------------------------- +Note: +Several of the packages described below can be obtained from our +archive, either by ftp-ing from archive.cs.ruu.nl [131.211.80.5], in +directory TEX/TOOLS, or by sending a message to mail-server@cs.ruu.nl +containing the line: +send TEX/TOOLS/INDEX +or replacing INDEX with an appropriate file name. +If you are not familiar with the mail-server, use "send HELP" first. +---------------------------------------------------------------------- + +Contents: + +1. Web and derivatives +1.1 Cweb +1.2 Fweb +1.3 Spiderweb +2. Tgrind +3. C2latex +4. C++2latex +5. Cprog macros +6. program environment +7. Scheme +8. Ada +9. Modula-2/Pascal +10. sundry + +------------------------------------------------------------------------ +1.1 Cweb +------------------------------------------------------------------------ + +ctangle, cweave - translate CWEB to C and/or TeX + +The ctangle program converts a CWEB source document into a C +program that may be compiled in the usual way. The output +file includes #line specifications so that debugging can be +done in terms of the CWEB source file. + +The cweave program converts the same CWEB file into a TeX +file that may be formatted and printed in the usual way. It +takes appropriate care of typographic details like page +layout and the use of indentation, italics, boldface, +etc.,and it supplies extensive cross-index information that +it gathers automatically. + +CWEB allows you to prepare a single document containing all +the information that is needed both to produce a compilable +C program and to produce a well-formatted document +describing the program in as much detail as the writer may +desire. The user of CWEB ought to be familiar with TeX as +well as C. + +Don Knuth wrote WEB for TeX and Pascal. Silvio Levy designed +and developed CWEB by adapting the WEB conventions to C and +by recoding everything in CWEB. + +Subject: Levy's Cweb system ported to MS-DOS and VAX/VMS + +On the UK TeX Archive at Aston University, directory [tex-archive.web.cweb] +contains the sources for building Silvio Levy's CWEB system (a WEB suite +which uses C as the programming language, and TeX as the typesetting +language) under Unix; this includes a bootstrapping version of Ctangle +which permits one to get Cweave, etc., working. + +Originally this was accompanied by a file VMS.CH which purported to +port Cweb onto VAX/VMS: however, Vax-C has been revised since Levy +released this, and further changes were necessary to get the system +working under VMS. The original VMS.CH has threfore been deleted, and a +new subdirectory [tex-archive.web.cweb.vms] added to hold the files for +bootstrapping CWEB onto VMS, and the change files to make this Ctangle +and Cweave. + +In addition, I have ported CWEB to MS-DOS (under Borland's Turbo-C V1.5). +This was a *major* undertaking, because of clashes between identifiers +used in ANSI-standard function prototypes in Borland's libraries and +constants defined in the .web files. Other very extensive changes were +required to handle the large data structures, which exceed the 64kB +segment limit of the PC architecture. However, it's all working +eventually, and the files required for bootstrapping it, and the change +files, will be found in [tex-archive.web.cweb.ms-dos]. + +For both of the above ports, the majority of the files of the Unix +distribution will also be required. + +To get started, fetch the file [tex-archive.web.cweb]00readme.txt from +Aston, either by NIFTP (username PUBLIC, password PUBLIC), or by sending +mail to <TeXserver@Uk.Ac.Aston.TeX>, with the body of the message +consisting of the two lines: + FILES + [tex-archive.web.cweb]00readme.txt + +This file will tell you which other files will be required to be fetched +to have a working version of CWEB under Unix, VMS or MS-DOS. + + Brian {Hamilton Kelly} + +------------------------------------------------------------------------ +1.2 Fweb +------------------------------------------------------------------------ + + The WEB System of Structured + Software Design and Documentation + for C, C++, Fortran, Ratfor, and TeX + + Release 1.22 + September 21, 1991 + + John A. Krommes + Princeton University + + +INTRODUCTION + + This message is for new users of the so-called FWEB processors, which +implement a version of Knuth's WEB system that supports multiple languages and +a variety of other useful features. If you are already on the FWEB mailing +list, you should have already received announcements about version 1.22, +and there is nothing new in the following. If you would like to be added +to the mailing list, please let me know. (Please supply an Internet +address if possible.) + + The WEB system consists of EASY-TO-USE software tools that aid in +software design and documentation. In fact, one can say that the +documentation IS the code, and vice versa. The documentation facility is +fully integrated with TeX; book-quality documentation of both text and code +can be produced essentially automatically. Knuth's fundamental philosophy +of rearrangable and pluggable modules of code fragments substantially +simplifies the translation of logical ideas into compilable code. A fully +indexed, 150 page user manual based on Knuth's original brief memo is +included with this release. + + The most significant features that distinguish FWEB from its predecessors +are: + + * SUPPORT for MULTIPLE LANGUAGES + + Presently supported are C, C++, Fortran--77, Fortran--90, + Ratfor (RATional FORtran), and (to a limited extent) TeX + itself. + + * A POWERFUL, C-LIKE MACRO PREPROCESSOR + + This is particularly useful for Fortran and Ratfor; it + makes programming in those languages substantially less + painful. + + * A BUILT-IN RATFOR PROCESSOR + + Ratfor endows Fortran with a C-like syntax and certain + useful commands such as `for' and `switch'. If you must + program in Fortran, try Ratfor. + +In addition, many user-friendly features and options have been added to +this release. + + FWEB was originally released in 1989. Since then, it has undergone +substantial development and testing on a variety of machines. It is +written in ANSI C, so it is very portable. An INCOMPLETE list of machines +and operating systems on which FWEB runs is + + [ansi] (any system that has a fully ANSI C compiler) + Apollo + Cray-2 + DECstation + IBM-PC (executable files are supplied in addition to source code) + NeXT + Silicon Graphics Personal Iris + Sun (both gcc and cc compilers) + VAX/VMS + +FWEB is compiled on all machines in the above list except the Apollo before +each release. + + +OBTAINING VERSION 1.22 + + Version 1.22 of the FWEB system is available via anonymous guest ftp from +Internet host + + lyman.pppl.gov + +in public area + + /pub/fweb/v1.22/ + +Here is a sample ftp dialog. (The precise commands may differ slightly on +your system.) + + ftp lyman.pppl.gov + Name: anonymous + Password: guest + ftp> cd pub/fweb/v1.22 + ftp> ls + ftp> get READ_ME.FWEB (brief instructions) +[If you're a new user, you may initially want to skip the next two lines:] + ftp> type image + ftp> get TAR.v1.22.Z (the entire release) +[If you get the TAR file, the next two lines are unnecessary:] + ftp> cd manual + ftp> get INSTALL_FWEB.tex (detailed installation instructions) + ftp> quit + +Follow the instructions in READ_ME.FWEB or, in much more detail, in +INSTALL_FWEB.tex. The TAR file contains the complete release, except that +the executable files for the IBM-PC are not included in it. You must +obtain those by separate get commands, e.g., + + ftp> cd boot/pc + ftp> mget *.exe + +To unpack the TAR file, say in an empty subdirectory + + uncompress TAR.v1.22 + tar -xvf TAR.v1.22 * + +After you've done this, obtain the user manual + + make -n fwebman + +to see what will happen, then say ``make fwebman'' to really do it. + + If you can't use ftp, you may be able to use the intermediary of bitftp, +available through bitnet. You type a valid ftp session into a file, then +send that file as a message to bitftp@pucc.bitnet. You will get the files +you requested---e.g., TAR.v1.22.Z---back in the form of a message or +messages, possibly uuencoded if the file is large. To obtain help on using +bitftp, send to the above address a message containing the single word +``help''. + + +NEW in VERSION 1.22 + + Version 1.22 is essentially the non-beta version of v1.20--beta that was +made available in February 1991; it fixes a wide variety of bugs with that +earlier version, and adds a few new features. A short list of the changes +and principal bug fixes can be found at the beginning of the detailed +installation guide INSTALL_FWEB.tex. Note the following in particular [new +users will be most interested in point (1) about support for LaTeX]: + +(1) This version is intended to run with LaTeX as well as with Plain TeX, +and it is recommended that you use LaTeX if you can. However, this recent +enhancement has not been tested thoroughly. If you run across macro +conflicts or other difficulties with using LaTeX in conjunction with +fweave, please let me know. Note that fwebmac usurps LaTeX's \output +routine, so you won't be able to do fancy things with output unless you dig +into the details of fwebmac. But simple LaTeX environments such as tables +are supposed to work. + +(2) IBM--PC users should note that executable files are provided with this +release, so you don't need a C compiler to proceed. That's the good news. +The bad news is that I haven't yet been able to squeeze this version down +enough so that the processors can do themselves. To get a feeling for the +size of things, you should begin with small test programs and use the -s +command-line option to look at the memory allocation statistics. + +(3) SYSTEM INSTALLERS SHOULD NOTE THAT THE BOOTSTRAPPING PROCEDURE HAS BEEN +GREATLY SIMPLIFIED. All source files with the exception of one are now +common to all machines. The exception is custom.web/custom.h. For +bootstrapping, if a custom.h for your machine is not provided in the +relevant boot subdirectory, you should first copy a version of custom.h +into the web subdirectory, then edit that copy following the instructions +contained in the file. Then compile and link as usual. A short version of +the bootstrapping procedure is provided in READ_ME.FWEB; more details are +given in manual/INSTALL_FWEB.tex. + + I continue to be very interested in what changes you must make to get +FWEB running on your machine. For example, you might have to do something +that's not covered in custom.h. Unless you know better, always begin by +trying the ansi customization (in boot/unix/ansi/custom.h). If your C +compiler isn't ANSI, complain to the vendor; standards are useful. If your +compiler crashes, complain to the vendor and notify me. + + This version has benefited from the bug reports and suggestions of a +large number of patient beta-testers and manual readers of v1.20. I am +very grateful to all of you. + + +OBTAINING HELP and REPORTING BUGS + + FWEB is an evolving project [supported by just one author, in (allegedly) +spare time] that benefits greatly from user feedback. An attempt is made +to answer FWEB-related mail promptly---at least once a week, generally more +frequently. Please feel ABSOLUTELY FREE to request help, advice, and new +features, and to report bugs or inconsistencies in the documentation. +Thanks very much for your help. + +--- John Krommes + September 21, 1991 + + krommes@princeton.edu | John A. Krommes + | Plasma Physics Laboratory + ``princeton.edu'' is a synonym for | P.O. Box 451 + lyman.pppl.gov == 192.55.106.129 | Princeton, NJ 08543 + + | Phone: (609) 243--2606 + +------------------------------------------------------------------------ +1.3 Spiderweb +------------------------------------------------------------------------ + +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% To be used for research purposes only +% For more information, see file COPYRIGHT in the parent directory + +\documentstyle[11pt]{article} +\title{A note about a new implementation of {\tt WEB}} +\author{Norman Ramsey\\Odyssey Research Associates} +\date{July 4, 1988} +\setcounter{secnumdepth}{0} +\begin{document} +\maketitle + +\begin{abstract} +Literate programming has received recent attention in the {\sl +Communications of the ACM}~\cite{bentley:lp,cvw:loom}. +{\tt WEB} is a tool intended for literate programming, but +until recently it was useful only for writing PASCAL programs. +The author has developed a new tool, {\tt SPIDER}, which reads a +description of a programming language and writes a {\tt WEB} system +that can be used to write programs in that language. +{\tt SPIDER} has been used in the author's organization to build {\tt +WEB} systems for Ada, C, AWK, and other languages. +The author hopes that {\tt SPIDER} will enable people to write +literate programs in many more languages than they could before. +\end{abstract} + +\section{Introduction} +Donald Knuth developed the {\tt WEB} system of structured documentation +as part of the {\TeX} project~\cite{knuth:literate-programming}. +His implementation of {\tt WEB} combined PASCAL and {\TeX}. + The {\tt WEB} idea suggests a way of combining {\em any} +programming language with {\em any} document formatting language, +but until recently there was no software support for writing in {\tt +WEB} anything but PASCAL programs. +In~1987, Silvio Levy rewrote the {\tt WEB} system in C for C, +while retaining {\TeX} as the formatting language~\cite{levy:cweb}. +I have has modified Levy's implementation by removing the parts +that make C the target programming language, and I have + added a third tool, {\tt SPIDER}, which complements {\tt WEAVE} +and {\tt TANGLE}. +{\tt SPIDER} reads a description of a programming language, and writes +source code for a {\tt WEAVE} and {\tt TANGLE} which support that +language. +Using {\tt SPIDER}, a C~compiler, and an AWK~interpreter, an experienced +systems programmer can generate in a few hours a {\tt WEB} system for +an Algol-like language. + +\section{Features of Spidery {\tt WEB}} +An exhaustive list of Spidery {\tt WEB}'s features would interest only +{\tt WEB} experts, +but I do want to mention some features that I hope will encourage +people to use Spidery {\tt WEB}. +\begin{itemize} +\item +{\tt TANGLE} and {\tt WEAVE} can read from multiple files (this +feature is present in Levy's {\tt CWEB}), and +{\tt TANGLE} can write to multiple files. +Included files will be searched for on a path if not found in the +current directory. +These features make Spidery {\tt WEB} more usable on systems that have +{\tt make}. +\item +{\tt TANGLE} can expand macros with multiple parameters. +\item +The starred sections in Spidery {\tt WEB} can be organized +hierarchically (in three levels). +We have a UNIX tool that can extract different pieces of the hierarchy +from the output of {\tt WEAVE}, so that it is possible to take +excerpts from {\tt WEB} documents. +\item +{\tt TANGLE} writes {\tt \#line} directives, so you can debug at the +{\tt WEB} source level if your compiler respects the C~conventions for +{\tt\#line}. +\item +Many features of {\tt WEB} seem to exist only to compensate for +deficiencies in PASCAL, and most of those were dropped in {\tt CWEB}. +I have changed much of {\tt CWEB} in order to avoid being bound too +much by C conventions. +As a result, there are dozens of minor differences between Spidery +{\tt WEB} and original {\tt WEB}. +To give just one example, Spidery {\tt WEB} supports +octal and hexadecimal constants using {\tt WEB}-style +notation, not the C~notation used in {\tt CWEB}. +\end{itemize} + +\section{Scope of {\tt SPIDER}} +{\tt SPIDER} can generate {\tt WEB} systems for a variety +of languages. +The author has written {\tt SPIDER} description files for C, AWK, Ada, +SSL (a language that describes attribute grammars to the +Cornell Synthesizer Generator), +the Larch Shared Language (a language for describing equational +theories), +and Dijkstra's language of guarded commands. +Debugging the grammar that {\tt WEAVE} uses to +prettyprint the language is the most time-consuming part of creating a +{\tt WEB} system for a new target language, +and {\tt SPIDER} makes it trivial to change that grammar. +To make a {\tt SPIDER} description file for an Algol-like language +that uses infix expression notation, an experienced systems programmer +should be able to adapt an existing {\tt SPIDER} description file very +quickly. + +{\tt SPIDER}'s major limitations are lexical. + All Spidery {\tt WEB}s +assume that spaces and tabs in the input are not significant, except +as separators; +this makes it impossible to construct Spidery {\tt WEB}s for languages +like Fortran and Miranda, where the position of text on a line is +significant. +The lexical structures of identifiers, string literals, and numeric +literals are fixed. + +\section{Conclusions} +{\tt SPIDER} is a modest piece of engineering; it does not introduce +new ideas. +{\tt SPIDER} does make it possible to create a new {\tt WEB} quickly, +and to tinker with it easily. +The author's group routinely uses Spidery {\tt WEB} to write programs +in Ada, C, and~SSL, and has been pleased with the result. +We have written in {\tt WEB} an application of eighteen thousand +lines, and +we are very pleased at how easy it has been to review and maintain +this code. +The author hopes that the availability of Spidery {\tt WEB} will +encourage other groups to try literate programming, and that they, +too, will be pleased with the results. + +\begin{thebibliography}{Van~Wyk~9999} +\bibitem[Bentley~86]{bentley:lp} +Jon L. Bentley, ``Programming Pearls,'' +{\sl Communications of the ACM} {\bf 29:5} (May~1986), 364--368, and +{\bf 29:6} (June~1986), 471--483. +\bibitem[Knuth~84]{knuth:literate-programming} +Donald E. Knuth, ``Literate Programming,'' {\sl The Computer Journal} +{\bf 27:2} (1984), 97--111. +\bibitem[Levy~87]{levy:cweb} +Silvio Levy, ``{\tt WEB} Adapted to C, Another Approach,'' + {\sl TUGBoat} {\bf 8:1} (1987), 12--13. +\bibitem[Van~Wyk~87]{cvw:loom} +Christopher J. Van~Wyk, ``Literate Programming,'' +{\sl Communications of the ACM} {\bf 30:7} (July~1987), 593--599, and +{\bf 30:12} (December~1987), 1000--1010. +\end{thebibliography} + +------------------------------------------------------------------------ +2. Tgrind +------------------------------------------------------------------------ + +From: Ken Yap <ken@rochester.arpa> + +Several people have asked about including program source in TeX +documents. I believe the most general approach is to use a utility like +tgrind (TeX analog of vgrind). One specifies the language to be +processed (so that tgrind can detect keywords). Tgrind converts tabs +into the appropriate spacing (generates things like \tab{24} for 3 +tabs), boldens keywords, prints quoted strings in typewriter font, +prints comments in italics, and other nice things. All these goodies +are customizable. This requires an extra pass, but the preprocessing +is quite fast. + +Tgrind is on the Unix TeX tape, in the directory TeXcontrib/van. It was +written by Van Jacobson of LBL. Unfortunately it is Unix specific, but +I think equivalents for other OS are no problem. Heck, just take your +favourite pretty-printer and generate TeX instead of prettified +output. + +Ken + +tgrind - grind nice program listings using TeX or LaTeX + +Tgrind formats program sources in a nice style using TeX. +Comments are placed in italics, keywords in bold face and +strings in typewriter font. Source file line numbers appear +in the right margin (every 10 lines). The start of a +function is indicated by the function name in large type in +the right margin. + +In regular mode tgrind processes its input file(s) and +passes them to TeX for formating and output. + +In format mode (i.e., when the flag is used), tgrind +processes its input file(s) and writes the result to +standard output. This output can be saved for later +editting, inclusion in a larger document, etc. + +Currently known are + PASCAL, RATFOR, Modula-2, MODEL, C, ISP, Yacc, + Prolog, Icon, TeX, CSH, and Bourne Shell . + +Van Jacobson, Lawrence Berkeley Laboratory (based on +"vgrind" by Dave Presotto & William Joy of UC Berkeley). +------------------------------------ +Jerry Leichter improved tgrind. His version is available from +venus.ycc.yale.edu in [.TGRIND]. + +I've added some functionality to Jerry's version of tgrind and called +it lgrind, as it only really works with LaTeX (as does Jerry's). +Essentially, what I did was to add a facility for having fragments of +code in comments (a la WEB) and to improve the embedded mode, where +lgrind filters a LaTeX file with embedded chunks of code. + +I was going to release lgrind by itself, but now it's going to be part +of Pretty!, a suite of prettyprinting programs by Joerg `joke' +Heitkoetter (heitkoet@gorbi.informatik.uni-dortmund.de), who writes: + Pretty! currently consists of Modula2LaTeX (c.s.m.vol22i79-81), lgrind + and C++2LaTeX, plus a library for writing indentation tools like the + BSD indent (which might be rewritten by me for BSD4.4), plus low level + stuff like expand/unexpand(1) tools, etc. + I already made a proposal to FSF to call it "GNU Pretty!", we'll see... + +/George +________________ +George V. Reilly `Georges Cinq' gvr@cs.brown.edu +1 (401) 863-7693 +uunet!brunix!gvr gvr@browncs.bitnet Box 1910, Brown U, Prov, RI 02912 +------------------------------------ +I hope you got George V Reilly's addendum to your "Currently available +tools for program documentation" list, I hope to alpha release +"Pretty! -- Utilities for Typesetting Formal Languages" during the +next weeks... + +It contains LAGRiND, which is based on Van Jacobsen's tgrind, Jerry +Leichter's update to tgrind, and some ideas developed by George's group at +Brown University. It will make *any* tgrind version obsolete, because +you can emulate the older versions with a switch. + +Pretty! (the ! belongs the the logo) is a collection of tools of the +following kind: + + 1. formatters (BSD indent) + 2. typesetters (LaGRiND, Modula2LaTeX, C++2LaTeX) + 3. low level utilities (expand/unexpand) + +Pretty! was much inspired by suite's like Rich Murphey's GNU Graphics, and +Jef Poskanzer's PBM+. I hope Pretty! will be the a kind of clearing house +for this special usage of LaTeX/TeX usage. We'll see. + +Thanx again and so long + + -joke + +-- +Joerg Heitkoetter +Systems Analysis Group +University of Dortmund, Germany +(heitkoet@gorbi.informatik.uni-dortmund.de). + +------------------------------------------------------------------------ +3. C2latex +------------------------------------------------------------------------ + +From: ramsdell@celebes.mitre.org (John D. Ramsdell) +Subject: c2latex--Simple Support for Literate Programming in C + +C2latex provides simple support for literate programming in C. Given +a C source file in which the comments have been written in LaTeX, +c2latex converts the C source file into a LaTeX source file. It can +be used to produce typeset listings of C programs and/or documentation +associated with the program. + +The C source given to c2latex usually has the following form. It +starts with a large comment containing LaTeX commands that start a +document along with any initial text. Then there is a sequence of +comment and code pairs, with the comment explaining the code to +follow. The source file is ended by a comment containing LaTeX +commands that finish the document. + +C2latex produces LaTeX source by implementing a small number of rules. +A C comment that starts at the beginning of a line is copied +unmodified into the LaTeX source file. Otherwise, non-blank lines are +surrounded by a pair of formatting commands (\begin{flushleft} and +\end{flushleft}), and the lines are separated by \\*. Each non-blank +line is formatted using LaTeX's \verb command, except comments within +the line are formatted in an \mbox. + +The c2latex program is written in ANSI C and can be processed by +c2latex to produce LaTeX source containing a typeset listing of +itself. It has a copyright similar to those distributed with GNU +software. c2latex is available from me as a shar file via electronic +mail. If there is enough interest, I will request that the sources be +placed on a public server. + +John + +------------------------------------------------------------------------ +4. C++2latex +------------------------------------------------------------------------ + +The program c++2latex converts ANSI-C/C++ programs into LaTeX source. + +It requires flex which can be found on various ftp sites, + e.g. prep.ai.mit.edu. For those without flex and without the possibility +to get one, I can email the flex'ed program. + +Please notice that this program is under GNU Copyleft. + + DESCRIPTION + +c++2latex is a tool for generating LateX source from ANSI-C +or C++ programs. It recogizes all keywords, strings, and +comments. These recognized parts can be set in different +fonts. c++2latex can generate complete LaTeX files which +can directly passed through latex or parts of LaTeX files +which can be included in other files (either direct or by +the \input or \include commands). The output filename is +searched in various steps. First, if the {-o,+output} flag +is given, the output is written to the file pointed to by +the value of this flag. If the {-t,+pipe} option is given, +the output is written to stdout. (It is an error to specify +both options together.) If none of this options but an input +pathname is given, the output is written to a file who's +name is the last component of the input pathname with the +substituted or else added suffix '.tex'. If the input is +read from stdin and none of the above options is given, the +output is written to '<program-name>.tex' with <program- +name> being the name of this program. + +------------------------------------------------------------------------ +5. Cprog macros +------------------------------------------------------------------------ + +The cprog macros allow programs in C, C++, Pascal, and Modula-2 to be +included directly into TeX documents. Program text is set in a Roman +font, comments in slanted, and strings in typewriter. Operators such as +<= are optionally combined into single symbols like $\le$. Keywords are +*not* emphasised---I find this ugly and distracting. (By purest +coincidence it would also be very hard to do.) + +These macros can be \input in plain TeX or used as a style file in LaTeX. +They provide a convenient alternative to tgrind, particularly for program +fragments embedded in documents. Full instructions for use appear in the +macro package itself. + + +\'Eamonn McManus <emcmanus@cs.tcd.ie> <emcmanus%cs.tcd.ie@cunyvm.cuny.edu> + +This allows C programs to be formatted directly by TeX. It can be +invoked by \cprogfile{filename} or (in LaTeX) \begin{cprog} ... +\end{cprog} or (in plain TeX) \cprog ... \end{cprog}. In LaTeX, the +alternative form \begin{cprog*} is allowed, where spaces in C strings +are printed using the `square u' character (like LaTeX {verbatim*}). +In plain TeX, you have to use \csname cprog*\endcsname for this (sorry). +If you are using \cprogfile, say \cprogttspacetrue beforehand if you +want this effect. + +The formatting is (necessarily) simple. C text is set in a normal Roman +font, comments in a slanted font, and strings in a typewriter font, with +spaces optionally made visible as the `square u' symbol. Tabs are +expanded to four spaces (this does not look good when comments are +aligned to the right of program text). Some pairs of input characters +appear as single output characters: << <= >> >= != -> are respectively +TeX's \ll \le \gg \ge \ne \rightarrow. Say \cprogpairsfalse to disable +this. + +You can escape to TeX within cprog text by defining an escape character. +The character @ is suitable for C and Pascal. I have not tested other +characters so they may interact badly with their existing definitions here. +To define @ as the escape character, do \cprogescape@. Then within text +you can do @ followed by TeX commands. These commands will be in a TeX +group with the \catcodes of \{}% as normal. The commands are terminated +by a newline, which is not considered part of the program text. + +The fonts below can be changed to alter the setting of the various parts +of the program. The \cprogbaselineskip parameter can be altered to +change the line spacing. LaTeX's \baselinestretch is taken into account +too. The indentation applied to the whole program is \cprogindent, +initially 0. Before and after the program there are skips of +\beforecprogskip and \aftercprogskip; the default values are \parskip +and 0 respectively (since there will often be a \parskip after the +program anyway). + +If the source text is Pascal or Modula-2, say \pascaltrue or \modulatrue +(respectively) before formatting it. This makes (* *) be recognised for +comments instead of /* */. Braces {} are also recognised for Pascal. +\pascalfalse or \modulafalse as appropriate restores the default of C. + +This package works by making a large number of characters active. Since +even spaces are active, it is possible to examine the next character in +a macro by making it a parameter, rather than using \futurelet as one +would normally do. This is more convenient, but the coding does mean +that if the next character itself wants to examine a character it may +look at a token from the macro rather than the input text. I think that +all cases that occur in practice have been looked after. + +The macros could still do with some work. For example, the big macro +defined with [] taking the place of {} could be recoded to use {} and so +be more legible. The internal macros etc should have @ in their names, +and should be checked against LaTeX macros for clashes. + +------------------------------------------------------------------------ +6. Program environment +------------------------------------------------------------------------ +\documentstyle[program2]{article} +\oddsidemargin 10mm \evensidemargin 10mm +\marginparwidth 20mm \marginparsep 7pt +\topmargin 0mm \headheight 12pt \headsep 1cm \footheight 12pt \footskip 30pt +\textheight 220mm \textwidth 147mm \columnsep 10pt \columnseprule 0pt +\def\lijn{\rule{\textwidth}{1pt}} +\begin{document} +\title{How to layout a (Pascal-)program in \LaTeX} +\author{Rein Smedinga \\ +{\small department of computing science, p.o.box 800, 9700 AV Groningen }\\ +{\small tel. 050--633937 (633939), email: \verb!rein @cs.rug.nl!}} +\maketitle +\def\framed#1{\framebox[\textwidth][l]{\vbox{#1}}} +\def\bep{\begin{program}\skipprog}% begin programtext +\def\eep{\end{program}\noindent}% end programtext + +In \TeX\ or \LaTeX\ is it possible, but difficult, to create a nice layout +for programs. The easiest way is to use the \verb!verbatim! environment. +The layout is then copied from the input file. In most books a program +(e.g., a PASCAL-program) is displayed using boldface reserved words, +using math-italic for statements and using teletype fonts for string +representations. Without extra equipment this can be done in \TeX\ as +well as in \LaTeX\ using a \verb!tabbing!-environment. +Of course, each font choice +should be made explicitly, e.g., you must say \verb!{\bf begin}! to +create a boldface begin-symbol and \verb!$x:=x+1$! to denote an +assignment. Furthermore, the user is responsible for setting the tabs and +jumping to the right ones. This is far from being user-friendly. + +The \verb!program!-environment tries to be of some help while displaying +program-texts. It contains a number of macros of the form \verb!\BEGIN!, +\verb!\PROCEDURE! and alike that not only put down a boldface begin- +or procedure-symbol but also sets and jumps to the right tabs. Using +the \verb!program! environment from the \verb!program2!-style file +also automatically puts the statements +in math-mode (you do not have to use \verb!$!-signs anymore). + +------------------------------------------------------------------------ +A similar style: + +program.sty: a LaTeX style file for typesetting algorithms. +Copyright (C) 1991 Martin Ward + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation. + +This is the "program" style option which sets up the +program and programbox environments, +keywords for programs and a few goodies. +NOTE: Within the program environment: +(1) Newlines are significant. +(2) Each line is in math mode, so for example spaces in the input + file are not significant. +(3) \\ within a line causes a linebreak in the output. + +We also define a "programbox" environment which typesets a program in a box. +Useful for keeping a piece of code on one page or for typesetting small +programs in running text. +We also redefine \( and \) as \begin{programbox} and \end{programbox}. +The \tab and \untab commands are defined to have no effect while outside +a program environment, hence a single-line program can be typeset in +maths mode without the overhead associated with programbox. + +------------------------------------------------------------------------ +7. Scheme +------------------------------------------------------------------------ + +From: John D. Ramsdell <ramsdell%linus@mitre-bedford.ARPA> +Subject: SchemeTeX---Simple support for literate programming in Lisp. + +SchemeTeX provides simple support for literate programming in any +dialect of Lisp on Unix. Originally created for use with Scheme, it +defines a new source file format which may be used to produce LaTeX +code or Lisp code. Roughly speaking, LaTeX formats Lisp code in a +verbatum-like environment, and it formats Lisp comments in an ordinary +environment. + +SchemeTeX is available via anonymous FTP from linus (192.12.120.51) in +the shar file named "pub/schemeTeX.sh". Included is an operating +system independent version for the T dialect of Lisp. + +John + +------ +From: dorai@tone.rice.edu (Dorai Sitaram) +Subject: typesetting Scheme code + +I wrote something called SLaTeX that allows listings of Scheme code in +LaTeX without restricting it to the usual monospace typewriter font +supported by other code typesetters. + +I've placed the current version in the titan.rice.edu's anonymous ftp +area: get public/slatex.sh. + +SLaTeX decides which tokens should be, say, boldfaced, italicized, or +sansserifed, pretty much along the style of the Little Lisper [1]. +(The user can completely control this default decision process, so +much so that he can flip the fonts around, add new fonts, or even do +something silly like make everything come out in typewriter -- i.e., +turn the program into a no-op.) + +I'd been leery of distributing SLaTeX before because of the frequent +updating that it's undergone following the Rice Scheme-and-similar- +language users' lively demands for bells and whistles, e.g., + +o allowing arbitrarily positionable displays, boxed code, in-text code, + and directly inputing actual Scheme files; + +o getting little pockets of LaTeX text or mathmode into the Scheme + code, for readable Schemelike pseudocode (useful for + expository papers and class handouts); + +o making it learn automatically that a macro definition implies that + keyword should henceforth be boldfaced, etc. + +At any time, the ftp site will contain the most recent code. The shar +file contains the Scheme source (Ch*z, but should carry over to other +Schemes with minor changes), a shellscript that piggybacks the +codesetter on to LaTeX, the requisite LaTeX style file, installation +instructions, a manual in LaTeX, a man page, and a copyleft. The +first 2 sections in the manual suffice for most uses, with fine tuning +being described later. (The code, as of now, contains more fine +tuning than documented -- I'll update the docs when I next get time.) + +This is free(ly distributable) software, and hence no warranty, though +I'll be glad to field bug and other reports. + + +[1] D.P. Friedman and M. Felleisen, _The Little Lisper_, Science +Research Associates (3e), 1989, and The MIT Press, 1987. + +------------------------------------------------------------------------ +8. Ada. +------------------------------------------------------------------------ + +See TUGboat 10#1, April 1989 + Sriram Sankar APE -- A set of TeX macros to format Ada + programs + +I have developed a set of macros to do exactly this for Ada programs. +To get more details on these macros, read the report in the April issue +of TUGBoat, or the Nov/Dec issue of Ada Letters (both in 1989). + +The macros are available by anonymous ftp to anna.stanford.edu in the +pub directory (I think). I can send them to you if you are willing +to cover the costs. + +Sriram. + +See also: + GUTenberg'90 + May 15-18, 1990 +University Paul Sabatier, Toulouse, FRANCE + +Typesetting ADA programs (P. Naudin, C. Quitte) + +------------------------------------------------------------------------ +9. Modula-2/Pascal +------------------------------------------------------------------------ + +m2latex - a Modula-2 to LaTeX converter + +m2latex is a tool for generating LaTeX sources from Pascal +or Modula-2 It recogizes all keywords, strings, and com- +ments. These recognized parts can be typeset in different +fonts. m2latex can generate complete LaTeX files which can +pass directly through latex(1) or parts of LaTeX files which +can be included in other files (either direct or by the +\input or \include commands). + +The output filename is searched in various steps. First, if +the {-o,+output} flag is given, the output is written to the +file pointed to by the value of this flag. If the {-p,+pipe} +option is given, the output is written to stdout. (It is an +error to specify both options together.) If none of these +options but an input filename is given, the output is writ- +ten to a file who's name is the last component of the input +filename with the added suffix '.tex'. + +* Copyright (C) 1991 Joerg Heitkoetter +* Systems Analysis Group, University of Dortmund, Germany. +* (heitkoet@gorbi.informatik.uni-dortmund.de). +(distributed under GNU copyleft) + +------------------------------------------------------------------------ +10. Sundry. +------------------------------------------------------------------------ + +From: rosenber@ra.abo.fi (Robin Rosenberg INF) +Subject: Re: Typesetting programming languages in LaTeX + +About two years ago I wrote a program that converts programs to TeX. +The program sets keywords in boldface (or any font you select) using a +data file to find out which strings are keywords and how to skip +comments. I have data files for Modula-2, C, C++, Pascal, Occam, Beta, +and some more. The program is written in C (under VMS) and could well +be improved. However it does what I want it to do, it makes programs +_look_ nice in listing. As said it translates to TeX and not LaTex but that is no big deal to change I'd guess. + +If you need this program send a mail to rosenber@ra.abo.fi. mail + +Robin Rosenberg + +------------------------------------------------------------------------ +I have an SED script and Pascal environment for LaTeX that follows +the standard Algol 60 style for setting Pascal text. The SED +script translates everything between \begin{pascal} and \end{pascal} +in various ways that the pascal environment understands. The only +problem with the thing is that indenting must be in multiples of +4 spaces, but I've used it for a number of publications without +hearing any complaints about my awkward indenting style. + +In any case, I strongly recommend the notion of environments for +language types, as opposed to the various grind programs. It would +be nice to have a standard set of environment parameters to control +things like keyword font so language environments from different +sources could be at least somewhat interchangable. + + Doug Jones + jones@herky.cs.uiowa.edu + +------------------------------------------------------------------------ +% manpage.sty + +% Rong Chen (rchen@cs.uiuc.edu) +% Department of Computer Science +% University of Illinois at Urbana-Champaign +% Urbana, IL 61801 + +% Copyright (c) 1990 by Rong Chen +% Permission to copy all or part of this work is granted, provided +% that the copies are not made or distributed for resale, and that +% the copyright notice and this notice are retained. +% +% THIS WORK IS PROVIDED ON AN "AS IS" BASIS. THE AUTHOR PROVIDES NO +% WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, +% INCLUDING WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS +% FOR ANY PARTICULAR PURPOSE. + +% This style option is designed to work with the report document style +% of LaTeX version 2.09. Use \documentstyle[11pt,manpage]{report} +% +% This LaTeX style file is similer to the UNIX troff man macros in format and +% is specially tuned for documenting the C++ library that the author wrote. +% +% The commands that are created in the style file are: +% +% \begin{manpage}{Title}{Module}{Version} % see an example, all will be clear +% \end{manpage} % end of manpage environment +% \variable{#1} (e.g., \variable{int foo}) % with \medskip added +% \variable*{#1} (e.g., \variable*{int bar})% no extra spacing +% \function{#1} (e.g., \function{void demo(int dummy)}) % with \medskip added +% \function*{#1} (e.g., \function*{void demo(int dummy)})% no extra spacing +% \subtitle{#1} (e.g., \subtitle{AUTHOR}) % fit in the same line if possible +% \subtitle*{#1} (e.g., \subtitle*{AUTHOR})% always break a newline +% "#1" (e.g., "dummy_variable") % argument is in italic&unbreakable +% \separator % draw a thin line to seperate suntitle from the text +% \header{#1}{#2}{#3} % in case you want to have a header and +% \footer{#1}{#2}{#3} % a footer outside of the manpage environment +% \dq % print double quote character (") +% +% In the \function macro, data types and their dummy arguments are separated +% by a space. So if you have a function like "int f(const int n)", you should +% document it as \function{int f(const~int n)}. The argument n is optional. +% In the \subtitle macro, two lines of text may be devided by "\\". +--------------------------------------------------------------------------- +MAKEPROG +--------------------------------------------------------------------------- +Another possibility, which comes very close to your suggestion, is +J. Schrod's MAKEPROG. With this you can write plain-TeX or LaTeX documents +with embedded program fragments (simply enclosed in \beginprog and +\endprog), that will be typeset just verbatim. MAKEPROG extracts the program +fragments from the source and joins them together (in linear order only). +All in all, MAKEPROG has less capabilities than WEB, but is not limited to a +given programming language. You can get it from the address above in the +directory /soft/tex/utilities. I wrote an enhancement to MAKEPROG, that +makes the layout of the documentation more WEB-like; if you are interested, +I will mail it to you. + +Hans-Hermann Bode +Arbeitsgruppe Systemforschung, Universit\"at Osnabr\"uck +Tel.: (49)-541-9692545 +e-mail: HHBODE@DOSUNI1.BITNET + +------------------------------------------------------------------------ +CNOWEB: +------------------------------------------------------------------------ +There's another C to plain TeX system, cnoweb, available from +u.washington.edu in pub/tex/cnoweb. + +c-NO_WEB (a c program pretty printer) +by Jim Fox, February 1987 +version 1.1, August 10, 1989 +version 1.2, October 30, 1989 + fixed spacing after ?, :, etc. +version 1.3, June 28, 1990 + added OOdent and IIdent, added \|typewriter| +version 1.4, January 4, 1991 + allow /* and */ in strings + +----------------------------------------------------------------- + +The TeX input file is a c source program. It is assumed to have +this structure: + + /* comments ignored by c-no-web + \input cnoweb + \title{A one line title of the program (optional) } + \synopsis{Synopsis of the program (optional) } + \section{Name of the first section} + rest of comments */ + +The rest of the file is normal c code. +Within the title a \\ may be used to separate lines. + +Each major section begins with + /* \section{name of the section} .... */ +The section names are printed boldface, marked for reference in +the page headline, and written to the table of contents. + +Each minor section begins with + /* \subsection{name of the subsection} .... */ +The subsection names are written to the table of contents. + +A new page can be forced by + /* \newpage */ + +Code and other text containing special characters may be +typed in text mode if it is bracked by *< ... >* +e.g. /* *<inactive c-code>* */ +but this may not be used in a macro argument. + +You can print in bold by enclosing text in double quotes: \"text". +You can print in typewriter by enclosing text in vertical bars: \|text|. +You can print in italics by enclosing text in single quotes: \'text'. + +The file must end with \endc in a comment. e.g., + ... last c code statement ... + /* \endc */ +------------------------------------------------------------------------ +-- +Piet* van Oostrum, Dept of Computer Science, Utrecht University, +Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands. +Telephone: +31 30 531806 Uucp: uunet!mcsun!ruuinf!piet +Telefax: +31 30 513791 Internet: piet@cs.ruu.nl (*`Pete') + diff --git a/web/glasgow/lit2x-0.16/mkworld/Jmakefile b/web/glasgow/lit2x-0.16/mkworld/Jmakefile new file mode 100644 index 0000000000..06d7716931 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/Jmakefile @@ -0,0 +1,72 @@ +/* + * partain: from... + * + * $XConsortium: Jmakefile,v 1.7 89/12/12 12:37:28 jim Exp $ + * + * This is used to recreate jmake. Makefile.BOOT is used to generate jmake + * if there is no Makefile in this directory (i.e., the first time). + */ + +#define IHaveSubdirs + +/* just documents subdir */ +#define NoAllTargetForSubdirs +#define NoInstallTargetForSubdirs +#define NoTagTargetForSubdirs + +SUBDIRS = docs + +/* ------------------------- */ + +SRCS_C = jmake.c ccjmake.c +DEPLIBS = +HEADERS = jmakemdep.h + +JCONFIGFILES = $(HEADERS) TEMPLATE.jm \ + install-GEN.jm macros-GEN.jm \ + plat-DEF.jm plat-TRIGGERS.jm \ + plat-mipsriscos.jm plat-sun.jm plat-linux.jm plat-alpha.jm \ + site-DEF.jm site.jm \ + suffixes-GEN.jm utils-GEN.jm + +DEFINES = $(SIGNAL_DEFINES) + +all:: jmake jmkmf + +MsubNeededHere(jmkmf) + +/* override the usual rule */ +#undef JmakeNeededHere +#define JmakeNeededHere(dummy) @@\ +Makefile:: jmake + +/* BUILDING =======================================================*/ + +BuildPgmFromCFiles(jmake,jmake.o,,) + +/* modelled on X11R4's xmkmf (via DuBois) */ +MsubMakefileDependentProgramScriptTarget(PerlCmd,jmkmf,jmkmf.prl,/*no flags*/,/*Makefile*/) + +/* INSTALLATION ===================================================*/ + +INSTDATADIR_MKWORLD = $(INSTDATADIR)/mkworld + +MakeDirectories(install,$(INSTBINDIR) $(INSTSCRIPTDIR) $(INSTDATADIR_MKWORLD)) +InstallBinaryTarget(jmake,$(INSTBINDIR)) + +InstallMsubbedScriptTarget(PerlCmd,jmkmf,jmkmf.prl,$(INSTSCRIPTDIR)) + +InstallScriptTarget(jrestoredeps,$(INSTSCRIPTDIR)) + +jconfigfiles : $(JCONFIGFILES) +InstallTarget(jconfigfiles) +InstallMultNonExecTargets(jconfigfiles,$(JCONFIGFILES),$(INSTDATADIR_MKWORLD)) + +/* OTHER STUFF ===================================================*/ +ExtraStuffToClean(ccjmake) + +ExtraStuffToBeVeryClean( ccjmake $(STD_VERY_CLEAN) $(JCONFIGFILES) ) + +EtagsNeededHere(tags) /* need this to do "make tags" */ +ClearTagsFile() +CTagsTarget( $(SRCS_C) $(JCONFIGFILES) ) diff --git a/web/glasgow/lit2x-0.16/mkworld/Makefile.BOOT b/web/glasgow/lit2x-0.16/mkworld/Makefile.BOOT new file mode 100644 index 0000000000..908a5cb7ff --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/Makefile.BOOT @@ -0,0 +1,80 @@ +# +# WARNING WARNING WARNING WARNING WARNING WARNING WARNING +# +# This is NOT an automatically generated Makefile! It is hand-crafted as a +# bootstrap, may need editing for your system. The BOOTSTRAPCFLAGS variable +# may be given at the top of the build tree for systems that do not define +# any machine-specific preprocessor symbols. +# + +BOOTSTRAPCFLAGS = +PROJECTLABEL = none +SETUPLABEL = std +CDEBUGFLAGS = +CFLAGS = $(BOOTSTRAPCFLAGS) $(CDEBUGFLAGS) +SHELL = /bin/sh +RM = rm -f +MV = mv -f +MAKE = make +CLEAN_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a tags TAGS make.log +NPROC = 1 + +TOP = .. +CURRENT_DIR = ./mkworld + +JMAKESRC = $(TOP)/mkworld +JMAKE = $(JMAKESRC)/jmake + +JMAKE_CMD = $(JMAKE) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) -DTopDir=$(TOP) -DCurDir=$(CURRENT_DIR) $(BOOT_DEFINES) + +LIT2PGM = lit2pgm -q + +.SUFFIXES : .ljm .jm + +.ljm.jm: + $(RM) $@ + $(LIT2PGM) $(LIT2PGMFLAGS) -o $@ $< + @chmod 444 $@ + +all: jmake Makefile + +jmake:: + @echo "making jmake with BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS)" + +jmake:: ccjmake jmake.c + $(CC) -o jmake $(CFLAGS) jmake.c `./ccjmake` + +ccjmake: ccjmake.c + $(CC) -o ccjmake $(CFLAGS) ccjmake.c + +relink: + $(RM) jmake + $(MAKE) $(MFLAGS) jmake + +clean: + $(RM) ccjmake jmake + $(RM) \#* + +depend: + + +# for manual use + +Makefile :: + -@if [ -f Makefile ]; then \ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(JMAKE_CMD) + @if cmp -s Makefile Makefile.bak; then $(RM) Makefile.bak ; fi + @chmod 444 Makefile + @echo ==== The new Makefile is for\: ==== + @$(MAKE) whoami + +tags: + +install: + +install_docs: + +Makefiles: diff --git a/web/glasgow/lit2x-0.16/mkworld/Makefile.DUMMY b/web/glasgow/lit2x-0.16/mkworld/Makefile.DUMMY new file mode 100644 index 0000000000..8bd7aa66bb --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/Makefile.DUMMY @@ -0,0 +1,21 @@ +Makefile:: + +Makefiles:: + +depend:: + +all:: + +runtests:: + +install:: + +docs:: + +install_docs:: + +clean:: + +veryclean:: + +tags:: diff --git a/web/glasgow/lit2x-0.16/mkworld/PATCHLEVEL b/web/glasgow/lit2x-0.16/mkworld/PATCHLEVEL new file mode 100644 index 0000000000..2136a5e328 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/PATCHLEVEL @@ -0,0 +1 @@ +Glasgow `make world' configuration system, version 0.16, patchlevel 0 diff --git a/web/glasgow/lit2x-0.16/mkworld/README b/web/glasgow/lit2x-0.16/mkworld/README new file mode 100644 index 0000000000..1bc06e06fc --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/README @@ -0,0 +1,26 @@ +This is the Glasgow "make world" configuration system. We always +distribute as a component of another system (e.g., the Glasgow Haskell +compiler), but it can be used separately. + +It is based on "imake" in the MIT distribution of the X Window System, +as hacked on by Paul DuBois to support "multiple projects". None of +those people would probably recognise it now. + +The instructions for using this system come with the main system (ghc, +nofib, etc.) They may, however, aim you at the documentation here: + + docs/mkworld_guide/mkw_guide.{dvi,info} + general user's guide + + docs/mkworld_ref/mkw_ref.{dvi,info} + reference guide -- actually the ``make world'' + source in literate form. + + docs/<other> documents related to X11 `imake' or Paul + DuBois's variant, the ancestors of this + system. + +Bug reports and comments would be most welcome. + +Will Partain +partain@dcs.glasgow.ac.uk diff --git a/web/glasgow/lit2x-0.16/mkworld/TEMPLATE.jm b/web/glasgow/lit2x-0.16/mkworld/TEMPLATE.jm new file mode 100644 index 0000000000..8fcd80bc73 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/TEMPLATE.jm @@ -0,0 +1,199 @@ +# line 1 "TEMPLATE.ljm" +# line 37 "TEMPLATE.ljm" +#define YES 1 +#define NO 0 + +#if __STDC__ +#define CAT2(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#define CAT5(a,b,c,d,e) a##b##c##d##e +#else +#define CAT2(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#define CAT5(a,b,c,d,e) a/**/b/**/c/**/d/**/e +#endif /* not STDC */ +# line 66 "TEMPLATE.ljm" +#include "plat-TRIGGERS.jm" + +/*# Platform-specific stuff was read from: PlatformFile */ +#include PlatformIncludeFile +#include <plat-DEF.jm> +# line 84 "TEMPLATE.ljm" +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include SITE_SETUP_FILE /* site-specific things for a setup of a project */ +#endif +#include SITE_PROJECT_FILE /* site-specific things for a project */ +#endif /* Project != none */ + +#include <site.jm> /* project-independent site-specific things */ +#include <site-DEF.jm> /* _defaults_ for site-specific things */ +# line 106 "TEMPLATE.ljm" +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include MACROS_SETUP_FILE +#endif +#include MACROS_PROJECT_FILE +#endif /* Project != none */ + +#include <macros-GEN.jm> +# line 123 "TEMPLATE.ljm" +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include ONLY4_SETUP_FILE +#endif +#include ONLY4_PROJECT_FILE +#endif /* Project != none */ +# line 132 "TEMPLATE.ljm" +/*# Project identification -- name, version, and stuff */ +#ifndef ProjectName +#define ProjectName NO_SPECIFIC_PROJECT +#endif +#ifndef ProjectVersion +#define ProjectVersion NO_SPECIFIC_VERSION +#endif +PROJECTNAME = ProjectName +PROJECTVERSION = ProjectVersion +PROJECTLABEL = ProjectLabel +SETUPLABEL = SetupLabel +#ifdef HaveProjectMkworldDir +PROJ_MKWORLD_DIR = ProjectMkworldDir +#else +PROJ_MKWORLD_DIR = +#endif +HOSTPLATFORM = HostPlatform +/* HOSTPLATFORM: the platform we expect the thing we are building will run on. */ + +/* BUILDPLATFORM: the platform we are building on NOW (if we can figure it out) + set by the platform-specific files +*/ +# line 163 "TEMPLATE.ljm" +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include SUFFIXES_SETUP_FILE +#endif +#include SUFFIXES_PROJECT_FILE +#endif /* Project != none */ + +#include <suffixes-GEN.jm> +# line 180 "TEMPLATE.ljm" +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include UTILS_SETUP_FILE +#endif +#include UTILS_PROJECT_FILE +#endif /* Project != none */ + +#include <utils-GEN.jm> +# line 197 "TEMPLATE.ljm" +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include INSTALLATION_SETUP_FILE +#endif +#include INSTALLATION_PROJECT_FILE +#endif /* Project != none */ + +#include <install-GEN.jm> +# line 214 "TEMPLATE.ljm" +/* something so "all" is the first target... */ +all :: + +#include INCLUDE_JMAKEFILE +# line 227 "TEMPLATE.ljm" +/*# end of stuff from Jmakefile */ +/*# --------------------------- */ +/*# common end-of-Makefile rules -- (still) DO NOT EDIT !!! */ +/* + * These need to be here so that rules in Jmakefile occur first; the blank + * all is to make sure that an empty Jmakefile doesn't default to make clean. + */ +emptyrule:: + +CleanTarget() + +VeryCleanTarget() + +#ifndef IHaveSpecialMakefileTarget +MakefileTarget() +#endif + +/* tags not in by default: you have to ask: TagsTarget() */ +tags:: + +#ifdef MakefileAdditions +MakefileAdditions() +#endif + + +#ifdef IHaveSubdirs +/*########################################################################### + # rules for building in SUBDIRS - DO NOT EDIT !!! +*/ +#ifndef NoAllTargetForSubdirs +DoAllinSubdirs($(SUBDIRS)) +#endif +#ifndef NoDocsTargetForSubdirs +DoDocsinSubdirs($(SUBDIRS)) +#else +docs:: /* nothing */ +#endif +#ifndef NoRunTestsTargetForSubdirs +RunTestsSubdirs($(SUBDIRS)) +#else +runtests:: + @echo "runtests in $(CURRENT_DIR) done" +#endif +#ifndef NoInstallTargetForSubdirs +InstallSubdirs($(SUBDIRS)) +#else +install:: + @echo "install in $(CURRENT_DIR) done" +#endif +#ifndef NoInstallDocsTargetForSubdirs +InstallDocsSubdirs($(SUBDIRS)) +#else +install_docs:: + @echo "install_docs in $(CURRENT_DIR) done" +#endif +#ifndef NoDependTargetForSubdirs +DependSubdirs($(SUBDIRS)) +#else +depend:: + @echo "depend in $(CURRENT_DIR) done" +#endif +#ifndef NoTagTargetForSubdirs +TagSubdirs($(SUBDIRS)) +#endif + +CleanSubdirs($(SUBDIRS)) +VeryCleanSubdirs($(SUBDIRS)) +MakefileSubdirs($(SUBDIRS)) + +#else +/*########################################################################### + # empty rules for directories that do not have SUBDIRS - DO NOT EDIT !!! +*/ +/* clean and veryclean rules not given here because they're added above... */ + +docs:: + +tags:: + @echo "tags in $(CURRENT_DIR) done" + +runtests:: + @echo "runtests in $(CURRENT_DIR) done" + +install:: + @echo "install in $(CURRENT_DIR) done" + +install_docs:: + @echo "install_docs in $(CURRENT_DIR) done" + +Makefiles:: + +depend:: + @echo "depend in $(CURRENT_DIR) done" + +#endif /* if subdirectory rules are needed */ diff --git a/web/glasgow/lit2x-0.16/mkworld/TEMPLATE.ljm b/web/glasgow/lit2x-0.16/mkworld/TEMPLATE.ljm new file mode 100644 index 0000000000..43fd2a404b --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/TEMPLATE.ljm @@ -0,0 +1,322 @@ +%************************************************************************ +%* * +\section[mkworld-TEMPLATE]{Main ``mkworld'' template; slurps in ...} +%* * +%************************************************************************ + +\begin{pseudocode} +#define JMAKE_TEMPLATE "TEMPLATE.jm" +#define INCLUDE_JMAKEFILE <Jmakefile> +#define SetupLabel std +#define SetupIsStd 1 +#define ProjectLabel none +#define ProjectIsNone 1 +#define SITE_SETUP_FILE <site-none-std.jm> +#define SITE_PROJECT_FILE <site-none.jm> +#define ONLY4_SETUP_FILE <only4-none-std.jm> +#define ONLY4_PROJECT_FILE <only4-none.jm> +#define SUFFIXES_SETUP_FILE <suffixes-none-std.jm> +#define SUFFIXES_PROJECT_FILE <suffixes-none.jm> +#define MACROS_SETUP_FILE <macros-none-std.jm> +#define MACROS_PROJECT_FILE <macros-none.jm> +#define UTILS_SETUP_FILE <utils-none-std.jm> +#define UTILS_PROJECT_FILE <utils-none.jm> +#define INSTALLATION_SETUP_FILE <install-none-std.jm> +#define INSTALLATION_PROJECT_FILE <install-none.jm> +\end{pseudocode} + + +This is the main template that is ``filled in'' by the @mkworld@ +configuration system, to create a Makefile. + +This whole scheme is derived from the fine work on a ``multi-project +Imake'' by Paul DuBois at the Wisconsin Regional Primate Research Center. + +First some pervasive, needed-everywhere definitions: +\begin{code} +#define YES 1 +#define NO 0 + +#if __STDC__ +#define CAT2(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#define CAT5(a,b,c,d,e) a##b##c##d##e +#else +#define CAT2(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#define CAT5(a,b,c,d,e) a/**/b/**/c/**/d/**/e +#endif /* not STDC */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-platform]{Platform-specific things} +%* * +%************************************************************************ + +@plat-TRIGGERS.jm@ uses the ``trigger'' symbols to decide what +platform-specific stuff to drag in; then it is so dragged. + +Defaults for any platform-ish things can be defined in @plat-GEN.jm@, +with overrides in the individual platform-configuration files. + +\begin{code} +#include "plat-TRIGGERS.jm" + +/*# Platform-specific stuff was read from: PlatformFile */ +#include PlatformIncludeFile +#include <plat-DEF.jm> +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-site]{Site-specific things} +%* * +%************************************************************************ + +Site-specific configuration stuff is, by definition, to override +default definitions to satisfy the needs of a particular ((setup of a) +project at a) site. + +\begin{code} +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include SITE_SETUP_FILE /* site-specific things for a setup of a project */ +#endif +#include SITE_PROJECT_FILE /* site-specific things for a project */ +#endif /* Project != none */ + +#include <site.jm> /* project-independent site-specific things */ +#include <site-DEF.jm> /* _defaults_ for site-specific things */ +\end{code} + + +%************************************************************************ +%* * +\subsection[mkworld-template-macros]{Main mkworld CPP macros} +%* * +%************************************************************************ + +These don't generate any Makefile text, just define macros to be used +later. They have to come early, notably before the ONLY4 stuff. + +\begin{code} +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include MACROS_SETUP_FILE +#endif +#include MACROS_PROJECT_FILE +#endif /* Project != none */ + +#include <macros-GEN.jm> +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-only4]{Extra things ``only for'' a specific project} +%* * +%************************************************************************ + +\begin{code} +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include ONLY4_SETUP_FILE +#endif +#include ONLY4_PROJECT_FILE +#endif /* Project != none */ +\end{code} + +\begin{code} +/*# Project identification -- name, version, and stuff */ +#ifndef ProjectName +#define ProjectName NO_SPECIFIC_PROJECT +#endif +#ifndef ProjectVersion +#define ProjectVersion NO_SPECIFIC_VERSION +#endif +PROJECTNAME = ProjectName +PROJECTVERSION = ProjectVersion +PROJECTLABEL = ProjectLabel +SETUPLABEL = SetupLabel +#ifdef HaveProjectMkworldDir +PROJ_MKWORLD_DIR = ProjectMkworldDir +#else +PROJ_MKWORLD_DIR = +#endif +HOSTPLATFORM = HostPlatform +/* HOSTPLATFORM: the platform we expect the thing we are building will run on. */ + +/* BUILDPLATFORM: the platform we are building on NOW (if we can figure it out) + set by the platform-specific files +*/ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-suffixes]{Suffix rules} +%* * +%************************************************************************ + +\begin{code} +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include SUFFIXES_SETUP_FILE +#endif +#include SUFFIXES_PROJECT_FILE +#endif /* Project != none */ + +#include <suffixes-GEN.jm> +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-utils]{``Utilities''} +%* * +%************************************************************************ + +\begin{code} +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include UTILS_SETUP_FILE +#endif +#include UTILS_PROJECT_FILE +#endif /* Project != none */ + +#include <utils-GEN.jm> +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-installation]{Installation stuff} +%* * +%************************************************************************ + +\begin{code} +#if ProjectIsNone == NO +#if SetupIsStd == NO +#include INSTALLATION_SETUP_FILE +#endif +#include INSTALLATION_PROJECT_FILE +#endif /* Project != none */ + +#include <install-GEN.jm> +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-dir-specific]{Bring in directory-specific stuff (@Jmakefile@)} +%* * +%************************************************************************ + +\begin{code} +/* something so "all" is the first target... */ +all :: + +#include INCLUDE_JMAKEFILE +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-template-end-Makefile]{Common end-of-Makefile stuff} +%* * +%************************************************************************ + +\begin{code} +/*# end of stuff from Jmakefile */ +/*# --------------------------- */ +/*# common end-of-Makefile rules -- (still) DO NOT EDIT !!! */ +/* + * These need to be here so that rules in Jmakefile occur first; the blank + * all is to make sure that an empty Jmakefile doesn't default to make clean. + */ +emptyrule:: + +CleanTarget() + +VeryCleanTarget() + +#ifndef IHaveSpecialMakefileTarget +MakefileTarget() +#endif + +/* tags not in by default: you have to ask: TagsTarget() */ +tags:: + +#ifdef MakefileAdditions +MakefileAdditions() +#endif + + +#ifdef IHaveSubdirs +/*########################################################################### + # rules for building in SUBDIRS - DO NOT EDIT !!! +*/ +#ifndef NoAllTargetForSubdirs +DoAllinSubdirs($(SUBDIRS)) +#endif +#ifndef NoDocsTargetForSubdirs +DoDocsinSubdirs($(SUBDIRS)) +#else +docs:: /* nothing */ +#endif +#ifndef NoRunTestsTargetForSubdirs +RunTestsSubdirs($(SUBDIRS)) +#else +runtests:: + @echo "runtests in $(CURRENT_DIR) done" +#endif +#ifndef NoInstallTargetForSubdirs +InstallSubdirs($(SUBDIRS)) +#else +install:: + @echo "install in $(CURRENT_DIR) done" +#endif +#ifndef NoInstallDocsTargetForSubdirs +InstallDocsSubdirs($(SUBDIRS)) +#else +install_docs:: + @echo "install_docs in $(CURRENT_DIR) done" +#endif +#ifndef NoDependTargetForSubdirs +DependSubdirs($(SUBDIRS)) +#else +depend:: + @echo "depend in $(CURRENT_DIR) done" +#endif +#ifndef NoTagTargetForSubdirs +TagSubdirs($(SUBDIRS)) +#endif + +CleanSubdirs($(SUBDIRS)) +VeryCleanSubdirs($(SUBDIRS)) +MakefileSubdirs($(SUBDIRS)) + +#else +/*########################################################################### + # empty rules for directories that do not have SUBDIRS - DO NOT EDIT !!! +*/ +/* clean and veryclean rules not given here because they're added above... */ + +docs:: + +tags:: + @echo "tags in $(CURRENT_DIR) done" + +runtests:: + @echo "runtests in $(CURRENT_DIR) done" + +install:: + @echo "install in $(CURRENT_DIR) done" + +install_docs:: + @echo "install_docs in $(CURRENT_DIR) done" + +Makefiles:: + +depend:: + @echo "depend in $(CURRENT_DIR) done" + +#endif /* if subdirectory rules are needed */ +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/ccjmake.c b/web/glasgow/lit2x-0.16/mkworld/ccjmake.c new file mode 100644 index 0000000000..08909fa70a --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/ccjmake.c @@ -0,0 +1,21 @@ +/* + * $XConsortium: ccjmake.c,v 1.12 89/10/16 12:09:23 jim Exp $ + * + * Warning: This file must be kept as simple as posible so that it can + * compile without any special flags on all systems. Do not touch it unless + * you *really* know what you're doing. Make changes in jmakemdep.h, not here. + */ + +#define CCJMAKE /* only get jmake_ccflags definitions */ +#include "jmakemdep.h" /* things to set when porting jmake */ + +#ifndef jmake_ccflags +#define jmake_ccflags "-O" +#endif + +main() +{ + write(1, jmake_ccflags, sizeof(jmake_ccflags) - 1); + exit(0); +} + diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/Jmakefile b/web/glasgow/lit2x-0.16/mkworld/docs/Jmakefile new file mode 100644 index 0000000000..1158494761 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/Jmakefile @@ -0,0 +1,9 @@ +#define IHaveSubdirs + +/* just documents here */ +#define NoAllTargetForSubdirs +#define NoInstallTargetForSubdirs +#define NoTagTargetForSubdirs + +SUBDIRS = mkworld_guide \ + mkworld_ref diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/appendix-X11R4.ms b/web/glasgow/lit2x-0.16/mkworld/docs/appendix-X11R4.ms new file mode 100644 index 0000000000..112722b468 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/appendix-X11R4.ms @@ -0,0 +1,2413 @@ +.\" format with +.\" tbl % | xroff -ms | lpr +.\" +.\" revision date - change whenever this file is edited +.ds Rd 28 January 1991 +.\" document revision number - change each time document is released +.ds Rn 1.01 +.\" +.nr PO 1.2i \" page offset 1.2 inches +.nr PD .7v \" inter-paragraph distance +.\" +.EH 'Imake in X11R4'- % -'' +.OH ''- % -'Imake in X11R4' +.OF 'Revision date:\0\0\*(Rd'\s+1\*-MORE DRAFT SCRIBBLINGS\*-\s-1'Printed:\0\0\n(dy \*(MO 19\n(yr' +.EF 'Revision date:\0\0\*(Rd'\s+1\*-MORE DRAFT SCRIBBLINGS\*-\s-1'Printed:\0\0\n(dy \*(MO 19\n(yr' +.\" +.\" +.\" I - italic font (taken from -ms and changed) +.de I +.nr PQ \\n(.f +.if t \&\\$3\\f2\\$1\\fP\&\\$2 +.if n .if \\n(.$=1 \&\\$1 +.if n .if \\n(.$>1 \&\\$1\c +.if n .if \\n(.$>1 \&\\$2 +.. +.\" start block. LP gives a bit extra space. Can say .Ds .IP C, etc. +.de Ds +.if \\n(.$<1 .LP +.if \\n(.$>=1 \\$1 +.if \\n(.$<2 .DS +.if \\n(.$>=2 .DS \\$2 \\$3 \\$4 \\$5 +.. +.\" end block. If arg is given, it replaces the .LP (e.g., .De .IP). +.de De +.DE +.if \\n(.$<1 .LP +.if \\n(.$>=1 \\$1 \\$2 \\$3 \\$4 \\$5 +.. +.\" if the Sy definition changes, there are four symbols which had to be +.\" manually formatted and which need to be changed manually, +.\" UNCOMPRESSFILT, BDFTOSNFFILT, SHELLPATH, ZBDFTOSNFFILT +.de Sy \" symbol definition +.br +.ta 6iR +\fB\\$1\fR \\$3 +.br +\0\0default: \\$2 +.. +.de Ru \" imake rule +.br +.ne 3v +.B \\$1 +.. +.NH +Appendix +.LP +.I cpp +symbols and +.I make +variables defined in the X configuration files are listed and described here. +Much of this information can be found in those files and in +.I mit/config/README . +.LP +There are a number of places where I confess ignorance. +If you fill me in on the missing pieces, I'll revise this document. +.LP +Besides symbols used for rule macros, symbols may be classed in +three categories. +Some are used as booleans and are defined as YES or NO. +Some are simply defined as nothing or left undefined. +Boolean and defined/not-defined symbols are rarely if ever +associated with variables appearing in +.I Makefiles ; +rather, they are used for control purposes to modify the configuration +and build process. +.LP +The other symbols are general-purpose, usually (but not always) +having a value that is assigned to some +.I Makefile +variable. +The value may be empty (that is, the symbol may be defined as nothing): +.Ds +.ta 1i 2i +#define \fIsymbol\fR /* as nothing */ +.De +The descriptions below give symbol names, and their defaults and +symbol class where applicable. +A default of ``nothing'' means the empty definition. +.LP +.B Note: +The symbol UseInstalled is not defined in any of the configuration +files. +It should be defined (by you, as nothing) in +.I site.def +if you want to use installed versions of +.I imake , +.I makedepend +and the configuration files. +It can be defined in +.I site.def , +but you must leave it undefined on the initial build, +obviously, since the configuration programs +and files will not have been installed yet. +.NH +Imake.tmpl +.NH 2 +Global Constant Definitions +.LP +This section defines the two symbols YES and NO: +.Ds +.ta 1i 2i +#define YES 1 +#define NO 0 +.De +These are heavily used to define boolean symbols. +.NH 2 +Header Blocks +.LP +Every header block in this section of +.I Imake.tmpl +defines two symbols: +.LP +.Sy MacroIncludeFile <generic.cf> general +.Sy MacroFile generic.cf general +.IP +Both of these name the platform-specific file to be included by the +template after the header block section. +The defaults are deliberately rebarbative and are selected only if the +correct header block for your system was not triggered. +Otherwise these symbols will have values like +.I platform .cf> < +and +.I platform .cf, +where +.I platform +is ``ultrix'', ``sun'', ``hp'', ``apollo'', etc. +.IP +There are two symbols associated with this name because it is used two +different ways. +MacroIncludeFile is used by +.I cpp +to include the platform file. +MacroFile is used to generate file names. +.IP +In addition to the above two symbols, header blocks may define one or more +of the following symbols to indicate the software and/or hardware platform. +.Ds .IP +.ta 3i +AIXArchitecture PS2Architecture +ATTArchitecture PegasusArchitecture +ApolloArchitecture RtArchitecture +CrayArchitecture SGIArchitecture +HPArchitecture SonyArchitecture +IBMArchitecture StellarArchitecture +M4330Architecture SunArchitecture +MacIIArchitecture UltrixArchitecture +MipsArchitecture VaxArchitecture +.De .IP +Some of these symbols may be defined in more than one header block. +The platform file may also define other \fIxxx\fRArchitecture symbols +.I sun.cf ( +does so, for instance, to allow SPARC- or i386-dependencies to be selected.) +.NH +System/Build Definitions +.NH 2 +Preprocessor Symbols +.LP +Symbols are listed in order of their appearance in +.I Imake.tmpl . +The default value of some symbols is determined based +on whether SystemV is YES or NO. +For these symbols both defaults are listed, with the SystemV=YES case first. +.LP +.Sy SystemV varies boolean +.IP +SystemV indicates whether your system is System V based (YES) or not +(NO). +If not, that usually means BSD based. +The default value of many other symbols depends on SystemV, so it is +usually set explicitly early +in the platform-specific file to make sure it's correct. +.LP +.Sy OSMajorVersion "0" general +.Sy OSMinorVersion "0" general +.IP +These two symbols indicate the major and minor version numbers of the +operating system. +They are often used as control symbols in the platform files +to select symbol values that vary depending on the OS version. +For this reason, they are usually set in the platform file. +.IP +Example: if some feature of your OS didn't appear until version 5.7, +you could test for that with: +.Ds .IP +/**/# these definitions would go in the platform file +# ifndef OSMajorVersion +# define OSMajorVersion 5 +# endif +# ifndef OSMinorVersion +# define OSMinorVersion 7 +# endif + +/**/# this test would go wherever you need to test for 5.7 and up +# if OSMajorVersion >= 5 && OSMinorVersion >= 7 + /**/# 5.7-and-up specific stuff here +# endif +.De +.LP +.Sy UnalignedReferencesAllowed "NO" boolean +.IP +Some processors can dereference pointers to arbitrary addresses. +Others cannot\*-inability to dereference odd addresses is a typical problem +for such processors. +If your pointers must be specifically aligned (e.g., on word +boundaries), define UnalignedReferencesAllowed as NO. +The default reflects a conservative approach. +.LP +.Sy ExecableScripts "NO/YES" boolean +.IP +Whether the kernel +.I exec () +system call correctly executes scripts beginning with ``#!''. +ExecableScripts determines the way the CppScriptTarget() rule macro is +expanded and thus the way shell scripts are built. +.IP +Script prototypes begin with a line that says ``#!/bin/sh''. +If ExecableScripts is NO, that line is stripped out and replaced with +one that says ``:''.\** +.FS +I would say that a better way to do it might be to explicitly write +a line into the script using the value of ${SHELL} if ExecableScripts +is YES and ``:'' otherwise. +This would allow the value of SHELL to propagate into scripts were it +defined as something other than +.I /bin/sh . +.FE +.LP +.Sy BourneShell "/bin/sh" general +.IP +Path name of Bourne shell. +This is used to set the value of SHELL, and in construction of some +commands that run shell scripts. +.LP +.Sy ConstructMFLAGS "YES/NO" boolean +.IP +Whether to construct MFLAGS +.I make +variable from MAKEFLAGS. +This is used (I think) for compatibility with versions of +.I make +that use MFLAGS instead of MAKEFLAGS. +.LP +.Sy HasLargeTmp "NO" boolean +.IP +Whether the file system on which +.I /tmp +resides has lots of free space. +The meaning of ``lots'' is roughly 1MB, although that may need to be revised +upward for future releases. +This symbol determines the default value of ArCmd. +.LP +.Sy HasSockets "NO/YES" boolean +.IP +Whether the system has BSD socket support. +.LP +.Sy HasVFork "NO/YES" boolean +.IP +Whether the +.I vfork () +system call is supported. +Presumably this causes +.I fork() +to be used instead of +.I vfork() +if HaveVFork is NO. +.LP +.Sy HasPutenv "NO" boolean +.IP +Whether the +.I putenv () +C library call is supported. +.LP +.Sy HasVoidSignalReturn "YES/NO" boolean +.IP +Whether the +.I signal () +C library call returns +.I void * +(YES) +or +.I int * +(NO). +The default is YES for System V platforms, but +if you have a BSD platform, you should not assume NO. +Some BSD-based systems (e.g., Ultrix and Sun) have changed from +.I int * +to +.I void * +in new OS releases. +Some machines try to support both sets of semantics. +.LP +.Sy HasBsearch "YES/NO" boolean +.IP +Whether the +.I bsearch () +C library call is supported. +.LP +.Sy HasSaberC "NO" boolean +.IP +Whether the system has the Saber C development environment. +The default value of this symbol will usually be overridden in the +platform file. +.B Warning: +some of the platform files define HasSaberC as YES, so be sure to +check this and change it if necessary. +.LP +.Sy HasFortran "NO" boolean +.IP +Whether the system has a FORTRAN compiler. +Needed for GKS support. +.LP +.Sy HasNdbm "NO" boolean +.IP +Whether the system has the NDBM database manager (supercedes DBM). +.LP +.Sy HasDESLibrary "NO" boolean +.IP +Whether the system has a DES (digital encryption standard) library. +.LP +.Sy NeedFunctionPrototypes "NO" boolean +.Sy NeedWidePrototypes "YES" boolean +.IP +These are used to support use of function prototypes. +Apparently they are not well-liked judging from the deprecatory comments +in the latter part of +.I Imake.tmpl . +.LP +.Sy HasSunOSSharedLibraries "NO" boolean +.IP +Whether SunOS shared libraries are supported. +.LP +.Sy SharedCodeDef "varies" general +.IP +Flags to compile sharable library code. +.LP +.Sy SharedLibraryDef "varies" general +.IP +Flags to turn on use of shared libraries. +.LP +.Sy HasSharedLibraries "varies" boolean +.IP +Whether shared libraries are supported. +.B Note: +This symbol is defined +.I inside +the (convoluted) definition of SharedLibraryDef. +.LP +.Sy StripInstalledPrograms "NO" boolean +.IP +If YES, strip symbol table from installed programs, otherwise leave intact. +Setting to YES can save lots of disk space on some machines, but +leaving it as NO can help during debugging. +This symbol affects use of InstPgmFlags. +.LP +.Sy DestDir nothing general +.IP +Prefix to prepend to installation directory pathnames. +Normally this is left empty. +If you want to install under an alternate root, the X folks recommend that +you compile with the default value, then install with +.Ds .IP +make install DESTDIR=/alt/root +.De .LP +.Sy UsrLibDir "$(DESTDIR)/usr/lib" general +.IP +Directory under which to install system libraries (e.g., +.I lint +libraries; see description of LintlibDir under +.I Project.tmpl ). +This is also used as the basis for the default value of LibDir (in +.i Project.tmpl ), which is used for installation of libraries for +.I xdm , +.I awm , +.I twm ... +.LP +.Sy IncRoot "$(DESTDIR)/usr/include" general +.IP +Path to root of system header file hierarchy. +X11 header files are installed under this. +(A default for this symbol is also included in +.I Project.tmpl ; +you can ignore it because the definition in +.I Imake.tmpl +occurs first and will override it.) +.LP +.Sy UNCOMPRESSPATH "/usr/ucb/uncompress" general +.IP +Command to run the +.I uncompress +program. +I think this is used to uncompress compressed font files. +If you override this symbol, the definition should probably be a full +path name. +.LP +.Sy OptimizedCDebugFlags "\-O" general +.IP +C compiler flags to turn on optimization. +.LP +.Sy DebuggableCDebugFlags "\-g" general +.IP +C compiler flags to turn on debugging information. +.LP +.Sy NoOpCDebugFlags nothing general +.IP +C compiler flags to not turn on optimization or debugging. +.LP +.Sy DefaultCDebugFlags "OptimizedCDebugFlags" general +.IP +C compiler flags to turn on optimization for programs. +.LP +.Sy LibraryCDebugFlags "OptimizedCDebugFlags" general +.IP +C compiler flags to turn on optimization for libraries. +.LP +.Sy DefaultCCOptions nothing general +.IP +Special C compiler flags (other than \-I's and \-D's? +See StandardDefines, StandardCppDefines). +Useful, e.g., for turning on floating point options. +.LP +.Sy LibraryCCOptions "DefaultCCOptions" general +.IP +Special C compiler flags for compiling libraries. +.LP +.Sy ServerCCOptions "DefaultCCOptions" general +.IP +Special C compiler flags for compiling the server. +(This is X-specific and should be in +.I Project.tmpl , +perhaps?) +.LP +.Sy PexCDebugFlags "\-g" general +.IP +C compiler flags to turn on debugging information for PEX. +(This is X-specific and should be in +.I Project.tmpl , +perhaps?) +.LP +.Sy InstPgmFlags "\-s" general +.IP +Flags for installing programs. +The default strips symbol tables. +This symbol is used in conjunction with StripInstalledPrograms to set +the +.I make +variable INSTPGMFLAGS. +Note that INSTPGMFLAGS applies to installs of +binary programs and also shell +scripts; some systems give a warning when you try to strip a script +because they have no symbol table (such warnings can be ignored). +.LP +.Sy InstBinFlags "\-m 0755" general +.IP +Flags for setting the mode of installed executable files. +.LP +.Sy InstUidFlags "\-m 4755" general +.IP +Flags for setting the mode of installed set-user-id files (e.g., +.I xterm +needs to +.I chown +pty's). +.LP +.Sy InstLibFlags "\-m 0664" general +.IP +Flags for setting the mode of installed libraries. +.LP +.Sy InstIncFlags "\-m 0444" general +.IP +Flags for setting the mode of installed header files. +.LP +.Sy InstManFlags "\-m 0444" general +.IP +Flags for setting the mode of installed manual pages. +.LP +.Sy InstDatFlags "\-m 0444" general +.IP +Flags for setting the mode of installed data (non-executable) files. +.LP +.Sy InstKmemFlags "InstUidFlags" general +.IP +Flags for installing programs that need to read +.I /dev/kmem , +e.g., +.I xload . +The default makes such programs setuid, which is overkill, since +typically all that's needed is setgid to the group having access to +.I /dev/kmem . +InstKmemFlags +is a good symbol to define in +.I site.def . +Be sure to include the correct group, e.g., ``\-g kmem \-m 2755''. +The group is not set in the default value of this symbol because +it's difficult to determine a good default group. +.LP +.Sy ArCmd "varies" general +.IP +Command to create archive files. +If HasLargeTmp is YES, +.I /tmp +is used for temp file space, otherwise the current directory is used. +.LP +.Sy BootstrapCFlags nothing general +.IP +Defines needed to get +.I ccimake +compiled and by +.I imake +to get +.I cpp +to select the correct header block in +.I Imake.tmpl . +.LP +.Sy CcCmd "cc" general +.IP +Command to run the C compiler. +.LP +.Sy HasGcc "NO" boolean +.IP +Whether GNU CC, +.I gcc , +is available. +.LP +.Sy ServerCcCmd "CcCmd" general +.IP +Command to run the C compiler to compile the server. +(This is X-specific and should be in +.I Project.tmpl , +perhaps?) +.LP +.Sy LibraryCcCmd "CcCmd" general +.IP +Command to run the C compiler to compile libraries. +.LP +.Sy FortranCmd "f77" general +.IP +Command to run the FORTRAN compiler. +.LP +.Sy FortranFlags nothing general +.IP +General flags for FORTRAN compiler. +.LP +.Sy FortranDebugFlags nothing general +.IP +Flags for FORTRAN compiler to turn on debugging information. +.LP +.Sy AsCmd "as" general +.IP +Command to run the assembler. +.LP +.Sy CompressCmd "compress" general +.IP +Command to run +.I compress . +.LP +.Sy CppCmd "/lib/cpp" general +.IP +Command to run C preprocessor. +.LP +.Sy PreProcessCmd "CcCmd \-E" general +.IP +Command to preprocess input. +This is used by the script version of +.I makedepend . +.LP +.Sy InstallCmd "$(SCRIPTSRC)/bsdinst.sh / install" general +.IP +Command to install files. +It should be compatible with the BSD version of +.I install . +.LP +.Sy LdCmd "ld" general +.IP +Command to run the loader. +.LP +.Sy LintCmd "lint" general +.IP +Command to run +.I lint . +.LP +.Sy LintLibFlag "\-o/\-C" general +.IP +Flags to build +.I lint +libraries. +.LP +.Sy LintOpts "\-ax/\-axz" general +.IP +Flags to tell +.I lint +how picky to be. +.LP +.Sy CpCmd "cp" general +.IP +Command to copy files. +.LP +.Sy LnCmd "ln/ln \-s" general +.IP +Command to link files. +Symbolic links are used if available (not System V). +.LP +.Sy MakeCmd "make" general +.IP +Command to run +.I make . +.LP +.Sy MvCmd "mv" general +.IP +Command to rename files. +.LP +.Sy RanlibCmd "/bin/true / ranlib" general +.IP +Command to run +.I ranlib . +On System V platforms this command is missing. +.I /bin/true , +a nop, is used instead. +.I /bin/true "" ( +always succeeds, which is important for +.I make .) +.LP +.Sy RanlibInstFlags nothing general +.IP +Flags to pass to +.I ranlib +when run on libraries that have already been installed. +``\-t'' is a good option here, if you have it. +.LP +.Sy RmCmd "rm \-f" general +.IP +Command to remove files. +.LP +.Sy StandardCppDefines "\-DSYSV/nothing" general +.IP +\-D's for C preprocessor. +.LP +.Sy StandardIncludes nothing general +.IP +\-I's for C compiler. +.LP +.Sy StandardDefines "\-DSYSV/nothing" general +.IP +\-D's for C compiler. +.LP +.Sy NdbmDefines "varies" general +.IP +Flags to turn on NDBM support. +Affected by HasNdbm. +.LP +.Sy ExtraLibraries nothing general +.IP +Extra libraries needed to get programs to compile. +.LP +.Sy ExtraLoadFlags nothing general +.IP +Extra flags needed to get loader to work. +.LP +.Sy LdCombineFlags "\-X \-r" general +.IP +Flags for incremental loader support. +.LP +.Sy CompatibilityFlags nothing general +.IP +Flags to turn on R3 backward compatibility support. +.LP +.Sy TagsCmd "ctags" general +.IP +Command to generate tags files. +.LP +.Sy LoaderLibPrefix nothing general +.IP +Flags to specify before libraries (see +.I cray.cf ). +.LP +.Sy TOPDIR "." general +.Sy CURDIR "." general +.IP +Top of source tree, and current directory. +The +.I make +variables associated with these (TOP, CURRENT_DIR) +are overridden by recursive +.I make +rules. +The defaults are correct for the top of the source tree. +TOP and CURRENT_DIR are reset for each +.I Makefile +during ``make Makefiles''. +TOP is the path to the top of the source tree, from the current +directory. +CURRENT_DIR is the path to the current directory from the top of the +source tree. +.LP +.Sy FilesToClean "*.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut" general +.IP +List of files to be removed by ``make clean''. +Note that ``*~'' is in this list, and see discussion of the +RemoveProgramTarget() rule. +If you are in the habit of using ``cp x x~'' to make a backup copy of +files you modify, ``make clean'' will remove those copies, which may +not be what you want. +.NH 2 +Make Variables +.LP +Many of the +.I make +variables in +.I Imake.tmpl +are simply set to the preprocessor variable of the same name (e.g., +INSTBINFLAGS = InstBinFlags). +.LP +Most +.I make +variables referring to commands are set to the preprocessor symbol having +the same name and a suffix ``Cmd''. +For instance, CC and MAKE are set to CcCmd and MakeCmd, respectively. +.LP +The rest of the variables are set to +preprocessor symbols with names that differ a bit from the variable +name (e.g., SHELL = BourneShell), or are defined in terms of other +.I make +variables (e.g., MFLAGS = -$(MAKEFLAGS)), or a combination of +preprocessor symbols and +.I make +variables (e.g., RM_CMD = $(RM) FilesToClean). +.NH +platform.cf +.LP +Symbols which definitely should be set here are +BuildServer (and X\fIxxx\fRServer if BuildServer is YES), +OSName, OSMajorVersion, and OSMinorVersion. +Some other symbols you should think about setting are +CCompilerMajorVersion, +CCompilerMinorVersion, +BootstrapCFlags, +SystemV, +UnalignedReferencesAllowed, +SetTtyGroup, +ExecableScripts, +and +ConstructMFLAGS. +.NH +site.def +.LP +You should read through the +.I site.def +file and follow the comments there which tell whether you should +supply +override definitions for a number of symbols. +This is the place to indicate whether you have a large temp area +(HasLargeTmp), whether you have GNU +.I cc +(HasGcc), whether you want to compile in R3 backward compatibility +(CompatibilityFlags), etc. +It's also a good place to set symbols such as InstKmemFlags and +BuildExamples. +.NH +Project.tmpl +.NH 2 +Preprocessor Symbols +.LP +Symbols are listed in order of their appearance in +.I Project.tmpl . +.LP +.Sy ProjectX 4 general +.IP +X11 Release number. +The +.I README +says this is a boolean, which is incorrect. +.LP +.Sy BuildServer YES boolean +.IP +Whether to build the server. +This should be defined as NO in +.I site.def +on client-only systems. +On platforms which have no server implementation, the value of +BuildServer may already be set to NO in the platform file. +.LP +.Sy BuildExamples YES boolean +.IP +Whether to build the example programs. +It will speed up your builds to override this as NO, and less disk +space will be used. +.IP +It is probably possible to build selected examples only. +Define BuildExamples as YES, then build all the Makefiles from the +source root. +Then build the ``clean'' and ``depend'' targets. +Define BuildExamples as NO and rebuild the Makefiles. +The examples directories should be left alone since BuildExamples +is NO, but you can then go into an example directory and build the +program since its +.I Makefile +should be correct. +(This is all conjecture.) +.LP +.Sy BuildXawBC NO boolean +.IP +Whether to build backward-compatible X Athena Widgets (I think). +.LP +.Sy InstallXinitConfig NO boolean +.IP +Whether to install sample +.I xinit +configuration files. +.LP +.Sy InstallXdmConfig NO boolean +.IP +Whether to install sample +.I xdm +configuration files. +.LP +.Sy InstallAppDefFiles YES boolean +.IP +Whether to install application defaults +files. +.LP +.Sy InstallOldHeaderFiles NO boolean +.IP +Whether to install R3 header files. +.LP +.Sy DebugLibX NO boolean +.IP +Whether to build debugging into the X library. +.LP +.Sy DebugLibXArchive NO boolean +.IP +Whether to build debugging into the archive file version of the X library. +.LP +.Sy ProfileLibX NO boolean +.IP +Whether to build profiling into the X library. +.LP +.Sy ProfileLibXArchive NO boolean +.IP +Whether to build profiling into the archive file version of the X library. +.LP +.Sy DebugOldLibX NO boolean +.Sy ProfileOldLibX NO boolean +.Sy DebugLibXt NO boolean +.Sy ProfileLibXt NO boolean +.Sy DebugLibXaw NO boolean +.Sy ProfileLibXaw NO boolean +.Sy DebugLibXext NO boolean +.Sy ProfileLibXext NO boolean +.Sy DebugLibXmu NO boolean +.Sy ProfileLibXmu NO boolean +.IP +Whether to build debugging and/or profiling into the old X library, X +Toolkit library, X Athena Widget library, X Extension library or the +X mu library. +.LP +.Sy NeedBerklibInXlib NO boolean +.IP +Whether BSD emulation is needed in Xlib. +If YES, then BandAidLibrary is set to YES, some other related symbols +are defined, and the BandAidLibraryMake() rule macro is defined. +.LP +.Sy ManDirectoryRoot /usr/man general +.IP +Path to the top of the manual page hierarchy relative to the default root +directory. +See also ManPath. +.LP +.Sy ManSuffix n general +.IP +Suffix for program manual pages. +See ManSourcePath, ManDir. +.LP +.Sy LibManSuffix 3 general +.IP +Suffix for library manual pages. +See ManSourcePath, LibmanDir. +.LP +.br +.ta 6iR +\fBUNCOMPRESSFILT\fR general +.br +\0\0default: \-DUNCOMPRESSFILT=\e"UNCOMPRESSPATH\e" +.IP +\-D's to run +.I uncompress . +.LP +.br +.ta 6iR +\fBBDFTOSNFFILT\fR (default: general +.br +\0\0default: \-DBDFTOSNFFILT=\e"$(BINDIR)/bdftosnf\e" +.IP +\-D's to run +.I bdftosnf +to convert fonts from binary distribution format to server natural +format. +.LP +.br +.ta 6iR +\fBSHELLPATH\fR general +.br +\0\0default: \-DSHELLPATH=\e"/bin/sh\e" +.IP +\-D's for command to run the shell. +.LP +.br +.ta 6iR +\fBZBDFTOSNFFILT\fR general +.br +\0\0default: \-DZBDFTOSNFFILT=\e"UNCOMPRESSPATH" | $(BINDIR)/bdftosnf $(FONTCFLAGS)\e"" +.IP +\-D's to run +.I uncompress +and +.I bdftosnf +to convert compressed binary distribution format font files to server natural +format. +.LP +.Sy FontFilters "UNCOMPRESSFILT BDFTOSNFFILT SHELLPATH ZBDFTOSNFFILT" general +.IP +\-D's for font conversion filters. +.LP +.Sy PrimaryScreenResolution 72 general +.IP +Resolution of default server screen, in dots per inch (dpi). +This number applies both to horizontal and to vertical resolution; X +assumes square pixels. +.LP +.Sy DefaultFontPath varies general +.IP +Path to font directory. +If not set somewhere else, a default is guessed, based +on PrimaryScreenResolution, to select between 75 dpi and 100 dpi fonts. +.LP +.Sy DefaultRGBDatabase $(LIBDIR)/rgb general +.IP +Path to RGB color database. +.LP +.Sy FontCompilerFlags \-t general +.IP +Flags for +.I bdftosnf . +.LP +.Sy ConnectionFlags "\-DTCPCONN \-DUNIXCONN" general +.IP +What kinds of connections the server will accept. +Common values are \-DTCPCONN, \-DUNIXCONN, \-DSTREAMSCONN. +More than one can be specified. +If the server is built, at least one must be specified. +.LP +.Sy FontDefines "\-DFONT_SNF \-DFONT_BDF \-DCOMPRESSED_FONTS" general +.IP +\-D's for font options. +.LP +.Sy ExtensionDefines nothing general +.IP +\-D's for server extensions. +Default is nothing, for ``no extensions''. +This is typically overridden in the platform file for servers that +know about particular extensions, or in +.I site.def . +.LP +.Sy ServerCDebugFlags OptimizedCDebugFlags general +.IP +C compiler flags to turn on optimization/debugging in server. +.LP +.Sy LibraryDefines StandardDefines general +.IP +\-D's for compiling libraries. +.LP +.Sy ServerDefines "StandardDefines ExtensionDefines" general +.IP +\-D's for compiling the server. +.LP +.Sy CppSourcesPresent NO boolean +.IP +Whether you have BSD +.I cpp +sources. +.LP +.Sy CppSources /usr/src/lib/cpp general +.IP +Path to BSD +.I cpp +sources. +Not used if CppSourcesPresent is NO. +.LP +.Sy BinDir $(DESTDIR)/usr/bin/X11 general +.IP +Where to install programs. +.LP +.Sy IncRoot $(DESTDIR)/usr/include general +.IP +IGNORE this symbol in +.I Project.tmpl ; +it's redundant. +See its definition in the system/build section of +.I Imake.tmpl . +.LP +.Sy BuildIncRoot $(TOP) general +.IP +Relative path to (parent of) top of header file tree within source tree. +.LP +.Sy BuildIncTop .. general +.IP +Top of header file tree within source tree, relative to $(TOP)/X11. +.LP +.Sy LibDir $(USRLIBDIR)/X11 general +.IP +X library installation directory (other directories are installed under +this, e.g., FontDir, XinitDir). +.LP +.Sy ConfigDir $(LIBDIR)/config general +.IP +Where to install configuration files. +.LP +.Sy LintlibDir $(USRLIBDIR)/lint general +.IP +Where to install lint libraries. +Note that the default uses USRLIBDIR, not LIBDIR. +Also note that the name of this symbol is LintlibDir, not LintLibDir. +.LP +.Sy FontDir $(LIBDIR)/fonts general +.IP +Where to install fonts. +.LP +.Sy AdmDir $(DESTDIR)/usr/adm general +.IP +Where system log files are found. +.LP +.Sy XinitDir $(LIBDIR)/xinit general +.IP +Where to install +.I xinit +files. +.LP +.Sy XdmDir $(LIBDIR)/xdm general +.IP +Where to install +.I xdm +files. +.LP +.Sy XdmConfigurationSubdirectory config/default general +.IP +Default +.I xdm +configuration directory. +.LP +.Sy AwmDir $(LIBDIR)/awm general +.IP +Where to install +.I awm +files. +.LP +.Sy TwmDir $(LIBDIR)/twm general +.IP +Where to install +.I twm +files. +.LP +.Sy GwmDir $(LIBDIR)/gwm general +.IP +Where to install +.I gwm +files. +.LP +.Sy ManPath $(DESTDIR)ManDirectoryRoot general +.IP +Full path to top of manual page hierarchy. +.LP +.Sy ManSourcePath $(MANPATH)/man general +.IP +Path to top of manual page hierarchy, plus common suffix of manual page +directories there. +.LP +.Sy ManDir $(MANSOURCEPATH)ManSuffix general +.IP +Where to install program manual pages. +.LP +.Sy LibmanDir $(MANSOURCEPATH)LibManSuffix general +.IP +Where to install library manual pages. +.LP +.Sy XAppLoadDir $(LIBDIR)/app-defaults general +.IP +Where to install application defaults files. +.LP +.Sy OsNameDefines nothing general +.IP +I don't know what this is used for. +It's referenced in +.I lib/Xdmcp/Imakefile +and +.I lib/Xmu/Imakefile . +.LP +.Sy DefaultUserPath :/bin:/usr/bin:$(BINDIR):/usr/ucb general +.IP +Default +.I xdm +user PATH environment variable. +.LP +.Sy DefaultSystemPath /etc:/bin:/usr/bin:$(BINDIR):/usr/ucb general +.IP +Default +.I xdm +system PATH environment variable. +.LP +.Sy DefaultSystemShell BourneShell general +.IP +Default shell. +.LP +.Sy UseCCMakeDepend NO boolean +.IP +Whether to use the slow shell script version of +.I makedepend +(uses +.I "cc \-E" ). +It's best to use the compiled version if it works on your system. +If the compiled version does not work as supplied with the distribution, +it's probably +worth a little effort to see if you can get it to work +(particularly if you can't get the shell script version to work, +either, which sometimes happens!). +Possible problems: +.I /usr/include +is hardwired into the code; if you use +.I gcc , +the library path is hardwired, too. +.LP +.Sy DependDir "varies" general +.IP +Path to +.I makedepend +sources. +The default is dependent on UseCCMakeDepend. +.LP +.Sy ContribDir $(TOP)/../contrib general +.IP +Top of user-contributed source tree. +.LP +.Sy DependCmd $(DEPENDSRC)/makedepend general +.IP +Command to run +.I makedepend. +.LP +.Sy RemoveTargetProgramByMoving NO boolean +.IP +This symbol affects expansion of the RemoveProgramTarget() rule. +``Program'' in that rule's name is misleading; it can be used to remove any +file, not just programs. +.LP +.Sy AllocateLocalDefines nothing general +.IP +\-D's to turn on +.I alloca (). +.LP +.Sy SharedLibX varies boolean +.Sy SharedOldLibX varies boolean +.Sy SharedLibXt varies boolean +.Sy SharedLibXaw varies boolean +.Sy SharedLibXmu varies boolean +.Sy SharedLibXext varies boolean +.IP +Whether to build shared versions of the X, old X, X Toolkit, X Athena +Widget, X mu or X Extension libraries. +The defaults are YES if HasSunOSSharedLibraries is YES, NO otherwise. +.LP +.Sy SharedXlibRev 4.2 general +.Sy SharedOldXRev 4.0 general +.Sy SharedXtRev 4.0 general +.Sy SharedXawRev 4.0 general +.Sy SharedXmuRev 4.0 general +.Sy SharedXextRev 4.0 general +.IP +Version (revision) numbers of shared libraries. +.LP +.Sy HasInputExtension YES boolean +.IP +Whether there are any input extensions. +.LP +.Sy DoInstallExtensionsIntoXlib NO boolean +.IP +Whether the extension library should be merged into the X library. +.LP +.Sy BandAidLibraryNeeded YES boolean +.Sy BandAidLibrarySources Berklib.c general +.Sy BandAidLibraryObjects Berklib.o general +.LP +.LP +.Sy BandAidLibraryMake() "take a look" general +.LP +.LP +.Sy BandAidLibraryNeeded NO boolean +.IP +Whether a band-aid library is needed. +This will be YES if NeedBerklibInXlib is YES. +.IP +I'm not sure what all the band-aid stuff is for. +Perhaps for BSD socket emulation on System V platforms. +.LP +.Sy XawClientDepLibs "$(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)" general +.IP +Library dependencies for clients using the Athena Widgets (DEPLIBS). +.LP +.Sy XawClientLibs "$(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB)" general +.IP +Library needed by clients using the Athena Widgets (LOCAL_LIBRARIES). +.LP +.Sy NeedDefaultDepLibs YES boolean +.LP +Affects the definitions of DEPLIBS, DEPLIBS1, DEPLIBS1, DEPLIBS3. +.LP +.NH 2 +Make Variables +.LP +Many of the +.I make +variables in +.I Project.tmpl , +like those in +.I Imake.tmpl , +bear a direct name relationship to proprocessor symbols with which they are +associated. +.LP +Since much of the project source and installation directory layout +is specified in this file, the number of variables defined in terms of other +.I make +variables (e.g., XMUSRC = $(LIBSRC)Xmu, DEMOSRC = $(TOP)/demos) is quite large. +.NH +Imake.rules +.LP +The X +.I Imake.rules +file rule definitions make heavy use of the following techniques: +.IP (1) +Use of the ``::'' construct is quite prevalent. +In a +.I make +rule, if a target name is followed by ``:'', it's assumed to be the +only rule for that target. +If another rule with the same target is found, it's an error. +If target names are followed by ``::'', there may be multiple rules +for the targets. +The X configuration files rely on this property of ``::'' in the +following ways: +.RS +.IP (a) +To make sure that certain targets are always present in the +.I Makefile , +even if they are not otherwise generated from expansion of the macros +in +.I Imakefile . +This way, subdirectory-traversing +.I make +operations can rely on those targets being present. +For instance, many rules that build programs automatically generate a +``clean'' target to remove the program. +But if no such rule is used in the +.I Imakefile , +there might be no ``clean'' target in the +.I Makefile , +and ``make clean'' fails. +That's not a disaster, but a ``make clean'' from the root of the +source tree can result in a lot of apparent errors. +To avoid this, an empty ``clean'' target is written to the +.I Makefile , +using ``clean::''. +If there is another ``clean'' target, the empty one doesn't hurt anything. +If there isn't, the empty one prevents error messages. +.IP +Other default targets generated are ``tags'', ``install'', +``install.man'', ``Makefile'', ``Makefiles'' and ``includes''. +.IP (b) +To allow commands like ``make all'' to trigger builds of an arbitrary +number of targets. +Without the ``::'' construct, the configuration process would need to +be able to determine exactly which targets ``make all'' should +generate, and produce a single ``all: target1 target2 ...'' rule. +This would be a difficult task. +Using ``::'', each program-building rule can generate its own ``all:: +target'' and they are all triggered. +.RE +.IP (2) +Definitions are allowed to be overridden. +All rules are defined using the following construct: +.Ds .IP +# ifndef \fIrulename\fR +# define \fIrulename(arguments)\fR ... +# endif +.De .IP +This should look familiar because it's the same construct used +in the other configuration files to allow symbol values to be overridden. +Since +.I Imake.rules +is the last configuration file read during a +.I Makefile +build, +.I any +of its rules may be redefined. +Doing so can have far-reaching consequences, of course, so that's not +something you want to do without thinking it through first. +Nevertheless, it's sometimes useful, or even necessary. +.IP +The likely places for such overriding to occur are: +.IP +.I platform.cf \*-if +a system does things in some strange way that's +not easy to compensate for by defining the usual configuration symbols +properly. +For example, the file +.I sgi.cf +redefines a couple of rules, to account for non-standard file +extensions. +.IP +.I site.def \*-if +a rule just isn't right for your site, for some reason. +.IP +.I Imakefile \*-it's +sometimes useful to override a rule in a particular directory, which +can be done by defining the rule in that directory's +.I Imakefile . +The file +.I config/Imakefile +does this, for instance. +Such redefinitions do +.I not +carry down through subdirectories. +Also, since +.I Imake.rules +is seen before +.I Imakefile , +you need to #undef the macro before redefining it. +.IP (3) +If a directory has subdirectories, and +.I make +operations in that directory should recurse down through the +subdirectories, there should be a line that says +.Ds .IP +# define IHaveSubdirs +.De .IP +at the top of the +.I Imakefile . +This causes recursive ``install'', ``install.man'', +``clean'', ``tags'', ``Makefile'' and ``includes'' target rules to be +written into the +.I Makefile +(see end of +.I Imake.tmpl ; +the +.I make +variable SUBDIRS should set to the names of the subdirectories involved, as +well). +If you want CDEBUGFLAGS passed along to subdirectories, put another +line at the top of the +.I Imakefile +that says +.Ds .IP +# define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' +.De .IP (4) +As you scan through the rules, you'll notice that +.I if +constructs are not written like this: +.Ds .IP +if \fIcondition\fR then; \fIaction\fR; fi +.De .IP +Instead, they're written like this: +.Ds .IP +if \fIcondition\fR then; \fIaction\fR; else exit 0; fi +.De .IP +The reason for this is to deal with differing behaviors of +.I if +on various systems. +On some systems, if you write ``if \fIcondition\fR; then \fIaction\fR; fi'' +and +.I condition +is false, the value of the statement is zero (on the grounds that the +test executed to completion without error). +On other systems, the value of the statement is non-zero (on the grounds +that the test failed). +The latter behavior is broken behavior; Ultrix in particular is guilty +of it. +.IP +In the X rules, +.I if +tests are usually used to check whether some preliminary action needs to be +performed before proceeding to the next step. +Systems that return false when the +.I if +test fails cause +.I make +to exit early if the preliminary action does not need to be done, and +the next step is\*-incorrectly\*-never executed. +.IP +In order to get around this, all +.I if +statements explicitly include an +.I else +clause to return zero when the condition fails, so that +.I make +will continue whether the condition is true or not. +.NH 2 +Commonly Used Rules +.LP +Rules for building programs: +.Ds +NormalProgramTarget() +SimpleProgramTarget() +ComplexProgramTarget() +ComplexProgramTarget_1() +ComplexProgramTarget_2() +ComplexProgramTarget_3() +.De +Rules for building shell scripts: +.Ds +CppScriptTarget() +MakeScriptFromCpp() +.De +Rules for building libraries: +.Ds +NormalLibraryObjectRule() +NormalLibraryTarget() +.De +Rules for installing files: +.Ds +InstallProgram() +InstallLibrary() +InstallManPage() +InstallNonExec() +InstallSubdirs() +.De +Rules for cleaning up: +.Ds +RemoveTargetProgram() +CleanTarget() +CleanSubdirs() +.De +Rules for generating Makefiles and dependencies: +.Ds +MakefileTarget() +MakefileSubdirs() +DependTarget() +DependSubdirs() +.De +Many rules that compile programs also generate ``clean'' and ``all'' +targets. +.NH 2 +Rule Descriptions +.LP +Each rule-generating macro in +.I Imake.rules +is described below, in the order in which they appear in that file. +You should still read through the text of a rule before you use it +to write your own +.I Imakefile . +.LP +.B Disclaimer: +I myself do not, for the most part, use the X rules, except in +modified form for my own projects. +There are likely to be a number of errors of understanding here. +.LP +.Ru SaberProgramTarget(program,srclist,objlist,locallibs,syslibs) +.IP +If HasSaberC is NO, this is a nop, otherwise it expands to a rule for +``saber-\fIprogram\fR'' and causes Saber C to load source and object +files for the program. +Odd that ``#'' is in front of the rules, though. +.LP +.Ru RemoveTargetProgram(program) +.IP +Removes +.I program +(actually this symbol is misnamed because it can be used to remove any +file, not just programs). +If RemoveTargetProgramByMoving (from +.I Project.tmpl ) +is YES, +.I program +is moved to +.I program~ +instead. +This allows you to keep the previous version around. +Note that ``*~'' is in the list of files removed by CleanTarget(), so +unless you override FilesToClean, ``make clean'' will remove these +previous target versions. +.LP +.Ru BuildIncludes(srclist,dstsubdir,dstupdir) +.IP +Builds the header file directories in the source tree, +and populates them. +.LP +.Ru NormalProgramTarget(program,objects,deplibs,locallibs,syslibs) +.IP +Builds one program. +All object files and libraries are explicitly listed in the macro invocation. +.I program +is the program to be built. +.I objects +names the object files needed to build it from, e.g., +.I junk.o . +.I deplibs +names the libraries that must exist before linking is done. +.I locallibs +names the libraries in the source tree that should be linked in. +.I syslibs +names the system libraries (e.g., in +.I /usr/lib ) +that should be linked in. +These are named with +.I \-l , +e.g., +.I \-lm . +.IP +A ``clean'' rule is also generated to remove the program (but not the +objects). +.IP +Since this rule does not assume any default sources, you can use it +several times in an +.I Imakefile +to build multiple programs. +You should also set SRCS to the names of all the programs' +source files and invoke DependTarget() in the +.I Imakefile . +Also invoke AllTarget(), giving it the names +of all programs to build, and you'll need to include a rule to +generate +an ``install'' target for each program and an ``install.man'' target if +there is a manual page. +If you're a lint kind of person, you'll also want +LintTarget(). +.LP +.Ru SingleProgramTarget(program,objects,locallibs,syslibs) +.IP +This rule is deprecated. +Don't use it. +.LP +.Ru SimpleProgramTarget(program) +.IP +This macro is used when the +.I Imakefile +is supposed to build a single program, and that program consists of a single +source file. +The macro sets SRCS to +.I program.c , +OBJS to +.I program.o +and calls ComplexProgramTarget(). +The effect is to set up everything to generate rules to build the program, +install it and its man page, clean the program, generate dependencies, +and lint the program. +A real whiz bang. +See description of ComplexProgramTarget(). +.LP +.Ru ComplexProgramTarget(program) +.IP +This macro is used in an +.I Imakefile +that builds a single program. +Given the name of the program, rules are generated to build it, as well as +generate ``all'', ``install'', ``install.man'', ``depend'' and ``lint'' +targets, and to remove the program. +Several assumptions are made by this macro: +.RS +.IP (1) +SRCS has been set to the list of source files (so the ``depend'' target works). +.IP (2) +OBJS has been set to the list of object files (so the program build works). +.IP (3) +The +.I deplibs , +.I locallibs +and +.I syslibs +arguments as used in NormalProgramTarget() are assumed to be DEPLIBS, +LOCAL_LIBRARIES and LDLIBS. +.RE +.LP +.Ru ComplexProgramTarget_1(program,locallib,syslib) +.br +.Ru ComplexProgramTarget_2(program,locallib,syslib) +.br +.Ru ComplexProgramTarget_3(program,locallib,syslib) +.IP +These rules are use in an +.I Imakefile +that builds 1, 2 or 3 programs. +Actually, just 2 or 3 programs. +If you were building a single program, you'd use ComplexProgramTarget(). +Each macro takes 3 arguments. +.I program +is the name of the program to build. +.I locallib +names libraries built in the source tree that should be linked in +(e.g., XMULIB). +.I syslib +names system libraries to be linked in (e.g., +.I \-lm ). +.IP +The values of certain +.I make +variables are assumed to be set (by you). +SRCS1, SRCS2 and SRCS3 name the sources for each program. +(These are used to set SRCS so the ``depend'' target works.) +OBJS1, OBJS2 and OBJS3 name the objects for each program. +DEPLIBS1, DEPLIBS2 and DEPLIBS3 name the library dependencies for each program. +PROGRAMS names the programs to be built. +.IP +If you're only building 2 programs, then SRCS3, OBJS3, etc., do not +need to be set and will be assumed to have the empty value. +PROGRAMS should be the names of 2 programs, not 3. +.LP +.Ru ServerTarget(server,subdirs,objects,libs,syslibs) +.IP +Generates rules to build a server. +.I libs +doubles as +.I deplibs +and +.I locallibs +as those are used in NormalProgramTarget(). +The directories named by +.I subdirs +are used as dependencies and must exist before the target can be built. +.LP +.Ru InstallLibrary(libname,dest) +.IP +Installs +.I liblibname.a +into +.I dest/liblibname.a +and runs the command named by RANLIB on it. +The installation flags INSTLIBFLAGS are used. +.LP +.Ru MergeIntoInstalledLibrary(tolib,fromlib) +.IP +Merges +.I fromlib +into +.I tolib +using the +.I mergelib +script in the SCRIPTSRC directory. +.LP +.Ru InstallSharedLibrary(libname,rev,dest) +.IP +Installs +.I liblibname.so.rev +into +.I dest/liblibname.so.rev , +using INSTLIBFLAGS. +.LP +.Ru InstallSharedLibraryData(libname,rev,dest) +.IP +Installs +.I liblibname.sa.rev +into +.I dest/liblibname.sa.rev , +using INSTLIBFLAGS. +.LP +.Ru InstallLibraryAlias(libname,alias,dest) +.IP +In +.I dest , +makes +.I libalias.a +an alias for +.I liblibname.a +by generating a link. +.LP +.Ru InstallLintLibrary(libname,dest) +.IP +Installs +.I llib-llibname.ln +into the +.I dest +directory using library installation flags INSTLIBFLAGS. +.LP +.Ru InstallManPageLong(file,destdir,dest) +.IP +Generate rule to install a manual page and rename it. +The source manual page is +.I file.man +and is installed in +.I destdir/dest. ManSuffix +using installation flags INSTMANFLAGS. +This is used to install pages whose names are long enough to tickle +brain damage on systems that don't understand long file names. +.LP +.Ru InstallManPage(file,dest) +.IP +Generate rule to install the manual page +.I file.man +in +.I dest/file. ManSuffix +using installation flags INSTMANFLAGS. +.LP +.Ru InstallNonExec(file,dest) +.IP +Generate rules to install a non-executable file using installation +flags INSTDATFLAGS. +.LP +.Ru InstallProgramWithFlags(program,dest,flags) +.IP +Generate rules to install an executable program using the specified +flags. +.LP +.Ru InstallProgram(program,dest) +.IP +Generate rules to install an executable program. +The comments in +.I Imake.rules +for this macro say something about INSTALLFLAGS, but that variable +isn't actually used in the expansion of this macro, so I claim the +flags used are +simply INSTPGMFLAGS until someone demonstrates otherwise. +.LP +.Ru InstallScript(program,dest) +.IP +Generate rules to install +.I program.script +into +.I dest/program +using installation flags INSTPGMFLAGS. +.IP +This rule is obsolete. +Use CppScriptTarget() and InstallProgram(). +.LP +.Ru LinkFileList(step,list,dir,sub) +.IP +Generates rules for a target +.I step +to make links to all files in +.I list +in directory +.I dir . +The links are created in directory +.I sub . +Judging from the definition of this macro, +.I sub +is presumably so named because the rule changes directories into +.I dir +first and appears to expect +.I sub +to be a subdirectory. +(Strictly speaking, that need not be true, since +(i) +.I sub +could legally be an absolute path; +(ii) +.I sub +could have a value such as ``../..''. +But both those possibilities probably subvert the intent of the +macro.) +.LP +.Ru InstallMultipleDestFlags(step,list,dest,flags) +.IP +Generates rules for a target +.I step +(e.g., ``install'') to install all the files in +.I list +into the directory +.I dir +using installation flags +.I flags . +The files in +.I list +are made the rule dependencies. +.LP +.Ru InstallMultipleDest(step,list,dest) +.IP +Like InstallMultipleDestFlags(), but assuming INSTALLFLAGS as the +installation flags. +Note: INSTALLFLAGS is not set by the X configuration files; +you must give it a value in your +.I Imakefile . +.LP +.Ru InstallMultiple(list,dest) +.IP +Like InstallMultipleDest(), but assuming ``install'' as the +.I step +argument. +.LP +.Ru InstallMultipleFlags(list,dest,flags) +.IP +Like InstallMultipleDestFlags(), but assuming ``install'' as the +.I step +argument. +.LP +.Ru InstallMultipleMan(list,dest) +.IP +Like InstallMultipleDest(), but assuming ``install.man'' as the +.I step +argument. +.LP +.Ru InstallAppDefaults(class) +.IP +If InstallAppDefFiles (from +.I Project.tmpl ) +is #define'd, generates an ``install'' target to install +.I class.ad +into +.I $(XAPPLOADDIR)/class +using installation flags INSTAPPFLAGS. +.IP +INSTAPPFLAGS appears to be deprecated in +.I Project.tmpl . +.LP +.Ru DependDependency() +.IP +If UseInstalled is not #define'd, this macro generates rules to check for the +existence of +.I makedepend +in the source tree and build it if it's missing. +This differs from the R3 rules, which failed if +.I makedepend +was missing. +.LP +.Ru DependTarget() +.IP +Generate rule to determine dependencies for source files named by SRCS. +You have to define the value of SRCS yourself, unless you are using +rules such as +SimpleProgramTarget() or ComplexProgramTarget_{1,2,3}(), which do it +for you. +In the latter case, you need to define SRCS1, SRCS2 and SRCS3. +.IP +This macro uses DependDependency() to check for the existence of +.I makedepend +and build it if necessary. +.LP +.Ru CleanTarget() +.IP +Removes all the files named by FilesToClean and files whose names +begin with ``#''. +.IP +To understand how this rule works, see how RM_CMD is defined in +.I Imake.tmpl . +.LP +.Ru TagsTarget() +.IP +Generate rule to build a +.I TAGS +file from all +.I *.c +and +.I *.h +files. +.LP +.Ru ImakeDependency(target) +.IP +If UseInstalled is not #define'd, this macro generates rules to check for the +existence of +.I imake +in the source tree and build it if it's missing. +This differs from the R3 rules, which failed if +.I imake +was missing. +.LP +.Ru BuildMakefileTarget(imakefile,imakeflags) +.IP +Generate rules to build +.I Makefile . +The +.I imakefile +argument is superfluous (a bug?). +Since it's ignored, +.I Imakefile +is assumed as the source from which to build +.I Makefile . +.I imakeflags +is any special flags you want passed to the +.I imake +command. +.IP +This macro uses ImakeDependency() to check for the existence of +.I imake +and build it if necessary. +.IP +You don't use this rule explicitly unless you've #define'd +IHaveSpecialMakefileTarget in your +.I Imakefile . +.LP +.Ru MakefileTarget() +.IP +Generate rules to build a +.I Makefile +target from +.I Imakefile , +so you can say ``make Makefile''. +This target is automatically included in your +.I Makefile +when it is rebuilt by +.I imake , +unless ``#define IHaveSpecialMakefileTarget'' is present +in your +.I Imakefile , +in which case you should include an invocation of +BuildMakefileTarget() to build +.I Makefile . +.LP +.Ru NormalLibraryObjectRule() +.IP +Generate rule to turn a +.I .c +file into a +.I .o +file. +Include this macro (once) in your +.I Imakefile +if you're building a library from C source. +.LP +.Ru NormalFortranObjectRule() +.IP +Generate rule to turn a +.I .f +file into a +.I .o +file. +Include this macro (once) in your +.I Imakefile +if you're building a library from FORTRAN source. +(FORTRAN? +Isn't that something used to build COBOL compilers?) +.LP +.Ru ProfiledLibraryObjectRule() +.IP +Like NormalLibraryObjectRule(), but in addition to building the normal +target, a profiled target is built in the +.I profiled +subdirectory of the current directory. +.I profiled +is created if necessary. +A ``clean'' target to remove profiled objects is also generated. +.LP +.Ru DebuggedLibraryObjectRule() +.IP +Like ProfiledLibraryObjectRule(), but instead of profiled targets in +.I profiled , +debuggable targets are built in the +.I debugger +subdirectory. +.LP +.Ru DebuggedAndProfiledLibraryObjectRule() +.IP +A combination of ProfiledLibraryObjectRule() and DebuggedLibraryObjectRule(). +.LP +.Ru SharedLibraryObjectRule() +.IP +Like ProfiledLibraryObjectRule(), but instead of profiled targets in +.I profiled , +sharable targets are built in the +.I shared +subdirectory. +.LP +.Ru SharedAndDebuggedLibraryObjectRule() +.IP +A combination of SharedLibraryObjectRule() and DebuggedLibraryObjectRule(). +.LP +.Ru SpecialSharedAndDebuggedObjectRule(objs,depends,options) +.IP +Like SharedAndDebuggedLibraryObjectRule(), but allows targets +.I objs ), ( +dependencies and special compiler flags to be specified. +.LP +.Ru SpecialSharedObjectRule(objs,depends,options) +.IP +Like SharedLibraryObjectRule(), but allows targets +.I objs ), ( +dependencies and special compiler flags to be specified. +.LP +.Ru SpecialObjectRule(objs,depends,options) +.IP +Like NormalLibraryObjectRule(), but allows targets +.I objs ), ( +dependencies and special compiler flags to be specified. +.LP +.Ru SpecialProfiledObjectRule(objs,depends,options) +.IP +Like ProfiledLibraryObjectRule(), but allows targets +.I objs ), ( +dependencies and special compiler flags to be specified. +.LP +.Ru SpecialDebuggedObjectRule(objs,depends,options) +.IP +Like DebuggedLibraryObjectRule(), but allows targets +.I objs ), ( +dependencies and special compiler flags to be specified. +.LP +.Ru SpecialDebuggedAndProfiledObjectRule(objs,depends,options) +.IP +Like DebuggedAndProfiledLibraryObjectRule(), but allows targets +.I objs ), ( +dependencies and special compiler flags to be specified. +.LP +.Ru NormalLibraryTarget(libname,objlist) +.IP +Generate rules to create the library +.I liblibname.a +from the object files named by +.I objlist . +The library is RANLIB'd after being created. +.LP +.Ru NormalSharedLibraryTarget(libname,rev,solist) +.IP +Generate rules to create a shared library +.I liblibname.so.rev . +The library is created under a different name and then moved onto the +target name to maximize availability of any existing version. +.LP +.Ru NormalSharedLibraryDataTarget(libname,rev,salist) +.IP +Like NormalSharedLibraryTarget(), but for shared data +.I liblibname.sa.rev . +The comments claim +the library is created under a different name and then moved onto the +target name as for NormalSharedLibraryTarget() but that doesn't appear +to be true from the text of the macro. +.LP +.Ru NormalLibraryTarget2(libname,objlist1,objlist2) +.IP +Like NormalLibraryTarget(), but adds two lists of files to the +library, in two steps. +Used to create libraries with large numbers of files. +.LP +.Ru ProfiledLibraryTarget(libname,objlist) +.IP +Generate rules to create the library +.I liblibname_p.a +from the profiled objects in the +.I profiled +subdirectory. +.LP +.Ru DebuggedLibraryTarget(libname,objlist) +.IP +Generate rules to create the library +.I liblibname_d.a +from the debuggable objects in the +.I debugger +subdirectory. +.LP +.Ru AliasedLibraryTarget(libname,alias) +.IP +Generate rules to make +.I libalias.a +a link to +.I liblibname.a . +.LP +.Ru NormalRelocatableTarget(objname,objlist) +.IP +Generate rules to produce a relocatable object file +.I objname.o +from the object files named in +.I objlist . +This is built using the loader LD, called with flags LDCOMBINEFLAGS. +.LP +.Ru ProfiledRelocatableTarget(objname,objlist) +.IP +Like NormalRelocatableTarget(), but builds +.I objname_p.o +and uses loader flag +\-X instead of LDCOMBINEFLAGS, to produce a profiled relocatable +object file. +.LP +.Ru DebuggedRelocatableTarget(objname,objlist) +.IP +Like NormalRelocatableTarget(), but builds +.I objname_d.o +and uses loader flag +\-X instead of LDCOMBINEFLAGS, to produce a debuggable relocatable +object file. +.LP +.Ru LintLibraryTarget(libname,srclist) +.IP +Generate rules for a ``lintlib'' target that builds +.I llib-llibname.ln +from the source files named by +.I srclist . +.LP +.Ru NormalLintTarget(srclist) +.IP +Generate rules for a ``lint'' target that lints the source files named +by +.I srclist , +and for a ``lint1'' target that lints the file named by the +.I make +variable FILE (which you must set in +.I Imakefile ). +.LP +.Ru LintTarget() +.IP +Generate rules to lint files named by SRCS. +SRCS might be set by you in +.I Imakefile , +or, if you invoke macros such as SimpleProgramTarget() or +ComplexProgramTarget_{1,2,3}(), it will be done for you +automatically. +.LP +.Ru LinkSourceFile(src,dir) +.IP +Generate rule to make a link to a file in another directory. +The macro can be used to create links +to non-source files, too, of course. +.LP +.Ru MakeSubincludesForBuild(step,dir,srclist) +.IP +Generate rules for target +.I step +to ... to ... uh, I don't know! +.LP +.Ru NamedTargetSubdirs(name,dirs,verb,flags,subname) +.IP +Generate rules for a target +.I name +(e.g., ``depend'', ``install'') that causes the target +.I subname +to be built in the subdirectories named by +.I dirs . +This is done by changing into each subdirectory in turn and invoking +.I make +for the +.I subname +target. +.I flags +is any extra flags that should be passed to those +.I make +processes. +.I verb +is the -ing form of +.I name , +e.g., if +.i name +is ``make'', then +.I verb +is ``making''. +This is used to echo an indication of what +.I make +is doing in each directory as it proceeds. +.IP +This macro is used by virtually all other macros that have names like +XXXSubdirs(). +.LP +.Ru NamedMakeSubdirs(name,dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a target +.I name +that causes the ``all'' target to be built in the +subdirectories named by +.I dirs . +.IP +If you want CDEBUGFLAGS passed to the +.I make +processes forked in each subdirectory, the +.I Imakefile +should have a line at the top that says: +.RS +.Ds +# define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' +.De +.RE +.LP +.Ru MakeSubdirs(dirs) +.IP +Equivalent to NamedMakeSubdirs(all,dirs). +.LP +.Ru DependSubdirs(dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a ``depend'' +target that causes the ``depend'' target to be built in the +subdirectories named by +.I dirs . +.LP +.Ru InstallSubdirs(dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a ``install'' +target that causes the ``install'' target to be built in the +subdirectories named by +.I dirs . +.IP +This macro is automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile , +in which case SUBDIRS should be set to the names of the subdirectories +involved. +.LP +.Ru InstallManSubdirs(dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a ``install.man'' +target that causes the ``install.man'' target to be built in the +subdirectories named by +.I dirs . +.IP +This macro is automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile , +in which case SUBDIRS should be set to the names of the subdirectories +involved. +.LP +.Ru IncludesSubdirs(dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a ``includes'' +target that causes the ``includes'' target to be built in the +subdirectories named by +.I dirs . +.IP +This macro is automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile , +in which case SUBDIRS should be set to the names of the subdirectories +involved. +.LP +.Ru NamedCleanSubdirs(name,dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a target +.I name +that causes the ``clean'' target to be built in the +subdirectories named by +.I dirs . +.LP +.Ru CleanSubdirs(dirs) +.IP +Equivalent to NamedCleanSubdirs(clean,dirs). +.IP +This macro is automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile , +in which case SUBDIRS should be set to the names of the subdirectories +involved. +.LP +.Ru NamedTagSubdirs(name,dirs) +.IP +Invokes NamedTargetSubdirs() to generate rules for a target +.I name +that causes the ``tags'' target to be built in the +subdirectories named by +.I dirs . +.LP +.Ru TagSubdirs(dirs) +.IP +Equivalent to NamedTagSubdirs(tags,dirs). +.IP +This macro is automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile , +in which case SUBDIRS should be set to the names of the subdirectories +involved. +.LP +.Ru MakeLintSubdirs(dirs,target,subtarget) +.IP +Invokes NamedTargetSubdirs() to generate rules for a target +.I target +that causes the target +.I subtarget +to be built in the subdirectories named by +.I dirs . +.LP +.Ru LintSubdirs(dirs) +.IP +Equivalent to MakeLintSubdirs(dirs,lint,lint). +.IP +This macro is +.I not +automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile ; +you need to do so yourself. +.LP +.Ru MakeLintLibSubdirs(dirs) +.IP +Equivalent to MakeLintSubdirs(dirs,lintlib,lintlib). +.LP +.Ru MakeMakeSubdirs(dirs,target) +.IP +Generate rules for a target +.I target +to generate a +.I Makefile +in the subdirectories named by +.I dirs . +.IP +In R4, ``Makefiles'' rules handle values of ${TOP} that are either +relative or absolute. +The R3 rule only handled relative values. +.LP +.Ru MakeNsubdirMakefiles() +.IP +Generate a set of very very very ugly but quite wonderful rules for +use by MakeMakeSubdirs(). +Automatically invoked by MakefileSubdirs(); you shouldn't need to do +so yourself. +.LP +.Ru MakefileSubdirs(dirs) +.IP +Generate rules to build ``Makefiles'' +targets in the given subdirectories. +.IP +This macro is automatically invoked if IHaveSubdirs is #define'd in +.I Imakefile , +in which case SUBDIRS should be set to the names of the subdirectories +involved. +.LP +.Ru CppScriptTarget(dst,src,defs,deplist) +.IP +Generate rules to build a shell script +.I dst +from +.I src . +It figures out how to do this correctly for the current platform +depending on the value of ExecableScripts. +.I defs +is any extra flags, such as \-D's, to pass through to the +preprocessor. +.I deplist +names any targets that must exist before +.I dst +can be built. +.LP +.Ru MakeScriptFromCpp(name,defs) +.IP +Generate rule to build a script +.I name +from +.I name.cpp . +.I defs +is as for CppScriptTarget(). +.LP +.Ru MakeDirectories(step,dirs) +.IP +Generate rules for target +.I step +to create the directories named by +.I dirs . +This is often used to make sure that installation directories exist +before trying to install files in them. +(Not all verions of +.I install +create missing directories.) +.LP +.Ru MakeFonts() +.IP +Generate rules for ``fonts.dir'' target to build font database +.I fonts.dir . +The +.I make +variable OBJS must be set to the name of the files that should exist +before the database is built. +.LP +.Ru InstallFonts(dest) +.IP +Generate rules to install the directory +.I fonts.dir +into +.I dest +using installation flags INSTDATFLAGS. +.LP +.Ru InstallFontAliases(dest) +.IP +Generate rules to install font alias database +.I fonts.alias +into +.I dest +using installation flags INSTDATFLAGS. +.LP +.Ru FontTarget(basename) +.IP +Generate rules to create a font file by converting +.I basename.bdf +to +.I basename.snf . +.LP +.Ru CompressedFontTarget(basename) +.IP +Generate rules to create a compressed font file by converting +.I basename.bdf +(to +.I basename.snf.Z , +I suppose). +.LP +.Ru AllTarget(depends) +.IP +Generate rule for an ``all'' target to build targets named by +.I depends . +.LP +.NH +Imakefile +.LP +If HasSaberC is #define'd, some special Saber-C rules are generated. +.LP +Some symbols that you may want to #define (as nothing) at the top of +.I Imakefile +are: +.LP +.Ru IHaveSpecialMakefileTarget +.IP +If not #define'd (the normal case), MakefileTarget() is automatically +invoked. +If #define'd, it's assumed that you want to explicitly invoke a +.I Makefile -building +macro yourself. +.LP +.Ru MakefileAdditions +.IP +If #define'd, MakefileAdditions() is automatically invoked. +However, MakefileAdditions() appears not to be defined +anywhere, and I have no idea what it is supposed to do. +.LP +.Ru IHaveSubdirs +.IP +If #define'd, you should set SUBDIRS to the names of the current +directory's subdirectories, and subdirectory-traversing rules for +generating ``Makefile'', ``install'', ``install.man'', ``clean'', +``tags'' and ``includes'' targets will be automatically invoked. diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/config-X11R4-1.05.ms b/web/glasgow/lit2x-0.16/mkworld/docs/config-X11R4-1.05.ms new file mode 100644 index 0000000000..8d7d974ab0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/config-X11R4-1.05.ms @@ -0,0 +1,2456 @@ +.\" format with +.\" tbl % | xroff -ms | lpr +.\" +.\" revision date - change whenever this file is edited +.ds Rd 28 January 1991 +.\" document revision number - change each time document is released +.ds Rn 1.05 +.\" +.nr PO 1.2i \" page offset 1.2 inches +.nr PD .7v \" inter-paragraph distance +.\" +.EH 'Imake in X11R4'- % -'' +.OH ''- % -'Imake in X11R4' +.OF 'Revision date:\0\0\*(Rd'\s+1\*-DRAFT SCRIBBLINGS\*-\s-1'Printed:\0\0\n(dy \*(MO 19\n(yr' +.EF 'Revision date:\0\0\*(Rd'\s+1\*-DRAFT SCRIBBLINGS\*-\s-1'Printed:\0\0\n(dy \*(MO 19\n(yr' +.\" +.\" +.\" I - italic font (taken from -ms and changed) +.de I +.nr PQ \\n(.f +.if t \&\\$3\\f2\\$1\\fP\&\\$2 +.if n .if \\n(.$=1 \&\\$1 +.if n .if \\n(.$>1 \&\\$1\c +.if n .if \\n(.$>1 \&\\$2 +.. +.\" start block. LP gives a bit extra space. Can say .Ds .IP C, etc. +.de Ds +.if \\n(.$<1 .LP +.if \\n(.$>=1 \\$1 +.if \\n(.$<2 .DS +.if \\n(.$>=2 .DS \\$2 \\$3 \\$4 \\$5 +.. +.\" end block. If arg is given, it replaces the .LP (e.g., .De .IP). +.de De +.DE +.if \\n(.$<1 .LP +.if \\n(.$>=1 \\$1 \\$2 \\$3 \\$4 \\$5 +.. +.TL +Using Imake to Configure +.br +the X Window System +.br +Version 11, Release 4 +.AU +Paul DuBois +dubois@primate.wisc.edu +.AI +Wisconsin Regional Primate Research Center +Document revision:\0\0\*(Rn +Revision date:\0\0\*(Rd +.AB +The X Window System\(dg +.FS \(dg +X Window System is a trademark of the Massachusetts Institute of Technology. +.FE +is a large software project that, despite its size, +is remarkable in its portability. +Much of this is due to the method employed to configure the X +distribution for building and installation: use of a small number of +tools and isolation of machine dependencies into a small number of +files that can be easily maintained and modified. +This document discusses one of those tools, +.I imake , +and the design of the configuration files used in conjunction with it. +.AE +.NH +Introduction +.LP +This document describes how +.I imake +configuration files are set up in the X Window System. +It is assumed that you know something about what +.I imake +is supposed to be used for (in general), +and that you're reading this to find out something +about how that is accomplished in X (in particular). +The description applies to X Version 11, release 4 configuration files, which +are organized quite differently than those from previous releases. +.LP +Other documentation (from the X11R4 distribution) that you may find useful +includes: +.IP \(bu +Section 2 of ``X Window System, Version 11 Release 4 Release Notes,'' +by Jim Fulton. +.IP \(bu +.I mit/doc/config/usenixws/paper.ms : +``Configuration Management in the X Window System,'' also by Jim Fulton. +.IP \(bu +.I mit/config/README : +``X Window System Imake Configuration Guide, Release 4.'' +.IP \(bu +.I mit/config/imake.man : +manual page for +.I imake . +.IP \(bu +.I mit/util/makedepend/mkdepend.man : +manual page for +.I makedepend . +.IP \(bu +.I contrib/doc/imake/imake.tex : +``An +.I Imake +Tutorial,'' by Mark Moraes. +This was written between R3 and R4, but is worthwhile reading nonetheless. +.LP +You should also have access to the X configuration files (in +.I mit/config ). +These are not really documentation as such, +but it is expected that you have them at hand, for comparison +against the descriptions below. +.LP +.I imake +is generally conceded to have a pretty steep learning curve. +The +.I README +referred to above notes that +.I imake +``can be somewhat tricky to master,'' an observation attested to by +many who use it. +There seem to be three camps regarding +.I imake ; +those who think it's wonderful, those who think it's wretched, and those +who suspect it might be useful (else why would it be used to configure +a major publicly-available effort like X?) but are puzzled by it. +The present document was written to fill in some of the gaps in the +existing documentation, in order to try to swell the ranks of the first +group by depleting the membership of the third. +(Those who despise +.I imake \*-members +of the second group\*-have good reasons for doing so and the present +effort is not likely to sway them. +The author of +.I imake +is in this group.) +.LP +Where appropriate, the current X configuration files are compared to those +from previous releases to show how limitations of earlier configuration +architectures have been eased. +There are also occasional comments to indicate how +.I imake +and the X configuration files might be adapted for use in contexts +other than building X. +.LP +This document is independent of the efforts of the MIT X Consortium. +There are no doubt errors lurking within, both of understanding and of fact; +they are my own. +Please send corrections, criticisms and comments to the address above. +.LP +The overall organization followed here is: +.IP 1. +Introduction. +.IP 2. +X configuration tool description\*-the programs you use. +.IP 3. +X configuration file description\*-what each file is used for, how each fits +into the configuration process. +.IP 4. +How to build +.I imake . +.IP 5. +How to build X. +.IP 6. +Configuration file bugs. +.IP 7. +How to write your own +.I Imakefile . +You can read this section without reading the rest of the paper, +maybe. +.IP 8. +How to make mistakes writing an +.I Imakefile . +.IP Appendix +Listing of the symbols used in each configuration file, and +what they're used for. +.NH +The tools: imake, makedepend, xmkmf +.LP +.I imake +is a configuration tool\*-the main tool used to configure X. +It is not a replacement for the +.I make +program, but it does assume the availability of +.I make +as the tool used to direct project building and installation. +What +.I imake +provides is an alternative to writing +.I Makefiles +by hand. +The name means ``include-make''\*-\fIimake\fR +uses the C preprocessor +.I cpp , +taking advantage of its include-file and macro-processing +facilities for the purpose of generating +.I Makefiles +suitable for +.I make . +.LP +For each directory in the X distribution, +.I imake +reads a bunch of +configuration files that go to a lot of trouble to compensate for and +adjust to the individual characteristics of your system. +These are combined with an +.I Imakefile +from the current directory and the whole mess is sent through +.I cpp +to build a +.I Makefile +there. +The same configuration files are used to build every +.I Makefile ; +they are kept together in +.I mit/config , +isolating machine dependencies in one location to ease development +and maintenance. +In contrast, the +.I Imakefile +is directory-specific (it specifies the targets to be built in that directory) +and is machine-independent. +.LP +This means that when the distribution is built on a different machine, +only the configuration files need be changed. +The +.I Imakefiles +do not need to be. +If X configuration were specified directly using +.I Makefiles , +this would not be true. +Because +the configuration information in +.I Makefiles +is not portable, each one would have to be edited individually\*-bad +enough for a single +.I Makefile , +but an overwhelming prospect for a project the size of X. +.LP +The value of being able to localize machine-dependent configuration +information into one place should not be underestimated, particularly +as X becomes more sophisticated and the number of systems on which it +runs increases. +The number of +.I make +variables used to build X has increased from approximately 60 +in R1 to 100 in R3 to 150 in R4. +.LP +Another tool, +.I makedepend , +is used to generate header file dependencies for C source files in +each directory after the +.I Makefile +has been built. +Dependencies of targets upon object files can be statically listed in the +.I Imakefile , +but not those for header files. +Different systems organize these differently so dependencies on them +must be generated dynamically. +.LP +While X is being built, +.I imake +itself is located with the configuration files in +.I mit/config . +.I makedepend +lives in +.I util/makedepend +if you use the compiled version (preferred), +or in +.I util/scripts +if you use the shell script version (slower). +.LP +When X is installed, copies of +.I imake , +.I makedepend , +and a related tool, +.I xmkmf , +are placed in a public directory, and the configuration files are +copied to +.I /usr/lib/X11/config . +.I xmkmf +is used to bootstrap a +.I Makefile +from an +.I Imakefile +using the installed configuration files,\** +.FS +Normally a new +.I Makefile +is produced with ``make Makefile'', an operation that presumes you +already have a properly configured +.I Makefile +containing the rules necessary to run +.I imake . +Hence the bootstrap problem. +Obviously, if you know the proper incantation to utter, you can issue +the appropriate +.I imake +command manually, but +.I xmkmf +eliminates the need. +Besides, the only way you'd know which wand to wave is by having a +reasonable understanding of +.I imake +in the first place\*-in which case you wouldn't be reading this! +.FE +and can be used to build +programs from outside of the X source tree, such as you might write +yourself or get from comp.sources.x on Usenet. +.LP +The X configuration files make very +few assumptions about the capabilities of +.I make +itself. +Although several enhanced versions of +.I make +provide special features or extensions, any +.I Makefile +that relies on universal availability of those features +will fail on systems with less-capable versions of +.I make . +.I Makefiles +produced by +.I imake +in X do not use any of these constructs, so they should work with +even the lowest-common-denominator +.I make +program. +.LP +Since +.I imake +passes its input through +.I cpp , +the configuration file writer can take advantage of several features +not present in plain-vanilla +.I make , +such as parameterized macros (using #define), file inclusion (using +#include) and conditional testing (using #if, #ifdef, #ifndef). +This ameliorates much of the sobering effect of having to assume that a dumb +.I make +is the only one available. +.LP +Use of +.I cpp +can produce problems, too, of course: +.IP (1) +How to specify, in configuration files, comments that should end up in the +.I Makefile . +.I make +comments are introduced by a ``#'' character\*-unfortunately, +.I cpp +treats lines beginning with ``#'' as preprocessor directives. +A comment of the form +.Ds .IP +# if your system doesn't have ranlib, use /bin/true +.De .IP +is considered a symbol test by +.I cpp +(it begins with ``if'') and is gobbled up, while a comment like +.Ds .IP +# The next rule is a workaround for a broken compiler +.De .IP +is not understood by +.I cpp +and generates a syntax error. +To get around this, comments +should be preceded by ``/**/#'' instead of just ``#''. +.I cpp +will strip off the ``/**/'' (the empty C comment) +and won't treat the line as a directive (though it's +still liable to symbol substitution). +.IP +The exception to this ``comment-commenting'' convention is in the +.I Imakefile +itself, where +.I imake +automatically adds ``/**/'' onto lines beginning with ``#'' that are not +preprocessor directives. +The reason for this is to insulate the end user of +.I imake +(who simply writes the +.I Imakefile +and not the underlying configuration files) from the need to be aware +of, or abide by, the commenting convention. +I would hazard a guess that many people are not aware of this +exception, given the high incidence of +.I Imakefiles +containing ``/**/#''. +.IP +Comments that are not to be passed through to the +.I Makefile +can be written as normal C comments (text surrounded by ``/*'' and ``*/'') +and will be deleted by +.I cpp . +.IP (2) +Sometimes the values of +.I cpp +symbols are to be concatenated. +The symbol names cannot be concatenated in the configuration files, +because that results in a different symbol name, so they must be kept +apart somehow. +The empty C comment is useful here, too. +For instance, if Prefix, LibName and Suffix are defined as +.I lib , +.I mylib +and +.I .a , +respectively, then to obtain the concatentation value +.I libmylib.a , +one writes Prefix/**/LibName/**/Suffix, not PrefixLibNameSuffix. +.IP (3) +The configuration files define several multiple-line macros that are +intended to produce multiple lines of output. +.I cpp +joins multi-line macros into a single line, so some post-processing is +necessary. +.NH +Configuration file architecture +.LP +To produce a +.I Makefile +from an +.I Imakefile , +the following configuration files are used: +.Ds +.ta 1.5i +Imake.tmpl master template +\fIplatform\fR.cf platform-specific definitions (the filename varies) +site.def site-specific definitions +Project.tmpl X-specific default definitions +Imake.rules \fIcpp\fR macros to generate \fImake\fR rules +.De +In general, +if a port exists for your system, the only file that you should need to modify +to build and install X is +.I site.def . +In some cases it may be necessary to modify the platform file. +.I Imake.tmpl , +.I Project.tmpl +and +.I Imake.rules +should be left alone.\** +.FS +It should be emphasized that ``should be left alone'' applies +.I "only to building X itself" . +If you are adapting the configuration files for use with another +project, you will probably modify all of them somewhat. +You may even find yourself in the position of having modified them to such +an extent that they end up hacked to bits, incapable of configuring +anything, with you left possessing only the faint hope that something useful +will rise, Phoenix-like, from out of the remains. +Be assured\*-it won't. +But cheer up; start again and learn from your mistakes. +.FE +.LP +If you are porting X to a new platform, you will need to write your +own platform file, and modify the top part of +.I Imake.tmpl +slightly. +If you are doing a new port of X, +.I or +porting the X configuration files for use with a different project, you +are well-advised to study all of the configuration files thoroughly. +Ignorance is not bliss in such instances. +.LP +.I Imake.tmpl +contains an #include line for each of the other four configuration files and +for the +.I Imakefile +in the current directory. +It also contains in-line sections for global constant definitions, +header block selection, description of system characteristics, build +definitions, and extra +.I make +rules. +The template is +structured as follows to make everything fit together: +.LP +.TS +box tab (%) ; +l l s l l +l _ _ _ l +l | l l s | l +l | l l s | l +l | l _ l | l +l | l | l | l | l +l | l _ l | l +l | l _ l | l +l | l | l | l | l +l | l _ l | l +l | l l l | l +l | l l l | l +l | l _ l | l +l | l | l | l | l +l | l _ l | l +l | l _ l | l +l | l | l | l | l +l | l _ l | l +l | l _ l | l +l | l | l | l | l +l | l _ l | l +l | l l s | l +l _ _ _ l . +\h'.01i'%Imake.tmpl:%\h'.01i'%\h'.01i' +% +%\h'.01i'%global constants +%%header blocks +%% +%%#include <\fIplatform\fR.cf> +%% +%% +%%#include <site.def> +%% +%%system description and +%%build definitions +%% +%%#include <Project.tmpl> +%% +%% +%%#include <Imake.rules> +%% +%% +%%#include "./Imakefile" +%% +%%extra \fImake\fR rules +% +.TE +.LP +Before these sections of the template are described, there are some general +principles that should be kept in mind. +.LP +Much of the flexibility of the X configuration files is achieved +through the use of the following construct, which defines +.I symbol +only if it has not already been defined: +.Ds +#ifndef \fIsymbol\fR +#define \fIsymbol value\fR +#endif +.De +This construct allows any system-, build- or project-related symbol to +be given a default definition if none has been supplied earlier; +coupled with support for inclusion of platform- and site-specific +files prior to the section in which the default is defined, +the default may be overridden +by a definition occurring within those files. +For example, the default for the C compiler symbol occurs in the build +definitions section of +.I Imake.tmpl +and is defined thus: +.Ds +#ifndef CcCmd +#define CcCmd cc +#endif +.De +If the GNU C compiler is to be used instead, the default definition +can be overridden +simply by putting the following in +.I site.def : +.Ds +#ifndef CcCmd +#define CcCmd gcc +#endif +.De +Use of the #ifndef/#endif construct is pervasive throughout the X11R4 +configuration files, to a much greater extent than in the X11R3 files. +This is especially true in the platform-specific files. +.LP +A fairly consistent pattern followed within the system/build section of +.I Imake.tmpl +and within +.I Project.tmpl +is that definitions for +.I cpp +symbols are listed first, followed by definitions for +.I make +variables. +I presume this is done because there is greater flexibility +available in defining +.I cpp +symbols, e.g., through #ifndef conditional testing. +Since +.I cpp +can't tell whether a +.I make +variable has previously been defined, the strategy adopted is to associate a +.I cpp +symbol with a given +.I make +variable thus: +define the symbol conditionally to allow the possibility of +overriding, then equate the +variable to whatever value the symbol finally ends up with. +For instance, +.I Imake.tmpl +contains: +.Ds +#ifndef CcCmd +#define CcCmd cc +#endif +.sp .3v +\&. . . +.sp .3v +CC = CcCmd +.De +If no earlier definition of CcCmd overrides the default +CC ends up as +``cc''. +On the other hand, if the default is overridden to use ``gcc'' +instead (e.g., in +.I site.def ), +CC ends up as ``gcc''. +.LP +Sometimes ``mixed'' symbol definitions occur, in which +.I cpp +symbols are defined in terms of +.I make +variables. +There are at least two reasons to do this. +.IP (1) +To avoid order-of-definition problems. +Consider the two sets of definitions below. +.Ds .IP +.ta 3i +#ifndef a #ifndef a +#define a b #define a ${B} +#endif #endif +A = a A = a +.sp .3v +\&. . . . . . +.sp .3v +#ifndef b #ifndef b +#define b z #define b z +#endif #endif +B = b B = b +.De .IP +What ends up in the +.I Makefile +is: +.Ds .IP +.ta 3i +A = b A = ${B} +B = z B = z +.De .IP +The example on the left is dependent on the order in which a and b are +defined. +As written above, a (and hence A) is defined in terms of +a symbol that hasn't been defined yet; both get the value of a +literal ``b''. +The example on the right works; b is defined as ``z'', B gets +the same value. +A becomes ``${B}'', which is not evaluated further until +.I make +is run. +At that time A evaluates properly to ``z'', independently of the order in +which a and b are defined in the configuration file. +.IP (2) +To allow for greater flexibility at installation time. +For example, UsrLibDir and USRLIBDIR are defined as: +.Ds .IP +#ifndef UsrLibDir +#define UsrLibDir $(DESTDIR)/usr/lib +#endif +.sp .3v +\&. . . +.sp .3v +USRLIBDIR = UsrLibDir +.De .IP +Symbols such as IncRoot, BinDir, AdmDir are defined similarly, even +though DestDir (to which DESTDIR is eventually equated) is defined +earlier (i.e., there is no order-of-definition problem here). +If a user wants the install to take place under a different root than +DestDir, the command ``make DESTDIR=/alternate/root install'' +suffices, by overriding the definition of DESTDIR in the +.I Makefile . +If UsrLibDir, etc., were defined directly in terms of DestDir rather +than DESTDIR, this would not be possible.\** +.FS +Actually, it would be possible, but cumbersome: ``make install +BINDIR=/alt/bin/dir ADMDIR=/alt/adm/dir LIBDIR=/alt/lib/dir ...'' +.FE +.LP +Each of the sections of +.I Imake.tmpl +is described below. +The descriptions only contain representative examples of the symbols +used in each configuration file. +For exhaustive (and exhausting?) lists, consult the appendix. +.NH 2 +Global constant definitions +.LP +This section of +.I Imake.tmpl +defines two symbols (YES as 1 and NO as 0). +References to these symbols are legion +throughout the rest of the configuration +specification and their values should not be changed. +.LP +Note: symbols #define'd in the configuration files or the +.I Imakefile +have nothing to do with symbols #define'd in your programs; they +are entirely independent.\** +.FS +I once wondered about this, which seems pretty ridiculous now. +.FE +.NH 2 +Header block selection +.LP +The header block section of +.I Imake.tmpl +determines the type of machine on which +.I imake +is being run. +This is done by looking for a +.I trigger \*-a +.I cpp +preprocessor symbol that uniquely and unambiguously indicates a given platform. +For instance, +``sun'' is defined only on Sun systems, ``apollo'' only on Apollo systems, +and +``ultrix'' is only on Ultrix systems. +Their header blocks look like this: +.Ds +.ta 3i +\fBSun:\fR \fBUltrix:\fR +#ifdef sun #ifdef ultrix +#define MacroIncludeFile <sun.cf> #define MacroIncludeFile <ultrix.cf> +#define MacroFile sun.cf #define MacroFile ultrix.cf +#undef sun #ifdef vax +#define SunArchitecture #undef vax +#endif /* sun */ #define VaxArchitecture + #endif +\fBApollo:\fR #ifdef mips +#ifdef apollo #undef mips +#define MacroIncludeFile <apollo.cf> #define MipsArchitecture +#define MacroFile apollo.cf #endif +#undef apollo #undef ultrix +#define ApolloArchitecture #define UltrixArchitecture +#endif /* apollo */ #endif +.De +The trigger symbol might be predefined by +.I cpp +itself; if no such predefined symbol is available,\** +.FS +A goal ANSI C will help us reach? +.FE +.I imake +is built to explicitly pass a definition for one to +.I cpp +to cause the correct header block to be selected. +.LP +If no trigger is defined, a generic configuration +header block is selected instead. +Since that means the platform wasn't +properly determined, a warning is written into the +.I Makefile : +.Ds +# WARNING: Imake.tmpl not configured; guessing at definitions!!! +# This might mean that BOOTSTRAPCFLAGS wasn't set when building imake. +.De +The resulting generically-configured +.I Makefile +will probably fail in one of a number of strange and wondrous ways when +used to try to build anything, +With any luck, the hapless user will examine the +.I Makefile +to figure out +what went wrong, see the warning, and realize that the platform wasn't +determined properly. +.LP +Failure to find a defined trigger symbol might occur because no +port exists for the machine in question, and thus no header block for +it exists. +(Each time X is ported, a header block for the new platform is added +to this section of +.I Imake.tmpl .) +Failure will also occur if +.I imake +was not built properly (i.e., it doesn't pass the +proper trigger symbol definition to +.I cpp ). +.LP +Assuming the proper header block is selected, several +things happen inside of it. +The name of the associated platform-specific +.I .cf +file is defined for later inclusion by the template; one or more architecture +indicator symbols are defined that can be used +by later configuration sections +to test for particular software or hardware platforms; +the trigger symbol is undefined so it won't trigger any other header +block. +.LP +A header block may define a single architecture indicator symbol that refers +both to the software and hardware, +or separate indicators may be defined for an operating system that +runs on multiple hardware types, +For example, ``ultrix'' indicates an Ultrix system, but it is no longer +true (as it once was) that a VAX can be assumed as the hardware +platform\*-RISC Ultrix systems run on MIPS chips now. +Thus UltrixArchitecture is defined as the software indicator symbol, and +VaxArchitecture or MipsArchitecture as the hardware indicator. +.LP +Software indicator symbols should be unique. +Hardware indicator symbols are not necessarily unique in themselves +and may be shared across different software +platforms, e.g., MipsArchitecture can be defined for Ultrix or SGI systems, +VaxArchitecture for Ultrix or BSD systems. +.LP +.I Imakefiles +should always test for indicator symbols rather than trigger symbols, +since the former are more reliable (the latter are undefined by the +header block, anyway). +.LP +The use of predefined or +.I imake -supplied +.I cpp +trigger symbols is fraught with peril, and one must construct the +header blocks carefully, for two reasons: +.IP (1) +Symbols may be ambiguous. +For instance, ``vax'' can be defined both under Ultrix and under BSD. +Thus, the Ultrix header block must come first. +It tests for ``ultrix'' and if that succeeds, defines UltrixArchitecture +and undefines ``vax'' so the BSD block will fail. +.IP (2) +Symbols may become ambiguous in unanticipated ways in the +future. +The ``mips'' symbol is an example. +In R3 it was used to unambiguously detect a true MIPS machine. +This can no longer be done given the presence of that symbol on other +systems that also run on MIPS chips now. +.LP +When porting X to other platforms, it is sometimes +difficult to know either what the trigger symbol should be, or what +indicator symbol(s) to use. +Consider MIPS machines running RISC/os. +``mips'' is insufficient as a trigger, because it is does not +unambiguously define MIPS systems. +The hardware indicator symbol is clear enough, MipsArchitecture, but +the software indicator is less so. +The name of the MIPS operating system suggests that +RiscosArchitecture might be a good choice. +Guess again. +Acorn Computers Ltd. has an OS with a similar name, ``RISC OS''.\** +.FS +My own preference is to use ``mipsriscos'' as the trigger symbol, +MipsArchitecture as the hardware indicator, +and MipsRiscosArchitecture +(which seems suitably unique, but has the disadvantage of being quite +long, and uneuphonious to boot) as the software indicator. +MIPS Computers now claims to consider ``RISCOS'' their trigger symbol. +.FE +.NH 2 +platform.cf +.LP +After the header block section has determined which platform-specific +file to use, that file is then included by +.I Imake.tmpl : +.Ds +/**/################################################################ +/**/# platform-specific configuration parameters - edit MacroFile to change +#include MacroIncludeFile +.De +where MacroIncludeFile has been defined properly by the header block. +.LP +The platform file contains definitions needed to make X build and +install correctly on a particular system. +Some common things found here are definitions for the operating +system name version numbers (major and minor), C compiler version +numbers, and workarounds for missing commands. +Overall, these files are really quite a hodgepodge of different things, +and it is difficult to describe them in any general way. +You should read through the +.I .cf +file for your system before you try to compile anything, to get an +idea what can be done with it. +(It doesn't hurt to read +.I all +the +.I .cf +files, as a matter of fact, especially if you are doing a new port.) +.LP +It is important that version numbers in the platform file +accurately reflect your system. +Some symbol values are contingent upon the OS or C +compiler version, to accommodate system changes, deficiencies, or +bugs, so you want to make sure you get the right definitions. +For example, +.I sun.cf +contains the following: +.Ds +#if OSMajorVersion <= 3 +#define HasVoidSignalReturn NO +#else +#define HasVoidSignalReturn YES +#endif +.De +This reflects a change in the return type of the +.I signal() +system call (from +.I int* +to +.I void* ) +on Sun systems beginning with SunOS 4.0. +Ultrix systems underwent a similar change between 3.0 and 3.1 but the +.I ultrix.cf +file doesn't yet reflect the change. +Perhaps in R5. +.LP +A common missing-command workaround occurs for those systems +that have no BSD-compatible +.I install +command, such as in +.I cray.cf : +.Ds +#define InstallCmd sh $(SCRIPTSRC)/install.sh +.De +It is important to set the value of the SystemV symbol to either YES or NO +in the platform file because +(1) the value of parameters defined in +.I site.def +may depend on it, and the default value is not set until +the system/build definition section (i.e., after +.I site.def ); +(2) +the default values of many parameters in later parts of the template +depend on the value of SystemV. +For instance, there is usually no +.I ranlib +under System V, so the default is defined as a no-op: +.Ds +#ifndef RanlibCmd +#if SystemV +#define RanlibCmd /bin/true +#else +#define RanlibCmd ranlib +#endif +#endif +.De +It is perhaps safer to rely on predefined +.I cpp +symbols (should they exist) in the platform-specific files +than in the header block section of +.I Imake.tmpl . +Once you know the system type, the universe of such +symbols is more constrained and their meanings cannot clash with those +of symbols defined on other vendors' systems. +.LP +The platform files were significantly reorganized between R3 and R4. +In R3, each platform file was expected to contain a definition for +each of the build parameters (C compiler, loader, link command, +etc.). +Whenever a change was made that affected one platform file, such as +defining a new symbol, it usually affected them all. +Since the definitions were usually broadly similar across platforms, +this was more work than necessary. +The approach adopted in R4 is to supply best-guess values as the +default definitions for these parameters in the template, which +individual platform files may override as necessary. +This set of defaults defines a baseline configuration. +There are two advantages to this method. +The platform files need only specify where they +.I differ +from the baseline, by overriding the default definitions; and changes or +additions to the baseline usually require retrofitting of only a few +platform files. +.NH 2 +site.def +.LP +This file contains site-specific definitions. +It is used to reflect local site-wide conventions. +Should you wish to override the defaults, +this is the place to indicate installation directories, whether to +build the server and example programs, any special versions of +programs to use during the build, etc. +.LP +The name +.I site.def +seems, to me at least, something of a misnomer. +For instance, one of the things that is likely to be set there +is HasLargeTmp, to indicate whether you have a large temp file +directory. +.I site.def +is the place for this definition (it depends on your particular +file system layout, so it doesn't go in the platform-specific file, +and it's not +.I cpp -guessable, +so it doesn't go in the system description section). +But a ``site'' can be a location at which multiple hosts +are administered, and which may be configured dissimilarly. +Some may have a large temp directory, others may not. +Similarly, +.I site.def +is the logical place to specify that you want to use the GNU C +compiler, +but you might not necessarily want to use it on all hosts at a site. +In some ways +.I host.def +might be a better name for this file. +.NH 2 +System description and build parameter definitions +.LP +The platform- and site-specific files are followed by a section containing +a number of default definitions. +Generally, these describe system characteristics +(e.g., does it have +.I vfork() ? +does it have sockets?) or are related to management of the +build and installation\** +.FS +Viz., +.I how +things should be installed, not +.I where ; +defaults for the latter are in +.I Project.tmpl . +.FE +processes (e.g., what is the name of the C compiler? +does the loader need any special flags?). +These are not X issues and so are segregated into their own section. +.LP +This section of +.I Imake.tmpl +should not be modified; definitions should be overridden +in platform- or site-specific files. +.NH 2 +Project.tmpl +.LP +This +file contains definitions for parameters that are specific to X. +Examples: whether to build debuggable versions of libraries, the +screen resolution, what sorts of connections to accept (UNIX, TCP +or DECnet sockets), where programs or libraries should be installed. +.LP +A number of the +.I make +variables in +.I Project.tmpl +are directory locations. +Most of them are named in one of two ways, \fIXXX\fRDIR or \fIXXX\fRSRC. +Variables of the first form are defined by equating them to the +values +.I cpp +symbols having similar names (e.g., LIBDIR=LibDir). +The +.I cpp +symbols are defined in the usual default-provided-but-override-allowed +manner, +because they refer to where things are to be placed +at installation time, something which the installer might wish to +change. +.LP +Variables of the second form, \fIXXX\fRSRC, indicate the layout of various +source directories within the X distribution. +They are not supposed to be changed, so there is no provision for +overriding them; rather than being equated to +.I cpp +symbols, they are simply defined +directly (e.g., SERVERSRC=$(TOP)/server). +.LP +.I Project.tmpl +should not be modified; definitions should be overridden +in platform- or site-specific files. +.NH 2 +Imake.rules +.LP +This file contains +.I cpp +macros used to generate +.I make +rules from concise descriptions of targets and dependencies. +Since all the +.I cpp +symbol substitution functionality is available, these macros can be +very powerful and are sometimes quite complicated. +.LP +.B Example: +A simple rule to compile a program might be (this isn't an actual X +rule): +.Ds +.ta .5i +4i +# define CompileProgram(program,objects,libraries) +program: objects + cc \-o program objects libraries +.De +If invoked in an +.I Imakefile +as ``CompileProgram (xproga, main.o, \-lm)'', this macro would expand in the +.I Makefile +to: +.Ds +.ta .5i +xproga: main.o + cc \-o xproga main.o \-lm +.De +The invocation +``CompileProgram (xprogb, main.o parse.o scan.o, \-lm \-ll \-ly)'' +would expand to: +.Ds +.ta .5i +xproga: main.o parse.o scan.o + cc \-o xproga main.o parse.o scan.o \-lm \-ll \-ly +.De +There is one problem with these examples, which is that the CompileProgram() +macro definition spans multiple lines, and +.I cpp +macros are normally single-line. +One can can write multiple-line macros by putting a ``\e'' at the end +of lines to be continued onto the next, but this doesn't work for +.I imake's +purpose since +.I cpp +will still collapse the expanded macro onto a single (possibly quite long) +line. +That makes +.I make +quite unhappy. +.LP +To get around this, special place markers ``@@\e'' are used on all +lines of a rule definition but the last. +The ``\e'' allows multiple-line definitions for +.I cpp +and the ``@@'' lets +.I imake +know how to postprocess +.I cpp +output in order to split expanded macros back up into multiple lines +suitable for +.I make . +This keeps both +.I cpp +and +.I make +happy. +.LP +So: +the +.I real +way to write the CompileProgram() macro is: +.Ds +.ta .5i +4i +# define CompileProgram(program,objects,libraries) @@\e +program: objects @@\e + cc \-o program objects libraries +.De +The invocation ``CompileProgram (xproga, main.o, \-lm)'' comes out of +.I cpp +looking like this: +.Ds +xproga: main.o @@ cc \-o xproga main.o \-lm +.De +.I imake +sees the ``@@'' and knows it has to break the line back up to +produce the intended result. +.LP +In short, +the purpose of the strange syntax is to keep +.I cpp +from totally destroying the usefulness of the output for +.I make +purposes. +Thus, although +.I imake +relies heavily on +.I cpp , +one of +.I imake 's +jobs is to undo some of the damage done by +.I cpp \*-an +uneasy alliance indeed.\** +.FS +This use of ``@@\e'' seems quite natural and obvious, now that I have worked +with it for a while. +I remember, though, that the first few times I looked at the X +.I imake +rules, especially the more complicated ones, +the formatting and syntax seemed so bizarre to me that +a switch flipped in my brain, which then refused to comprehend +anything at all. +Repeated exposure gradually inured me to the infelicities of the +syntax. +.FE +.LP +All the macro definitions in +.I Imake.rules +are embedded within the standard override construct: +.Ds +#ifndef \fIrulename\fR +#define \fIrulename\fR .\0.\0. +#endif +.De +Thus, even rules are subject to being overridden. +If a rule needs to be overridden for a particular platform, +the default definition will be placed in the +platform-specific +file (\fIsgi.cf\fR does this). +If a rule only needs redefining in a single directory, it may be +better to undefine it and redefine right it in that directory's +.I Imakefile +(see +.I mit/config/Imakefile +for an example). +.LP +In R3, rule definitions were not bracketed within #ifndef/#endif pairs. +This meant that although individual +.I Imakefiles +could undefine and redefine rules, platform files could not. +Any definition of a rule in a platform file would be unconditionally replaced +by the definition in +.I Imake.rules +(possibly accompanied by a ``symbol redefined'' message). +The R4 architecture is an improvement because it is not +constrained by this limitation. +.LP +.I Imake.rules +should not be modified; definitions should be overridden +in platform- or site-specific files. +.NH 2 +\&./Imakefile +.LP +The last file included by the template is the +.I Imakefile +from the current directory. +As already mentioned, +.I imake +causes +.I make +comments in this file to be made +.I cpp -safe +by preceding them with ``/**/'' if necessary. +The +.I Imakefile +indicates targets to be built and installed, and their +dependencies, in terms of the +.I cpp +macros defined in +.I Imake.rules . +There may also be targets for generating dependencies, creating +installation directories, creating lint libraries or tag files, etc. +.LP +.I Imakefile -writing +is described in more detail in a later section. +.NH 2 +Extra make rules +.LP +The last section of +.I Imake.tmpl +adds some common targets to the +.I Makefile , +such as a ``Makefile'' target to regenerate the +.I Makefile +itself, and default ``tags'' and ``clean'' targets. +If the directory has subdirectories, rules to +recurse through them for the ``install'', ``install.man'', ``clean'', +``tags'', ``Makefiles'' and ``includes'' targets are generated. +These rules are added if the +.I cpp +symbol IHaveSubdirs is defined and the +.I make +variable SUBDIRS is equated to the list of subdirectories in the +.I Imakefile . +.NH +Building imake +.LP +Before you can build any part of X, +.I imake +itself must be built. +``make World'' in the top-level X source directory builds +.I imake +automatically (in +.I mit/config ). +The following discussion explains what happens during that process and +some of the things you may need to do in preparation for the ``World'' +build. +You want to read this section if ``make World'' dies when you try it, or you +want to port X to another platform, +or you want to build +.I imake +or adapt the X configuration files for use with other projects. +You need to look at the following files: +.I Makefile.ini ; +.I imakemdep.h ; +.I Imake.tmpl . +.NH 2 +Determine what you are trying to accomplish +.LP +When you build +.I imake +you want to +(1) get it to compile successfully, so you can use it; +(2) guarantee that it makes sure +.I cpp +knows the trigger symbol\*-whether +.I cpp +predefines it or not\*-so you don't end up with generically-configured +.I Makefiles . +.LP +Conspiring to keep you from your goal are three dilemmas. +.IP \(bu +.I imake +generates +.I Makefiles +for use in compiling programs; +.I imake +is compiled using a +.I Makefile . +.IP \(bu +.I imake +needs to know your system's trigger symbol in order to pass it along to +.I cpp +for proper +.I Makefile +generation. +But +.I imake +doesn't know the trigger itself if neither +.I cc +nor +.I cpp +predefine it. +.IP \(bu +Some systems require special C compiler flags to ensure proper +compilation of all but the most trivial programs. +One of the facilities provided by +.I imake -generated +.I Makefiles +is that these flags can be automatically specified. +Of course, that is small consolation when the program to be compiled is +.I imake \*-which +happens to be just such a non-trivial program itself. +.LP +The solution to the first dilemma is to use a minimal handwritten file +.I Makefile.ini +instead.\** +.FS +There might be a +.I Makefile +in +.I mit/config +already, +but it might not have been generated on your system, so it's not safe to +use. +It has a bug in it, anyway. +.FE +You might need to hack +.I Makefile.ini +file slightly for your system\*-but only slightly. +If you find yourself making large changes, that is a symptom you don't +understand what you're supposed to be doing. +Stop and think some more first. +.LP +The second and third dilemmas are solved by manually passing the trigger symbol +to the +.I imake +compilation and using a small bootstrap program that knows what +special flags are necessary to get +.I imake +to compile without error. +The commands in +.I Makefile.ini +that build +.I imake +look something like this:\** +.FS +The commands actually use CFLAGS, which includes BOOTSTRAPCFLAGS as part +of its definition; you get the idea. +.FE +.Ds +$(CC) \-o ccimake $(BOOTSTRAPCFLAGS) ccimake.c +$(CC) \-o imake $(BOOTSTRAPCFLAGS) imake.c `./ccimake` +.De +BOOTSTRAPCFLAGS is the +.I make +variable used to pass the trigger value for your system to +.I ccimake +and +.I imake +so they know the platform type. +It is typically ``BOOTSTRAPCFLAGS=\-D\fItrigger\fR'' +if your +.I cpp +doesn't predefine the trigger, empty otherwise.\** +.FS +The BOOTSTRAPCFLAGS mechanism was not present in some earlier versions +of X11 (e.g., R1). +The number of systems to which X had been ported then was smaller and +all of them had +.I cpp 's +that predefined a unique symbol. +.FE +.LP +.I ccimake +is the bootstrap program. +It is\*-by design\*-so simple that it should compile +without any special treatment, and is used to figure out any extra +flags needed on your platform to get +.I imake +to compile. +BOOTSTRAPCFLAGS is supplied to the +.I ccimake +build so it can select the necessary flags by platform type. +.LP +.I imake +is built using the flags supplied by +.I ccimake , +so that it compiles correctly, and with the +the trigger value supplied in BOOTSTRAPCFLAGS, +so that it learns and memorizes the trigger for +itself. +When +.I imake +passes the trigger to +.I cpp , +that in turn allows +.I cpp +to properly determine the correct header block in +.I Imake.tmpl +when +.I Makefiles +are generated. +.NH 2 +Lay the groundwork +.LP +First, you need to determine what the trigger symbol is for your system, +as well as the value of BOOTSTRAPCFLAGS. +For existing ports, you can find out the trigger symbol by +examining the header block section of +.I Imake.tmpl . +The value of BOOTSTRAPCFLAGS can be found in the platform +.I .cf +file for your system. +Look for a line that defines BootstrapCFlags; if +.I cpp +predefines the trigger, there will likely be no such line. +This means BOOTSTRAPCFLAGS is empty. +Otherwise the value will probably be ``\-D\fItrigger\fR'', e.g., +``\-DmacII'', ``\-Datt'', ``\-Daix''. +.LP +A complication likely to arise in the future with regard to +predefined preprocessor symbols is that ANSI C takes a dim view of +all (or almost all) such. +BOOTSTRAPCFLAGS is likely +to be non-empty on more systems as implementations of ANSI C become +distributed more widely. +.LP +For new ports, you need to invent a trigger symbol +that uniquely identifies your system and define +BOOTSTRAPCFLAGS accordingly. +Suppose you have a Brand X system. +You can use ``brandx'' as the trigger and ``BOOTSTRAPCFLAGS=\-Dbrandx''. +You also must modify +.I imakemdep.h . +This header file is #include'd by three programs, +.I ccimake , +.I imake +and +.I makedepend , +and has one section for each.\** +.FS +.I Imake.tmpl +contains some comments near its beginning pertaining to new ports. +These indicate that +.I imake.c , +and +.I main.c +in the +.I makedepend +source, should be modified. +These comments are correct for R3 but evidently were not updated for R4; +in both cases the modifications should be made to +.I imakemdep.h . +Similarly, the +.I README +file refers to +.I ccflags.c , +the R3 equivalent of +.I ccimake.c . +.FE +.LP +The first section of +.I imakemdep.h +pertains to +.I ccimake ; +it consists of a bunch of #ifdef/#endif blocks that define +.I imake_ccflags +according to the trigger symbol. +.I imake_ccflags +is defined as the flags needed to compile +.I imake +on your platform. +For instance, if your Brand X system is System V-based, you need to +specify that: +.Ds +#ifdef brandx +#define imake_ccflags "\-DSYSV" +#endif +.De +.I ccimake +simply writes the value of +.I imake_ccflags +to its standard output. +Common flags in this definition are \-DSYSV or \-DUSG to indicate System +V or USG systems. +Other flags might also be necessary\*-see the ``hpux'' and ``umips'' +blocks for some particularly unpleasant examples. +If no special flags are necessary to compile +.I imake +(e.g., under Ultrix or BSD), +there need not be any block for your system, and +.I ccimake +simply writes out a default definition of +.I imake_ccflags +(currently \-O). +.LP +You might have to fool around trying to compile +.I imake +by hand to determine the correct flags before you know how to define +.I imake_ccflags . +.LP +The second section of +.I imakemdep.h +is for +.I imake . +It too has a set of #ifdef/#endif blocks, this time to select a +trigger symbol definition based on the trigger symbol. +That sounds circular and it is. +These blocks add entries to +.I cpp_argv [\|], +which is an array of strings to be passed to +.I cpp +by +.I imake . +If your +.I cpp +predefines the correct trigger symbol automatically, you don't need to +do anything to this. +Otherwise, this is where you want your trigger symbol to be listed, +and there should be a block something like this: +.Ds +#ifdef brandx + "\-Dbrandx", /* for Brand X systems */ +#endif +.De +This causes +.I imake +to pass ``\-Dbrandx'' to +.I cpp +to make it simulate predefinition of the trigger. +When +.I cpp +reads the configuration files the trigger will have been defined and +the correct header block in +.I Imake.tmpl +will be selected. +.LP +Following the sections for +.I ccimake +and +.I imake , +.I imakemdep.h +contains a third section for +.I makedepend +(the compiled version; if you use the shell script version of +.I makedepend +in +.I mit/util/scripts , +this section of +.I imakemdep.h +is irrelevant). +It looks for various system- and compiler-related definitions that may +be predefined by +.I cc +and/or +.I cpp . +.I makedepend +uses this information to be smart. +Consider the following C program fragment: +.Ds +#ifdef ultrix +#include "inca.h" +#else +#include "incb.h" +#endif /* ultrix */ +.De +If ``ultrix'' is defined, +.I makedepend +knows to generate a dependency for ``inca.h'' and not +``incb.h''; +a dumb +.I makedepend +has to to assume dependencies on both. +.LP +It's easiest simply to leave this section of +.I imakemdep.h +alone. +.NH 2 +Build the program +.LP +You're ready to begin (this should actually be simple if you've done +the above correctly). +The first thing to do is ensure the absence of any detritus that might +be laying around from previous builds: +.Ds +make \-f Makefile.ini clean +.De +Then build +.I ccimake +and +.I imake . +If your +.I cpp +predefines the trigger, you can build with: +.Ds +make \-f Makefile.ini +or +make \-f Makefile.ini BOOTSTRAPCFLAGS= +.De +Otherwise, specify the trigger explicitly. +E.g., for Brand X, use: +.Ds +make \-f Makefile.ini BOOTSTRAPCFLAGS=\-Dbrandx +.De .NH 2 +Test your handiwork +.LP +If +.I imake +is supposed to pass a trigger symbol definition to +.I cpp , +you should test whether it actually does or not by executing the +following command (\fB\-T\fI/dev/null\fR provides an empty input template, and +\fB\-s\fI/dev/null\fR throws away the output so it doesn't clobber the +.I Makefile +in your current directory): +.Ds +imake \-v \-T/dev/null \-s/dev/null +.De +.B \-v +causes +.I imake +to print out the +.I cpp +command that it executes. +If you don't see a \-D\fItrigger\fR +in that command, +.I imake +wasn't built properly. +.NH 2 +Modifying other configuration files for a new platform +.LP +If you are developing a new port to another system, +you have to do more than be able to compile +.I imake , +you also need to be able to use it +in conjunction with the configuration files. +First, you must modify the header block section of +.I Imake.tmpl +to add a block for your system.\** +.FS +This is the only section of +.I Imake.tmpl +that should ever need modifying. +Other changes would be specified in the platform-specific file for +your system. +.FE +It will look something like this: +.Ds +#ifdef brandx +#define MacroIncludeFile <brandx.cf> +#define MacroFile brandx.cf +#undef brandx +#define BrandxArchitecture +#endif /* brandx */ +.De +Second, you must create a platform-specific file +.I brandx.cf . +If your bootstrap flags are non-empty, this should contain, at +minimum, ``#define BootstrapCFlags \-Dbrandx''. +Most certainly it will have other things in it, too. +You will discover just what as you go through the process +of porting the server and/or clients. +.NH +Building X Itself, or, When Is BOOTSTRAPCFLAGS Necessary? +.LP +The question addressed in this section is: +how can you get all the +.I Makefiles +built? +(This document is really about configuring X, not building it, and +configuring X amounts to building the +.I Makefiles .) +.LP +If you have gotten this far, you know you can get +.I imake +compiled and can proceed to build X itself. +.I "Before you do anything else," +copy the top-level +.I Makefile +somewhere safe (outside of the source tree). +If something goes wrong and this file gets trashed, +you want to be able to recover it. +You're asking for trouble if you don't. +.LP +The ``do everything'' operation in building X is ``make World''. +It builds +.I imake , +generates all the +.I Makefiles , +removes extraneous object files, builds the header file tree, +generates dependencies, and compiles everything. +The interesting parts of this +from a configuration perspective are the first two steps. +.LP +The important questions are: (1) what is the value of BOOTSTRAPCFLAGS; +and (2) when +must BOOTSTRAPCFLAGS be specified? +You have already answered the first question by determining how to +build +.I imake , +so only the second is considered below. +.LP +When you build +.I imake +``manually'' in +.I mit/config +using +.I Makefile.ini , +you must specify BOOTSTRAPCFLAGS explicitly if it is non-empty. +What about when building from the top-level directory, e.g., ``make +World''? +It is a useful exercise to build +.I imake +by hand to test your understanding of the issues involved, but that +won't help you to do the ``World'' build\*-the first thing +``make World'' does, unfortunately, is throw +.I imake +away and rebuild it from scratch. +.LP +The X Release Notes (section 2) indicate that for +``make World'' you should +specify BOOTSTRAPCFLAGS if you find a definition for BootstrapCFlags in the platform +.I .cf +file (which means there is no unique predefined +.I cpp +symbol). +By implication, you do not need to specify BOOTSTRAPCFLAGS +if there is no value of BootstrapCFlags in your platform +.I .cf +file. +This means essentially that the empty value ``BOOTSTRAPCFLAGS='' is sufficient to +compile +.I imake +properly, which brings up a subtle point. +Each +.I Makefile +created in the X distribution contains a line that says +.Ds +BOOTSTRAPCFLAGS=\fIsomething\fR +.De +where +.I something +is the default value for any +.I make +operation, and may or may not be empty. +Thus, when you execute a command such as +.Ds +make World BOOTSTRAPCFLAGS=\-Dbrandx +.De +you are not just +.I providing +a value of BOOTSTRAPCFLAGS, you are also +.I overriding +the default value in the +.I Makefile . +.LP +The implication that BOOTSTRAPCFLAGS need not be specified if +BootstrapCFlags is +not defined involves a hidden assumption, i.e., that BOOTSTRAPCFLAGS +.I already +has the empty value in the top-level +.I Makefile . +If you obtain your X distribution from a system on which X has been built +and on which BOOTSTRAPCFLAGS is non-empty, that assumption is incorrect. +If you don't explicitly provide an empty value by saying +.Ds +make World BOOTSTRAPCFLAGS= +.De +to override the default in the +.I Makefile , +a value which is incorrect for your system is used instead. +You can get some very strange results this way. +.LP +I submit that, in the general case, the deciding factor determining +whether to specify BOOTSTRAPCFLAGS is not so much whether +BootstrapCFlags is defined or not, but whether you've built your +.I Makefiles +yet. +If not, you need to specify BOOTSTRAPCFLAGS, +.I "even if it's empty." +Otherwise, you don't have to. +In practice, this means that when you are building X on a new system, +you should assume BOOTSTRAPCFLAGS in the +.I Makefile +is incorrect and explicitly override it on the command line. +Normally this will be on the first ``World'' build. +.LP +The Release Notes do not cover the general case. +Rather, they assume you are working from a virgin distribution (where +the default BOOTSTRAPCFLAGS is in fact empty). +.LP +Once the +.I Makefiles +have been built properly, +BOOTSTRAPCFLAGS will be defined correctly in them and +they will take care of propagating the right value +for you automatically\*-forever, even into another operation that +rebuilds +.I imake +and the +.I Makefiles . +You can test this for yourself on a machine that +has a non-empty BOOTSTRAPCFLAGS. +Do ``make World BOOTSTRAPCFLAGS=\-D\fItrigger\fR'', then ``make +World''. +You'll see during the ``make World'' that BOOTSTRAPCFLAGS is supplied for you. +.LP +.B "Note 1:" +It is not necessary to do a ``World'' build to build +.I imake +and the +.I Makefiles ; +there is a ``mastermakefiles'' target that will do so. +This is a far more modest undertaking than doing the ``World'' build +and you can check a few of the +.I Makefiles +afterward to see if the ``World'' build is likely to succeed or not: +If BOOTSTRAPCFLAGS is correct and the correct header block was selected, +you can +then go ahead and do ``make World'' without having to specify BOOTSTRAPCFLAGS. +.LP +.B "Note 2:" +The above discussion assumes that if BOOTSTRAPCFLAGS is not empty, BootstrapCFlags is +defined +correctly in the platform +.I .cf +file, because BOOTSTRAPCFLAGS normally gets its value from that symbol when +.I Makefiles +are generated. +.NH 2 +Alternatives ways of specifying BOOTSTRAPCFLAGS +.LP +There are two alternatives to specifying BOOTSTRAPCFLAGS explicitly +on the +command line when you build +the +.I Makefiles , +both sneaky and both deprecated. +They are mentioned here in order to point out why you shouldn't use +them. +.LP +First, you can edit +.I config/Makefile.ini +manually to set the value of BOOTSTRAPCFLAGS directly. +The reason this is not a good idea is that if you give your X +distribution to somebody else that doesn't have the same kind of +machine, you've given away an explicitly misconfigured +.I Makefile.ini . +The recipient might fail to appreciate the subtle irony of this +gesture. +.LP +Second, you can forget about BOOTSTRAPCFLAGS entirely. +That's correct\*-you can build +.I imake +with wild abandon and total lack of regard for whether it knows about +the correct trigger symbol or not. +``But on some systems, +.I imake +must pass the trigger definition to +.I cpp +explicitly,'' you say, ``and +.I imake +compiled in such a reckless and irresponsible manner may not do the job.'' +Quite right. +However... +.I imake +also examines your environment, and the value of IMAKEINCLUDE, if +defined there, is passed to +.I cpp . +The value of IMAKEINCLUDE must begin with ``\-I'' (or +.I imake +will reject it), but you can be clever and set it +to ``\-I. \-Dbrandx'' and the +trigger symbol will be passed through to +.I cpp +and your +.I Makefiles +will build happily. +.LP +This is sneaky because it uses the environment to affect the +build process in a way that is not evident. +Worse yet, if you actually install an +.I imake +built this way, it won't work for anyone else who isn't privy to the +IMAKEINCLUDE convention. +.LP +(A third alternative is to edit +BOOTSTRAPCFLAGS to the proper value in the top-level +.I Makefile +before ``make World''. +This is functionally equivalent to specifying it on the command line.) +.NH +Imakeconoclasm\*-X configuration bugs +.LP +Given the size of the X project, there are astonishingly few outright +errors in the files involved in the configuration process. +The ones I know about are listed below. +.IP (1) +Assume the following scenario. +You do a ``make World''. +This builds +.I imake , +generates all the +.I Makefiles , +cleans all the directories and finally builds the X stuff. +.IP +Then you decide to do some work in an X directory that requires the +.I Makefile +to be rebuilt, so you execute +``make Makefile''. +What happens? +You might be surprised to observe that +.I imake +is rebuilt before your +.I Makefile +is regenerated. +This reason is that the rules for the ``Makefile'' target check +whether +.I imake +exists, and if not they build it first. +Since the ``World'' build does a clean after generating the +.I Makefiles , +.I imake +was thrown away. +.IP +In fact, +.I imake +will be built the first time ``make Makefile'' is done after the +``World'' build even if the +cleaning had not been done. +The rules that check for +.I imake 's +existence look for +.I Makefile +in +.I mit/config/Makefile.ini +and build +.I imake +with that if it's there. +(It will be because the ``World'' build generates it.) +But the dependency for +.I imake +in +.I Makefile +is +.I imake.o +while the dependency in +.I Makefile.ini +(with which +.I imake +is initially built) is +.I imake.c . +This means that even if +.I imake +is present in +.I mit/config , +it will be built again because +.I imake.o +isn't. +.IP +That isn't actually a bug, but it can be confusing. +Possibly even more confusing than the previous paragraph. +.IP +What +.I is +a bug is that +.I Makefile +in +.I mit/config +does not pass BOOTSTRAPCFLAGS to the +.I imake +compilation. +If your BOOTSTRAPCFLAGS is non-empty, you end up with a bad +.I imake. +The fix is as follows: +.Ds .IP +Change: + DEFINES = $(SIGNAL_DEFINES) +To: + DEFINES = $(SIGNAL_DEFINES) $(BOOTSTRAPCFLAGS) +.De .IP (2) +The IncRoot symbol is defined twice, once in +.I Imake.tmpl +and once in +.I Project.tmpl . +This is a minor nit, since it gets the same value in both files. +However, if you use a copy of the configuration files as a base for your own +projects, you will probably +modify these files and you should be aware that changing the definition in +.I Project.tmpl +has no effect if you leave both definitions in. +.IP (3) +.I makedepend +has some hardwired pathnames in the source code. +This may bite you if you use +.I gcc +or compile on a MIPS system under the BSD environment, or on other +systems that put include files somewhere other than +.I /usr/include . +.IP (4) +The default value of ExecableScripts in +.I Imake.tmpl +should be given a value based on SystemV, not SYSV. +.Ds .IP +Change: + #ifndef ExecableScripts + #ifdef SYSV +To: + #ifndef ExecableScripts + #ifdef SystemV +.De .IP +This is simply for consistency. +Probably the right thing always happens anyway. +.NH +Writing Imakefiles. +.LP +.B +This section is miserably incomplete. +.LP +This section assumes that +.I imake , +.I makedepend +and +.I xmkmf +are installed in a public directory somewhere, which implies the +additional assumption that the +configuration files are installed where +.I xmkmf +can get at them. +Why make these assumptions? +.LP +Normally you work with both an +.I Imakefile +and a +.I Makefile +and after you make changes to the +.I Imakefile , +you do ``make Makefile'' to regenerate the +.I Makefile . +You can use +.I Makefile +to rebuild itself this way because it has a +``Makefile'' target in it containing rules to do so. +.LP +That doesn't work when you're starting from scratch with just +.I Imakefile . +This is where +.I xmkmf +comes in useful. +Once you've written your +.I Imakefile , +you just execute ``xmkmf'' and it will bootstrap a +.I Makefile +for you. +Thereafter you can use ``make Makefile'' when +.I Makefile +needs rebuilding. +.LP +However, in order to bootstrap +.I Makefile , +you need +.I xmkmf . +.I xmkmf +assumes +.I imake +has been built and installed. +If an installed +.I imake +is used, an installed +.I makedepend +must also be used.\** +.FS +To see why, you need to look at the ImakeDependency() and +DependDependency() macros in +.I Imake.rules . +Notice that both macros depend on the value of UseInstalled, so if one +is installed, the other must be as well. +Also see the definitions of IMAKE and MAKEDEPEND in +.I Project.tmpl . +.FE +And if installed versions of +.I xmkmf , +.I imake +and +.I makedepend +are used, they will expect the configuration files to have been +installed. +Hence the assumptions at the beginning of this section. +.LP +Stuff that should go in here. +.Ds +1) ComplexProgramTarget() all, program, install, install.man, depend, + lint, clean (still need CleanTarget()) +2) ComplexProgramTarget_{1,2,3} +3) SimpleProgramTarget() = CPT with only single source file +4) NormalProgramTarget() +.De +.LP +Here is the simplest +.I Imakefile : +.Ds +.ta 1i + \(<- that's it right over there +.De +That was easy. +But what can you do with it? +First, execute ``xmkmf'', and you'll have the corresponding +.I Makefile . +Then you can try a few operations such as ``make +clean'', ``make'', ``make Makefile'' to see what happens. +(Note in particular that last target and observe that +you can get your first +.I Makefile +with ``touch Imakefile; xmkmf''.) +.LP +Since +.I make +actually executes correctly for all of those targets (or should, +anyway), you can see that a lot of structure is supplied for you by +the configuration files. +If you look at the +.I Makefile +generated from the null +.I Imakefile , +you might be surprised by the complexity of it. +.LP +To test the syntactic correctness of your +.I Imakefile : +.Ds +xmkmf ; make Makefile +.De +This builds +.I Makefile +twice. +.I xmkmf +builds the +.I Makefile +from scratch and fails if the configuration is bad. +.I make +builds a new +.I Makefile +using the one built by +.I xmkmf , +and fails if that one is not legal. +(say how that can happen, e.g., spelling errors cause it.) +This should not happen with a null +.I Imakefile , +but it may very well happen when you're writing real ones. +.NH 2 +Miscellaneous Observations +.IP \(bu +Don't forget ``make depend'' after ``make Makefile''. +.IP \(bu +If you intend to use +.I if +or +.I for +constructs in an +.I Imakefile , +you are well advised to copy the way in which they +are used in +.I Imake.rules . +(See the beginning of the +.I Imake.rules +section of the Appendix for some notes on +.I if +constructs.) +.IP \(bu +If you need to pass special \-D's to the C compiler, set the +.I make +variable DEFINES. +If you need to pass special \-I's to the C compiler, set the +.I make +variable INCLUDES. +These will be passed to compilations automatically in CFLAGS +(see definitions of CFLAGS, ALLDEFINES and ALLINCLUDES in +.I Imake.tmpl ). +.IP \(bu +Some rules may not work as you expect after changing +.I Imakefile . +In particular, +problems can occur the first time you try ``make \fItarget\fR'' that +mysteriously disappear the second time. +As an instance of this, +note that the following command lines are not always equivalent: +.Ds +make Makefile Makefiles +make Makefile ; make Makefiles +.De +You normally want to build the ``Makefiles'' target when there are +subdirectories. +Suppose you add a new subdirectory. +This is done by adding it to the definition of +SUBDIRS in the current directory's +.I Imakefile . +You then need to rebuild the +.I Makefile +so that the definition of SUBDIRS is reset, and then rebuild +.I Makefile +in each of those subdirectories. +The first command line above builds the ``Makefiles'' target using the +(old) value of SUBDIRS from the (current) +.I Makefile , +which is incorrect. +The second command line rebuilds the +.I Makefile , +then runs a second +.I make +process to build ``Makefiles''. +The second process sees the (new) value of SUBDIRS in the (new) +.I Makefile , +which includes the new subdirectory, and has the intended result. +.IP +What can be especially confusing is that if you executed ``make +Makefile Makefiles'' twice, it would not do what you expected the +first time, but it +.I would +the second time. +.NH +Courting disaster: How to do the wrong thing +.LP +.I imake +is wonderful for portability when everything is configured +properly. +However, subtle syntax errors in the configuration files are often difficult +to track down when you begin to make any significant changes to them. +This section describes some of the misfortunes that may beset you +should you make so bold as to engage in such an endeavor. +.LP +For X, the source of problems might be in any of +.I Imakefile , +.I Imake.rules , +.I Imake.tmpl , +the platform +.I .cf +file, or +.I site.def . +The most likely candidates are +.I site.def +and the platform file, though, since those are the only ones you're supposed +to edit. +(If you're writing an +.I Imakefile , +add that to the list, too.) +Just remember that the effects of mistakes in the early files may +not be manifest until much later on. +Problems may appear to originate at locations far from the actual +cause. +.IP (1) +.I Makefile +trashing +.IP +A number of problems during ``make Makefile'' can result in a trashed +.I Makefile . +If you have +.I xmkmf +working, you can use that to regenerate the +.I Makefile +after fixing whatever the problem was. +Otherwise you must recover it somehow. +If you have a copy of +.I Makefile +stashed somewhere, you can use that. +If not: +the first thing that ``make Makefile'' does is to move the original +.I Makefile +to +.I Makefile.bak ; +if the new +.I Makefile +isn't created properly, you can +usually recover it with ``cp Makefile.bak Makefile''. +Then you can fix +the problem and try again. +If +.I Makefile.bak +is trashed as well, you can +grab the +.I Makefile +from another directory at the same level and use that (this works because +they both contain the same ``make Makefile'' +rule). +You can also use a +.I Makefile +from a directory at another level, +but you need to edit the line that sets TOP to reflect where the top +project directory is in relation to the current directory. +.IP +Moral: make sure +.I xmkmf +is working first! +.IP (2) +Boolean vs. existent/nonexistent symbols +.IP +Some symbols are used in boolean fashion and are defined as +YES or NO. +They are tested by ``#if \fIsymbol\fR'' or ``#if !\fIsymbol\fR''. +Others are turned on simply by being defined. +They are tested by ``#ifdef \fIsymbol\fR'' or ``#ifndef \fIsymbol\fR''. +Failure to distinquish the sense in which a symbol is used can lead to +problems. +It is necessary to define symbols properly +.I and +to test them properly. +.IP +.B Example: +YES/NO symbols must be defined properly. +SystemV is such a symbol, and the proper test is ``#if SystemV''. +If you use ``#define SystemV'' instead of ``#define SystemV YES'', +thinking that the former will turn it on, you'll +have problems; ``#if SystemV'' turns into just ``#if'' and generates: +.Ds .IP +cpp: /usr/tmp/tmp-imake.\fImmm\fR:line \fInnn\fR: syntax error +.De .IP +.B Example: +YES/NO symbols must be tested properly. +If you test such a symbol with #ifdef, the test will always succeed, +whether the value is YES or NO; the symbol is defined in +.I both +cases. +.IP +.B Example: +Existent/nonexistent symbols must be tested properly. +A symbol such as UseInstalled is simply defined (as nothing) or left undefined. +If you say ``#define UseInstalled NO'', thinking that will turn it +off, you will be surprised. +(The test ``#ifdef UseInstalled'' will succeed.) +.IP +.B Example: +Existent/nonexistent symbols must be properly. +Such a symbol may be defined as nothing. +If you test it, incorrectly, with ``#if symbol'', the test will fail. +Use #ifdef. +.IP (3) +Rule definition problems +.IP +These can occur after ``make Makefile'', if a rule in +.I Imake.rules +is +#define'd with a space between the rule name and the argument list: +.Ds .IP +#define rule(arglist) right +#define rule (arglist) wrong! +.De .IP +.I cpp +will define rulename as ``(arglist)''. +When this happens, you'll see +.Ds .IP +make: line \fInnn\fR: syntax error +.De .IP +and you'll find `` (arglist)'' on line nnn of the +.I Makefile +because ``rule'' wasn't expanded properly (or at least not the way you +expect). +Fix it and try again. +.IP +Other similar errors can occur if rules are defined or used with spaces +anywhere between the end of the macro name to the closing parenthesis of +the argument list. +This is particularly true if a macro argument is used +to generate rule target names or file names. +For example, AliasedLibaryTarget() looks like this: +.Ds .IP +.ta .5i +4i +#define AliasedLibraryTarget(libname,alias) @@\e +AllTarget(lib/**/alias.a) @@\e + @@\e +lib/**/alias.a: lib/**/libname.a @@\e + $(RM) $@ @@\e + $(LN) lib/**/libname.a $@ +.De .IP +If invoked as ``AliasedLibraryTarget(xyz, libxyz)'', this will +expand to: +.Ds .IP +lib libxyz.a: libxyz.a + $(RM) $@ + $(LN) libxyz.a $@ +.De .IP +which won't do very well when +.I make +gets ahold of it. +There will appear to be two targets (not one) having a dependency on +.I libxyz.a \*-and +one of them is itself! +.IP (4) +Failure to supply +.I cpp +symbol default values +.IP +When a +.I make +variable is equated to a +.I cpp +symbol, the +.I cpp +symbol must be defined somewhere, even if it's just +defined as nothing. +Otherwise the make variable will be set to the literal +.I cpp +symbol name. +That is, if you have ``MAKEVAR=CppSymbol'', it must be preceded +somewhere by: +.Ds .IP +#ifndef CppSymbol +#define CppSymbol \fIwhatever\fR /* (``whatever'' might be empty) */ +#endif +.De .IP +or MAKEVAR will end up with the literal value ``CppSymbol''. +.IP (5) +Macro expansion failure +.IP +Suppose you include the following line in your +.I Imakefile +so that a special version of your library will be compiled: +.Ds .IP +DebuggedAndProfiledLibraryObjectrule() +.De .IP +After you regenerate +.I Makefile , +you try to use it and get the message: +.Ds .IP +Make: Must be a separator on rules line \fInnn\fR. Stop. +.De .IP +This is symptomatic of a spelling error. +If you look closely at the +.I Imake.rules +file, you'll find that the rule name is actually spelled +``DebuggedAndProfiledLibraryObjectRule()''. +If you don't spell a rule name correctly, it won't be expanded. +Fortunately, these problems are easy to find, because at least the error +message tells you where to look. +Unfortunately, you can't say ``make Makefile'' after you fix +.I Imakefile , +because the effect of the error is to make your +.I Makefile +unusable. +Use +.I xmkmf . diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/config-wrprc.ms b/web/glasgow/lit2x-0.16/mkworld/docs/config-wrprc.ms new file mode 100644 index 0000000000..21f0036cfe --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/config-wrprc.ms @@ -0,0 +1,691 @@ +.\" format with +.\" xroff -ms % | lpr +.\" +.\" revision date - change whenever this file is edited +.ds RD 24 July 1990 +.nr PO 1.2i \" page offset 1.2 inches +.nr PD .7v \" inter-paragraph distance +.\" +.EH 'Multiple-project Imake'- % -'' +.OH ''- % -'Multiple-project Imake' +.OF 'Revision date:\0\0\*(RD'\s+2\*-DRAFT\*-\s-2'Printed:\0\0\n(dy \*(MO 19\n(yr' +.EF 'Revision date:\0\0\*(RD'\s+2\*-DRAFT\*-\s-2'Printed:\0\0\n(dy \*(MO 19\n(yr' +.\" +.\" I - italic font (taken from -ms and changed) +.de I +.nr PQ \\n(.f +.if t \&\\$3\\f2\\$1\\fP\&\\$2 +.if n .if \\n(.$=1 \&\\$1 +.if n .if \\n(.$>1 \&\\$1\c +.if n .if \\n(.$>1 \&\\$2 +.. +.TL +Using Imake for Multiple Projects +.sp .5v +(document version 1.02) +.AU +Paul DuBois +dubois@primate.wisc.edu +.AI +Wisconsin Regional Primate Research Center +Revision date:\0\0\*(RD +.NH +Introduction +.LP +.I imake +is a tool for generating makefiles and is used to allow software projects +to be configured easily on a wide variety of target machines. +It is distributed with projects such as the X Window System and the Kerberos +authentication system. +The tool +.I makedepend +is typically used in conjunction with +.I imake +to generate dependencies in makefiles. +.I xmkmf +is also used, for bootstrapping makefiles from imakefiles. +.LP +This document describes the particular way +.I imake +is used to configure projects at WRPRC. +The method is patterned after the way +.I imake +is employed in the X Window System (version 11, release 4). +The X11R4 method is significantly more developed than in X11R3. +Presumably, +.I imake +as used in Kerberos (currently at protocol revision 4) +might have been used as a base, but I judged it +unsuitable for two reasons: (i) I learned +.I imake +from studying X, so I'm probably imprinted to it; +(ii) development of the configuration files in Kerberos appears to be +at a more primitive level even than in X11R3. +.LP +The X11R4 approach allows configuration files to be stored either +in a well-known system-wide location (e.g., +.I /usr/lib/config ), +or in a +.I config +directory under the project top-level directory. +.LP +A more-than-passing acquaintance with +.I imake +is assumed here. +Helpful companion documentation includes ``Configuration Management in +the X Window System,'' the configuration and +.I README +files in the X11R4 distribution (in the +.I mit/config +directory), and the WRPRC configuration files (see below for +information on distribution and availability). +.NH +Statement of Problem +.LP +Because of the flexibility +.I imake +provides as a +configuration tool (once you figure out how to use it!), +I had begun to use it on all my projects. +Since these were all developed at the same site, the projects naturally +had quite a bit of configuration information in common. +On the other hand, different projects just as naturally had their own +individual requirements. +.LP +What I had been doing was creating a +.I config +directory in each project directory, with a copy of the configuration files +in each, modified as necessary for the project (otherwise known as ``using +brute force''). +I did not use configuration files in a system-wide location +because of differing project requirements. +At the same time, there was a great deal of redundancy between sets of +configuration files since projects were built and installed +in similar ways. +It seemed rather wasteful and silly not to take advantage of this overlap, +besides the fact that the multiple copies of files contributed to a +maintenance inefficiency when changes were made that affected all projects. +.LP +This (unsatisfactory) situation prompts the question: +how can the number of files to be maintained be minimized and how can +configuration files be shared among projects without sacrificing the ability +to specify project-specific information as necessary? +.NH +Solution to Problem +.LP +Since +.I imake +possessed the ability to look through multiple directories when looking +for configuration files, the simplest solution to the problem seemed to be: +.IP (i) +Create a set of standard configuration files and store them in a well-known +location (referred to here as StdConfigDir). +.IP (ii) +Allow projects to define an alternate configuration directory (referred to +here as ProjConfigDir, typically the +.I config +directory under the project directory). +.IP (iii) +Tell +.I imake +to look through ProjConfigDir, then StdConfigDir for configuration files. +This means changing +.I xmkmf , +which executes +.I imake , +and the configuration file definitions that construct +.I imake +commands. +.LP +In other words, +a standard set of configuration files is created and stored in a well-known +location for use by multiple projects. +However, should it be required, +individual projects place configuration files in their own +.I config +directory, which takes precedence over StdConfigDir when +searching for files. +In the degenerate case, projects need supply nothing if +the standard stuff is sufficient; only files in StdConfigDir will be +used. +.NH +Implementation of Solution +.NH 2 +Imake.tmpl Architecture +.LP +The architecture of the +.I imake +template, +.I Imake.tmpl , +as used in X11R4 is, roughly: +.LP +.DS +.ta 3i +header block section +#include <\fIplatform\fR.cf> (platform-specific definitions) +#include <site.def> (site-specific definitions) +system description, build and installation definitions +#include <Project.tmpl> (project-specific definitions) +#include <Imake.rules> (\fIimake\fR rules) +#include "./Imakefile" (\fIImakefile\fR for current directory) +.DE +.LP +The header block section determines the machine type and the +platform-specific file +.I platform .cf +to be included. +.LP +To accommodate other project-specific files, extra +#include's are introduced into +.I Imake.tmpl . +The resulting modified architecture becomes: +.LP +.DS +header block section +.sp .2v +#include <\fIplatform\fR.pcf> +#include <\fIplatform\fR.cf> +.sp .2v +#include <site.pdef> +#include <site.def> +.sp .2v +system description, build and installation definitions +.sp .2v +#include <Project.ptmpl> +#include <Project.tmpl> +.sp .2v +#include <Imake.prules> +#include <Imake.rules> +.sp .2v +#include "./Imakefile" +.DE +.LP +The header block section now additionally determines the name of the +project-specific platform file +.I platform .pcf. +.LP +The modification is based on the notion of override files. +Before any of the platform, site, project or rules +files are included, another related file is +included which may contain project-specific information. +Standard versions of these project-specific files +.I *.pcf , ( +.I site.pdef , +.I Project.ptmpl +and +.I Imake.prules ) +are present in +StdConfigDir (to prevent file-inclusion errors) but they are all empty. +If a given project has special configuration requirements, it may +supply its own private versions of any of these files in its +.I config +directory. +Since +.I imake +will search that directory before StdConfigDir, the standard (empty) +versions will be overridden. +The project does not have to actually replace them. +.LP +.B "Example 1:" +At the one extreme, when a project has +no special project-specific configuration requirements (no +.I config +directory, or an empty one), +only the files in StdConfigDir are used to create makefiles. +Since the default project-specific files are empty, the new +architecture of +.I Imake.tmpl +is functionally equivalent to the old. +At the other extreme, a project can replace +.I all +the configuration files; nothing from StdConfigDir is used then. +.LP +.B "Example 2:" +The standard +.I site.def +file might be used by the system administrator to set the value of +BinDir to the directory in which programs are installed. +A project might want them installed somewhere else; this could be done +by defining BinDir in the project-specific site file +.I site.pdef +to override the value in +.I site.def . +.LP +.B "Example 3:" +Override files may also be used to extend the standard configuration +by defining symbols not appearing at all in the standard files. +For instance, if some programs were to be installed in the standard +BinDir, but others were to be installed in a private directory, a +symbol such as ProjBinDir could be defined for the latter purpose in +.I Project.ptmpl . +.LP +One bothersome thing about this architecture is the naming of +.I Project.tmpl +and +.I Project.ptmpl . +If +.I Project.tmpl +contains ``project-specific'' information, then what does +.I Project.ptmpl +contain? +``Project-project-specific'' information? +Ugh. +I prefer to consider +.I Project.tmpl +to contain ``standard'' (i.e., best-guess) project configuration +parameters, and +.I Project.ptmpl +to contain the parameters which actually are specific to a given project. +.LP +The disadvantages of this architecture are obvious: +.IP \(bu +.I Imake.tmpl +is somewhat more complex. +.IP \(bu +StdConfigDir must be populated with the additional +.I *.pcf , +.I site.pdef , +.I Project.ptmpl +and +.I Imake.prules +files (although this is easy since they are all empty). +.LP +The advantages are: +.IP \(bu +Configuration information is centralized, but flexibility is maintained. +Projects may +override definitions in the the standard configuration files +without replacing those files directly, and multiple projects may use +files in StdConfigDir cooperatively without interfering with each other. +.IP \(bu +Override files minimize the need for individual +projects to modify the standard non-project specific files +.I Imake.tmpl , ( +.I *.cf , +.I site.def , +.I Project.tmpl +and +.I Imake.rules ) +directly. +The philosophy underlying the architecture is that the standard files +describe a common ``baseline'' configuration, and +individual projects need specify configuration information (using +private +.I *.pcf , +.I site.pdef , +.I Project.ptmpl +and +.I Imake.prules +files) only to the extent that they +.I differ +from the standard. +.IP \(bu +When improvements are made to the standard files, the changes are +immediately available to any project using them via a normal +configuration step, i.e., ``make Makefile;make Makefiles''. +(Of course, it also becomes possible to break a lot of projects if an +erroneous change is made.) +.IP \(bu +Overall, fewer files need to be maintained, and less space is used. +.NH 2 +Other Changes +.LP +.I xmkmf +is used to bootstrap makefiles from imakefiles. +To accommodate the above scheme, it was +modified from the version distributed with X11R4 to search the project's +.I config +directory, then the standard configuration directory +(i.e., ProjConfigDir then StdConfigDir, not just StdConfigDir). +.LP +The definition of the makefile variable IMAKE_CMD in the configuration +files was also changed: +.LP +.DS +Old (from X11R4): +#ifdef UseInstalled + IRULESRC = $(CONFIGDIR) + IMAKE_CMD = $(IMAKE) -DUseInstalled \e + -I$(IRULESRC) \e + $(IMAKE_DEFINES) +#else + IRULESRC = $(CONFIGSRC) + IMAKE_CMD = $(NEWTOP)$(IMAKE) \e + -I$(NEWTOP)$(IRULESRC) \e + $(IMAKE_DEFINES) +#endif +.DE +.\" allow page break here if necessary... +.DS +New: +#ifdef UseInstalled + IMAKE_CMD = $(IMAKE) -DUseInstalled \e + -I$(NEWTOP)$(PROJCONFIGDIR) \e + -I$(STDCONFIGDIR) \e + $(IMAKE_DEFINES) +#else + IMAKE_CMD = $(NEWTOP)$(IMAKE) \e + -I$(NEWTOP)$(PROJCONFIGDIR) \e + -I$(STDCONFIGDIR) \e + $(IMAKE_DEFINES) +#endif +.DE +.LP +The old rule determines whether to use versions of +.I imake +(and +.I makedepend ) +already installed in public directories or +build them in the source tree based on whether UseInstalled is defined or not. +That symbol also determines where to look for configuration files and +defines the value of IRULESRC accordingly. +If UseInstalled is undefined, searches look in CONFIGSRC, the project's +.I config +directory, otherwise in CONFIGDIR, the standard configuration directory. +.LP +This behavior is unsuitable for the purposes described here, since both of +those directories should be searched, if they exist. +The new rule makes UseInstalled relevant only for determining where +to find (and possibly build) +.I imake +and +.I makedepend , +not where to look for configuration files. +.NH +Test of Implementation +.LP +After making the changes described above, a flight test was arranged. +Nine projects developed under six different logins were converted to use +the standard files. +Projects supplied override files where necessary. +These projects were all initially developed using configuration files +that bore a +fairly strong relationship to the standard set, so it was expected +that conversion would not be unbearably odious. +The degree of relationship broke down as follows: +.IP \(bu +Two projects used configuration files that were identical (or nearly +so) to the standards. +Each of these projects, unlike the other seven, comprised only a +single source directory. +As expected, conversion was completely trivial, once the top-level +.I Makefile +was rebuilt with +.I xmkmf . +.IP \(bu +Four projects required additional project-specific specification +beyond the standard configuration +(special include file directories, link libraries, +installation directories, etc.). +These usually required only +.I site.pdef +and +.I Project.tmpl +files in their local +.I config +directories. +One project required a +.I platform.pcf +file. +Project owner and group names (used for install operations) were moved +out of +.I site.def +files into +.I site.pdef . +.IP \(bu +Three projects diverged from the standard files fairly significantly, +because although their configuration files were initially set up from +files similar to the standards, less effort had been exerted to keep +them in sync as project development progressed. +Besides the changes made to the projects described in the previous +paragraph, there were additional special commands for compilation, special +.I Imakefile +rules, etc. +Nevertheless, conversion proceeded smoothly and without incident. +.LP +One thing I had done in the original +.I Project.tmpl +files was to define certain +makefile variables directly (e.g., ``INCLUDESRC=$(TOP)/h''), rather +than by using a previously #define'd +.I cpp +symbol (e.g., ``INCLUDESRC=IncludeSrc'', where IncludeSrc is #define'd +within a #ifndef/#endif block). +This was a short-cut, that works in a non-shared environment but +needed to be fixed to work in a shared environment. +A default value of IncludeSrc needs to be placed in +.I Project.tmpl , +and individual projects redefine that symbol as necessary in +.I Project.ptmpl . +.LP +It was necessary to place a number of +.I cpp +symbol definitions in +.I Project.tmpl +within #ifndef/#endif blocks, since they became liable to being +overridden in +.I Project.ptmpl . +.LP +In the top-level imakefiles for the multiple source directory +projects, the ``make World'' rules had to be adjusted to account for +whether UseInstalled is defined or not. +If so, the build process does not need to try to build +.I imake +and +.I makedepend +in the project source tree. +(That would be a mistake since the source for those programs would not +necessarily be present.) +.LP +Overall, conversion was simple and straightforward. +I judged the conversion odiousness coefficient acceptably low. +.NH +Another Problem\*-Project Groups +.LP +The mechanism described above allows a group of similarly-configured +projects to share configuration files and selectively extend or +override them as necessary. +This provides a solution to the original problem (how to avoid +maintaining multiple full sets of files while maintaining flexibility), +but leads to another. +Suppose that instead of a group of projects, there exist several +groups of projects, such that projects within a group are similar, but +differences between groups are quite large. +This can happen, for instance, if projects designed and developed at one +site under certain conventions are installed at another +site where different conventions are used. +.LP +The difficulty here is that there are two sets of ``standard'' configuration +files, and they cannot both be installed in the same well-known +location. +This problem can be overcome quite simply. +Instead of using StdConfigDir as the single well-known location in which +the standards are installed, define StdConfigPath to be that +directory, and use it as the root of a set of +subdirectories, each of which corresponds to a project group. +Each group's standard configuration files are installed in the appropriate +directory, and StdConfigDir for a given project group +will be defined as that directory (e.g., StdConfigPath/\fIabc\fR for +project \fIabc\fR). +.LP +To allow +.I xmkmf +to be used for bootstrapping, +it was modified slightly again to select +one of the subdirectories as the hardwired-in default, but allow +another to be selected through a +.B \-C +option. +For convenience, the argument following +.B \-C +may be absolute or relative. +If absolute, it is used unchanged. +If relative, StdConfigDir is prepended. +.LP +This modification makes +.I xmkmf +incompatible with the version distributed with X11R4, which is a +problem for sites using that version. +Assuming X configuration files are installed in +.I /usr/lib/X11/config +and the value of StdConfigPath is +.I /usr/lib/config , +this incompatibility can be obviated as follows: +.LP +.DS +mkdir /usr/lib/config +cd /usr/lib/config +ln -s /usr/lib/X11/config X11 +ln -s X11 default +.DE +.LP +For sites without symbolic links, the files in +.I /usr/lib/X11/config +can be copied into +.I /usr/lib/config/X11 , +and +.I xmkmf +can be hacked to use +.I /usr/lib/config/X11 +instead of +.I /usr/lib/config/default +as the default. +Ugly, but workable. +(Also known as ``crude, but effective''.) +.LP +With these conventions, +projects within groups can share redundant information, as before, and +project groups can coexist peacefully. +.LP +The nine projects previously converted were tested against these +additional modifications. +They required only ``xmkmf;make Makefile;make Makefiles'' to properly +reset the configuration information in the makefiles. +.NH +Distribution of Projects +.LP +The mechanism described in this document appears to solve +the problem of reusing +configuration files while allowing for extension and override within +individual projects. +However, when a project is packaged for distribution, it's very little +use to include only those configuration files which are unique to the +project, if the receiving site doesn't have the standard files. +Several alternatives come to mind. +.IP \(bu +Provide the standards as a separate distribution, along with the +sources to +.I imake +and +.I makedepend . +This is perhaps inconvenient for the receiver, as it is another +distribution that needs to be retrieved. +.IP \(bu +Copy all the standard files into the project's +.I config +directory and distribute along with the project. +One has to be careful when doing the copying not to destroy the +project's override files, +the resulting distribution size is larger, and +distributing the standards is unnecessary if receiving site +has them already. +Also, it is not clear which files are actually unique to the project +when this is done. +.IP \(bu +Keep the project's unique configuration files in +.I config +(where they are normally anyway), and copies of the standard files in +.I config-std . +If the receiver has the latter already, they can be jettisoned easily, +otherwise installed in the project's StdConfigDir. +.LP +It is unclear whether any of these has any compelling advantage over +the others. +.NH +Beginning New Projects +.LP +If a new project has special configuration requirements, a file +.I README.{project-name} +should be created in +.I config +explaining what they are. +.NH 2 +Define UseInstalled, or Not? +.LP +If a project wants to use the installed versions of +.I imake +and +.I makedepend , +the initial makefile should be created from the the imakefile by executing +.I xmkmf +with no arguments (or just +.B \-C +.I configdir ) +in the project top-level directory. +This will cause -DUseInstalled to be passed to +.I imake +which will in turn cause the version of IMAKE_CMD that +includes -DUseInstalled to be selected from the configuration files. +Thus -DUseInstalled will propagate nicely through all future ``make Makefile'' +operations. +.LP +If +.I imake +and +.I makedepend +are to be built in the project source tree, UseInstalled should not be defined, +and you must have the source under the project. +.I imake +source is in +.I config +and +.I makedepend +source is in +.I util/makedepend +or +.I util/scripts , +depending on the definition of UseCCMakeDepend. +Execute ``xmkmf \fB.\fR'' (note the \fB.\fR!) in the project top-level +directory. +This will run +.I imake +without -DUseInstalled, and the proper IMAKE_CMD in the config +files will be selected. +.LP +One problematic aspect of +.I xmkmf +is that it really should always pass -DUseInstalled, since it assumes there +is an installed version of +.I imake +anyway (it doesn't specify a path to it). +But then the problem becomes how to turn UseInstalled off later? +You can't run ``make Makefile'' because the version of IMAKE_CMD that +uses -DUseInstalled has already been selected. +.NH +Distribution and Availability +.LP +The standard WRPRC configuration files are (or will be soon) +available for anonymous +.I ftp +access in the +.I ~ftp/pub/imake-stuff +directory, in file +.I config-WRPRC.shar.Z +on host +.I indri.primate.wisc.edu +(Internet address 128.104.230.11). +These files illustrate the concepts discussed in this document. +.LP +This distribution also includes parts of the X11R4 +.I mit/util +source tree (where +.I makedepend +and +.I xmkmf +are found) as well as +.I msub , +a locally-developed utility for yanking the values of +variables directly from makefiles to produce target files from templates. +.LP +The X11R4 configuration files are in the same directory, in +.I config-X11R4.shar.Z . diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/imake-moraes.tex b/web/glasgow/lit2x-0.16/mkworld/docs/imake-moraes.tex new file mode 100644 index 0000000000..afcc96b846 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/imake-moraes.tex @@ -0,0 +1,884 @@ +% Document type: LaTeX +% +% $Header: imake.tex,v 1.1 89/02/25 03:25:37 moraes Exp $ +% +% Copyright 1986, Mark Moraes +% May be freely used for non-commercial purposes provided acknowledgement +% to the source is given. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%\documentstyle[fullpage,notes]{article} +\documentstyle[fullpage]{article} +%\documentstyle[dvidoc]{article} + +\title{An {\em Imake} tutorial} + +\author{Mark Moraes, Computer Systems Research Institute,\\ +University of Toronto\\ +moraes@csri.toronto.edu} +\date {Revised \today} + +\begin{document} +\maketitle + +{\em {\tt \$(TOP)} in the document refers to the top level directory +of the X Windows source tree.} + +\section{Introduction} {\em Imake} is a tool for generating Makefiles +\footnote{Familiarity with the {\em make} program and C preprocessor +syntax is assumed in this document. Those unfamiliar with these are +advised to read their system manuals for {\em make} and {\em cpp} and +experiment with them} for large software distributions. + +{\em Imake} uses the C preprocessor on macro-makefiles (called {\em +Imakefiles}) to generate Makefiles. It uses a predefined template file +for default values and macros. The {\em imake} program is part of, and +used by the X Windows System software distribution. (The following +description uses fragments from the X Windows distribution as examples +--- you might want to look at the files in {\tt +\$(TOP)/config} for more detailed information. The source +code for {\tt imake} is in {\tt \$(TOP)/util/imake}, and includes a {\tt +sample.rules} file as well as a manual page) + +This document attempts to provide a working introduction to {\em +imake}. In particular, it provides an annotated tour of some of the +relevant files, and through some example {em Imakefiles}. For a more +precise description of {\em imake}'s workings, see the manual page. + +\section{Why {\em Imake}} + +Makefiles have some limitations for large software distributions, +distributed over multiple directories, viz. + +\begin{itemize} + +\item A single makefile doesn't handle multiple directories well, + which means that each directory needs a makefile. At that + point, to change a default value, for example the directory + where the binaries are to be installed, you have to change all + the makefiles. + +\item Typically, makefiles are used to achieve a limited set of + actions, like create a binary from a set of object files, or + generate a library from some object files, etc. These can be + encapsulated in rules that are slightly more complex that the + ones {\em make} supports (which are only suffix based) + +\item A production makefile which supports all the actions necessary + for a development environment, can get fairly long --- + typically, you want a {\em clean} target, an {\em install} + target, a {\em depend} target, and an {\em all} target. + +\item For a system that is ported to many different systems, there are + bound to be differences in the requirements of the systems, + that cannot be dealt with solely at the C source level. For + instance, some System V Unix \footnote{Unix is a trademark of + AT\&T} machines provide a BSD compatibility library which must + be linked in with {\tt -lbsd}, and BSD includes that must the + C compiler must be told about with a {\tt -I/usr/include/bsd + option}. Vanilla {\em make} allows no facilities for changes + like this, and you end up having multiple makefiles, with + suffixes to indicate the type of system being used. +\end{itemize} + +\section{A simple example} +For example, for a simple program, {\tt xcalc}, the Imakefile looks something +like: + +\begin{quote} +\begin{verbatim} + LOCAL_LIBRARIES = $(XLIB) + SYS_LIBRARIES = -lm + #ifdef MacIIArchitecture + DEFINES = -DIEEE + #endif /* MacIIArchitecture */ + SRCS = xcalc.c sr.c + OBJS = xcalc.o sr.o + + ComplexProgramTarget(xcalc) +\end{verbatim} +\end{quote} + +This will generate a Makefile which will contain an {\tt all} target, +and an {\tt xcalc} target, both of which will result in the program +{\tt xcalc} being compiled and linked. The Makefile will also contain +an {\tt install} target, which will install the binaries in specified +destination directories, an {\tt install.man} target, which will +install the manual pages for the program, a {\tt clean} target, which +will remove all compiler generated files, editor backup files, etc., +and a {\tt depend} target which will invoke the {\em makedepend} +program to generate Makefile depenencies. + +It will also contain a {\tt Makefile} target, so you only need to type +{\tt make Makefile} to regenerate the Makefile should the Imakefile +change. + +The real work lies in {\tt ComplexProgramTarget}, which is defined in +the template as a {\tt \#define} macro, which expands out to the make +rules needed to generate program {\em xcalc}, from the variables {\tt +SRCS} and {\tt OBJS}. Let's take a look at that particular rule. + +\begin{quote} +\begin{verbatim} +/* + * This target is the general interface for building a single program + */ +#define ComplexProgramTarget(program) @@\ + PROGRAM = program @@\ + @@\ +AllTarget(program) @@\ + @@\ +program: $(OBJS) $(LOCAL_LIBRARIES) @@\ + $(RM) $@ @@\ + $(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES) @@\ + @@\ +relink:: @@\ + $(RM) $(PROGRAM) @@\ + $(MAKE) $(MFLAGS) $(PROGRAM) @@\ + @@\ +InstallProgram(program,$(BINDIR)) @@\ +InstallManPage(program,$(MANDIR)) @@\ +DependTarget() @@\ +clean:: @@\ + $(RM) $(PROGRAM) +\end{verbatim} +\end{quote} + +Ignoring {\tt AllTarget()} for now, we see that {\tt program} is +defined to depend on the {\tt OBJS}, and {\tt LOCAL\_LIBRARIES}, and to +make it, the old version is removed (a precaution to save disk space, +among other things), and then, {\tt program} is linked from {\tt OBJS}, +{\tt LOCAL\_LIBRARIES}, and {\tt SYSLAST\_LIBRARIES}. ({\tt LDFLAGS} +are link flags) + +An additional target {\tt relink::} is also generated, which can be +used if libraries change. {\tt InstallProgram} generates the the +{\tt install::} target, which puts the program in {\tt BINDIR}, +{\tt InstallManPage} installs the manual page, {\tt DependTarget} generates +the target for {\em make depend} which invokes a {\em makedepend} +program to follow all {\tt \#includes} in the source. These macros are +listed below --- they aren't very complex. + +\begin{quote} +\begin{verbatim} +/* + * Install a man page. + */ +#define InstallManPage(file,dest) @@\ +InstallManPageLong(file,dest,file) + +/* + * Install a program + */ +#define InstallProgram(program,dest) @@\ +install:: program @@\ + $(INSTALL) -c $(INSTALLFLAGS) program dest + + +/* + * This makes the depend target given OBJS. + */ +#define DependTarget() @@\ +depend:: $(DEPEND) @@\ + @@\ +depend:: @@\ + $(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS) @@\ + @@\ +$(DEPEND): @@\ + @echo "making $@"; \ @@\ + cd $(DEPENDSRC); $(MAKE) @@\ + + +#define AllTarget(depends) @@\ +all:: depends +\end{verbatim} +\end{quote} + +Note the use of make variables like {\tt \$(INSTALL)} to describe +programs that are used - this makes it possible to define these in the +templates, and thus enhances portability. + +Also, note that the make targets use a conditional dependency branch +with double colons (::) rather than the more common single colon (:). +This allows multiple make targets. + +Based on all this, the Imakefile expands to the following Makefile: + +\begin{quote} +\begin{verbatim} +LOCAL_LIBRARIES = $(XLIB) + SYS_LIBRARIES = -lm + + SRCS = xcalc.c sr.c + OBJS = xcalc.o sr.o + + PROGRAM = xcalc + +all:: xcalc + +xcalc: $(OBJS) $(LOCAL_LIBRARIES) + $(RM) $@ + $(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES) + +relink:: + $(RM) $(PROGRAM) + $(MAKE) $(MFLAGS) $(PROGRAM) + +install:: xcalc + $(INSTALL) -c $(INSTALLFLAGS) xcalc $(BINDIR) + +install.man:: xcalc.man + $(INSTALL) -c $(INSTMANFLAGS) xcalc.man $(MANDIR)/xcalc.n + +depend:: $(DEPEND) + +depend:: + $(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS) + +$(DEPEND): + @echo "making $@"; \ + cd $(DEPENDSRC); $(MAKE) + +clean:: + $(RM) $(PROGRAM) +\end{verbatim} +\end{quote} + + +We've omitted a few standard definitions for {\tt CFLAGS, CC, DEPEND, +INSTALL, RM, LDFLAGS} etc. These are installation and system +dependent, and form part of the Imake template. They will precede the +above text. + +\section{Generating the Makefile for the first time} + +Invoking {\em Imake} for the first time is a little complex because +you have to tell it where to find the template, as well as define the +top level directory. The simplest way to do it is to use the {\tt ximake} +script that should have been installed along with the rest of +{\tt X} and {\tt imake}. The invocation is simply +\begin{quote} +{\tt ximake} +\end{quote} + +\section{The {\em Imake} template} + +For a more portable setup, it is possible to split the template file +into the following components: +\begin{itemize} +\item the rules +\item the system-dependent macros, which vary depending on the + specific architecture/operating-system combination, things + like the compiler name, flags. +\item the site dependent variables --- where to install the + binaries, libraries etc. +\end{itemize} + +For example the X distribution has an {\tt Imake.rules} file, which +defines various rules like {\tt ComplexProgramTarget()}, system +dependent files of the form {\em machinetype}{\tt .cf}, eg. {\tt +sun.cf, ultrix.cf}, ..., and a site dependent variables file called +{\tt site.def}. The template looks something like the following: (This +is abbreviated to keep the flavour but omit much detail, deemed +unnecessary for the purposes of this tutorial --- annotations in C +style comments) + +\begin{quote} +\begin{verbatim} +#ifdef sun +#define MacroIncludeFile "sun.cf" +#define MacroFile sun.cf +#undef sun +#define SunArchitecture +#endif /* sun */ + +/* + * The macrofile sun.cf contains definitions specific to Sun + * machines --- examples from it are after this file + */ +/**/########################################################################### +/**/# platform-specific configuration parameters - edit MacroFile to change +#include MacroIncludeFile + +/**/########################################################################### +/**/# site-specific configuration parameters - edit site.def to change +#include "site.def" + +/***************************************************************************** + * * + * DEFAULT DEFINITONS * + * * + * The following section contains defaults for things that can be overridden * + * in the various .macros files and site.def. DO NOT EDIT! * + * * + ****************************************************************************/ + +#ifndef SystemV +#define SystemV NO /* need system 5 style */ +#endif +#ifndef BuildServer +#define BuildServer YES /* go ahead and build server */ +#endif +#ifndef UnalignedReferencesAllowed +#define UnalignedReferencesAllowed NO /* if arbitrary deref is okay */ +#endif +#ifndef BourneShell /* to force shell in makefile */ +#define BourneShell /bin/sh +#endif + +/* + * Lots and lots more variables that can be overridden in the site.def + * including: + */ + +#ifndef DestDir +#define DestDir /* as nothing */ +#endif +#ifndef UsrLibDir +#define UsrLibDir $(DESTDIR)/usr/lib +#endif +#ifndef BinDir +#define BinDir $(DESTDIR)/usr/bin/X11 +#endif +#ifndef IncDir +#define IncDir $(DESTDIR)/usr/include/X11 +#endif +#ifndef IncRoot +#define IncRoot $(DESTDIR)/usr/include +#endif +#ifndef AdmDir +#define AdmDir $(DESTDIR)/usr/adm +#endif +#ifndef LibDir +#define LibDir $(USRLIBDIR)/X11 +#endif +#ifndef LintlibDir +#define LintlibDir $(USRLIBDIR)/lint +#endif +#ifndef FontDir +#define FontDir $(LIBDIR)/fonts +#endif + +/* + * This is followed by the actual definitions that will appear in the + * Makefile, again, the list is partial. + */ +/* + * This list must be reflected in the DIRS_TO_BUILD list in the top-level + * Makefile. + */ + DESTDIR = DestDir /* root of install */ + USRLIBDIR = UsrLibDir /* libraries */ + BINDIR = BinDir /* programs */ + INCDIR = IncDir /* header files */ + INCROOT = IncRoot /* base for header files */ + ADMDIR = AdmDir /* server log files */ + LIBDIR = LibDir /* rgb, XErrorDB, etc. */ + LINTLIBDIR = LintlibDir /* lint libraries */ + FONTDIR = FontDir /* font directories */ + + CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) + LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT + LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES) + TOP = TOPDIR +#ifdef CompileWithInstalled + EXTENSIONLIB = $(USRLIBDIR)/lib/libXext.a + XLIB = $(USRLIBDIR)/libX11.a + XMULIB = $(USRLIBDIR)/libXmu.a + OLDXLIB = $(USRLIBDIR)/liboldX.a + XTOOLLIB = $(USRLIBDIR)/libXt.a + XAWLIB = $(USRLIBDIR)/libXaw.a + INCLUDES = -I$(INCDIR) -I$(INCROOT) +#else /* ! CompileWithInstalled */ + EXTENSIONLIB = $(EXTENSIONSRC)/lib/libXext.a + XLIB = $(XLIBSRC)/libX11.a + XMULIB = $(XMUSRC)/libXmu.a + OLDXLIB = $(OLDXLIBSRC)/liboldX.a + XTOOLLIB = $(TOOLKITSRC)/libXt.a + XAWLIB = $(AWIDGETSRC)/libXaw.a + INCLUDES = -I$(TOP) +#endif /* CompileWithInstalled */ + +/* + * The above fragment illustrates how different makefiles can be + * generated for the distribution, presumably, once with + * CompileWithInstalled not defined in site.def, so that the + * distribution can be bootstrapped and built for the first time, then + * with CompileWithInstalled defined in site.def so that it uses the + * already installed libraries instead of requiring the compiled + * objects remain forever in src directories + */ + + MACROFILE = MacroFile + ICONFIGFILES = $(IRULESRC)/Imake.tmpl \ + $(IRULESRC)/$(MACROFILE) $(IRULESRC)/site.def + IMAKE_DEFINES = /* leave blank, for command line use only */ + IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl -I$(NEWTOP)$(IRULESRC) \ + -s Makefile $(IMAKE_DEFINES) + +/* + * Now include the actual rules file --- this contains the definitions + * of macros like ComplexProgramTarget, as described earlier + */ + +#include "Imake.rules" + +/* + * INCLUDE_IMAKEFILE is defined by the imake program to be the name of + * the Imakefile you are processing, usually just Imakefile. It + * gets included here. + */ +/**/########################################################################### +/**/# start of Imakefile +#include INCLUDE_IMAKEFILE + +/* + * Followed by some basic rules for all Makefiles, especially useful + * for Imakefiles where all you want to do is make the subdirectories. + */ +/**/########################################################################### +/**/# Imake.tmpl common rules for all Makefiles - do not edit +/* + * These need to be here so that rules in Imakefile occur first; the blank + * all is to make sure that an empty Imakefile doesn't default to make clean. + */ +emptyrule:: + +CleanTarget() +MakefileTarget() +TagsTarget() + +#ifdef IHaveSubdirs + +/**/########################################################################### +/**/# rules for building in SUBDIRS - do not edit + +InstallSubdirs($(SUBDIRS)) +InstallManSubdirs($(SUBDIRS)) +CleanSubdirs($(SUBDIRS)) +TagSubdirs($(SUBDIRS)) +MakefileSubdirs($(SUBDIRS)) + +#else + +/**/########################################################################### +/**/# empty rules for directories that do not have SUBDIRS - do not edit + +install:: + @echo "install done" + +install.man:: + @echo "install.man done" + +Makefiles:: + +#endif /* if subdirectory rules are needed */ + +/**/########################################################################### +/**/# dependencies generated by makedepend +\end{verbatim} +\end{quote} + +The {\tt Sun.macros} file looks something + +\begin{quote} +\begin{verbatim} +#define SunOSPlatform YES /* set to NO if not running SunOS */ +#define OSName SunOS 3.5 +#define OSMajorVersion 3 +#define OSMinorVersion 5 + +/**/# platform: $XConsortium: Sun.macros,v 1.52 88/10/23 11:00:55 jim Exp $ +/**/# operating system: OSName + +#if SunOSPlatform && OSMajorVersion == 3 && OSMinorVersion <= 2 +#define OptimizedCDebugFlags /* as nothing */ +#endif + +BOOTSTRAPCFLAGS = + AS = as + CC = cc + CPP = /lib/cpp + LD = ld + LINT = lint + INSTALL = install + TAGS = ctags + RM = rm -f + MV = mv + LN = ln -s + RANLIB = ranlib +RANLIBINSTFLAGS = -t + AR = ar clq + LS = ls + LINTOPTS = -axz + LINTLIBFLAG = -C + MAKE = make +STD_CPP_DEFINES = + STD_DEFINES = + +/* This defines the server you want */ +#define XsunServer Xsun +\end{verbatim} +\end{quote} + +There's more in the macros file but the rest of the definitions are X +dependent. + +Most of the definitions shown here can be overridden in the {\tt +site.def} file, so a system administrator can completely reconfigure +the setup, if necessary. + +\section{Simple Imakefiles} + +We end with a few simple examples to illustrate the rules in the X +Imake.rules. + +\subsection{A single program, one source file} + +The first is for a simple program that has only one source file {\tt +xstring.c} and a corrsponding manual page {\tt xstring.man} It +requires the libraries {\tt XAWLIB, XTOOLLIB, and XLIB} (the X Athena +widgets, the X Toolkit, and the C library interface to X). + +\begin{quote} +\begin{verbatim} +LOCAL_LIBRARIES = $(XAWLIB) $(XTOOLLIB) $(XLIB) + +SimpleProgramTarget(xstring) +\end{verbatim} +\end{quote} + +\subsection{A single program, multiple source files} + +A slightly more complex Imakefile is the one for {\tt xcalc}, the +example described earlier. + +\begin{quote} +\begin{verbatim} +LOCAL_LIBRARIES = $(XLIB) + SYS_LIBRARIES = -lm +#ifdef MacIIArchitecture + DEFINES = -DIEEE +#endif /* MacIIArchitecture */ + SRCS = xcalc.c sr.c + OBJS = xcalc.o sr.o + +ComplexProgramTarget(xcalc) +\end{verbatim} +\end{quote} + +\subsection{Multiple programs} + +An Imakefile for a directory with multiple programs is a little more +complicated. {\tt ComplexProgramTarget\_1} is similar to {\tt +ComplexProgramTarget} but it uses {\tt OBJS1} to link the program +instead of {\tt OBJS}. The first argument is the program name, the +second is the list of {\tt LOCAL\_LIBRARIES}, and the third is the list of +{\tt SYSLAST\_LIBRARIES}. It is possible to have more complex programs +defined (the X Imake rules allow for 3 such targets) called +{\tt ComplexProgramTarget\_1, ComplexProgramTarget\_2,} and {\tt +ComplexProgramTarget\_3} which link {\tt OBJS1, OBJS2} and {\tt OBJS3} +respectively. + +{\tt SingleProgramTarget} is a variant that allows multiple programs +to be built - it differs from a {\tt ComplexProgramTarget\_}n in that +it does not generate targets to install the program or the manual +page, so it can be used for internal programs as well --- i.e. +programs that are compiled to generate files or preprocess data for +the installable targets. + +{\tt CFLAGS}, {\tt LINTFLAGS} and {\tt LDFLAGS} is defined as follows: +\begin{quote} +\begin{verbatim} + CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) + LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT + LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES) +\end{verbatim} +\end{quote} + +An Imakefile can redefine some of the right hand side variables - +typically, +\begin{itemize} +\item {\tt CDEBUGFLAGS} can be {\tt -g} or {\tt -O}, or if you're +using the GNU C compiler, {\tt -g -O}, + +\item{\tt INCLUDES} is usually {\tt -I\$\{TOP\}} by default, + +\item {\tt DEFINES} is left for user defined {\tt-D} flags. +({\tt STD\_DEFINES} is defined by the system macros file +and should be left alone) + +\item {\tt SYS\_LIBRARIES} or {\tt SYSAUX\_LIBRARIES} can be used for +{\tt -l} options to link in system libraries. ({\tt SYSLAST\_LIBRARIES} +is defined by the system macros, typically for portability or +emulation. + +\end{itemize} + +\begin{quote} +\begin{verbatim} +XWSRC=$(CONTRIBSRC)/widgets/Xhp +XPICLIBDIR=$(LIBDIR)/xpic +# The documents go in $(DOCDIR)/xpic - see the install target. +DOCDIR=/local/doc/X11 +############################################################# +# -DXPIC is used by the filename completion code. +# -DMAGIC will include code that puts a '#! $(BINDIR)/xpic' +# header on the saved xpic files, and make them executable, so +# you can just execute the saved xpic file and it starts up +# xpic. +# -DDEBUG turns on debugging output - do you really want that?! +# -DDRAWBBOX is also for debugging - it draws the bounding box +# of all gels. +# -DGRAB should be defined if XtAddGrab and XtRemoveGrab can be +# made to work in Minibuf.c and input.c - I can't seem to get them +# to work. +# -DTYPEOUT includes the typeout code - this is still not used by +# xpic - not much point defining it. +DEFINES = -DXPIC -DMAGIC +############################################################# +CDEBUGFLAGS = -g +INCLUDES = -I$(XWSRC) -Ibitmaps +############################################################# +# Note - You need the HP widgets (Xw) for the X11 Toolkit +# These should be defined in an Imake.tmpl - except that the +# normal Imake.tmpl insists on these being compiled in the +# X directory tree. +# For X11R3, the HP widgets use the R2 Intrinsics, which are +# provided in with the HP src. +XWLIB=$(XWSRC)/lib/libXw.a +XTOOLLIB=$(XWSRC)/lib/libXt.a +# Sigh - we use sin(), cos(), atan2() for arrow. +MATHLIB=-lm + +OBJS1 = main.o windows.o xpic.o handlers.o input.o \ + event.o grid.o error.o spline.o arrow.o newfonts.o \ + util.o gels.o null.o obj_line.o obj_spline.o obj_text.o \ + obj_box.o obj_circ.o obj_ell.o obj_block.o obj_elem.o \ + updown.o text.o isqrt.o ask.o xtypeout.o Minibuf.o Window.o +SRCS1 = main.c windows.c xpic.c handlers.c input.c \ + event.c grid.c error.c spline.c arrow.c newfonts.c \ + util.c gels.c null.c obj_line.c obj_spline.c obj_text.c \ + obj_box.c obj_circ.c obj_ell.c obj_block.c obj_elem.c \ + updown.c text.c isqrt.c ask.c xtypeout.c Minibuf.c Window.c +############################################################# +OBJS2 = x2pic.o hash.o +SRCS2 = x2pic.c hash.c +############################################################# +OBJS3 = x2ps.o hash.o +SRCS3 = x2ps.c hash.c + +PROGRAMS = xpic x2ps x2pic + +/* + * ComplexProgramTarget(program, local libraries, system libraries) + * + * The difference between local libraries and system libraries is that + * the program will depend on the local libraries, so they must be + * filenames, while the system libraries are not dependencies, so + * you can use -l + */ +ComplexProgramTarget_1(xpic,$(XWLIB) $(XTOOLLIB) $(XLIB),$(MATHLIB)) + +/* + * SingleProgramTarget(program, objects, local libraries, system libraries) + * + * Note that this does not generate install: targets so we do that + * explicitly + */ +SingleProgramTarget(x2pic,$(OBJS2) $(MALLOC),,) +InstallProgram(x2ps, $(BINDIR)) +InstallManPage(x2ps, $(MANDIR)) + +SingleProgramTarget(x2ps,$(OBJS3) $(MALLOC),,$(MATHLIB)) +InstallProgram(x2pic, $(BINDIR)) +InstallManPage(x2pic, $(MANDIR)) + +/* + * This will install the script x2tex.script as $(BINDIR)/x2tex + */ +InstallScript(x2tex, $(BINDIR)) +InstallManPage(x2tex, $(MANDIR)) + +/* + * Some additional files we want to install. This is ordinary Make + * stuff, but we use Imake defined variables like $(INSTALL). + * $(INSTALLAPPFLAGS) is meant for normal text files. + */ + +install:: + -mkdir $(XPICLIBDIR) + $(INSTALL) $(INSTAPPFLAGS) x2ps.pro $(XPICLIBDIR) + $(INSTALL) $(INSTAPPFLAGS) x2ps.tra $(XPICLIBDIR) + -mkdir $(XPICLIBDIR)/fontdesc + $(INSTALL) $(INSTAPPFLAGS) fontdesc/xpic $(XPICLIBDIR)/fontdesc + $(INSTALL) $(INSTAPPFLAGS) fontdesc/x2pic $(XPICLIBDIR)/fontdesc + $(INSTALL) $(INSTAPPFLAGS) fontdesc/x2tpic $(XPICLIBDIR)/fontdesc + $(INSTALL) $(INSTAPPFLAGS) fontdesc/x2ps $(XPICLIBDIR)/fontdesc + +/* + * This is a trick that generates a .h file from the Makefile + * variables. We compare the newly generated file tune.h.new with + * the old one tune.h, and replace the old one with the new one only + * if it is different. This will prevent unnecessary compiles, and + * avoids the need to have .c files depend on the Makefile because + * you want them recompiled if a -D define changes + */ +tune.h: Makefile + echo \#define LIBDIR \"$(XPICLIBDIR)\" > tune.h.new + echo \#define PROGRAMNAME \"$(BINDIR)/xpic\" >> tune.h.new + echo \#define DUMPDIR \"$(DUMPDIR)\" >> tune.h.new + -cmp -s tune.h.new tune.h || cp tune.h.new tune.h +\end{verbatim} +\end{quote} + +\subsection{A library archive of object files} + +An Imakefile for a library looks something like: + +\begin{quote} +\begin{verbatim} +# +# This library contains miscellaneous utility routines and is not part +# of the Xlib standard. +# + + STD_DEFINES = LibraryDefines + CDEBUGFLAGS = LibraryCDebugFlags + INCLUDES = -I. -I$(TOP) -I$(TOP)/X11 + INSTALLFLAGS = $(INSTINCFLAGS) + LINTLIBS = $(LINTXLIB) + +#ifdef OsNameDefines +OS_NAME_DEFINES = OsNameDefines +#endif + +HEADERS = \ + Xmu.h + +SRCS = Atoms.c CrPixFBit.c CvtStdSel.c DefErrMsg.c DrRndRect.c FToCback.c \ + Lookup.c Lower.c RdBitF.c StrToBS.c StrToBmap.c StrToCurs.c \ + StrToJust.c StrToOrnt.c StrToWidg.c + +OBJS = Atoms.o CrPixFBit.o CvtStdSel.o DefErrMsg.o DrRndRect.o FToCback.o \ + Lookup.o Lower.o RdBitF.o StrToBS.o StrToBmap.o StrToCurs.o \ + StrToJust.o StrToOrnt.o StrToWidg.o + +all:: + +NormalLibraryTarget(Xmu,$(OBJS)) +LintLibraryTarget(Xmu,$(SRCS)) +InstallLibrary(Xmu,$(USRLIBDIR)) +InstallLintLibrary(Xmu,$(LINTLIBDIR)) + +InstallMultiple($(HEADERS),$(INCDIR)) + +DependTarget() + +NormalLintTarget($(SRCS)) + +\end{verbatim} +\end{quote} + +Sometimes, it is nice to be able to generate libraries compiled with +debugging on, and libraries compiled with profiling on, so that these +can be used by developers. Something like the following, added before +the {\tt NormalLibraryTarget} + +\begin{quote} +\begin{verbatim} +#if DebugLibXmu && ProfileLibXmu +DebuggedAndProfiledLibraryObjectRule() +#else +# if DebugLibXmu +DebuggedLibraryObjectRule() +# else +# if ProfileLibXmu +ProfiledLibraryObjectRule() +# else +NormalLibraryObjectRule() +# endif +# endif +#endif +\end{verbatim} +\end{quote} + +and something like the following added before the {\tt +InstallMultiple} would do the trick quite nicely. + +\begin{quote} +\begin{verbatim} +#if ProfileLibXmu +ProfiledLibraryTarget(Xmu,$(OBJS)) +InstallLibrary(Xmu_p,$(USRLIBDIR)) +#endif + +#if DebugLibXmu +DebuggedLibraryTarget(Xmu,$(OBJS)) +#endif +\end{verbatim} +\end{quote} + +If we wanted a debugging library, we'd define the symbol {\tt +DebugLibXmu} in the {\tt site.def} file, and the DebuggedLibraryRule +would ensure it generated a library target for {\tt lib}name{\tt \_d.a}, +while if we defined the {\tt ProfileLibXmu} symbol, we would get a +profiled library target for {\tt lib}name{\tt \_p.a}, in addition to +the usual {\tt lib}name{\tt .a}. This sort of configurability is very +hard to get from a vanilla makefile. + +\subsection{Subdirectories} + +The following Imakefile is for a directory that only contains +subdirectories, and we want to make each of the subdirectories: + +\begin{quote} +\begin{verbatim} +#define IHaveSubdirs +#define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' + +SUBDIRS = X \ + oldX \ + Xt \ + Xmu \ + Xaw + +MakeSubdirs($(SUBDIRS)) +DependSubdirs($(SUBDIRS)) +MakeLintLibSubdirs($(SUBDIRS)) +MakeLintSubdirs($(SUBDIRS),install.ln,install.ln) + +\end{verbatim} +\end{quote} + +This will have the {\tt Makefiles} target defined as well as {\tt +Makefile} and using the {\tt make Makefiles} command will cause it to +regenerate the Makefiles in the subdirectories. It does this by +prepending a ``../'' in front of the {\tt TOP} variable, which +means that {\tt TOP} should be a relative path. (This is the only +reason for {\tt TOP} to be a relative path - if there are no +subdirectories, {\tt TOP} can easily be an absolute path. + +\section{Miscellaneous} + +{\em Imake} puts null comments of the form {\tt \/\*\*\/} in front of +normal {\em make} style comments i.e. the {\tt \#} to protect them +from the C preprocessor. They survive unscathed in the resulting +Makefile, while C style comments vanish. This provides a good way to +distinguish betwen Imakefile comments and comments that you want to +appear in the Makefile. + +However, it does not protect comments in the files that are included {\tt +(site.def, Imake.rules, machine.macros)} so if you want to use {\tt +\#} style comments in those files, you must protect them yourself with +{\tt \/\*\*\/} in front of them. + +\section{History} + +{\em Imake} was originally written by Todd Brunhoff (toddb@tekcrl.crl) +for X Windows Version 11 Release 1. The configurations for X Windows +Version 11 Releases 2, 3 and 4 were reworked considerably by Jim Fulton +(jim@expo.lcs.mit.edu) to isolate the rules, machine dependent +information, and site dependent information into separate files. + +\end{document} diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_guide/Jmakefile b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_guide/Jmakefile new file mode 100644 index 0000000000..21e70e9142 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_guide/Jmakefile @@ -0,0 +1,4 @@ +LitStuffNeededHere(docs depend) +InfoStuffNeededHere(docs) + +LitDocRootTarget(mkw_guide,lit) diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_guide/mkw_guide.lit b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_guide/mkw_guide.lit new file mode 100644 index 0000000000..2de7bf5199 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_guide/mkw_guide.lit @@ -0,0 +1,716 @@ +% +% $Header$ +% +\begin{onlystandalone} +\documentstyle[11pt,literate]{article} +\begin{document} +\title{The ``make world'' configuration system---a guide for the brave} +\author{The GRASP Team (scribe: Will Partain), \\ +Department of Computing Science, \\ +University of Glasgow, \\ +Glasgow, G12 8QQ, UK. \\ +\\ +Email: glasgow-haskell-\{bugs,request\}\@dcs.glasgow.ac.uk} +\maketitle +\begin{rawlatex} +\tableofcontents +\clearpage +\end{rawlatex} +\end{onlystandalone} + +%************************************************************************ +%* * +\section[make-world-tutorial]{An introduction to the ``make world'' configuration subsystem} +%* * +%************************************************************************ + +{\em [MEGA-NOTE: This subsystem needs SUBSTANTIAL REVISION; however, +the required time hasn't sprung/isn't springing free. Also, there is +no clear winner emerging in the How-to-Configure-Free-Software +sweepstakes. (Ideas welcome.) This documentation is only intended as +a ``survival guide'' in the interim.]} + +Our sources are manipulated with a variant of the ``imake'' system +that comes with the X Window System.\footnote{Actually, our variant is +a variant of Paul DuBois's ``imake for multiple projects,'' from the +Wisconsin Regional Primate Research Center. We are grateful to him +for making his work available to the world.} (We call our version of +the main program ``jmake,'' so things don't get mixed up.) Our +everyday term for the system is ``make world,'' because the system's +mission is to (re-)build {\em everything} correctly when you type +\tr{make world}. + +%************************************************************************ +%* * +\subsection[make-world-goals]{Goals of ``make world''} +%* * +%************************************************************************ + +The purpose of the ``make world'' subsystem is to help with these +configuration tasks: +\begin{itemize} +\item +Manipulating the system as a whole. We want to be able to do: +\begin{verbatim} +% cd ghc-<version> +% make <target> +\end{verbatim} + +and for the make \tr{<target>} to be built {\em throughout} the system +(e.g., \tr{make depend}, to build all make dependencies in the +distribution). The code to do this recursive make-ery must live in +one place and must {\em not} rely on (zillions of) hand-built +Makefiles to work. + +\item +Porting the system to a new machine platform. All machine dependencies +must be gathered together in one place and, again, must not be +distributed through zillions of Makefiles (just waiting to go wrong). + +\item +Customising the system for a particular site. Same rationale. + +\item +Customising the \Haskell{} compilation system that you build. Example +possibilities (not all relevant at this time): choosing one of several +parsers, choosing which optimisation passes to build in, choosing to +omit/include some debugging code, choosing which code generator(s) to +build in, choosing which C compiler to use in compiling +\Haskell{}-generated C files, what C compiler options to use in that +case, and on and on.... + +\item +Customising the installation of the compilation system. Where the +binaries go, where the library files go, ... + +\item +Supporting several builds/customisations ongoing simultaneously. + +\item +Supporting several people working from a master copy of the source. +\end{itemize} + +%************************************************************************ +%* * +\subsection[make-world-concepts]{Basic concepts of ``make world''} +%* * +%************************************************************************ + +The ``make world'' subsystem builds an ordinary \tr{Makefile} for each +directory in a system, from a set of system-wide configuration files +(in the \tr{mkworld/} directory) and a single directory-specific file, +called the \tr{Jmakefile}. Things the ``make world'' system needs to know +from you: +\begin{description} +\item[Machine architecture of the host you're building with:] +It normally figures this out for itself. + +\item[What project you're configuring for:] For the new Glasgow +Haskell compiler, use \tr{ghc}. + +\item[What setup of the project you're configuring for:] Unless you +have reason to do otherwise, use the \tr{std} setup. + +\item[The absolute pathname of the top of the source tree.] +\end{description} + +Armed with this information, the ``make world'' system will create +\tr{Makefiles} in all the subdirectories of a system. Each of the +Makefiles will be, in effect, a {\em database of configuration facts}. +Obviously, the program \tr{make} can then use these facts. You can +also use the utility program \tr{msub} to substitute these facts into +other source files. + +%************************************************************************ +%* * +\subsection[make-world-operation]{Basic operation of ``make world''} +%* * +%************************************************************************ + +Just like its ``imake'' ancestor for the X Window System, ``make +world'' is a {\em low-tech} solution to the tasks mentioned above. +The files involved are: +\begin{description} +\item[Platform-, site-, project-, and setup-dependent configuration files:] +{\em All} such information lives in {\em one} directory, notably the +top-level \tr{mkworld} directory. + +\item[Configuration file for a particular directory:] +This is what the one-per-directory \tr{Jmakefile}s are. +\end{description} + +All of the above files are a mixture of \tr{cpp} (C pre-processor) +directives and plain-vanilla make stuff (very plain vanilla---so it +will work with any make). The \tr{jmake} program simply feeds the +master template file (\tr{mkworld/Jmake.tmpl}) into \tr{cpp}, which +will then \tr{#include} all of the appropriate platform-, site-, +etc., dependent files, as well as the \tr{Jmakefile} for the directory +in question. \tr{cpp} expands all of the \tr{#define}d macros, and +what you are left with is an ordinary (but large and confusing) +\tr{Makefile}! + +Here is a small, possibly instructive example, from the \tr{Jmakefile} +for this document: +\begin{verbatim} +INeedLitStuffHere(all depend) + +LitDocRootTargetWithNamedOutput(root,lit,root-standalone) +\end{verbatim} + +The exact meanings of these \tr{cpp} macro-invocations are not +important;\footnote{They say that (1)~the literate stuff must be available +before doing \tr{make all} or \tr{make depend}, and (2)~we want to +build a literate document with provision for both standalone +processing and otherwise.} what is important is what you {\em don't} +see: hard-wired filenames about where to find the literate programs or +other tools, hardwired install directories, presuppositions about how +your man pages are arranged, what kind of hardware you have, +idiosyncratic (and probably inappropriate) \tr{make} suffix rules, +etc., etc. + +After expanding the master \tr{Jmake.tmpl} template with all of the +appropriate configuration files in \tr{mkworld/}, the above fragment +blows out into (in the real \tr{Makefile}):\footnote{Some long lines +truncated.} +\begin{verbatim} +all depend:: $(INFO) $(MAKEINFO) $(POSTMAKEINFO) + +$(INFO) $(MAKEINFO) $(POSTMAKEINFO): + @echo "checking $@ over in" $(INFOSRC) "first..."; \ + cd $(INFOSRC); $(MAKE) all; \ + echo "okay, continuing in $(CURRENT_DIR)" + +all depend:: $(LITSRC)/lit2pgm $(LITSRC)/lit2texi $(LITSRC)/lit2latex [...] + +$(LITSRC)/lit2pgm $(LITSRC)/lit2texi $(LITSRC)/lit2latex [...] + @(cd $(LITSRC); if [ -f lit2pgm ]; then \ + echo "checking $@ in $(LITSRC) first..."; $(MAKE) all; else \ + echo "bootstrapping $@ with lit2pgm.BOOT in $(LITSRC) first..."; \ + $(MAKE) LIT2PGM="lit2pgm.BOOT -Alit2pgm" lit-deatify all; fi; \ + echo "okay, continuing in $(CURRENT_DIR)") + +docs:: root.info root.dvi + +clean:: + $(RM) root.info root.dvi root.texi root.tex + +depend:: + $(MKDEPENDLIT) $(MKDEPENDLITFLAGS) root.lit + +root.info:: root.texi + $(RM) $@ + $(MAKEINFO) $(MAKEINFOFLAGS) root.texi \ + && $(POSTMAKEINFO) root.info + +root.dvi:: root.tex + $(RM) $@ + $(LTX) root.tex + +root.texi: root-standalone.itxi + $(RM) $@ + $(LIT2TEXI) -S $(LIT2TEXIFLAGS) -N root.info -o root.texi root-standalone.itxi + +root-standalone.itxi: root.lit + $(RM) $@ + $(LIT2TEXI) -S -c $(LIT2TEXIFLAGS) -o root-standalone.itxi root.lit + +root.tex: root-standalone.itex + $(RM) $@ + $(LIT2LATEX) -S $(LIT2LATEXFLAGS) -o root.tex root-standalone.itex + +root-standalone.itex: root.lit + $(RM) $@ + $(LIT2LATEX) -S -c $(LIT2LATEXFLAGS) -o root-standalone.itex root.lit +\end{verbatim} + +%************************************************************************ +%* * +\subsection[make-world-more-info]{More information about Imake (``make world'' ancestor)} +%* * +%************************************************************************ + +{\em As I say, the ``make world'' system is a clear candidate for +revision, so we aren't over-exerting ourselves to make this version +better.} + +I got the ``imake'' code that I turned into ``jmake'' (a.k.a. ``make +world'') from Paul DuBois, at the Wisconsin Regional Primate Research +Center. The principles of operation are {\em exactly} the same, so I +have put a copy of every known ``imake'' document in the +\tr{mkworld/doc/} subdirectory. + +%************************************************************************ +%* * +\subsection[config-file-org]{Organisation of the \tr{mkworld} configuration files} +%* * +%************************************************************************ + +The main Makefile template in \tr{mkworld/} is \tr{Jmake.tmpl}. It +first determines the machine type, then starts slurping these files +(all in \pl{mkworld/}) in this order (assume project \tr{project} and +setup \tr{setup}): +\begin{verbatim} +# find out things about the machine +<a platform-specific file> + +# now things about your site +site-project-setup.odef +site-project.odef +site.def + +# things all projects can use but that your project/setup might override +AllProjects-project-setup.otmpl +AllProjects-project.otmpl +AllProjects.tmpl + +# things just for your project +Project-project-setup.otmpl +Project-project.tmpl + +# the rules, or macro definitions, actually used in Jmakefiles +# (may be overidden [uncommon]) +Jmake-project-setup.orules +Jmake-project.orules +Jmake.rules + +# finally, the directory-specific what-you-want-to-happen info +Jmakefile +\end{verbatim} + +Notice how you can always use a \tr{*-project-setup.*} file to +override a \tr{*-project.*} file, which you can use to override the +general defaults... + +%************************************************************************ +%* * +\subsection[std-make-world-actions]{Standard actions in ``make world''} +%* * +%************************************************************************ + +The expected normal cycle of \tr{make}ing with a ``make world''-ified +project (once you're sure all your configuration files are set up +correctly!): +\begin{description} +\item[\tr{make Makefile}:] +Make the very topmost Makefile. It's crucial to get this right! +\item[\tr{make Makefiles}:] +Make all the other Makefiles (recursively). +\item[\tr{make depend}:] +Make all the automatically-generated dependencies (with +\tr{mkdependHS}, \tr{mkdependC}, \tr{mkdependlit} etc.). +\item[\tr{make all}:] +Build the system(s). +\item[\tr{make tags}:] +Make some Emacs-friendly TAGS files, if you believe in them. +\item[\tr{make runtests}:] +Run any test suite that you may have provided. +\item[\tr{make docs}:] +Make any documentation that goes with the system(s). +\item[\tr{make install}:] +Install the system(s). +\item[\tr{make install_docs}:] +Install the documentation. +\item[\tr{make clean}:] +Clean up after yourself. +\item[\tr{make veryclean}:] +If you really want to get rid of all machine-generated files... +\end{description} + +Another generally-supported make target is: \tr{make whoami} (echos +the project and setup strings). + +%************************************************************************ +%* * +\subsection[when-to-make-what]{When to use what \tr{make} target} +%* * +%************************************************************************ + +Several of the standard ``make world'' targets depend upon you to +re-run them at the right time. + +\begin{itemize} +\item +The normal thing you do 90\% of the time is just type: +\tr{make} (or, equivalently, \tr{make all}). + +\item +If you change a \tr{Jmakefile} (or the configuration files in the +\tr{mkworld/} directory), then you need to re-\tr{make Makefile}. + +\item +If you changed the configuration files in some globally-important way, +then you should re-\tr{make Makefiles}, {\em after} the +\tr{make Makefile}. + +\item +If you change anything from which make dependencies are automatically +generated (e.g., import declarations in \Haskell{} modules or +\tr{#include} directive in C programs), then you need to +re-\tr{make depend} before continuing with a regular \tr{make}. +\end{itemize} + +Rather than worry too much about these constraints, we re-run these +things every night: +\begin{verbatim} +% (make Makefile && make Makefiles && make depend) >& overnight.log +\end{verbatim} + +%************************************************************************ +%* * +\section[day-to-day-make-worlding]{Day-to-day use of ``make world'' (valuable tips!)} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsection[bad-Makefile]{When you mess up your \tr{Makefile}} +%* * +%************************************************************************ + +The NUMBER ONE \tr{make}ing RULE: If, in running \tr{make Makefile} or +\tr{make depend} or {\em anything}, you get a message indicating your +\tr{Makefile} is rubbish, {\em immediately} (a)~save a copy to look +at, and (b)~restore a viable \tr{Makefile} with: +\begin{verbatim} +mv Makefile.bak Makefile +\end{verbatim} +That way, at least you will have a working (if out-of-date) +\tr{Makefile} while you consider your options! + +%************************************************************************ +%* * +\subsection[new-dir-in-mkworld]{Adding a directory to a ``make world'' source tree} +%* * +%************************************************************************ + +\begin{verbatim} +% mkdir new_dir + +% emacs ./Jmakefile + # Add "new_dir" to the list of SUBDIRS (in parent directory). + +% emacs new_dir/Jmakefile + # Create a Jmakefile for the new subdir; probably copy one from elsewhere. + # An empty Jmakefile works, and is sometimes useful. + +% make Makefile + # Tells current-directory's Makefile that it has a new subdirectory. + +% make SUBDIRS=new_dir Makefiles + # makes the Makefile (from the new Jmakefile) in "new_dir" +\end{verbatim} + +%************************************************************************ +%* * +\subsection[feeding-flags-with-mkworld]{Feeding command flags into ``make world''} +%* * +%************************************************************************ + +NOT DONE YET. + +%************************************************************************ +%* * +\subsection[overnight-mkworlding]{Nice ``mkworld'' things to do overnight} +%* * +%************************************************************************ + +Out-of-sync ``make world'' stuff spells eventual trouble. What we do +every night (at a minimum) is: +\begin{verbatim} +% cd top-of-your-world +% make Makefile +% make Makefiles +% make depend +% make all +\end{verbatim} + +%************************************************************************ +%* * +\subsection[fastmake-script]{Using the \tr{fastmake} script (to cheat)} +%* * +%************************************************************************ + +One rather great pain about the make-dependencies generated by +\tr{makedependHS} for the compiler is that there are zillions of them, +and quite innocuous changes to the source modules can spawn {\em +massive} recompilation. If you keep your wits about you, judicious +use of the \tr{fastmake} script (provided in \tr{utils/scripts}) can +help a lot. + +Typing \tr{fastmake -help} gets you the documentation for the script; +it also describes the only two uses that I would recommended: +(1)~Recompiling when interfaces are known to be stable [very common], and +(2)~Compiling a module that's just had functions {\em added} then +tweaking the \tr{.hi} file's timestamp so the change ``doesn't show''. + +%************************************************************************ +%* * +\subsection[using-sun4s-and-sun3s]{Using both Sun4s and Sun3s to compile} +%* * +%************************************************************************ + +[This is happily irrelevant in a Sun4-only compiling-with-HBC world. +It is most useful if compiling-for-Sun3s (prototype Glasgow compiler), +but you'd really rather use a Sun4 to do it [to go faster].] + +It is a pain to build the compilation system for Sun3s, +even though most of us have Sun4s. This is really only a +problem for the compiler proper (\tr{compiler/hsc}). Here's what we +do. (We assume you have a copy of the Sun4-to-Sun3 version of the +prototype compiler.) + +The basic idea, after doing \tr{cd compiler}, is to do \tr{(l|fast)make asms} +on a Sun4 (to make all the \tr{.s} assembler files) and then finish +the job on a Sun3 with \tr{make hsc} (or \tr{make all}). + +The problem is that the rest of the distribution has been built for a +Sun3, so when \tr{make} reaches out to run some other part of the +distribution (e.g., \tr{lit-deatify}, run by \tr{lit2pgm}), you'll be +trying to run a Sun3 binary on a Sun4. No go. + +There are two solutions. Both depend on {\em installing} at least the +literate-programming stuff, and perhaps the ``make world'' stuff, too. +(\tr{cd} to those subdirectories, and see if \tr{make install} does +what you want.) + +The first solution is to use the \tr{lmake} script, provided in +\tr{utils/scripts/lmake.sh}, when you are compiling with a Sun4. +This trivial script merely overrides \tr{make}'s default ideas about +where to find some programs. + +The second solution is to reconfigure your whole system to use +``installed utilities,'' a mysterious and murky `feature' of the +make-world system. Cd to the root directory of your source tree and +proceed just as described in the installation document, +with {\em one change}: Instead of the magic line: +\begin{verbatim} +make -f Makefile.BOOT BOOT_DEFINES="-P ghc -S std -DTopDirPwd=/h/me/ghc-0.06" +\end{verbatim} + +use this other even more magic line: + +\begin{verbatim} +mkworld/jmkmf -P ghc -S std -DTopDirPwd=/h/me/ghc-0.06 +\end{verbatim} +Then \tr{make Makefiles}, \tr{make depend}, etc., as before. After +all this, you should be able to \tr{make asms} on either a Sun3 or +Sun4, without problems. + +%************************************************************************ +%* * +\section[sharing-w-link-trees]{Sharing source code using symbolic-link trees} +%* * +%************************************************************************ + +If you want to build the system for several architectures, setups, or +whatever, but not duplicate the sources, you can make a {\em link tree} +of the distribution---that is, a ``clone'' of the distribution +directory structure but with each file represented by a symbolic link +to the real source file. + +If you make changes to the real source file, then you simply have to +re-\tr{make} in the link tree to rebuild for that arch/setup. +Contrariwise, things that happen in the link tree should not affect +the master sources. + +This is what we do at Glasgow, where several people are hacking on +bits of the compiler at any given time. These notes were written +mainly to help us remember what we did last time! + +%************************************************************************ +%* * +\subsection[link-tree-principles]{The objectives of working this way} +%* * +%************************************************************************ + +What we want to have on our disks: +\begin{enumerate} +\item +A single common more-or-less-stable source tree that everyone can +share (assumed to be about a half dozen people). ``Read-only.'' + +\item +A handful of common ``builds'' of the common source for various +machines, which people can share. These ``build trees'', also +``read-only,'' link into the common source tree (above). + +Out of the whole distribution, one person is likely to be interested +in a tiny part of it. There is no reason they should have a full set +of object files (which is probably huge). By linking into a common +build tree, all those objects can be shared. + +\item +Separate link trees for individuals, that they can play with and use +to prepare wadges of ``stable code'' --- to be fed back into the +``common source tree'' periodically. +\end{enumerate} + +What we want to do with them: + +%************************************************************************ +%* * +\subsection[basic-link-trees]{Creating link trees of object files for everyone to share} +%* * +%************************************************************************ + +Let's assume that the basic source tree is in \tr{~grasp/ghc}. + +Now, if everyone simply links to this and \tr{makes} thereafter, each +link tree will end up with a full set of objects, most of which will +be of no interest to the link-tree owner. + +So, we do a basic build for each architecture, and then link {\em into +those object-full trees}! Here goes: +\begin{verbatim} +% mkdir ghc-full-hbc-sun4 # full setup, compile w/ hbc, for sun4 +% cd ghc-full-hbc-sun4 +% lndir ~grasp/ghc # make the links + +% make -f Makefile.BOOT BOOT_DEFINES="-P ghc -S full -DTopDirPwd=/users/fp/grasp/ghc-full-hbc-sun4" +\end{verbatim} + +%************************************************************************ +%* * +\subsection[create-link-tree]{Creating a link-tree version of the compiler} +%* * +%************************************************************************ + +Suppose the source is in \tr{~grasp/ghc}. We want to make a link tree +called \tr{./ghc-sun4}, which will be used to do a build for Sun4s. +Here's how to set up the basic structure: +\begin{verbatim} +% mkdir ghc-fred +% cd ghc-fred +% lndir ~grasp/ghc +\end{verbatim} + +If you wish to be a bit tidier: +\begin{verbatim} +% cd ghc-fred +% zap-junk-links +\end{verbatim} + +Now fiddle the configuration stuff, as described in the installation +document. make your Makefiles and dependencies, ..., also as +described there. It will be something like: +\begin{verbatim} +% make -f Makefile.BOOT BOOT_DEFINES="-P ghc -S fred-setup -DTopDirPwd=/u/h/ghc-fred" +\end{verbatim} + +ToDo: we need to provide emacs-ery to ensure copying works right. + +We often build not-quite-full link trees: usually just a link tree of +the \tr{compiler/} directory. See the example not too far below +about building a new setup. + +%************************************************************************ +%* * +\subsection[chopping-down-link-trees]{Finding the good stuff in a link tree} +%* * +%************************************************************************ + +(NOT TESTED RECENTLY.) + +Suppose, as in the previous section, you had a link tree +\tr{./ghc-sun4}, linked to \tr{~grasp/ghc}. Suppose that, for some +reason, you have made changes in the \tr{./ghc-sun4} tree, and you +want to find those changes, so that they might be applied to the +(presumably) master source in \tr{~grasp/ghc}. +\begin{verbatim} +make veryclean +# remove the links +find . -type l -print | xargs rm +# remove the generated Makefiles +find . -name Makefile -print | xargs rm +# rm the generated .prl files and lit2stuff in ./literate ??? +# take the diffs +diff -rc2 ~grasp/ghc . +# Remove the fluff from the diffs, mangle, etc., etc. +# Watch particularly for files that exist _only_ in ghc-sun4! +# ... +# now apply them if you wish +cd ~grasp/ghc +patch -p0 < <the-diffs-file> +\end{verbatim} + +%************************************************************************ +%* * +\subsection[new-setup]{Building a new setup (configuration) of the system} +%* * +%************************************************************************ + +NOT DONE YET. (Not expected to be hard.) + +This is what I did when I created a special setup for trying to +bootstrap the compiler (compile it with itself). + +First, I created a directory for it: +\begin{verbatim} +% mkdir ~grasp/ghc-boot +\end{verbatim} + +I then made symbolic links to the master copy of all parts of the +compilation, except the compiler itself. There, I made a whole +symlink-tree. +\begin{verbatim} +% cd ~grasp/ghc-boot +% ln -s ~grasp/ghc/* . +% rm compiler # put in a real directory for this one piece +% mkdir compiler + +% cd compiler +% lndir ~grasp/ghc/compiler # make the link tree -- takes time! + +% mkdir tests # lndir doesn't mess w/ "tests" subdirs +% touch tests/Jmakefile +\end{verbatim} + +This is going to be a setup called \tr{boot} (still for the project +\tr{ghc}). The ``make world'' system requires that the following +files exist (they can be empty): +\begin{verbatim} +ghc% ll mkworld/*boot* +-rw-rw-r-- 1 partain grasp 0 Aug 6 20:36 mkworld/AllProjects-ghc-boot.otmpl +-rw-rw-r-- 1 partain grasp 0 Aug 6 20:35 mkworld/Jmake-ghc-boot.orules +-rw-rw-r-- 1 partain grasp 0 Aug 6 20:36 mkworld/Project-ghc-boot.otmpl +-rw-rw-r-- 1 partain grasp 133 Aug 6 20:50 mkworld/site-ghc-boot.odef +\end{verbatim} + +Now, we need to tell the ``make world'' system about this special setup and +to tell it about the new ``top of the world'' (\tr{~grasp/ghc-boot}), I do: +\begin{verbatim} +% cd ghc-boot/compiler +% rm Makefile +% ../mkworld/jmake -P ghc -S boot -I../mkworld -DTopDirPwd=/users/fp/grasp/ghc-boot -DTopDir=../. -DCurDir=./compiler +../mkworld/site-ghc.odef: 9: TopDirPwd redefined +\end{verbatim} +(It's brute force, but it works! The crucial bits are: \tr{-S boot}, +and \tr{-DTopDirPwd=/users/fp/grasp/ghc-boot}.) + +Test that your \tr{Makefile} stuff is OK by... +\begin{verbatim} +% make Makefile +% make Makefiles +% make clean # tidy up some of the junk: + # won't work until the Makefiles are properly made +\end{verbatim} + +I had to fiddle some of the ``make world'' flags mentioned above even +after I'd made my Makefiles. No problem---after the fiddles, just do: +\begin{verbatim} +% make Makefile +% make Makefiles +% make depend +\end{verbatim} +(All three should have been successfully at some point before getting +down to business.) + +In my case, getting down to business was something like... +\begin{verbatim} +% fastmake -k hcs +\end{verbatim} + +\begin{onlystandalone} +\printindex +\end{document} +\end{onlystandalone} diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_ref/Jmakefile b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_ref/Jmakefile new file mode 100644 index 0000000000..b04c8d2a70 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_ref/Jmakefile @@ -0,0 +1,6 @@ +LitStuffNeededHere(docs depend) +InfoStuffNeededHere(docs) + +GENLIT_OPTS = -I$(JMAKESRC) + +LitDocRootTarget(mkw_ref,lit) diff --git a/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_ref/mkw_ref.lit b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_ref/mkw_ref.lit new file mode 100644 index 0000000000..5136c69543 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/docs/mkworld_ref/mkw_ref.lit @@ -0,0 +1,72 @@ +\begin{onlystandalone} +\documentstyle[11pt,literate,a4wide]{article} +\begin{document} +\title{``Make world'' configuration files} +\author{Will Partain} +\date{September 1992} +\maketitle +\begin{rawlatex} +\tableofcontents +\end{rawlatex} +\end{onlystandalone} + +\begin{onlypartofdoc} +\section[mkworld-files]{``Make world'' configuration files} +\downsection +\end{onlypartofdoc} + +% some intro needs to go here (ToDo) + +%---------------------------------------------------------------- +% template that shows the structure +\input{TEMPLATE.ljm} + +%---------------------------------------------------------------- +\section[mkworld-general]{General mkworld files} +\downsection + +\section[mkworld-gen-platform]{General platform-ish mkworld files} +\downsection +\input{plat-TRIGGERS.ljm} +\input{plat-DEF.ljm} +\upsection + +\section[mkworld-gen-site]{General site-ish mkworld files} +\downsection +\section[site.jm]{@site.jm@ is included HERE...} + +This is a file, prepared by hand, that records (a few) facts about the +local computing environment, e.g., where @perl@ lives, whether you +have the GNU C compiler, etc. + +\input{site-DEF.ljm} +\upsection + +\input{suffixes-GEN.ljm} +\input{macros-GEN.ljm} +\input{utils-GEN.ljm} +\upsection + +%---------------------------------------------------------------- +\section[mkworld-project-files]{Project-specific mkworld files} + +The @*.jm@ files specific to a project, or to a setup of a project, +can be used either to define brand-new stuff, or to override bits of +the general stuff in this document. + +You can get a ``literate source'' document for the @*.ljm@ files that +come with the @ghc@ and/or @nofib@ projects. Check in those projects' +individual \tr{mkworld/} directories. + +%\downsection +%\input{ghc/root.lit} +%\input{nofib/root.lit} +%\upsection + +\begin{onlypartofdoc} +\upsection +\end{onlypartofdoc} +\begin{onlystandalone} +\printindex +\end{document} +\end{onlystandalone} diff --git a/web/glasgow/lit2x-0.16/mkworld/install-GEN.jm b/web/glasgow/lit2x-0.16/mkworld/install-GEN.jm new file mode 100644 index 0000000000..64adf3044c --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/install-GEN.jm @@ -0,0 +1,139 @@ +# line 1 "install-GEN.ljm" +# line 8 "install-GEN.ljm" +/*# Where and how to install things (generally) */ +/*# [An individual project is likely to have its own ideas] */ +/*# WHERE: */ + +#ifndef InstRootDir +#define InstRootDir /usr/local +#endif +/* platform-specific binaries */ +#ifndef InstBinDir +#define InstBinDir $(INSTROOT)/bin/$(HOSTPLATFORM) +#endif +/* scripts are platform-independent executables */ +#ifndef InstScriptDir +#define InstScriptDir $(INSTROOT)/bin +#endif +/* "Lib" is where platform-specific stuff goes; + * "Data" is where platform-independent stuff goes. + * [arbitrary] + */ +#ifndef InstLibDir +#define InstLibDir $(INSTROOT)/lib/$(HOSTPLATFORM) +#endif +#ifndef InstDataDir +#define InstDataDir $(INSTROOT)/lib +#endif +INSTROOT = InstRootDir +INSTBINDIR = InstBinDir +INSTSCRIPTDIR = InstScriptDir +INSTLIBDIR = InstLibDir +INSTDATADIR = InstDataDir + +/* top of manual page tree to install in */ +/* NB: not necessarily the same place as to look for man pages (?) */ +#ifndef InstManRoot +#define InstManRoot ManDirectoryRoot +#endif +/* prefix for man page _sources_ (vs .../cat) */ +#ifndef InstManSrcRoot +#define InstManSrcRoot $(INSTMANROOT)/man +#endif +/* man pages for commands */ +#ifndef InstComManDir /* man pages for commands */ +#define InstComManDir CAT2($(INSTMANSRCROOT),$(COMMANSUFFIX)) +#endif +/* man pages for library routines */ +#ifndef InstLibManDir +#define InstLibManDir CAT2($(INSTMANSRCROOT),$(LIBMANSUFFIX)) +#endif +/* man pages for system commands */ +#ifndef InstSysManDir +#define InstSysManDir CAT2($(INSTMANSRCROOT),$(SYSMANSUFFIX)) +#endif + +/* suffix for installing commands'/etcs' man pages */ +#ifndef ComManSuffix +#define ComManSuffix l /* use just one tab or cpp will die */ +#endif +#ifndef LibManSuffix +#define LibManSuffix 3 /* use just one tab or cpp will die */ +#endif +#ifndef SysManSuffix +#define SysManSuffix 8 /* use just one tab or cpp will die */ +#endif +INSTMANROOT = InstManRoot +INSTMANSRCROOT = InstManSrcRoot +INSTCOMMANDIR = InstComManDir +INSTLIBMANDIR = InstLibManDir +INSTSYSMANDIR = InstSysManDir +COMMANSUFFIX = ComManSuffix +LIBMANSUFFIX = LibManSuffix +SYSMANSUFFIX = SysManSuffix + +#ifndef InstInfoDir +#define InstInfoDir $(INSTROOT)/info +#endif +INSTINFODIR = InstInfoDir + +/*# HOW: */ +/* this stuff about "who" does the installing doesn't have make vars + * as it is not intended to be runtime-changeable. + */ +#ifndef InstOwner +#ifdef Owner +#define InstOwner -o Owner +#else +#define InstOwner /* as nothing */ +#endif +#endif +#ifndef InstGroup +#ifdef Group +#define InstGroup -g Group +#else +#define InstGroup /* as nothing */ +#endif +#endif + +#ifndef InstFileFlags +#define InstFileFlags /* as nothing */ +#endif +#ifndef InstStrip +#define InstStrip /* as nothing */ +#endif +#ifndef InstBinFlags +#define InstBinFlags -m 0755 InstOwner InstGroup InstFileFlags InstStrip +#endif +/* + No strip flags on rest of these -- avoids message from install + about stripping non-binaries. +*/ +#ifndef InstScriptFlags +#define InstScriptFlags -m 0755 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstLibFlags +#define InstLibFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstDataLibFlags +#define InstDataLibFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstIncFlags +#define InstIncFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstDataFlags +#define InstDataFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstManFlags +#define InstManFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstRanlibFlags +#define InstRanlibFlags /*none*/ +#endif +INSTBINFLAGS = InstBinFlags +INSTSCRIPTFLAGS = InstScriptFlags +INSTLIBFLAGS = InstLibFlags +INSTINCFLAGS = InstIncFlags /* flags for include files */ +INSTDATAFLAGS = InstDataFlags +INSTMANFLAGS = InstManFlags +INSTRANLIBFLAGS = InstRanlibFlags diff --git a/web/glasgow/lit2x-0.16/mkworld/install-GEN.ljm b/web/glasgow/lit2x-0.16/mkworld/install-GEN.ljm new file mode 100644 index 0000000000..615223d66a --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/install-GEN.ljm @@ -0,0 +1,145 @@ +%************************************************************************ +%* * +\section[mkworld-install-GEN]{General stuff about installing things} +%* * +%************************************************************************ + +\begin{code} +/*# Where and how to install things (generally) */ +/*# [An individual project is likely to have its own ideas] */ +/*# WHERE: */ + +#ifndef InstRootDir +#define InstRootDir /usr/local +#endif +/* platform-specific binaries */ +#ifndef InstBinDir +#define InstBinDir $(INSTROOT)/bin/$(HOSTPLATFORM) +#endif +/* scripts are platform-independent executables */ +#ifndef InstScriptDir +#define InstScriptDir $(INSTROOT)/bin +#endif +/* "Lib" is where platform-specific stuff goes; + * "Data" is where platform-independent stuff goes. + * [arbitrary] + */ +#ifndef InstLibDir +#define InstLibDir $(INSTROOT)/lib/$(HOSTPLATFORM) +#endif +#ifndef InstDataDir +#define InstDataDir $(INSTROOT)/lib +#endif +INSTROOT = InstRootDir +INSTBINDIR = InstBinDir +INSTSCRIPTDIR = InstScriptDir +INSTLIBDIR = InstLibDir +INSTDATADIR = InstDataDir + +/* top of manual page tree to install in */ +/* NB: not necessarily the same place as to look for man pages (?) */ +#ifndef InstManRoot +#define InstManRoot ManDirectoryRoot +#endif +/* prefix for man page _sources_ (vs .../cat) */ +#ifndef InstManSrcRoot +#define InstManSrcRoot $(INSTMANROOT)/man +#endif +/* man pages for commands */ +#ifndef InstComManDir /* man pages for commands */ +#define InstComManDir CAT2($(INSTMANSRCROOT),$(COMMANSUFFIX)) +#endif +/* man pages for library routines */ +#ifndef InstLibManDir +#define InstLibManDir CAT2($(INSTMANSRCROOT),$(LIBMANSUFFIX)) +#endif +/* man pages for system commands */ +#ifndef InstSysManDir +#define InstSysManDir CAT2($(INSTMANSRCROOT),$(SYSMANSUFFIX)) +#endif + +/* suffix for installing commands'/etcs' man pages */ +#ifndef ComManSuffix +#define ComManSuffix l /* use just one tab or cpp will die */ +#endif +#ifndef LibManSuffix +#define LibManSuffix 3 /* use just one tab or cpp will die */ +#endif +#ifndef SysManSuffix +#define SysManSuffix 8 /* use just one tab or cpp will die */ +#endif +INSTMANROOT = InstManRoot +INSTMANSRCROOT = InstManSrcRoot +INSTCOMMANDIR = InstComManDir +INSTLIBMANDIR = InstLibManDir +INSTSYSMANDIR = InstSysManDir +COMMANSUFFIX = ComManSuffix +LIBMANSUFFIX = LibManSuffix +SYSMANSUFFIX = SysManSuffix + +#ifndef InstInfoDir +#define InstInfoDir $(INSTROOT)/info +#endif +INSTINFODIR = InstInfoDir + +/*# HOW: */ +/* this stuff about "who" does the installing doesn't have make vars + * as it is not intended to be runtime-changeable. + */ +#ifndef InstOwner +#ifdef Owner +#define InstOwner -o Owner +#else +#define InstOwner /* as nothing */ +#endif +#endif +#ifndef InstGroup +#ifdef Group +#define InstGroup -g Group +#else +#define InstGroup /* as nothing */ +#endif +#endif + +#ifndef InstFileFlags +#define InstFileFlags /* as nothing */ +#endif +#ifndef InstStrip +#define InstStrip /* as nothing */ +#endif +#ifndef InstBinFlags +#define InstBinFlags -m 0755 InstOwner InstGroup InstFileFlags InstStrip +#endif +/* + No strip flags on rest of these -- avoids message from install + about stripping non-binaries. +*/ +#ifndef InstScriptFlags +#define InstScriptFlags -m 0755 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstLibFlags +#define InstLibFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstDataLibFlags +#define InstDataLibFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstIncFlags +#define InstIncFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstDataFlags +#define InstDataFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstManFlags +#define InstManFlags -m 0644 InstOwner InstGroup InstFileFlags +#endif +#ifndef InstRanlibFlags +#define InstRanlibFlags /*none*/ +#endif +INSTBINFLAGS = InstBinFlags +INSTSCRIPTFLAGS = InstScriptFlags +INSTLIBFLAGS = InstLibFlags +INSTINCFLAGS = InstIncFlags /* flags for include files */ +INSTDATAFLAGS = InstDataFlags +INSTMANFLAGS = InstManFlags +INSTRANLIBFLAGS = InstRanlibFlags +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/jmake.c b/web/glasgow/lit2x-0.16/mkworld/jmake.c new file mode 100644 index 0000000000..4fcb5557bc --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/jmake.c @@ -0,0 +1,922 @@ +/*****************************************************************************\ + BASED ON: + $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ + * * + * Porting Note * + * * + * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table (in jmakemdep.h) * + * so that it will be passed to the template file. * + * * +\*****************************************************************************/ + +/* + * + * Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Original Author: + * Todd Brunhoff + * Tektronix, inc. + * While a guest engineer at Project Athena, MIT + * + * jmake: the include-make program. + * + * Usage: jmake [-Idir] [-Ddefine] [-T] [-f jmakefile ] [-s] [-e] [-v] [make flags] + * + * Jmake takes a template makefile (TEMPLATE.jm) and runs cpp on it + * producing a temporary makefile in /tmp. It then runs make on + * this pre-processed makefile. + * Options: + * -D define. Same as cpp -D argument. + * -I Include directory. Same as cpp -I argument. + * -T template. Designate a template other + * than TEMPLATE.jm + * -s[F] show. Show the produced makefile on the standard + * output. Make is not run is this case. If a file + * argument is provided, the output is placed there. + * -e[F] execute instead of show; optionally name Makefile F + * -v verbose. Show the make command line executed. + * + * Environment variables: + * + * JMAKEINCLUDE Include directory to use in addition to "." + * JMAKECPP Cpp to use instead of /lib/cpp + * JMAKEMAKE make program to use other than what is + * found by searching the $PATH variable. + * Other features: + * jmake reads the entire cpp output into memory and then scans it + * for occurences of "@@". If it encounters them, it replaces it with + * a newline. It also trims any trailing white space on output lines + * (because make gets upset at them). This helps when cpp expands + * multi-line macros but you want them to appear on multiple lines. + * + * The macros MAKEFILE and MAKE are provided as macros + * to make. MAKEFILE is set to jmake's makefile (not the constructed, + * preprocessed one) and MAKE is set to argv[0], i.e. the name of + * the jmake program. + * + * Theory of operation: + * 1. Determine the name of the jmakefile from the command line (-f) + * or from the content of the current directory (Jmakefile or jmakefile). + * Call this <jmakefile>. This gets added to the arguments for + * make as MAKEFILE=<jmakefile>. + * 2. Determine the name of the template from the command line (-T) + * or the default, TEMPLATE.jm. Call this <template> + * 3. Start up cpp an provide it with three lines of input: + * #define JMAKE_TEMPLATE " <template> " + * #define INCLUDE_JMAKEFILE < <jmakefile> > + * #include JMAKE_TEMPLATE + * Note that the define for INCLUDE_JMAKEFILE is intended for + * use in the template file. This implies that the jmake is + * useless unless the template file contains at least the line + * #include INCLUDE_JMAKEFILE + * 4. Gather the output from cpp, and clean it up, expanding @@ to + * newlines, stripping trailing white space, cpp control lines, + * and extra blank lines. This cleaned output is placed in a + * temporary file. Call this <makefile>. + * 5. Start up make specifying <makefile> as its input. + * + * The design of the template makefile should therefore be: + * <set global macros like CFLAGS, etc.> + * <include machine dependent additions> + * #include INCLUDE_JMAKEFILE + * <add any global targets like 'clean' and long dependencies> + */ +#include <stdio.h> +#if (defined(SVR4) || defined(_IBMR2) || defined(SYSV386)) && __STDC__ +FILE * fdopen(); +#endif +#include <ctype.h> +/*partain: #include "Xosdefs.h"*/ +#ifndef X_NOT_POSIX +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif +#endif +#include <sys/types.h> +#include <fcntl.h> +#ifdef X_NOT_POSIX +#include <sys/file.h> +#else +#include <unistd.h> +#endif +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include <signal.h> +#else +#define _POSIX_SOURCE +#include <signal.h> +#undef _POSIX_SOURCE +#endif +#include <sys/stat.h> +#ifndef X_NOT_POSIX +#ifdef _POSIX_SOURCE +#include <sys/wait.h> +#else +#define _POSIX_SOURCE +#include <sys/wait.h> +#undef _POSIX_SOURCE +#endif +#define waitCode(w) WEXITSTATUS(w) +#define waitSig(w) WTERMSIG(w) +typedef int waitType; +#else /* X_NOT_POSIX */ +#ifdef SYSV +#define waitCode(w) (((w) >> 8) & 0x7f) +#define waitSig(w) ((w) & 0xff) +typedef int waitType; +#else /* SYSV */ +#include <sys/wait.h> +#define waitCode(w) ((w).w_T.w_Retcode) +#define waitSig(w) ((w).w_T.w_Termsig) +typedef union wait waitType; +#endif +#ifndef WIFSIGNALED +#define WIFSIGNALED(w) waitSig(w) +#endif +#ifndef WIFEXITED +#define WIFEXITED(w) waitCode(w) +#endif +#endif /* X_NOT_POSIX */ +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +char *malloc(), *realloc(); +void exit(); +#endif +#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ +char *malloc(), *realloc(); +#endif /* macII */ +#ifdef X_NOT_STDC_ENV +extern char *getenv(); +#endif +#include <errno.h> +extern int errno; +#include "jmakemdep.h" + + +#define TRUE 1 +#define FALSE 0 + +#ifdef FIXUP_CPP_WHITESPACE +int InRule = FALSE; +#endif + +/* + * Some versions of cpp reduce all tabs in macro expansion to a single + * space. In addition, the escaped newline may be replaced with a + * space instead of being deleted. Blech. + */ +#ifndef FIXUP_CPP_WHITESPACE +#define KludgeOutputLine(arg) +#define KludgeResetRule() +#endif + +typedef unsigned char boolean; + +#ifndef DEFAULT_CPP +#ifdef USE_CC_E +#define DEFAULT_CPP "/bin/cc" +#else +#ifdef CPP_PROGRAM +#define DEFAULT_CPP CPP_PROGRAM +#else +#define DEFAULT_CPP "/lib/cpp" +#endif +#endif +#endif + +char *cpp = DEFAULT_CPP; + +char *tmpMakefile = "/tmp/Imf.XXXXXX"; +char *tmpJmakefile = "/tmp/IIf.XXXXXX"; +char *make_argv[ ARGUMENTS ] = { "make" }; + +int make_argindex; +int cpp_argindex; +char *make = NULL; +char *Jmakefile = NULL; +char *Makefile = "Makefile"; +char *Template = "TEMPLATE.jm"; +/* partain: SetupLabel and ProjectLabel are my additions */ +char *SetupLabel = "std"; +char *ProjectLabel = "none"; +char *ProjectMkworldDir = ""; +/* partain: net patch from dubois; orig: +char *program; +*/ +char *program = "jmake"; +char *FindJmakefile(); +char *ReadLine(); +char *CleanCppInput(); +char *Strdup(); +char *Emalloc(); + +boolean verbose = FALSE; +boolean show = TRUE; + +main(argc, argv) + int argc; + char **argv; +{ + FILE *tmpfd; + char makeMacro[ BUFSIZ ]; + char makefileMacro[ BUFSIZ ]; + + program = argv[0]; + init(); + SetOpts(argc, argv); +#ifdef USE_CC_E + AddCppArg("-"); +#endif + + Jmakefile = FindJmakefile(Jmakefile); + if (Makefile) + tmpMakefile = Makefile; + else { + tmpMakefile = Strdup(tmpMakefile); + (void) mktemp(tmpMakefile); + } + AddMakeArg("-f"); + AddMakeArg( tmpMakefile ); + sprintf(makeMacro, "MAKE=%s", program); + AddMakeArg( makeMacro ); + sprintf(makefileMacro, "MAKEFILE=%s", Jmakefile); + AddMakeArg( makefileMacro ); + + if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL) + LogFatal("Cannot create temporary file %s.", tmpMakefile); + + cppit(Jmakefile, Template, tmpfd, tmpMakefile); + + if (show) { + if (Makefile == NULL) + showit(tmpfd); + } else + makeit(); + wrapup(); + exit(0); +} + +showit(fd) + FILE *fd; +{ + char buf[ BUFSIZ ]; + int red; + + fseek(fd, 0, 0); + while ((red = fread(buf, 1, BUFSIZ, fd)) > 0) + fwrite(buf, red, 1, stdout); + if (red < 0) + LogFatal("Cannot write stdout.", ""); +} + +wrapup() +{ + if (tmpMakefile != Makefile) + unlink(tmpMakefile); + unlink(tmpJmakefile); +} + +#ifdef SIGNALRETURNSINT +int +#else +void +#endif +catch(sig) + int sig; +{ + errno = 0; + LogFatalI("Signal %d.", sig); +} + +/* + * Initialize some variables. + */ +init() +{ + char *p; + + make_argindex=0; + while (make_argv[ make_argindex ] != NULL) + make_argindex++; + cpp_argindex = 0; + while (cpp_argv[ cpp_argindex ] != NULL) + cpp_argindex++; + + /* + * See if the standard include directory is different than + * the default. Or if cpp is not the default. Or if the make + * found by the PATH variable is not the default. + */ + if (p = getenv("JMAKEINCLUDE")) { + if (*p != '-' || *(p+1) != 'I') + LogFatal("Environment var JMAKEINCLUDE %s\n", + "must begin with -I"); + AddCppArg(p); + for (; *p; p++) + if (*p == ' ') { + *p++ = '\0'; + AddCppArg(p); + } + } + if (p = getenv("JMAKECPP")) + cpp = p; + if (p = getenv("JMAKEMAKE")) + make = p; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, catch); +} + +AddMakeArg(arg) + char *arg; +{ + errno = 0; + if (make_argindex >= ARGUMENTS-1) + LogFatal("Out of internal storage.", ""); + make_argv[ make_argindex++ ] = arg; + make_argv[ make_argindex ] = NULL; +} + +AddCppArg(arg) + char *arg; +{ + errno = 0; + if (cpp_argindex >= ARGUMENTS-1) + LogFatal("Out of internal storage.", ""); + cpp_argv[ cpp_argindex++ ] = arg; + cpp_argv[ cpp_argindex ] = NULL; +} + +SetOpts(argc, argv) + int argc; + char **argv; +{ + errno = 0; + /* + * Now gather the arguments for make + */ + for(argc--, argv++; argc; argc--, argv++) { + /* + * We intercept these flags. + */ + if (argv[0][0] == '-') { + if (argv[0][1] == 'D') { + AddCppArg(argv[0]); + } else if (argv[0][1] == 'I') { + AddCppArg(argv[0]); + } else if (argv[0][1] == 'f') { + if (argv[0][2]) + Jmakefile = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -f flag\n", ""); + Jmakefile = argv[0]; + } + } else if (argv[0][1] == 's') { + if (argv[0][2]) + Makefile = ((argv[0][2] == '-') && !argv[0][3]) ? + NULL : argv[0]+2; + else { + argc--, argv++; + if (!argc) + LogFatal("No description arg after -s flag\n", ""); + Makefile = ((argv[0][0] == '-') && !argv[0][1]) ? + NULL : argv[0]; + } + show = TRUE; + } else if (argv[0][1] == 'e') { + Makefile = (argv[0][2] ? argv[0]+2 : NULL); + show = FALSE; + } else if (argv[0][1] == 'T') { + if (argv[0][2]) + Template = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -T flag\n", ""); + Template = argv[0]; + } +/* partain added -P <project>, -S <setup>, and -C <dir> (project mkworld dir) options */ + } else if (argv[0][1] == 'P') { + if (argv[0][2]) + ProjectLabel = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -P flag\n", ""); + ProjectLabel = argv[0]; + } + } else if (argv[0][1] == 'S') { + if (argv[0][2]) + SetupLabel = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -S flag\n", ""); + SetupLabel = argv[0]; + } + } else if (argv[0][1] == 'C') { + if (argv[0][2]) + ProjectMkworldDir = argv[0]+2; + else { + argc--, argv++; + if (! argc) + LogFatal("No description arg after -C flag\n", ""); + ProjectMkworldDir = argv[0]; + } + { char *temp = Emalloc(4096); /* hack */ + strcat(temp, "-I"); + strcat(temp, ProjectMkworldDir); + AddCppArg(temp); + } +/* end of addition */ + } else if (argv[0][1] == 'v') { + verbose = TRUE; + } else + AddMakeArg(argv[0]); + } else + AddMakeArg(argv[0]); + } +} + +char *FindJmakefile(Jmakefile) + char *Jmakefile; +{ + int fd; + + if (Jmakefile) { + if ((fd = open(Jmakefile, O_RDONLY)) < 0) + LogFatal("Cannot open %s.", Jmakefile); + } else { + if ((fd = open("Jmakefile", O_RDONLY)) < 0) + LogFatal("No description file (Jmakefile).", ""); + else + Jmakefile = "Jmakefile"; + } + close (fd); + return(Jmakefile); +} + +LogFatalI(s, i) + char *s; + int i; +{ + /*NOSTRICT*/ + LogFatal(s, (char *)i); +} + +LogFatal(x0,x1) + char *x0, *x1; +{ + extern char *sys_errlist[]; + static boolean entered = FALSE; + + if (entered) + return; + entered = TRUE; + + fprintf(stderr, "%s: ", program); + if (errno) + fprintf(stderr, "%s: ", sys_errlist[ errno ]); + fprintf(stderr, x0,x1); + fprintf(stderr, " Stop.\n"); + wrapup(); + exit(1); +} + +showargs(argv) + char **argv; +{ + for (; *argv; argv++) + fprintf(stderr, "%s ", *argv); + fprintf(stderr, "\n"); +} + +cppit(Jmakefile, template, outfd, outfname) + char *Jmakefile; + char *template; + FILE *outfd; + char *outfname; +{ + FILE *pipeFile; + int pid, pipefd[2]; + waitType status; + char *cleanedJmakefile; + + /* + * Get a pipe. + */ + if (pipe(pipefd) < 0) + LogFatal("Cannot make a pipe.", ""); + + /* + * Fork and exec cpp + */ + pid = fork(); + if (pid < 0) + LogFatal("Cannot fork.", ""); + if (pid) { /* parent */ + close(pipefd[0]); + cleanedJmakefile = CleanCppInput(Jmakefile); + if ((pipeFile = fdopen(pipefd[1], "w")) == NULL) + LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]); + + fprintf(pipeFile, "#define JMAKE_TEMPLATE\t\"%s\"\n", + template); + fprintf(pipeFile, "#define INCLUDE_JMAKEFILE\t<%s>\n", + cleanedJmakefile); + +/* partain added OVERRIDE_FILEs business */ + fprintf(pipeFile, "#define SetupLabel\t%s\n", SetupLabel); + fprintf(pipeFile, "#define SetupIsStd\t%d\n", (! strcmp("std", SetupLabel))); + fprintf(pipeFile, "#define ProjectLabel\t%s\n", ProjectLabel); + fprintf(pipeFile, "#define ProjectIsNone\t%d\n", (! strcmp("none", ProjectLabel))); + if (strcmp("", ProjectMkworldDir) != 0) { + fprintf(pipeFile, "#define HaveProjectMkworldDir\t1\n"); + fprintf(pipeFile, "#define ProjectMkworldDir\t%s\n", ProjectMkworldDir); + } + + fprintf(pipeFile, "#define SITE_SETUP_FILE\t\"site-%s-%s.jm\"\n", + ProjectLabel, SetupLabel); + fprintf(pipeFile, "#define SITE_PROJECT_FILE\t\"site-%s.jm\"\n", + ProjectLabel); + + fprintf(pipeFile, "#define ONLY4_SETUP_FILE\t\"only4-%s-%s.jm\"\n", + ProjectLabel, SetupLabel); + fprintf(pipeFile, "#define ONLY4_PROJECT_FILE\t\"only4-%s.jm\"\n", + ProjectLabel); + + fprintf(pipeFile, "#define SUFFIXES_SETUP_FILE\t\"suffixes-%s-%s.jm\"\n", + ProjectLabel, SetupLabel); + fprintf(pipeFile, "#define SUFFIXES_PROJECT_FILE\t\"suffixes-%s.jm\"\n", + ProjectLabel); + + fprintf(pipeFile, "#define MACROS_SETUP_FILE\t\"macros-%s-%s.jm\"\n", + ProjectLabel, SetupLabel); + fprintf(pipeFile, "#define MACROS_PROJECT_FILE\t\"macros-%s.jm\"\n", + ProjectLabel); + + fprintf(pipeFile, "#define UTILS_SETUP_FILE\t\"utils-%s-%s.jm\"\n", + ProjectLabel, SetupLabel); + fprintf(pipeFile, "#define UTILS_PROJECT_FILE\t\"utils-%s.jm\"\n", + ProjectLabel); + + fprintf(pipeFile, "#define INSTALLATION_SETUP_FILE\t\"install-%s-%s.jm\"\n", + ProjectLabel, SetupLabel); + fprintf(pipeFile, "#define INSTALLATION_PROJECT_FILE\t\"install-%s.jm\"\n", + ProjectLabel); +/* end of addition */ + + fprintf(pipeFile, "#include JMAKE_TEMPLATE\n"); + fclose(pipeFile); + while (wait(&status) > 0) { + errno = 0; + if (WIFSIGNALED(status)) + LogFatalI("Signal %d.", waitSig(status)); + if (WIFEXITED(status) && waitCode(status)) + LogFatalI("Exit code %d.", waitCode(status)); + } +#ifdef linux + freopen(outfname, "r+", outfd); +#endif + CleanCppOutput(outfd, outfname); + } else { /* child... dup and exec cpp */ + if (verbose) + showargs(cpp_argv); + dup2(pipefd[0], 0); + dup2(fileno(outfd), 1); + close(pipefd[1]); + execv(cpp, cpp_argv); + LogFatal("Cannot exec %s.", cpp); + } +} + +makeit() +{ + int pid; + waitType status; + + /* + * Fork and exec make + */ + pid = fork(); + if (pid < 0) + LogFatal("Cannot fork.", ""); + if (pid) { /* parent... simply wait */ + while (wait(&status) > 0) { + errno = 0; + if (WIFSIGNALED(status)) + LogFatalI("Signal %d.", waitSig(status)); + if (WIFEXITED(status) && waitCode(status)) + LogFatalI("Exit code %d.", waitCode(status)); + } + } else { /* child... dup and exec cpp */ + if (verbose) + showargs(make_argv); + if (make) + execv(make, make_argv); + else + execvp("make", make_argv); + LogFatal("Cannot exec %s.", make); + } +} + +char *CleanCppInput(Jmakefile) + char *Jmakefile; +{ + FILE *outFile = NULL; + int infd; + char *buf, /* buffer for file content */ + *pbuf, /* walking pointer to buf */ + *punwritten, /* pointer to unwritten portion of buf */ + *cleanedJmakefile = Jmakefile, /* return value */ + *ptoken, /* pointer to # token */ + *pend, /* pointer to end of # token */ + savec; /* temporary character holder */ + struct stat st; + + /* + * grab the entire file. + */ + if ((infd = open(Jmakefile, O_RDONLY)) < 0) + LogFatal("Cannot open %s for input.", Jmakefile); + fstat(infd, &st); + buf = Emalloc(st.st_size+1); + if (read(infd, buf, st.st_size) != st.st_size) + LogFatal("Cannot read all of %s:", Jmakefile); + close(infd); + buf[ st.st_size ] = '\0'; + + punwritten = pbuf = buf; + while (*pbuf) { + /* pad make comments for cpp */ + if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) { + + ptoken = pbuf+1; + while (*ptoken == ' ' || *ptoken == '\t') + ptoken++; + pend = ptoken; + while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n') + pend++; + savec = *pend; + *pend = '\0'; + if (strcmp(ptoken, "include") + && strcmp(ptoken, "define") + && strcmp(ptoken, "undef") + && strcmp(ptoken, "ifdef") + && strcmp(ptoken, "ifndef") + && strcmp(ptoken, "else") + && strcmp(ptoken, "endif") + && strcmp(ptoken, "if")) { + if (outFile == NULL) { + tmpJmakefile = Strdup(tmpJmakefile); + (void) mktemp(tmpJmakefile); + cleanedJmakefile = tmpJmakefile; + outFile = fopen(tmpJmakefile, "w"); + if (outFile == NULL) + LogFatal("Cannot open %s for write.\n", + tmpJmakefile); + } + fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile); + fputs("/**/", outFile); + punwritten = pbuf; + } + *pend = savec; + } + pbuf++; + } + if (outFile) { + fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile); + fclose(outFile); /* also closes the pipe */ + } + + return(cleanedJmakefile); +} + +CleanCppOutput(tmpfd, tmpfname) + FILE *tmpfd; + char *tmpfname; +{ + char *input; + int blankline = 0; + + while(input = ReadLine(tmpfd, tmpfname)) { + if (isempty(input)) { + if (blankline++) + continue; + KludgeResetRule(); + } else { + blankline = 0; + KludgeOutputLine(&input); + fputs(input, tmpfd); + } + putc('\n', tmpfd); + } + fflush(tmpfd); +#ifdef NFS_STDOUT_BUG + /* + * On some systems, NFS seems to leave a large number of nulls at + * the end of the file. Ralph Swick says that this kludge makes the + * problem go away. + */ + ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd)); +#endif +} + +/* + * Determine of a line has nothing in it. As a side effect, we trim white + * space from the end of the line. Cpp magic cookies are also thrown away. + */ +isempty(line) + char *line; +{ + char *pend; + + /* + * Check for lines of the form + * # n "... + * or + * # line n "... + */ + if (*line == '#') { + pend = line+1; + if (*pend == ' ') + pend++; + if (strncmp(pend, "line ", 5) == 0) + pend += 5; + if (isdigit(*pend)) { + while (isdigit(*pend)) + pend++; + if (*pend++ == ' ' && *pend == '"') + return(TRUE); + } + } + + /* + * Find the end of the line and then walk back. + */ + for (pend=line; *pend; pend++) ; + + pend--; + while (pend >= line && (*pend == ' ' || *pend == '\t')) + pend--; + *++pend = '\0'; + return (*line == '\0'); +} + +/*ARGSUSED*/ +char *ReadLine(tmpfd, tmpfname) + FILE *tmpfd; + char *tmpfname; +{ + static boolean initialized = FALSE; + static char *buf, *pline, *end; + char *p1, *p2; + + if (! initialized) { + int total_red; + struct stat st; + + /* + * Slurp it all up. + */ + fseek(tmpfd, 0, 0); + fstat(fileno(tmpfd), &st); + pline = buf = Emalloc(st.st_size+1); +#ifdef linux + total_red = fread(buf, 1, st.st_size, tmpfd); +#else + total_red = read(fileno(tmpfd), buf, st.st_size); +#endif + if (total_red != st.st_size) + LogFatal("cannot read %s\n", tmpMakefile); + end = buf + st.st_size; + *end = '\0'; +#ifdef linux + fseek(tmpfd, 0, 0); +#else + lseek(fileno(tmpfd), 0, 0); +#endif +#ifdef SYSV + freopen(tmpfname, "w+", tmpfd); +#else /* !SYSV */ + ftruncate(fileno(tmpfd), 0); +#endif /* !SYSV */ + initialized = TRUE; + fprintf (tmpfd, "# Makefile generated by jmake -- DO NOT EDIT!!!\n"); + fprintf (tmpfd, "# (edit the Jmakefile instead)\n"); +/* partain: no thanks + fprintf (tmpfd, "# %s\n", + "$XConsortium: jmake.c,v 1.51 89/12/12 12:37:30 jim Exp $"); +*/ +#ifdef FIXUP_CPP_WHITESPACE + { + static char *cpp_warning[] = { +"#", +"# The cpp used on this machine replaces all newlines and multiple tabs and", +"# spaces in a macro expansion with a single space. Jmake tries to compensate", +"# for this, but is not always successful.", +"#", +NULL }; + char **cpp; + + for (cpp = cpp_warning; *cpp; cpp++) { + fprintf (tmpfd, "%s\n", *cpp); + } + } +#endif /* FIXUP_CPP_WHITESPACE */ + } + + for (p1 = pline; p1 < end; p1++) { + if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */ + *p1++ = '\0'; + p1++; /* skip over second @ */ + break; + } + else if (*p1 == '\n') { /* real EOL */ + *p1++ = '\0'; + break; + } + } + + /* + * return NULL at the end of the file. + */ + p2 = (pline == p1 ? NULL : pline); + pline = p1; + return(p2); +} + +writetmpfile(fd, buf, cnt) + FILE *fd; + int cnt; + char *buf; +{ + errno = 0; + if (fwrite(buf, cnt, 1, fd) != 1) + LogFatal("Cannot write to %s.", tmpMakefile); +} + +char *Emalloc(size) + int size; +{ + char *p; + + if ((p = malloc(size)) == NULL) + LogFatalI("Cannot allocate %d bytes\n", size); + return(p); +} + +#ifdef FIXUP_CPP_WHITESPACE +KludgeOutputLine(pline) + char **pline; +{ + char *p = *pline; + + switch (*p) { + case '#': /*Comment - ignore*/ + break; + case '\t': /*Already tabbed - ignore it*/ + break; + case ' ': /*May need a tab*/ + default: + for (; *p; p++) if (p[0] == ':' && + p > *pline && p[-1] != '\\') { + if (**pline == ' ') + (*pline)++; + InRule = TRUE; + break; + } + if (InRule && **pline == ' ') + **pline = '\t'; + break; + } +} + +KludgeResetRule() +{ + InRule = FALSE; +} +#endif /* FIXUP_CPP_WHITESPACE */ + +char *Strdup(cp) + register char *cp; +{ + register char *new = Emalloc(strlen(cp) + 1); + + strcpy(new, cp); + return new; +} diff --git a/web/glasgow/lit2x-0.16/mkworld/jmakemdep.h b/web/glasgow/lit2x-0.16/mkworld/jmakemdep.h new file mode 100644 index 0000000000..579ef097cc --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/jmakemdep.h @@ -0,0 +1,379 @@ +/* + * Based on: + * $XConsortium: imakemdep.h,v 1.38 91/08/25 11:36:39 rws Exp $ + * + * This file contains machine-dependent constants for the jmake utility. When + * porting jmake, read each of the steps below and add in any necessary + * definitions. Do *not* edit ccjmake.c or jmake.c! + */ + +#ifdef CCJMAKE +/* + * Step 1: jmake_ccflags + * Define any special flags that will be needed to get jmake.c to compile. + * These will be passed to the compile along with the contents of the + * make variable BOOTSTRAPCFLAGS. + */ +#ifdef hpux +#ifdef hp9000s800 +#define jmake_ccflags "-DSYSV" +#else +#define jmake_ccflags "-Wc,-Nd4000,-Ns3000 -DSYSV" +#endif +#endif + +#if defined(macII) || defined(_AUX_SOURCE) +#define jmake_ccflags "-DmacII -DSYSV" +#endif + +#ifdef stellar +#define jmake_ccflags "-DSYSV" +#endif + +#ifdef att +#define jmake_ccflags "-Xc -DSVR4" +#endif + +#ifdef sony +#ifdef SYSTYPE_SYSV +#define jmake_ccflags "-DSVR4" +#else +#include <sys/param.h> +#if NEWSOS < 41 +#define jmake_ccflags "-Dbsd43 -DNOSTDHDRS" +#else +#define jmake_ccflags "-Dbsd43" +#endif +#endif +#endif + +#ifdef CRAY +/* -DX_NOT_STDC_ENV is just so we can bootstrap with cc instead of scc */ +#define jmake_ccflags "-DSYSV -DUSG -DX_NOT_STDC_ENV" +#endif + +#ifdef _IBMR2 +#define jmake_ccflags "-Daix -DSYSV -D_IBMR2" +#else +#ifdef aix +#define jmake_ccflags "-Daix -DSYSV" +#endif +#endif + +#ifdef Mips +# if defined(SYSTYPE_BSD) || defined(BSD) || defined(BSD43) +# define jmake_ccflags "-DMips -DBSD43" +# else +# define jmake_ccflags "-DMips -DSYSV" +# endif +#endif + +/* OLD: +#ifdef mips +#ifdef SYSTYPE_SYSV +#define jmake_ccflags "-DSYSV -I/usr/include/bsd -lbsd" +#endif +#endif +*/ + +#ifdef is68k +#define jmake_ccflags "-Dluna -Duniosb" +#endif + +#ifdef SYSV386 +# ifdef SVR4 +# define jmake_ccflags "-Xc -DSVR4" +# else +# define jmake_ccflags "-DSYSV" +# endif +#endif + +#ifdef __convex__ +#define jmake_ccflags "-fn -tm c1" +#endif + +#ifdef apollo +#define jmake_ccflags "-DX_NOT_POSIX" +#endif + +#else /* not CCJMAKE */ +#ifndef MAKEDEPEND +/* + * Step 2: dup2 + * If your OS doesn't have a dup2() system call to duplicate one file + * descriptor onto another, define such a mechanism here (if you don't + * already fall under the existing category(ies). + */ +#if defined(SYSV) && !defined(CRAY) && !defined(Mips) +#define dup2(fd1,fd2) ((fd1 == fd2) ? fd1 : (close(fd2), \ + fcntl(fd1, F_DUPFD, fd2))) +#endif + + +/* + * Step 3: FIXUP_CPP_WHITESPACE + * If your cpp collapses tabs macro expansions into a single space and + * replaces escaped newlines with a space, define this symbol. This will + * cause jmake to attempt to patch up the generated Makefile by looking + * for lines that have colons in them (this is why the rules file escapes + * all colons). One way to tell if you need this is to see whether or not + * your Makefiles have no tabs in them and lots of @@ strings. + */ +#if defined(sun) \ + || defined(linux) \ + || defined(__alpha) +#define FIXUP_CPP_WHITESPACE +#endif + + +/* + * Step 4: DEFAULT_CPP + * If the C preprocessor does not live in /lib/cpp, set this symbol to + * the appropriate location. + */ +#ifdef apollo +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#if defined(_IBMR2) && !defined(DEFAULT_CPP) +#define DEFAULT_CPP "/usr/lpp/X11/Xamples/util/cpp/cpp" +#endif + +/* + * Step 5: cpp_argv + * The following table contains the cpp flags that should be passed to + * cpp whenever a Makefile is being generated. If your preprocessor + * doesn't predefine any unique symbols, choose one and add it to the + * end of this table. Then, do the following: + * + * a. Use this symbol at the top of Jmake.tmpl when setting MacroFile. + * b. Put this symbol in the definition of BootstrapCFlags in your + * <platform>.cf file. + * c. When doing a make World, always add "BOOTSTRAPCFLAGS=-Dsymbol" + * to the end of the command line. + * + * Note that you may define more than one symbols (useful for platforms + * that support multiple operating systems). + */ + +#define ARGUMENTS 50 /* number of arguments in various arrays */ +char *cpp_argv[ARGUMENTS] = { +#ifdef USE_CC_E + "cc", /* replaced by the actual cpp program to exec */ + "-E", +#else + "cpp", /* replaced by the actual cpp program to exec */ +#endif /* USE_CC_E */ + "-I.", /* add current directory to include path */ +#ifdef unix + "-Uunix", /* remove unix symbol so that filename unix.c okay */ +#endif +#ifdef M4330 + "-DM4330", /* Tektronix */ +#endif +#ifdef M4310 + "-DM4310", /* Tektronix */ +#endif +#if defined(macII) || defined(_AUX_SOURCE) + "-DmacII", /* Apple A/UX */ +#endif +#ifdef att + "-Datt", /* AT&T products */ +#endif +#ifdef sony + "-Dsony", /* Sony */ +#ifndef SYSTYPE_SYSV + "-Dbsd43", +#endif +#endif +#ifdef _IBMR2 + "-D_IBMR2", /* IBM RS-6000 (we ensured that aix is defined above) */ +#ifndef aix +#define aix /* allow BOOTSTRAPCFLAGS="-D_IBMR2" */ +#endif +#endif /* _IBMR2 */ +#ifdef aix + "-Daix", /* AIX instead of AOS */ +#ifndef ibm +#define ibm /* allow BOOTSTRAPCFLAGS="-Daix" */ +#endif +#endif /* aix */ +#ifdef ibm + "-Dibm", /* IBM PS/2 and RT under both AOS and AIX */ +#endif +#ifdef luna + "-Dluna", /* OMRON luna 68K and 88K */ +#ifdef luna1 + "-Dluna1", +#endif +#ifdef luna88k /* need not on UniOS-Mach Vers. 1.13 */ + "-traditional", /* for some older version */ +#endif /* instead of "-DXCOMM=\\#" */ +#ifdef uniosb + "-Duniosb", +#endif +#ifdef uniosu + "-Duniosu", +#endif +#endif /* luna */ +#ifdef CRAY /* Cray */ + "-Ucray", +#endif +#ifdef Mips + "-DMips", /* Define and use Mips for Mips Co. OS/mach. */ +# if defined(SYSTYPE_BSD) || defined(BSD) || defined(BSD43) + "-DBSD43", /* Mips RISCOS supports two environments */ +# else + "-DSYSV", /* System V environment is the default */ +# endif +#endif /* Mips */ +#ifdef MOTOROLA + "-DMOTOROLA", /* Motorola Delta Systems */ +# ifdef SYSV + "-DSYSV", +# endif +# ifdef SVR4 + "-DSVR4", +# endif +#endif /* MOTOROLA */ +#ifdef SYSV386 /* System V/386 folks */ + "-DSYSV386", +# ifdef SVR4 + "-DSVR4", +# endif +# ifdef ISC + "-DISC", /* ISC 2.2.1 */ +# endif +# ifdef SCO + "-DSCO", +# endif +# ifdef ESIX + "-DESIX", +# endif +# ifdef ATT + "-DATT", +# endif +# ifdef DELL + "-DDELL", +# endif +#endif +#ifdef linux + "-traditional", +#endif +#ifdef __alpha + "-traditional", +#endif +}; +#else /* else MAKEDEPEND */ +/* + * Step 6: predefs + * If your compiler and/or preprocessor define any specific symbols, add + * them to the the following table. The definition of struct symtab is + * in util/makedepend/def.h. + */ +struct symtab predefs[] = { +#ifdef apollo + {"apollo", "1"}, +#endif +#ifdef ibm032 + {"ibm032", "1"}, +#endif +#ifdef ibm + {"ibm", "1"}, +#endif +#ifdef aix + {"aix", "1"}, +#endif +#ifdef sun + {"sun", "1"}, +#endif +#ifdef hpux + {"hpux", "1"}, +#endif +#ifdef vax + {"vax", "1"}, +#endif +#ifdef VMS + {"VMS", "1"}, +#endif +#ifdef cray + {"cray", "1"}, +#endif +#ifdef CRAY + {"CRAY", "1"}, +#endif +#ifdef att + {"att", "1"}, +#endif +#ifdef mips + {"mips", "1"}, +#endif +#ifdef ultrix + {"ultrix", "1"}, +#endif +#ifdef stellar + {"stellar", "1"}, +#endif +#ifdef mc68000 + {"mc68000", "1"}, +#endif +#ifdef mc68020 + {"mc68020", "1"}, +#endif +#ifdef __GNUC__ + {"__GNUC__", "1"}, +#endif +#if __STDC__ + {"__STDC__", "1"}, +#endif +#ifdef __HIGHC__ + {"__HIGHC__", "1"}, +#endif +#ifdef CMU + {"CMU", "1"}, +#endif +#ifdef luna + {"luna", "1"}, +#ifdef luna1 + {"luna1", "1"}, +#endif +#ifdef luna2 + {"luna2", "1"}, +#endif +#ifdef luna88k + {"luna88k", "1"}, +#endif +#ifdef uniosb + {"uniosb", "1"}, +#endif +#ifdef uniosu + {"uniosu", "1"}, +#endif +#endif +#ifdef ieeep754 + {"ieeep754", "1"}, +#endif +#ifdef is68k + {"is68k", "1"}, +#endif +#ifdef m68k + {"m68k", "1"}, +#endif +#ifdef m88k + {"m88k", "1"}, +#endif +#ifdef bsd43 + {"bsd43", "1"}, +#endif +#ifdef hcx + {"hcx", 1}, +#endif +#if defined(alpha) || defined(__alpha) || defined(__alpha__) + {"__alpha__", 1}, +#endif + /* add any additional symbols before this line */ + {NULL, NULL} +}; + +#endif /* MAKEDEPEND */ +#endif /* CCJMAKE */ + diff --git a/web/glasgow/lit2x-0.16/mkworld/jmkmf.prl b/web/glasgow/lit2x-0.16/mkworld/jmkmf.prl new file mode 100644 index 0000000000..fe4dcd2edf --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/jmkmf.prl @@ -0,0 +1,130 @@ +# this *.prl file is shoved through "msub" +# +# generate a Makefile from a Jmakefile from _outside_ [only] the GHC +# sources! +# +# based on X11R4 xmkmf /bin/sh script via Paul DuBois +# +# uses: +# (1) a new project with no special jmake requirements; want to use +# installed "none"-project stuff: +# type% cd top-of-project-sources +# type% jmkmf +# +# (2) a new project with a "project-label" (and maybe a "setup-label") +# +# type% cd top-of-project-sources +# type% jmkmf -P project-label -S setup-label [-C project-config-dir] +# +# (3) for a project using installed utils, jmkmf will be invoked when +# "make Makefile" happens: +# +# jmkmf -P <proj-label> -S <setup-label> - -DTopDir=<foo> -DTopDirPwd=<bar> -DCurDir=<baz> +# +# The "-" separates the getopt-able options from the rest. +# +# The -S option may be omitted if "setup-label" is "std" and -C option +# may be omitted if the project's config files happen to live in the +# std place (see -A). +# +# The "-A allprojects-config-dir" option may be used to override +# jmkmf's built-in idea of where the jmake config files are installed. +# +# don't let people fiddle with TopDir and CurDir +# +$Pgm = $0; $Pgm =~ s/.*\/([^\/]+)$/\1/; +$Status = 0; +do 'getopts.pl' || die "Giant error 'do'ing getopts.pl: $@"; +$Usage = "usage: $Pgm ". + '[-v] '. + '[-P project-label] '. + '[-S setup-label] '. + '[-C project-config-dir] '. + '[-A alternate-installed-config-dir] '. + "[- args to pass on to jmake]\n"; + +$TopDir = '.'; +$CurDir = '.'; +$jmake_extra_args = ''; + +chop($TopDirPwd = `pwd`); +$TopDirPwd =~ s/^\/tmp_mnt//; # anti-NFS attack + +if ( ! &Getopts('A:C:P:S:v')) { + print STDERR $Usage; + exit 1; +} else { + while ($#ARGV >= 0) { + $_ = $ARGV[0]; shift(@ARGV); + next if /^-$/; + $TopDir = $1, next if /^-DTopDir=(.*)$/; + $TopDirPwd = $1, next if /^-DTopDirPwd=(.*)$/; + $CurDir = $1, next if /^-DCurDir=(.*)$/; + $jmake_extra_args .= " $_"; + } +} + +$Verbose = ($opt_v) ? 1 : 0; +$Project_label = ($opt_P) ? $opt_P : 'none'; +$Setup_label = ($opt_S) ? $opt_S : 'std'; +$Project_config_dir = ($opt_C) ? $opt_C : ''; +# the next line fixed up by msub +$Std_config_dir = ($opt_A) ? $opt_A + : (( $(INSTALLING) ) ? '$(INSTDATADIR_MKWORLD)' + : '$(TOP_PWD)/$(CURRENT_DIR)'); + +# chk that all the config and dirs files will be there if needed? + +# relative-ise Project_config_dir +$Have_project_config_dir = ''; +$Project_config_dir_is_relative = ''; +if ($Project_config_dir) { + $Have_project_config_dir = '-DHaveProjectConfigDir'; + $Real_project_config_dir = $Project_config_dir; + if ($Project_config_dir !~ /^\//) { + $Project_config_dir_is_relative = '-DRelativeProjectConfigDir'; + if (! $TopDir) { + print STDERR "$Pgm: I don't know what TopDir is\n"; + } else { + $Real_project_config_dir= "$TopDir/$Project_config_dir"; + } + } + # tidy the name + $Project_config_dir =~ s/^(\.\/)+/\.\//; +} + +# do it +if ( -f Makefile ) { + print STDERR "mv Makefile Makefile.bak\n"; + $Makefile_moved = 1; + (system('mv -f Makefile Makefile.bak') >> 8) && die "$Pgm: mv -f Makefile Makefile.bak: failed\n"; +} else { + $Makefile_moved = 0; +} + +# should this always -DUseInstalledUtils? + +$jmake_args = "-DUseInstalledUtils -P $Project_label -S $Setup_label"; + +$jmake_args .= " $Have_project_config_dir"; +$jmake_args .= " $Project_config_dir_is_relative"; +if ($Project_config_dir) { + $jmake_args .= " -DProjectConfigDir=$Project_config_dir -I$Real_project_config_dir"; +} +$jmake_args .= " -I$Std_config_dir"; +$jmake_args .= " -DTopDir=$TopDir -DTopDirPwd=$TopDirPwd -DCurDir=$CurDir"; +$jmake_args .= $jmake_extra_args; + +print STDERR "jmake $jmake_args\n"; +if (system("jmake $jmake_args") >> 8) { + if ($Makefile_moved) { + print STDERR "$Pgm: trying to restore Makefile...\n"; + rename('Makefile.bak','Makefile') || die "$Pgm: mv Makefile.bak Makefile: failed\n"; + } else { + unlink('Makefile'); # don't want to confuse the issue + } + exit(1); +} +# chmod 0444, 'Makefile'; +exit 0; + diff --git a/web/glasgow/lit2x-0.16/mkworld/jrestoredeps b/web/glasgow/lit2x-0.16/mkworld/jrestoredeps new file mode 100644 index 0000000000..510185f727 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/jrestoredeps @@ -0,0 +1,63 @@ +eval "exec perl -S $0 $*" + if $running_under_some_random_shell; +# +$Verbose = 0; +if ($ARGV[0] eq '-v') { + $Verbose++; + shift(@ARGV); +} +# assuming we've just saved a Makefile as Makefile.bak +# and run "jmake" to make a new Makefile, we now want +# to grab all the old "make depend" stuff from Makefile.bak and +# re-glue it onto the new Makefile. + +open(MKF, "< Makefile") || die "Can't open Makefile\n"; +open(NEW, "> Makefile.new") || die "Can't open Makefile.new\n"; +while (<MKF>) { + # don't go past a "# DO NOT DELETE" line + last if /^# DO NOT DELETE/; + + # major HACK (to sidestep whitespace kludgery in jmake) + # IF a Makefile line starts with a tab + # AND IF it uses a make-variable followed by a backslashed semi-colon, + # THEN un-backslash the semi-colon. MEGA-SIGH + if (/^\t/ && /\$\([A-Z][A-Z_]*\\:/) { + s/(\$\([A-Z][A-Z_]*)\\:/\1:/g; + } + + # while here, we may as well tidy up some mess that + # an ANSI cpp can cause: + s/\$\(\s*([_A-Z]+)\s\)/\$\(\1\)/g; + + # while we're here, we might as well tidy up any directory names... + # s|/[^/.][^/]*/\.\.||g; # nuke: /<dir>/.. + # s|/\.[^.][^/]*/\.\.||g; # nuke: /./.. (and others) + # s| \./| |; + + print NEW $_; +} +close(MKF); + +open(BAK, "< Makefile.bak") || exit(0); # die "Can't open Makefile.bak\n"; + +# skip to "# DO NOT DELETE" +$_ = <BAK>; +while ($_ && ! /^# DO NOT DELETE/ ) { + $_ = <BAK>; +} +if (! $_) { + print STDERR "No old dependencies to restore were found in Makefile.bak\n" + if $Verbose; +} else { + # copy through "DO NOT DELETE" line + print NEW $_; + + # copy through the rest + while (<BAK>) { print NEW $_; } + + close(NEW); + close(BAK); +} + +# now rename Makefile.new to Makefile. +rename('Makefile.new', 'Makefile'); diff --git a/web/glasgow/lit2x-0.16/mkworld/macros-GEN.jm b/web/glasgow/lit2x-0.16/mkworld/macros-GEN.jm new file mode 100644 index 0000000000..42c950824d --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/macros-GEN.jm @@ -0,0 +1,853 @@ +# line 19 "../../mkworld/macros-GEN.ljm" +#ifndef CDependTarget +#define CDependTarget(deps) @@\ +MkDependCNeededHere(depend) @@\ + @@\ +depend:: deps @@\ + $(MKDEPENDC) $(MKDEPENDCFLAGS) -- $(CFLAGS) -- deps +#endif /* CDependTarget */ +# line 31 "../../mkworld/macros-GEN.ljm" +#ifndef HaskellDependTarget +#define HaskellDependTarget(deps) @@\ +MkDependHSNeededHere(depend) @@\ + @@\ +depend:: deps @@\ + $(MKDEPENDHS) $(MKDEPENDHSFLAGS) -- $(HCFLAGS) -- deps +#endif /* HaskellDependTarget */ +# line 43 "../../mkworld/macros-GEN.ljm" +#ifndef LitDependTarget +#define LitDependTarget(root,rootext) @@\ + @@\ +depend:: @@\ + $(MKDEPENDLIT) $(MKDEPENDLITFLAGS) root.rootext +#endif /* LitDependTarget */ +# line 61 "../../mkworld/macros-GEN.ljm" +#ifndef AllTarget +#define AllTarget(depends) @@\ +all:: depends +#endif +# line 71 "../../mkworld/macros-GEN.ljm" +#ifndef LinkTarget +#define LinkTarget(target,linkto) @@\ +AllTarget(target) @@\ +ExtraStuffToClean(target) @@\ +target:: linkto @@\ + RemoveTarget(target) @@\ + ${LN} linkto target +#endif +# line 101 "../../mkworld/macros-GEN.ljm" +#ifndef BuildPgm +#define BuildPgm(program,compiler,compileropts,objs,libs,deplibs) @@\ +AllTarget(program) @@\ +ExtraStuffToClean(program) @@\ +program:: objs deplibs @@\ + RemoveTarget($@) @@\ + compiler -o $@ compileropts $(LDOPTIONS) objs libs +#endif /* BuildPgm */ +# line 121 "../../mkworld/macros-GEN.ljm" +#ifndef BuildPgmFromCFiles +#define BuildPgmFromCFiles(program,objs,libs,deplibs) @@\ +BuildPgm(program,$(CC),$(CFLAGS),objs,libs,deplibs) +#endif + +#ifndef BuildPgmFromOneCFile +#define BuildPgmFromOneCFile(program) @@\ +SRCS_C = program.c @@\ +OBJS_C = program.o @@\ +BuildPgm(program,$(CC),$(CFLAGS),$(OBJS_C),/**/,/**/) +#endif +# line 137 "../../mkworld/macros-GEN.ljm" +/*ToDo: cmp => $(CMP)*/ + +#ifndef YaccRunWithExpectMsg +#define YaccRunWithExpectMsg(srcfile,ss,rs) @@\ +srcfile.tab.c : srcfile.y @@\ + $(RM) srcfile.tab.c srcfile.tab.h-SAVE y.tab.c y.tab.h y.output @@\ + @if [ -f srcfile.tab.h ] ; then $(MV) -f srcfile.tab.h srcfile.tab.h-SAVE ; fi @@\ + @echo expect ss shift/reduce conflicts and rs reduce/reduce conflicts @@\ + $(YACC) $(YFLAGS) srcfile.y @@\ + @if cmp -s srcfile.tab.h-SAVE y.tab.h ; then \ @@\ + $(MV) -f srcfile.tab.h-SAVE srcfile.tab.h ; \ @@\ + else \ @@\ + echo $(MV) -f y.tab.h srcfile.tab.h ; \ @@\ + $(MV) -f y.tab.h srcfile.tab.h ; \ @@\ + chmod 444 srcfile.tab.h ; \ @@\ + fi @@\ + @$(RM) y.tab.h @@\ + $(MV) y.tab.c srcfile.tab.c @@\ + @chmod 444 srcfile.tab.c @@\ + @@\ +srcfile.tab.h : srcfile.tab.c @@\ + @echo -n "" /* no-op */ +#endif +# line 182 "../../mkworld/macros-GEN.ljm" +#ifndef BuildPgmFromHaskellModules +#define BuildPgmFromHaskellModules(program,objs,libs,deplibs) @@\ +BuildPgm(program,$(HC),$(HCFLAGS),objs,libs,deplibs) +#endif + +#ifndef BuildPgmFromOneHaskellModule +#define BuildPgmFromOneHaskellModule(program,module,isuf) @@\ +SRCS_HS = module.isuf @@\ +OBJS_HS = module.o @@\ +BuildPgm(program,$(HC),$(HCFLAGS),$(OBJS_HS),,) +#endif +# line 197 "../../mkworld/macros-GEN.ljm" +#if HaveGlasgowHaskell == YES && UseGlasgowHaskell == YES + +#define _body_HaskellCompileWithSpecifiedFlags(module_isuf,module,isuf,flags) @@\ + $(RM) $@ \ + HaskellCompilePreProcessing(module_isuf,module,isuf) @@\ + $(HC) flags module_isuf -o module.o \ + HaskellCompilePostProcessing(module_isuf,module,isuf) + + +#elif HaveChalmersHBC == YES && UseChalmersHBC == YES + +#define _body_HaskellCompileWithSpecifiedFlags(module_isuf,module,isuf,flags) @@\ + @echo $(RM) $@; \ @@\ + $(RM) $@; \ \ + HaskellCompilePreProcessing(module_isuf,module,isuf) @@\ + iface=`basename module_isuf .isuf`.hi ; \ @@\ + if [ -f $(@D)/$$iface ] ; then \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + $(MV) -f $(@D)/$$iface $(@D)/$$iface-SAVE ; \ @@\ + fi ; \ @@\ + set +e; \ @@\ + echo $(HC) flags module_isuf -o module.o; \ @@\ + $(HC) flags module_isuf -o module.o; \ @@\ + if [ $$? -ne 0 ] ; then \ @@\ + $(MV) -f $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + exit 1; \ @@\ + fi ; \ @@\ + if cmp -s $(@D)/$$iface-SAVE $(@D)/$$iface ; then \ @@\ + $(MV) -f $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + else \ @@\ + if [ -f $(@D)/$$iface-SAVE ] ; then \ @@\ + diff -c1 $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + fi ; \ @@\ + fi \ + HaskellCompilePostProcessing(module_isuf,module,isuf) + +#else /* not GHC or HBC; presumably prototype Glasgow compiler (nhc) */ + +#define _body_HaskellCompileWithSpecifiedFlags(module_isuf,module,isuf,flags) @@\ + @echo $(RM) $@; \ @@\ + $(RM) $@; \ \ + HaskellCompilePreProcessing(module_isuf,module,isuf) @@\ + iface=`basename module_isuf .isuf`.hi ; \ @@\ + if [ -f $(@D)/$$iface ] ; then \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + $(MV) -f $(@D)/$$iface $(@D)/$$iface-SAVE ; \ @@\ + cp -p $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + chmod u+w $(@D)/$$iface ; \ @@\ + fi ; \ @@\ + set +e; \ @@\ + echo $(HC) flags module_isuf -o module.o; \ @@\ + $(HC) flags module_isuf -o module.o; \ @@\ + if [ $$? -ne 0 ] ; then \ @@\ + $(RM) STAT ; \ @@\ + $(MV) -f $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + exit 1; \ @@\ + fi ; \ @@\ + if [ -f STAT ] ; then $(MV) STAT module.STAT ; fi ; \ @@\ + if [ \( $(@D) != '.' \) -a \( $(@D) != './' \) ] ; then \ @@\ + iface=`basename module_isuf .isuf`.hi ; \ @@\ + $(UPDATEIFACE) $$iface $(@D)/$$iface ; \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + fi \ + HaskellCompilePostProcessing(module_isuf,module,isuf) + +#endif /* ! ChalmersHBC or GHC */ +# line 270 "../../mkworld/macros-GEN.ljm" +#ifndef HaskellCompilePreProcessing +#define HaskellCompilePreProcessing(module_isuf,module,isuf) /* nothing */ +#endif /* ! HaskellCompilePreProcessing */ + +#ifndef HaskellCompilePostProcessing +#define HaskellCompilePostProcessing(module_isuf,module,isuf) /* nothing */ +#endif /* ! HaskellCompilePostProcessing */ +# line 281 "../../mkworld/macros-GEN.ljm" +#ifndef HaskellCompileWithSpecifiedFlags +#define HaskellCompileWithSpecifiedFlags(module,isuf,flags) @@\ +module.o : module.isuf \ +_body_HaskellCompileWithSpecifiedFlags(module.isuf,module,isuf,flags) +#endif /* HaskellCompileWithSpecifiedFlags */ + +#ifndef HaskellCompileWithExtraFlags +#define HaskellCompileWithExtraFlags(module,isuf,flags) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS) flags) +#endif /* HaskellCompileWithExtraFlags */ + +#ifndef HaskellCompile +#define HaskellCompile(module,isuf) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS)) +#endif /* HaskellCompile */ +# line 301 "../../mkworld/macros-GEN.ljm" +#ifndef HaskellCompileWithMoreHeapAndStack +#define HaskellCompileWithMoreHeapAndStack(module,isuf,heapsize,stksize) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS) HaskellCompilerHeapSize(heapsize) HaskellCompilerStkSize(stksize)) +#endif /* HaskellCompileWithMoreHeapAndStack */ + +#ifndef HaskellCompileWithMoreHeap +#define HaskellCompileWithMoreHeap(module,isuf,heapsize) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS) HaskellCompilerHeapSize(heapsize)) +#endif /* HaskellCompileWithMoreHeap */ +# line 314 "../../mkworld/macros-GEN.ljm" +#if HaveGlasgowHaskell == YES && UseGlasgowHaskell == YES +#define HaskellCompilerHeapSize(size) -Rmax-heapsize size +#define HaskellCompilerStkSize(size) -Rmax-stksize size +#define HaskellCompilerRunCpp() -cpp +#define HaskellEndRTSFlags() /*none*/ + +#elif HaveChalmersHBC == YES && UseChalmersHBC == YES +#define HaskellCompilerHeapSize(size) CAT2(-H,size) +#define HaskellCompilerStkSize(size) CAT2(-V,size) +#define HaskellCompilerRunCpp() -M +#define HaskellEndRTSFlags() - + +#else /* not GHC or HBC; assume nhc */ +#define HaskellCompilerHeapSize(size) CAT2(-H,size) +#define HaskellCompilerStkSize(size) /*cant set stksize*/ +#define HaskellCompilerRunCpp() /*none*/ +#define HaskellEndRTSFlags() - + +#endif /* not GHC or HBC */ +# line 342 "../../mkworld/macros-GEN.ljm" +#ifndef ProgramScriptTarget +#if HasExecableScripts /* can use #! */ +#define ProgramScriptTarget(prog,dst,src,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo "#!"prog > $@ @@\ + cat src >> $@ @@\ + chmod a+x $@ +#else +#define ProgramScriptTarget(prog,dst,src,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo \: > $@ @@\ + echo 'x=/tmp/xx$$$$' >> $@ @@\ + echo "cat > "'$$x'" << 'EOF'" >> $@ @@\ + cat src >> $@ @@\ + echo EOF >> $@ @@\ + echo prog '$$x' '$$@' >> $@ @@\ + echo $(RM) '$$x' >> $@ @@\ + chmod a+x $@ +#endif /* HasExecableScripts */ +#endif /* ProgramScriptTarget */ +# line 372 "../../mkworld/macros-GEN.ljm" +#ifndef MsubTarget +#define MsubTarget(dst,src,flags,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(MSUB) flags src > dst +#endif +# line 388 "../../mkworld/macros-GEN.ljm" +#ifndef MsubProgramScriptTarget +#if HasExecableScripts /* can use #! */ +#define MsubProgramScriptTarget(prog,dst,src,flags,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo "#!"prog > $@ @@\ + ${MSUB} flags src >> $@ @@\ + chmod a+x $@ +#else +#define MsubProgramScriptTarget(prog,dst,src,flags,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo \: > $@ @@\ + echo 'x=/tmp/xx$$$$' >> $@ @@\ + echo "cat > "'$$x'" << 'EOF'" >> $@ @@\ + ${MSUB} flags src >> $@ @@\ + echo EOF >> $@ @@\ + echo prog '$$x' '$$@' >> $@ @@\ + echo $(RM) '$$x' >> $@ @@\ + chmod a+x $@ +#endif /* HasExecableScripts */ +#endif /* MsubProgramScriptTarget */ +# line 420 "../../mkworld/macros-GEN.ljm" +#ifndef MsubMakefileDependentProgramScriptTarget +#define MsubMakefileDependentProgramScriptTarget(prog,dst,src,flags,deplist) @@\ +MsubProgramScriptTarget(prog,dst,src,flags,deplist) @@\ + @@\ +Makefile:: @@\ + $(RM) dst +#endif +# line 430 "../../mkworld/macros-GEN.ljm" +#ifndef MsubScriptTarget +#define MsubScriptTarget(dst,src,flags,deplist) @@\ +MsubProgramScriptTarget(${SHELL},dst,src,flags,deplist) +#endif +# line 445 "../../mkworld/macros-GEN.ljm" +#ifndef NormalLibraryTarget +#define NormalLibraryTarget(libname,objlist) @@\ +AllTarget(CAT2(lib,libname.a)) @@\ +ExtraStuffToClean(CAT2(lib,libname.a)) @@\ +CAT2(lib,libname.a):: objlist @@\ + $(RM) $@ @@\ + $(AR) $@ objlist @@\ + $(RANLIB) $@ +#endif /* NormalLibraryTarget */ +# line 465 "../../mkworld/macros-GEN.ljm" +#ifndef RuntestsTarget +#define RuntestsTarget(depends) @@\ +runtests:: CAT2(runtest_,depends) +#endif + +#ifndef RunStdTestTimeCmd +#define RunStdTestTimeCmd /*none*/ +#endif + +#ifndef RunStdTest +#define RunStdTest(name,prog,teststuff) @@\ +RuntestsTarget(name) @@\ +CAT2(runtest_,name):: @@\ + @RunStdTestTimeCmd $(RUNSTDTEST) prog $(RUNSTDTEST_FLAGS) teststuff +#endif /* RunStdTest */ + +#ifndef AsPartOfTest +#define AsPartOfTest(test,cmdline) @@\ +RuntestsTarget(test) @@\ +CAT2(runtest_,test):: @@\ + cmdline +#endif /* AsPartOfTest */ +# line 499 "../../mkworld/macros-GEN.ljm" +#ifndef InstallMsubbedScriptTarget +#if HasExecableScripts /* can use #! */ +#define InstallMsubbedScriptTarget(prog,dst,src,installdir) @@\ +dst-tmp: src @@\ + $(RM) $@ @@\ + echo "#!"prog > $@ @@\ + ${MSUB} INSTALLING=1 src >> $@ @@\ + chmod a+x $@ @@\ + @@\ +InstallTargetWithNameAndFlags(dst-tmp,installdir,dst,) @@\ +install:: @@\ + $(RM) dst-tmp +#else +#define InstallMsubbedScriptTarget(prog,dst,src,installdir) @@\ +dst-tmp: src @@\ + $(RM) $@ @@\ + echo \: > $@ @@\ + echo 'x=/tmp/xx$$$$' >> $@ @@\ + echo "cat > "'$$x'" << 'EOF'" >> $@ @@\ + ${MSUB} INSTALLING=1 src >> $@ @@\ + echo EOF >> $@ @@\ + echo prog '$$x' '$$@' >> $@ @@\ + echo $(RM) '$$x' >> $@ @@\ + chmod a+x $@ @@\ + @@\ +InstallTargetWithNameAndFlags(dst-tmp,installdir,dst,) @@\ +install:: @@\ + $(RM) dst-tmp +#endif /* HasExecableScripts */ +#endif /* InstallMsubbedScriptTarget */ + +/* + INSTALLATION RULES. InstallTarget() should be a part of nearly + all of these, to add the target to the "install" rule. +*/ + +#ifndef InstallTarget +#define InstallTarget(depends) @@\ +install:: CAT2(install_,depends) +#endif + +#ifndef InstallDocTarget +#define InstallDocTarget(depends) @@\ +install_docs:: CAT2(install_doc_,depends) +#endif + +/* + Install a target specifying the flags to use. Many of the following + installation rules are instantiated as a particular expansion of this. +*/ + +#ifndef InstallTargetWithNameAndFlags +#define InstallTargetWithNameAndFlags(target,destdir,new_name,flags) @@\ +InstallTarget(new_name) @@\ +CAT2(install_,new_name):: target @@\ + $(INSTALL) -c flags target destdir/new_name +#endif + +#ifndef InstallTargetWithFlags +#define InstallTargetWithFlags(target,dest,flags) @@\ +InstallTargetWithNameAndFlags(target,dest,target,flags) +#endif + +#ifndef InstallDocTargetWithFlags +#define InstallDocTargetWithFlags(src,presuff,target,postsuff,dest,flags) @@\ +InstallDocTarget(CAT3(target,_,postsuff)) @@\ +CAT4(install_doc_,target,_,postsuff):: src.presuff @@\ + $(INSTALL) -c flags src.presuff dest/target.postsuff +#endif + +/* + Install a program +*/ + +#ifndef InstallBinaryTarget +#define InstallBinaryTarget(program,dest) @@\ +InstallTargetWithFlags(program,dest,$(INSTBINFLAGS)) +#endif + +/* Install a setuid/setgid/etc program -- DELETED (partain) +*/ + +/* + Install an executable script +*/ + +#ifndef InstallScriptTarget +#define InstallScriptTarget(script,dest) @@\ +InstallTargetWithFlags(script,dest,$(INSTSCRIPTFLAGS)) +#endif + +/* + Install a library (platform-dependent) +*/ + +#ifndef InstallLibraryTarget +#define InstallLibraryTarget(libname,dest) @@\ +InstallTargetWithFlags(CAT2(lib,libname).a,dest,$(INSTLIBFLAGS)) @@\ + ${RANLIB} dest/CAT2(lib,libname).a +#endif + +/* + Install an include file +*/ + +#ifndef InstallIncludeTarget +#define InstallIncludeTarget(file,dest) @@\ +InstallTargetWithFlags(file,dest,$(INSTINCFLAGS)) +#endif + +/* + Install a non-executable or data file (these are equivalent) +*/ + +#ifndef InstallDataTarget +#define InstallDataTarget(file,dest) @@\ +InstallTargetWithFlags(file,dest,$(INSTDATAFLAGS)) +#endif + +/* + Install a set of non-executable files + + DUMP THIS SOMETIME. +*/ + +#ifndef InstallMultNonExecTargets +#define InstallMultNonExecTargets(rule,targets,dest) @@\ +CAT2(install_,rule):: rule @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in targets ;\ @@\ + do \ @@\ + echo $(INSTALL) -c $(INSTDATAFLAGS) $$i dest/$$i; \ @@\ + $(INSTALL) -c $(INSTDATAFLAGS) $$i dest/$$i; \ @@\ + done +#endif + +/* + Install a man page. + + THIS IS WRONG - rules in Jmakefiles don't have suffix! + + file srcsuffix destdir dstsuffix ??? +*/ + +#ifndef InstallManPageTarget +#define InstallManPageTarget(file,destdir,suffix) @@\ +InstallDocTargetWithFlags(file,man,file,suffix,destdir,$(INSTMANFLAGS)) +#endif + +#ifndef InstallInfoFileTarget +#define InstallInfoFileTarget(src,target,destdir) @@\ +InstallDocTargetWithFlags(src,info,target,info,destdir,$(INSTMANFLAGS)) +#endif + +#ifndef InstallLinkTarget +#define InstallLinkTarget(target, linkto, dir) @@\ +InstallTarget(target) @@\ +CAT2(install_,target):: CAT2(install_,linkto) @@\ + RemoveTarget(dir/target) @@\ + ${LN} dir/linkto dir/target +#endif + +/* + Fake install rules for things not installed anywhere +*/ + +#ifndef FakeInstallTarget +#define FakeInstallTarget(target) @@\ +InstallTarget(target) @@\ +CAT2(install_,target):: target @@\ + @echo target is not installed anywhere. +#endif + +#ifndef FakeInstallLibrary +#define FakeInstallLibrary(libname) @@\ +InstallTarget(CAT2(lib,libname).a) @@\ +CAT2(install_lib,libname).a:: CAT2(lib,libname).a @@\ + @echo CAT2(lib,libname).a is not installed anywhere. +#endif +# line 689 "../../mkworld/macros-GEN.ljm" +#ifndef DocsTarget +#define DocsTarget(depends) @@\ +docs:: depends +#endif + +/* putting the InfoStuffNeededHere in semi-presumes that + LitDocRootTarget is only used once per directory (?) +*/ +#ifndef LitDocRootTargetWithNamedOutput +#define LitDocRootTargetWithNamedOutput(rootroot,rootext,rootout) @@\ +DocsTarget(rootroot.info rootroot.dvi) @@\ +ExtraStuffToClean(rootroot.info rootroot.dvi rootroot.texi rootroot.tex) @@\ +LitDependTarget(rootroot,rootext) @@\ + @@\ +rootroot.info:: rootroot.texi @@\ + RemoveTarget($@) @@\ + $(MAKEINFO) $(MAKEINFOFLAGS) rootroot.texi \ @@\ + && $(POSTMAKEINFO) rootroot.info @@\ + @@\ +rootroot.dvi:: rootroot.tex @@\ + RemoveTarget($@) @@\ + $(LTX) rootroot.tex @@\ + @@\ +rootroot.texi: rootout.itxi @@\ + RemoveTarget($@) @@\ + $(LIT2TEXI) -S $(LIT2TEXIFLAGS) -N rootroot.info -o rootroot.texi rootout.itxi @@\ + @@\ +rootout.itxi: rootroot.rootext @@\ + RemoveTarget($@) @@\ + $(LIT2TEXI) -S -c $(LIT2TEXIFLAGS) -o rootout.itxi rootroot.rootext @@\ + @@\ +rootroot.tex: rootout.itex @@\ + RemoveTarget($@) @@\ + $(LIT2LATEX) -S $(LIT2LATEXFLAGS) -o rootroot.tex rootout.itex @@\ + @@\ +rootout.itex: rootroot.rootext @@\ + RemoveTarget($@) @@\ + $(LIT2LATEX) -S -c $(LIT2LATEXFLAGS) -o rootout.itex rootroot.rootext +#endif /* LitDocRootTargetWithNamedOutput */ + +#ifndef LitDocRootTarget +#define LitDocRootTarget(rootroot,rootext) \ +LitDocRootTargetWithNamedOutput(rootroot,rootext,rootroot) +#endif /* LitDocRootTarget */ + +#ifndef VerbatimAndTibTarget +#define VerbatimAndTibTarget(root) @@\ +VerbatimNeededHere(docs root.tex) @@\ +DocsTarget(root.dvi) @@\ +ExtraStuffToClean(root.dvi root.tex) +#endif /* VerbatimAndTibTarget */ +# line 755 "../../mkworld/macros-GEN.ljm" +#ifndef ExtraStuffToClean +#define ExtraStuffToClean(extra) @@\ +clean:: @@\ + $(RM) extra +#endif /* ExtraStuffToClean */ + +#ifndef ExtraStuffToBeVeryClean +#define ExtraStuffToBeVeryClean(extra) @@\ +veryclean:: @@\ + $(RM) extra +#endif /* ExtraStuffToBeVeryClean */ + +#ifndef RemoveTarget +#if RemoveTargetByMoving +#define RemoveTarget(program) \ +$(RM) program; if [ -f program ]; then $(MV) program CAT2(program,~); fi +#else +#define RemoveTarget(program) $(RM) program +#endif /* ! RemoveTargetByMoving */ +#endif /* RemoveTarget */ +/* + * CleanTarget - generate rules to remove any garbage files; the #* is here + * instead of in the definition of CLEAN_CMD because System V would treat a + * pound sign in the CLEAN_CMD variable as a comment. + */ +#ifndef CleanTarget +#define CleanTarget() @@\ +clean:: @@\ + $(CLEAN_CMD) \#* +#endif /* CleanTarget */ + +/* + * VeryCleanTarget - generate rules for "make veryclean"; the idea is + * that "make clean" does what "you almost always want" and "make + * veryclean" removes ALL generated files. + */ +#ifndef VeryCleanTarget +#define VeryCleanTarget() @@\ +veryclean:: @@\ + $(CLEAN_CMD) \#* +#endif /* VeryCleanTarget */ +# line 805 "../../mkworld/macros-GEN.ljm" +/* this should normally precede <>TagsTarget commands */ +/* those commands *append* to the TAGS file */ +#ifndef ClearTagsFile +#define ClearTagsFile() @@\ +tags:: @@\ + $(RM) TAGS; touch TAGS +#endif + +/* + * CTagsTarget - generate rules to compute tags files for C source code. + * (specified as an arg) + * partain: we really expect "etags" to be used... + */ +#ifndef CTagsTarget +#define CTagsTarget(srcs) @@\ +tags:: @@\ + $(CTAGS) -a $(CTAGSFLAGS) srcs +#endif /* CTagsTarget */ + +/* Similarly for Perl and Haskell */ +#ifndef PerlTagsTarget +#define PerlTagsTarget(srcs) @@\ +tags:: @@\ + $(PERLTAGS) $(PERLTAGSFLAGS) srcs +#endif /* PerlTagsTarget */ + +#ifndef HsTagsTarget +#define HsTagsTarget(srcs) @@\ +tags:: @@\ + $(HSTAGS) $(HSTAGSFLAGS) srcs +#endif /* HsTagsTarget */ +# line 850 "../../mkworld/macros-GEN.ljm" +#ifndef BuildMakefileTarget +#define BuildMakefileTarget() @@\ +JmakeNeededHere(Makefile) @@\ + @@\ +Makefile:: $(MYJCONFIGFILES) @@\ + @@\ +Makefile:: @@\ + -@if [ -f Makefile ]; then \ @@\ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ @@\ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ @@\ + else exit 0; fi @@\ + $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(TOP) -DCurDir=$(CURRENT_DIR) @@\ + $(JRESTOREDEPS) @@\ + @if cmp -s Makefile Makefile.bak; then $(RM) Makefile.bak ; fi @@\ + @chmod 444 Makefile @@\ + @echo ==== The new Makefile is for\: ==== @@\ + @$(MAKE) whoami || \ @@\ + ( echo 'Putting old Makefile back (see Makefile.bad)...' && \ @@\ + $(MV) Makefile Makefile.bad && \ @@\ + $(MV) Makefile.bak Makefile ) @@\ + @@\ +whoami:: @@\ + @echo $(PROJECTNAME), version $(PROJECTVERSION) @@\ + @echo project\: $(PROJECTLABEL)\; setup\: $(SETUPLABEL) @@\ + @echo now building on a \`$(BUILDPLATFORM)\' host @@\ + @echo hoping to run on a \`$(HOSTPLATFORM)\' host +#endif /* BuildMakefileTarget */ +# line 881 "../../mkworld/macros-GEN.ljm" +#ifndef MakefileTarget +#define MakefileTarget() @@\ +BuildMakefileTarget() +#endif /* MakefileTarget */ +# line 894 "../../mkworld/macros-GEN.ljm" +#ifndef GenerateOptionsMakeVars +#define GenerateOptionsMakeVars(PGM,THINGS,AllProjectsPgmThings,PlatformPgmThings,ProjectPgmThings,SetupPgmThings) @@\ +CAT4(GLUED_,PGM,_,THINGS) = AllProjectsPgmThings PlatformPgmThings ProjectPgmThings SetupPgmThings $(CAT3(PGM,_,THINGS)) $(CAT4(EXTRA_,PGM,_,THINGS)) +#endif +# line 912 "../../mkworld/macros-GEN.ljm" +#ifndef NamedTargetSubdirs +#define NamedTargetSubdirs(name,dirs,verb,flags,subname) @@\ +name:: @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in dirs ;\ @@\ + do \ @@\ + (cd $$i ; echo verb "in $(CURRENT_DIR)/$$i..."; \ @@\ + $(MAKE) $(MFLAGS) flags subname); \ @@\ + done +#endif +# line 935 "../../mkworld/macros-GEN.ljm" +#ifndef NamedMakeSubdirs +#define NamedMakeSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"making" name,PassCDebugFlags,all) +#endif /* NamedMakeSubdirs */ +# line 947 "../../mkworld/macros-GEN.ljm" +#ifndef DependSubdirs +#define DependSubdirs(dirs) \ +NamedTargetSubdirs(depend,dirs,"making dependencies",/**/,depend) +#endif /* DependSubdirs */ +# line 962 "../../mkworld/macros-GEN.ljm" +#ifndef ProjectMakeVarsForAllinSubdirs +#define ProjectMakeVarsForAllinSubdirs /*none*/ +#endif + +#ifndef SetupMakeVarsForAllinSubdirs +#define SetupMakeVarsForAllinSubdirs /*none*/ +#endif + +#ifndef DoAllinSubdirs +#define DoAllinSubdirs(dirs) \ +NamedTargetSubdirs(all,dirs,"making all",ProjectMakeVarsForAllinSubdirs SetupMakeVarsForAllinSubdirs,all) +#endif /* DoAllinSubdirs */ +# line 979 "../../mkworld/macros-GEN.ljm" +#ifndef DoDocsinSubdirs +#define DoDocsinSubdirs(dirs) \ +NamedTargetSubdirs(docs,dirs,"making docs",/*no make flags*/,docs) +#endif /* DoDocsinSubdirs */ +# line 990 "../../mkworld/macros-GEN.ljm" +#ifndef ProjectMakeVarsForRunTestsinSubdirs +#define ProjectMakeVarsForRunTestsinSubdirs /*none*/ +#endif + +#ifndef SetupMakeVarsForRunTestsinSubdirs +#define SetupMakeVarsForRunTestsinSubdirs /*none*/ +#endif + +#ifndef RunTestsSubdirs +#define RunTestsSubdirs(dirs) \ +NamedTargetSubdirs(runtests,dirs,"running tests",ProjectMakeVarsForRunTestsinSubdirs SetupMakeVarsForRunTestsinSubdirs,runtests) +#endif /* RunTestsSubdirs */ +# line 1007 "../../mkworld/macros-GEN.ljm" +#ifndef InstallSubdirs +#define InstallSubdirs(dirs) \ +NamedTargetSubdirs(install,dirs,"installing",INSTROOT='$(INSTROOT)',install) +#endif /* InstallSubdirs */ +# line 1016 "../../mkworld/macros-GEN.ljm" +#ifndef InstallDocsSubdirs +#define InstallDocsSubdirs(dirs) \ +NamedTargetSubdirs(install_docs,dirs,"installing documentation",INSTROOT='$(INSTROOT)',install_docs) +#endif /* InstallDocsSubdirs */ +# line 1025 "../../mkworld/macros-GEN.ljm" +#ifndef NamedCleanSubdirs +#define NamedCleanSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"cleaning",RM='$(RM)',clean) +#endif /* NamedCleanSubdirs */ + +#ifndef CleanSubdirs +#define CleanSubdirs(dirs) \ +NamedCleanSubdirs(clean,dirs) +#endif +# line 1039 "../../mkworld/macros-GEN.ljm" +#ifndef NamedVeryCleanSubdirs +#define NamedVeryCleanSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"being veryclean",RM='$(RM)',veryclean) +#endif /* NamedCleanSubdirs */ + +#ifndef VeryCleanSubdirs +#define VeryCleanSubdirs(dirs) \ +NamedVeryCleanSubdirs(veryclean,dirs) +#endif +# line 1053 "../../mkworld/macros-GEN.ljm" +#ifndef NamedTagSubdirs +#define NamedTagSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"making tags",,tags) +#endif /* TagSubdirs */ + +#ifndef TagSubdirs +#define TagSubdirs(dirs) \ +NamedTagSubdirs(tags,dirs) +#endif +# line 1072 "../../mkworld/macros-GEN.ljm" +#ifndef MakeMakeSubdirs +#define MakeMakeSubdirs(dirs,target) @@\ +target:: @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in dirs ;\ @@\ + do \ @@\ + echo "making Makefiles in $(CURRENT_DIR)/$$i..."; \ @@\ + case "$$i" in \ @@\ + ./?*/?*/?*/?*) newtop=../../../../ sub=subsubsubsub;; \ @@\ + ./?*/?*/?*) newtop=../../../ sub=subsubsub;; \ @@\ + ./?*/?*) newtop=../../ sub=subsub;; \ @@\ + ./?*) newtop=../ sub=sub;; \ @@\ + */?*/?*/?*) newtop=../../../../ sub=subsubsubsub;; \ @@\ + */?*/?*) newtop=../../../ sub=subsubsub;; \ @@\ + */?*) newtop=../../ sub=subsub;; \ @@\ + *) newtop=../ sub=sub;; \ @@\ + esac; \ @@\ + case "$(TOP)" in \ @@\ + /?*) newtop= upprefix= ;; \ @@\ + *) upprefix=../ ;; \ @@\ + esac; \ @@\ + $(MAKE) $${sub}dirMakefiles UPPREFIX=$$upprefix NEWTOP=$$newtop \ @@\ + MAKEFILE_SUBDIR=$$i NEW_CURRENT_DIR=$(CURRENT_DIR)/$$i;\ @@\ + done +#endif /* MakeMakeSubdirs */ +# line 1104 "../../mkworld/macros-GEN.ljm" +#ifndef MakeNsubdirMakefiles +#define MakeNsubdirMakefiles() @@\ +subdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles @@\ + @@\ +subsubdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles @@\ + @@\ +subsubsubdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles @@\ + @@\ +subsubsubsubdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles +#endif /* MakeNsubdirMakefiles */ +# line 1153 "../../mkworld/macros-GEN.ljm" +#ifndef MakefileSubdirs +#define MakefileSubdirs(dirs) @@\ +MakeMakeSubdirs(dirs,Makefiles) @@\ + @@\ +MakeNsubdirMakefiles() +#endif /* MakefileSubdirs */ +# line 1162 "../../mkworld/macros-GEN.ljm" +#ifndef MakeDirectories +#define MakeDirectories(step,dirs) @@\ +step:: @@\ + $(MKDIRHIER) dirs +#endif +# line 1170 "../../mkworld/macros-GEN.ljm" +#ifndef LinkDirectories +#define LinkDirectories(step,dirs,todir) @@\ +step:: @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in dirs ; \ @@\ + do \ @@\ + echo "linking $$i to" todir; \ @@\ + $(LNDIR) todir $$i; \ @@\ + done +#endif diff --git a/web/glasgow/lit2x-0.16/mkworld/macros-GEN.ljm b/web/glasgow/lit2x-0.16/mkworld/macros-GEN.ljm new file mode 100644 index 0000000000..ec87a7d444 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/macros-GEN.ljm @@ -0,0 +1,1180 @@ +%************************************************************************ +%* * +\section[mkworld-macros-GEN]{Mkworld CPP macros for the masses} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsection[mkworld-macros-depend]{Macros related to \tr{depend} std target} +%* * +%************************************************************************ + +These \tr{*DependTarget} rules assume the relevant programs are in +their proper places. They won't reach out and build them for you. + +@CDependTarget@: generate rules to compute dependencies for all C files +in @deps@. +\begin{code} +#ifndef CDependTarget +#define CDependTarget(deps) @@\ +MkDependCNeededHere(depend) @@\ + @@\ +depend:: deps @@\ + $(MKDEPENDC) $(MKDEPENDCFLAGS) -- $(CFLAGS) -- deps +#endif /* CDependTarget */ +\end{code} + +@HaskellDependTarget@: generate rules to compute dependencies for all +Haskell files in @deps@. +\begin{code} +#ifndef HaskellDependTarget +#define HaskellDependTarget(deps) @@\ +MkDependHSNeededHere(depend) @@\ + @@\ +depend:: deps @@\ + $(MKDEPENDHS) $(MKDEPENDHSFLAGS) -- $(HCFLAGS) -- deps +#endif /* HaskellDependTarget */ +\end{code} + +@LitDependTarget@: generate rules to compute dependencies for the +specified ``literate root file''. +\begin{code} +#ifndef LitDependTarget +#define LitDependTarget(root,rootext) @@\ + @@\ +depend:: @@\ + $(MKDEPENDLIT) $(MKDEPENDLITFLAGS) root.rootext +#endif /* LitDependTarget */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-all]{Macros related to \tr{all} std target} +%* * +%************************************************************************ + +First, so easy ones. @AllTarget()@ should be a part of most of these +to automatically add the target to the \tr{all} rule. + +\begin{code} +#ifndef AllTarget +#define AllTarget(depends) @@\ +all:: depends +#endif +\end{code} + +Make a link to a target. Used when several targets use +the same object under different names. + +\begin{code} +#ifndef LinkTarget +#define LinkTarget(target,linkto) @@\ +AllTarget(target) @@\ +ExtraStuffToClean(target) @@\ +target:: linkto @@\ + RemoveTarget(target) @@\ + ${LN} linkto target +#endif +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-macros-bld-pgms]{Compiling modules/files and linking programs} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsubsubsection{General macros} +%* * +%************************************************************************ + +@BuildPgm@: generate rules to compile and link the +indicated program; since it does not use any default object files, it +may be used for multiple programs in the same @Jmakefile@. + +This target is the general interface for building a single program +(perhaps one of many in the @Makefile@). + +\begin{code} +#ifndef BuildPgm +#define BuildPgm(program,compiler,compileropts,objs,libs,deplibs) @@\ +AllTarget(program) @@\ +ExtraStuffToClean(program) @@\ +program:: objs deplibs @@\ + RemoveTarget($@) @@\ + compiler -o $@ compileropts $(LDOPTIONS) objs libs +#endif /* BuildPgm */ +\end{code} +ToDo: not sure all ``compilers'' will like that -o above... + +%************************************************************************ +%* * +\subsubsubsection{Compile C files, build C programs} +%* * +%************************************************************************ + +These depend on suitable suffix rules existing. + +\begin{code} +#ifndef BuildPgmFromCFiles +#define BuildPgmFromCFiles(program,objs,libs,deplibs) @@\ +BuildPgm(program,$(CC),$(CFLAGS),objs,libs,deplibs) +#endif + +#ifndef BuildPgmFromOneCFile +#define BuildPgmFromOneCFile(program) @@\ +SRCS_C = program.c @@\ +OBJS_C = program.o @@\ +BuildPgm(program,$(CC),$(CFLAGS),$(OBJS_C),/**/,/**/) +#endif +\end{code} + +This rule is formulated, esp \tr{*.tab.h} part, in case you have more +than one @YaccRunWithExpectMsg@ in a given directory. +\begin{code} +/*ToDo: cmp => $(CMP)*/ + +#ifndef YaccRunWithExpectMsg +#define YaccRunWithExpectMsg(srcfile,ss,rs) @@\ +srcfile.tab.c : srcfile.y @@\ + $(RM) srcfile.tab.c srcfile.tab.h-SAVE y.tab.c y.tab.h y.output @@\ + @if [ -f srcfile.tab.h ] ; then $(MV) -f srcfile.tab.h srcfile.tab.h-SAVE ; fi @@\ + @echo expect ss shift/reduce conflicts and rs reduce/reduce conflicts @@\ + $(YACC) $(YFLAGS) srcfile.y @@\ + @if cmp -s srcfile.tab.h-SAVE y.tab.h ; then \ @@\ + $(MV) -f srcfile.tab.h-SAVE srcfile.tab.h ; \ @@\ + else \ @@\ + echo $(MV) -f y.tab.h srcfile.tab.h ; \ @@\ + $(MV) -f y.tab.h srcfile.tab.h ; \ @@\ + chmod 444 srcfile.tab.h ; \ @@\ + fi @@\ + @$(RM) y.tab.h @@\ + $(MV) y.tab.c srcfile.tab.c @@\ + @chmod 444 srcfile.tab.c @@\ + @@\ +srcfile.tab.h : srcfile.tab.c @@\ + @echo -n "" /* no-op */ +#endif +\end{code} + +%************************************************************************ +%* * +\subsubsubsection{Compile Haskell modules, build Haskell programs} +%* * +%************************************************************************ + +Defined here... +\begin{description} +\item[@BuildPgmFromHaskellModules@:] + +\item[@BuildPgmFromOneHaskellModule@:] + +\item[@HaskellCompileWithSpecifiedFlags@:] +\item[@HaskellCompileWithExtraFlags@:] +\item[@HaskellCompileWithMoreHeapAndStack@:] +\item[@HaskellCompileWithMoreHeap@:] +\item[@HaskellCompile@:] +\end{description} + +\begin{code} +#ifndef BuildPgmFromHaskellModules +#define BuildPgmFromHaskellModules(program,objs,libs,deplibs) @@\ +BuildPgm(program,$(HC),$(HCFLAGS),objs,libs,deplibs) +#endif + +#ifndef BuildPgmFromOneHaskellModule +#define BuildPgmFromOneHaskellModule(program,module,isuf) @@\ +SRCS_HS = module.isuf @@\ +OBJS_HS = module.o @@\ +BuildPgm(program,$(HC),$(HCFLAGS),$(OBJS_HS),,) +#endif +\end{code} + +First, we define just the body of a hs-to-o rule... +\begin{code} +#if HaveGlasgowHaskell == YES && UseGlasgowHaskell == YES + +#define _body_HaskellCompileWithSpecifiedFlags(module_isuf,module,isuf,flags) @@\ + $(RM) $@ \ + HaskellCompilePreProcessing(module_isuf,module,isuf) @@\ + $(HC) flags module_isuf -o module.o \ + HaskellCompilePostProcessing(module_isuf,module,isuf) + + +#elif HaveChalmersHBC == YES && UseChalmersHBC == YES + +#define _body_HaskellCompileWithSpecifiedFlags(module_isuf,module,isuf,flags) @@\ + @echo $(RM) $@; \ @@\ + $(RM) $@; \ \ + HaskellCompilePreProcessing(module_isuf,module,isuf) @@\ + iface=`basename module_isuf .isuf`.hi ; \ @@\ + if [ -f $(@D)/$$iface ] ; then \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + $(MV) -f $(@D)/$$iface $(@D)/$$iface-SAVE ; \ @@\ + fi ; \ @@\ + set +e; \ @@\ + echo $(HC) flags module_isuf -o module.o; \ @@\ + $(HC) flags module_isuf -o module.o; \ @@\ + if [ $$? -ne 0 ] ; then \ @@\ + $(MV) -f $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + exit 1; \ @@\ + fi ; \ @@\ + if cmp -s $(@D)/$$iface-SAVE $(@D)/$$iface ; then \ @@\ + $(MV) -f $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + else \ @@\ + if [ -f $(@D)/$$iface-SAVE ] ; then \ @@\ + diff -c1 $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + fi ; \ @@\ + fi \ + HaskellCompilePostProcessing(module_isuf,module,isuf) + +#else /* not GHC or HBC; presumably prototype Glasgow compiler (nhc) */ + +#define _body_HaskellCompileWithSpecifiedFlags(module_isuf,module,isuf,flags) @@\ + @echo $(RM) $@; \ @@\ + $(RM) $@; \ \ + HaskellCompilePreProcessing(module_isuf,module,isuf) @@\ + iface=`basename module_isuf .isuf`.hi ; \ @@\ + if [ -f $(@D)/$$iface ] ; then \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + $(MV) -f $(@D)/$$iface $(@D)/$$iface-SAVE ; \ @@\ + cp -p $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + chmod u+w $(@D)/$$iface ; \ @@\ + fi ; \ @@\ + set +e; \ @@\ + echo $(HC) flags module_isuf -o module.o; \ @@\ + $(HC) flags module_isuf -o module.o; \ @@\ + if [ $$? -ne 0 ] ; then \ @@\ + $(RM) STAT ; \ @@\ + $(MV) -f $(@D)/$$iface-SAVE $(@D)/$$iface ; \ @@\ + exit 1; \ @@\ + fi ; \ @@\ + if [ -f STAT ] ; then $(MV) STAT module.STAT ; fi ; \ @@\ + if [ \( $(@D) != '.' \) -a \( $(@D) != './' \) ] ; then \ @@\ + iface=`basename module_isuf .isuf`.hi ; \ @@\ + $(UPDATEIFACE) $$iface $(@D)/$$iface ; \ @@\ + $(RM) $(@D)/$$iface-SAVE ; \ @@\ + fi \ + HaskellCompilePostProcessing(module_isuf,module,isuf) + +#endif /* ! ChalmersHBC or GHC */ +\end{code} + +The default for the ``pre-'' and/or ``post-processing'' part (possibly +swizzling around profiling/statistics files) is, of course, to do no +such thing. +\begin{code} +#ifndef HaskellCompilePreProcessing +#define HaskellCompilePreProcessing(module_isuf,module,isuf) /* nothing */ +#endif /* ! HaskellCompilePreProcessing */ + +#ifndef HaskellCompilePostProcessing +#define HaskellCompilePostProcessing(module_isuf,module,isuf) /* nothing */ +#endif /* ! HaskellCompilePostProcessing */ +\end{code} + +Now we just use the \tr{_body_*} thing above... +\begin{code} +#ifndef HaskellCompileWithSpecifiedFlags +#define HaskellCompileWithSpecifiedFlags(module,isuf,flags) @@\ +module.o : module.isuf \ +_body_HaskellCompileWithSpecifiedFlags(module.isuf,module,isuf,flags) +#endif /* HaskellCompileWithSpecifiedFlags */ + +#ifndef HaskellCompileWithExtraFlags +#define HaskellCompileWithExtraFlags(module,isuf,flags) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS) flags) +#endif /* HaskellCompileWithExtraFlags */ + +#ifndef HaskellCompile +#define HaskellCompile(module,isuf) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS)) +#endif /* HaskellCompile */ +\end{code} + +Asking for extra heap: the amount requested is the SEMI-SPACE size; +the actual amount of heap memory used will be twice that. +\begin{code} +#ifndef HaskellCompileWithMoreHeapAndStack +#define HaskellCompileWithMoreHeapAndStack(module,isuf,heapsize,stksize) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS) HaskellCompilerHeapSize(heapsize) HaskellCompilerStkSize(stksize)) +#endif /* HaskellCompileWithMoreHeapAndStack */ + +#ifndef HaskellCompileWithMoreHeap +#define HaskellCompileWithMoreHeap(module,isuf,heapsize) @@\ +HaskellCompileWithSpecifiedFlags(module,isuf,-c $(HCFLAGS) HaskellCompilerHeapSize(heapsize)) +#endif /* HaskellCompileWithMoreHeap */ +\end{code} + +But we need those per-compiler HeapSize/StkSize/RunCpp macros... +\begin{code} +#if HaveGlasgowHaskell == YES && UseGlasgowHaskell == YES +#define HaskellCompilerHeapSize(size) -Rmax-heapsize size +#define HaskellCompilerStkSize(size) -Rmax-stksize size +#define HaskellCompilerRunCpp() -cpp +#define HaskellEndRTSFlags() /*none*/ + +#elif HaveChalmersHBC == YES && UseChalmersHBC == YES +#define HaskellCompilerHeapSize(size) CAT2(-H,size) +#define HaskellCompilerStkSize(size) CAT2(-V,size) +#define HaskellCompilerRunCpp() -M +#define HaskellEndRTSFlags() - + +#else /* not GHC or HBC; assume nhc */ +#define HaskellCompilerHeapSize(size) CAT2(-H,size) +#define HaskellCompilerStkSize(size) /*cant set stksize*/ +#define HaskellCompilerRunCpp() /*none*/ +#define HaskellEndRTSFlags() - + +#endif /* not GHC or HBC */ +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-macros-scripts]{Processing scripts into ``executables''} +%* * +%************************************************************************ + +\begin{code} +#ifndef ProgramScriptTarget +#if HasExecableScripts /* can use #! */ +#define ProgramScriptTarget(prog,dst,src,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo "#!"prog > $@ @@\ + cat src >> $@ @@\ + chmod a+x $@ +#else +#define ProgramScriptTarget(prog,dst,src,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo \: > $@ @@\ + echo 'x=/tmp/xx$$$$' >> $@ @@\ + echo "cat > "'$$x'" << 'EOF'" >> $@ @@\ + cat src >> $@ @@\ + echo EOF >> $@ @@\ + echo prog '$$x' '$$@' >> $@ @@\ + echo $(RM) '$$x' >> $@ @@\ + chmod a+x $@ +#endif /* HasExecableScripts */ +#endif /* ProgramScriptTarget */ +\end{code} + +Create a target by running it through @msub@: +\begin{code} +#ifndef MsubTarget +#define MsubTarget(dst,src,flags,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(MSUB) flags src > dst +#endif +\end{code} + +@MsubProgramScriptTarget@: generate rules to create a script for an +arbitrary program by running the input through @msub@. If +@HasExecableScripts@ isn't @YES@, then make sure that the first line +begins with a colon and write the script into a temp file, have the +program execute that, and remove the temp file when done. Ugly ugly +ugly... @prog@ must be a full pathname... +\begin{code} +#ifndef MsubProgramScriptTarget +#if HasExecableScripts /* can use #! */ +#define MsubProgramScriptTarget(prog,dst,src,flags,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo "#!"prog > $@ @@\ + ${MSUB} flags src >> $@ @@\ + chmod a+x $@ +#else +#define MsubProgramScriptTarget(prog,dst,src,flags,deplist) @@\ +AllTarget(dst) @@\ +ExtraStuffToClean(dst) @@\ +dst:: src deplist @@\ + $(RM) $@ @@\ + echo \: > $@ @@\ + echo 'x=/tmp/xx$$$$' >> $@ @@\ + echo "cat > "'$$x'" << 'EOF'" >> $@ @@\ + ${MSUB} flags src >> $@ @@\ + echo EOF >> $@ @@\ + echo prog '$$x' '$$@' >> $@ @@\ + echo $(RM) '$$x' >> $@ @@\ + chmod a+x $@ +#endif /* HasExecableScripts */ +#endif /* MsubProgramScriptTarget */ +\end{code} + +For an @msub@ target that really slurps things out of the +\tr{Makefile}, we delete it as part of \tr{make Makefile(s)}, so that +it will be re-made. +\begin{code} +#ifndef MsubMakefileDependentProgramScriptTarget +#define MsubMakefileDependentProgramScriptTarget(prog,dst,src,flags,deplist) @@\ +MsubProgramScriptTarget(prog,dst,src,flags,deplist) @@\ + @@\ +Makefile:: @@\ + $(RM) dst +#endif +\end{code} + +\begin{code} +#ifndef MsubScriptTarget +#define MsubScriptTarget(dst,src,flags,deplist) @@\ +MsubProgramScriptTarget(${SHELL},dst,src,flags,deplist) +#endif +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-macros-bld-libs]{Linking modules/files into libraries} +%* * +%************************************************************************ + +@NormalLibraryTarget@: generate rules to create a library. + +\begin{code} +#ifndef NormalLibraryTarget +#define NormalLibraryTarget(libname,objlist) @@\ +AllTarget(CAT2(lib,libname.a)) @@\ +ExtraStuffToClean(CAT2(lib,libname.a)) @@\ +CAT2(lib,libname.a):: objlist @@\ + $(RM) $@ @@\ + $(AR) $@ objlist @@\ + $(RANLIB) $@ +#endif /* NormalLibraryTarget */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-runtests]{Macros related to \tr{runtests} std target} +%* * +%************************************************************************ + +Rules to do with standard @runtests@ target. + +\begin{code} +#ifndef RuntestsTarget +#define RuntestsTarget(depends) @@\ +runtests:: CAT2(runtest_,depends) +#endif + +#ifndef RunStdTestTimeCmd +#define RunStdTestTimeCmd /*none*/ +#endif + +#ifndef RunStdTest +#define RunStdTest(name,prog,teststuff) @@\ +RuntestsTarget(name) @@\ +CAT2(runtest_,name):: @@\ + @RunStdTestTimeCmd $(RUNSTDTEST) prog $(RUNSTDTEST_FLAGS) teststuff +#endif /* RunStdTest */ + +#ifndef AsPartOfTest +#define AsPartOfTest(test,cmdline) @@\ +RuntestsTarget(test) @@\ +CAT2(runtest_,test):: @@\ + cmdline +#endif /* AsPartOfTest */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-install]{Macros related to \tr{install} std target} +%* * +%************************************************************************ + +Run script through @msub@ with \tr{INSTALLING=1}, +putting result in a tmp file (don't mess w/ the @dst@ file here); +install that tmp file in the right place. +\begin{code} +#ifndef InstallMsubbedScriptTarget +#if HasExecableScripts /* can use #! */ +#define InstallMsubbedScriptTarget(prog,dst,src,installdir) @@\ +dst-tmp: src @@\ + $(RM) $@ @@\ + echo "#!"prog > $@ @@\ + ${MSUB} INSTALLING=1 src >> $@ @@\ + chmod a+x $@ @@\ + @@\ +InstallTargetWithNameAndFlags(dst-tmp,installdir,dst,) @@\ +install:: @@\ + $(RM) dst-tmp +#else +#define InstallMsubbedScriptTarget(prog,dst,src,installdir) @@\ +dst-tmp: src @@\ + $(RM) $@ @@\ + echo \: > $@ @@\ + echo 'x=/tmp/xx$$$$' >> $@ @@\ + echo "cat > "'$$x'" << 'EOF'" >> $@ @@\ + ${MSUB} INSTALLING=1 src >> $@ @@\ + echo EOF >> $@ @@\ + echo prog '$$x' '$$@' >> $@ @@\ + echo $(RM) '$$x' >> $@ @@\ + chmod a+x $@ @@\ + @@\ +InstallTargetWithNameAndFlags(dst-tmp,installdir,dst,) @@\ +install:: @@\ + $(RM) dst-tmp +#endif /* HasExecableScripts */ +#endif /* InstallMsubbedScriptTarget */ + +/* + INSTALLATION RULES. InstallTarget() should be a part of nearly + all of these, to add the target to the "install" rule. +*/ + +#ifndef InstallTarget +#define InstallTarget(depends) @@\ +install:: CAT2(install_,depends) +#endif + +#ifndef InstallDocTarget +#define InstallDocTarget(depends) @@\ +install_docs:: CAT2(install_doc_,depends) +#endif + +/* + Install a target specifying the flags to use. Many of the following + installation rules are instantiated as a particular expansion of this. +*/ + +#ifndef InstallTargetWithNameAndFlags +#define InstallTargetWithNameAndFlags(target,destdir,new_name,flags) @@\ +InstallTarget(new_name) @@\ +CAT2(install_,new_name):: target @@\ + $(INSTALL) -c flags target destdir/new_name +#endif + +#ifndef InstallTargetWithFlags +#define InstallTargetWithFlags(target,dest,flags) @@\ +InstallTargetWithNameAndFlags(target,dest,target,flags) +#endif + +#ifndef InstallDocTargetWithFlags +#define InstallDocTargetWithFlags(src,presuff,target,postsuff,dest,flags) @@\ +InstallDocTarget(CAT3(target,_,postsuff)) @@\ +CAT4(install_doc_,target,_,postsuff):: src.presuff @@\ + $(INSTALL) -c flags src.presuff dest/target.postsuff +#endif + +/* + Install a program +*/ + +#ifndef InstallBinaryTarget +#define InstallBinaryTarget(program,dest) @@\ +InstallTargetWithFlags(program,dest,$(INSTBINFLAGS)) +#endif + +/* Install a setuid/setgid/etc program -- DELETED (partain) +*/ + +/* + Install an executable script +*/ + +#ifndef InstallScriptTarget +#define InstallScriptTarget(script,dest) @@\ +InstallTargetWithFlags(script,dest,$(INSTSCRIPTFLAGS)) +#endif + +/* + Install a library (platform-dependent) +*/ + +#ifndef InstallLibraryTarget +#define InstallLibraryTarget(libname,dest) @@\ +InstallTargetWithFlags(CAT2(lib,libname).a,dest,$(INSTLIBFLAGS)) @@\ + ${RANLIB} dest/CAT2(lib,libname).a +#endif + +/* + Install an include file +*/ + +#ifndef InstallIncludeTarget +#define InstallIncludeTarget(file,dest) @@\ +InstallTargetWithFlags(file,dest,$(INSTINCFLAGS)) +#endif + +/* + Install a non-executable or data file (these are equivalent) +*/ + +#ifndef InstallDataTarget +#define InstallDataTarget(file,dest) @@\ +InstallTargetWithFlags(file,dest,$(INSTDATAFLAGS)) +#endif + +/* + Install a set of non-executable files + + DUMP THIS SOMETIME. +*/ + +#ifndef InstallMultNonExecTargets +#define InstallMultNonExecTargets(rule,targets,dest) @@\ +CAT2(install_,rule):: rule @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in targets ;\ @@\ + do \ @@\ + echo $(INSTALL) -c $(INSTDATAFLAGS) $$i dest/$$i; \ @@\ + $(INSTALL) -c $(INSTDATAFLAGS) $$i dest/$$i; \ @@\ + done +#endif + +/* + Install a man page. + + THIS IS WRONG - rules in Jmakefiles don't have suffix! + + file srcsuffix destdir dstsuffix ??? +*/ + +#ifndef InstallManPageTarget +#define InstallManPageTarget(file,destdir,suffix) @@\ +InstallDocTargetWithFlags(file,man,file,suffix,destdir,$(INSTMANFLAGS)) +#endif + +#ifndef InstallInfoFileTarget +#define InstallInfoFileTarget(src,target,destdir) @@\ +InstallDocTargetWithFlags(src,info,target,info,destdir,$(INSTMANFLAGS)) +#endif + +#ifndef InstallLinkTarget +#define InstallLinkTarget(target, linkto, dir) @@\ +InstallTarget(target) @@\ +CAT2(install_,target):: CAT2(install_,linkto) @@\ + RemoveTarget(dir/target) @@\ + ${LN} dir/linkto dir/target +#endif + +/* + Fake install rules for things not installed anywhere +*/ + +#ifndef FakeInstallTarget +#define FakeInstallTarget(target) @@\ +InstallTarget(target) @@\ +CAT2(install_,target):: target @@\ + @echo target is not installed anywhere. +#endif + +#ifndef FakeInstallLibrary +#define FakeInstallLibrary(libname) @@\ +InstallTarget(CAT2(lib,libname).a) @@\ +CAT2(install_lib,libname).a:: CAT2(lib,libname).a @@\ + @echo CAT2(lib,libname).a is not installed anywhere. +#endif +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-docs]{Macros related to \tr{docs} std target} +%* * +%************************************************************************ + +Need rules just to make a man page or info file. + +\begin{code} +#ifndef DocsTarget +#define DocsTarget(depends) @@\ +docs:: depends +#endif + +/* putting the InfoStuffNeededHere in semi-presumes that + LitDocRootTarget is only used once per directory (?) +*/ +#ifndef LitDocRootTargetWithNamedOutput +#define LitDocRootTargetWithNamedOutput(rootroot,rootext,rootout) @@\ +DocsTarget(rootroot.info rootroot.dvi) @@\ +ExtraStuffToClean(rootroot.info rootroot.dvi rootroot.texi rootroot.tex) @@\ +LitDependTarget(rootroot,rootext) @@\ + @@\ +rootroot.info:: rootroot.texi @@\ + RemoveTarget($@) @@\ + $(MAKEINFO) $(MAKEINFOFLAGS) rootroot.texi \ @@\ + && $(POSTMAKEINFO) rootroot.info @@\ + @@\ +rootroot.dvi:: rootroot.tex @@\ + RemoveTarget($@) @@\ + $(LTX) rootroot.tex @@\ + @@\ +rootroot.texi: rootout.itxi @@\ + RemoveTarget($@) @@\ + $(LIT2TEXI) -S $(LIT2TEXIFLAGS) -N rootroot.info -o rootroot.texi rootout.itxi @@\ + @@\ +rootout.itxi: rootroot.rootext @@\ + RemoveTarget($@) @@\ + $(LIT2TEXI) -S -c $(LIT2TEXIFLAGS) -o rootout.itxi rootroot.rootext @@\ + @@\ +rootroot.tex: rootout.itex @@\ + RemoveTarget($@) @@\ + $(LIT2LATEX) -S $(LIT2LATEXFLAGS) -o rootroot.tex rootout.itex @@\ + @@\ +rootout.itex: rootroot.rootext @@\ + RemoveTarget($@) @@\ + $(LIT2LATEX) -S -c $(LIT2LATEXFLAGS) -o rootout.itex rootroot.rootext +#endif /* LitDocRootTargetWithNamedOutput */ + +#ifndef LitDocRootTarget +#define LitDocRootTarget(rootroot,rootext) \ +LitDocRootTargetWithNamedOutput(rootroot,rootext,rootroot) +#endif /* LitDocRootTarget */ + +#ifndef VerbatimAndTibTarget +#define VerbatimAndTibTarget(root) @@\ +VerbatimNeededHere(docs root.tex) @@\ +DocsTarget(root.dvi) @@\ +ExtraStuffToClean(root.dvi root.tex) +#endif /* VerbatimAndTibTarget */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-install-docs]{Macros related to \tr{install_docs} std target} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsection[mkworld-macros-cleaning]{Macros related to \tr{clean} (and \tr{veryclean}) std targets} +%* * +%************************************************************************ + +\begin{code} +#ifndef ExtraStuffToClean +#define ExtraStuffToClean(extra) @@\ +clean:: @@\ + $(RM) extra +#endif /* ExtraStuffToClean */ + +#ifndef ExtraStuffToBeVeryClean +#define ExtraStuffToBeVeryClean(extra) @@\ +veryclean:: @@\ + $(RM) extra +#endif /* ExtraStuffToBeVeryClean */ + +#ifndef RemoveTarget +#if RemoveTargetByMoving +#define RemoveTarget(program) \ +$(RM) program; if [ -f program ]; then $(MV) program CAT2(program,~); fi +#else +#define RemoveTarget(program) $(RM) program +#endif /* ! RemoveTargetByMoving */ +#endif /* RemoveTarget */ +/* + * CleanTarget - generate rules to remove any garbage files; the #* is here + * instead of in the definition of CLEAN_CMD because System V would treat a + * pound sign in the CLEAN_CMD variable as a comment. + */ +#ifndef CleanTarget +#define CleanTarget() @@\ +clean:: @@\ + $(CLEAN_CMD) \#* +#endif /* CleanTarget */ + +/* + * VeryCleanTarget - generate rules for "make veryclean"; the idea is + * that "make clean" does what "you almost always want" and "make + * veryclean" removes ALL generated files. + */ +#ifndef VeryCleanTarget +#define VeryCleanTarget() @@\ +veryclean:: @@\ + $(CLEAN_CMD) \#* +#endif /* VeryCleanTarget */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-tags]{Macros related to \tr{tags} std target} +%* * +%************************************************************************ + +\begin{code} +/* this should normally precede <>TagsTarget commands */ +/* those commands *append* to the TAGS file */ +#ifndef ClearTagsFile +#define ClearTagsFile() @@\ +tags:: @@\ + $(RM) TAGS; touch TAGS +#endif + +/* + * CTagsTarget - generate rules to compute tags files for C source code. + * (specified as an arg) + * partain: we really expect "etags" to be used... + */ +#ifndef CTagsTarget +#define CTagsTarget(srcs) @@\ +tags:: @@\ + $(CTAGS) -a $(CTAGSFLAGS) srcs +#endif /* CTagsTarget */ + +/* Similarly for Perl and Haskell */ +#ifndef PerlTagsTarget +#define PerlTagsTarget(srcs) @@\ +tags:: @@\ + $(PERLTAGS) $(PERLTAGSFLAGS) srcs +#endif /* PerlTagsTarget */ + +#ifndef HsTagsTarget +#define HsTagsTarget(srcs) @@\ +tags:: @@\ + $(HSTAGS) $(HSTAGSFLAGS) srcs +#endif /* HsTagsTarget */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-Makefile]{Macros related to \tr{make Makefile}} +%* * +%************************************************************************ + +@BuildMakefileTarget@: generate rules to build a \tr{Makefile} from a +\tr{Jmakefile} (and, in the past, any special jmake flags). This is +generally done automatically by the template or by any special +Jmakefiles. + +\begin{code} +#ifndef BuildMakefileTarget +#define BuildMakefileTarget() @@\ +JmakeNeededHere(Makefile) @@\ + @@\ +Makefile:: $(MYJCONFIGFILES) @@\ + @@\ +Makefile:: @@\ + -@if [ -f Makefile ]; then \ @@\ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ @@\ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ @@\ + else exit 0; fi @@\ + $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(TOP) -DCurDir=$(CURRENT_DIR) @@\ + $(JRESTOREDEPS) @@\ + @if cmp -s Makefile Makefile.bak; then $(RM) Makefile.bak ; fi @@\ + @chmod 444 Makefile @@\ + @echo ==== The new Makefile is for\: ==== @@\ + @$(MAKE) whoami || \ @@\ + ( echo 'Putting old Makefile back (see Makefile.bad)...' && \ @@\ + $(MV) Makefile Makefile.bad && \ @@\ + $(MV) Makefile.bak Makefile ) @@\ + @@\ +whoami:: @@\ + @echo $(PROJECTNAME), version $(PROJECTVERSION) @@\ + @echo project\: $(PROJECTLABEL)\; setup\: $(SETUPLABEL) @@\ + @echo now building on a \`$(BUILDPLATFORM)\' host @@\ + @echo hoping to run on a \`$(HOSTPLATFORM)\' host +#endif /* BuildMakefileTarget */ +\end{code} + +@MakefileTarget@: generate rules to build a normal \tr{Makefile}. +\begin{code} +#ifndef MakefileTarget +#define MakefileTarget() @@\ +BuildMakefileTarget() +#endif /* MakefileTarget */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-macros-MISC]{MISCELLANEOUS macros} +%* * +%************************************************************************ + +\begin{code} +#ifndef GenerateOptionsMakeVars +#define GenerateOptionsMakeVars(PGM,THINGS,AllProjectsPgmThings,PlatformPgmThings,ProjectPgmThings,SetupPgmThings) @@\ +CAT4(GLUED_,PGM,_,THINGS) = AllProjectsPgmThings PlatformPgmThings ProjectPgmThings SetupPgmThings $(CAT3(PGM,_,THINGS)) $(CAT4(EXTRA_,PGM,_,THINGS)) +#endif +\end{code} + + +%************************************************************************ +%* * +\subsection[mkworld-macros-subdir]{Sub-directories: things for std targets...} +%* * +%************************************************************************ + +\subsubsection{@NamedTargetSubdirs@} + +Recursively make a series of steps. + +\begin{code} +#ifndef NamedTargetSubdirs +#define NamedTargetSubdirs(name,dirs,verb,flags,subname) @@\ +name:: @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in dirs ;\ @@\ + do \ @@\ + (cd $$i ; echo verb "in $(CURRENT_DIR)/$$i..."; \ @@\ + $(MAKE) $(MFLAGS) flags subname); \ @@\ + done +#endif +\end{code} + +\subsubsection{@NamedMakeSubdirs@} + +Generate rules to do makes in the given subdirectories. If you want +@CDEBUGFLAGS@ passed along to subdirectories, provide a line like the +following in the appropriate @Jmakefile@: + +\begin{verbatim} +#define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' +\end{verbatim} + +\begin{code} +#ifndef NamedMakeSubdirs +#define NamedMakeSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"making" name,PassCDebugFlags,all) +#endif /* NamedMakeSubdirs */ +\end{code} + +\subsubsection{@DependSubdirs@} + +Generate rules to recursively compute dependencies as +part of the make depend step. + +\begin{code} +#ifndef DependSubdirs +#define DependSubdirs(dirs) \ +NamedTargetSubdirs(depend,dirs,"making dependencies",/**/,depend) +#endif /* DependSubdirs */ +\end{code} + + + +\subsubsection{@DoAllinSubdirs@} + +Generate rules to recursively \tr{make all}. The +\tr{...MakeVarsForAll...} things can be set to have certain +make-variable setting passed downwards. + +\begin{code} +#ifndef ProjectMakeVarsForAllinSubdirs +#define ProjectMakeVarsForAllinSubdirs /*none*/ +#endif + +#ifndef SetupMakeVarsForAllinSubdirs +#define SetupMakeVarsForAllinSubdirs /*none*/ +#endif + +#ifndef DoAllinSubdirs +#define DoAllinSubdirs(dirs) \ +NamedTargetSubdirs(all,dirs,"making all",ProjectMakeVarsForAllinSubdirs SetupMakeVarsForAllinSubdirs,all) +#endif /* DoAllinSubdirs */ +\end{code} + +\subsubsection{@DoDocsinSubdirs@} +Generate rules to recursively \tr{make docs}. +\begin{code} +#ifndef DoDocsinSubdirs +#define DoDocsinSubdirs(dirs) \ +NamedTargetSubdirs(docs,dirs,"making docs",/*no make flags*/,docs) +#endif /* DoDocsinSubdirs */ +\end{code} + +\subsubsection{@RunTestsSubdirs@} + +Generate rules to recursively \tr{make runtests}. + +\begin{code} +#ifndef ProjectMakeVarsForRunTestsinSubdirs +#define ProjectMakeVarsForRunTestsinSubdirs /*none*/ +#endif + +#ifndef SetupMakeVarsForRunTestsinSubdirs +#define SetupMakeVarsForRunTestsinSubdirs /*none*/ +#endif + +#ifndef RunTestsSubdirs +#define RunTestsSubdirs(dirs) \ +NamedTargetSubdirs(runtests,dirs,"running tests",ProjectMakeVarsForRunTestsinSubdirs SetupMakeVarsForRunTestsinSubdirs,runtests) +#endif /* RunTestsSubdirs */ +\end{code} + +\subsubsection{@InstallSubdirs@} +Generate rules to recursively \tr{make install}. +\begin{code} +#ifndef InstallSubdirs +#define InstallSubdirs(dirs) \ +NamedTargetSubdirs(install,dirs,"installing",INSTROOT='$(INSTROOT)',install) +#endif /* InstallSubdirs */ +\end{code} + +\subsubsection{@InstallDocsSubdirs@} +Generate rules to recursively \tr{make install_docs}. +\begin{code} +#ifndef InstallDocsSubdirs +#define InstallDocsSubdirs(dirs) \ +NamedTargetSubdirs(install_docs,dirs,"installing documentation",INSTROOT='$(INSTROOT)',install_docs) +#endif /* InstallDocsSubdirs */ +\end{code} + +\subsubsection{@CleanSubdirs@} +Generate rules to recursively \tr{make clean}. +\begin{code} +#ifndef NamedCleanSubdirs +#define NamedCleanSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"cleaning",RM='$(RM)',clean) +#endif /* NamedCleanSubdirs */ + +#ifndef CleanSubdirs +#define CleanSubdirs(dirs) \ +NamedCleanSubdirs(clean,dirs) +#endif +\end{code} + +\subsubsection{@VeryCleanSubdirs@} +Generate rules to recursively \tr{make veryclean}. +\begin{code} +#ifndef NamedVeryCleanSubdirs +#define NamedVeryCleanSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"being veryclean",RM='$(RM)',veryclean) +#endif /* NamedCleanSubdirs */ + +#ifndef VeryCleanSubdirs +#define VeryCleanSubdirs(dirs) \ +NamedVeryCleanSubdirs(veryclean,dirs) +#endif +\end{code} + +\subsubsection{@TagSubdirs@} +Generate rules to recursively \tr{make tags} (create TAGS files). +\begin{code} +#ifndef NamedTagSubdirs +#define NamedTagSubdirs(name,dirs) \ +NamedTargetSubdirs(name,dirs,"making tags",,tags) +#endif /* TagSubdirs */ + +#ifndef TagSubdirs +#define TagSubdirs(dirs) \ +NamedTagSubdirs(tags,dirs) +#endif +\end{code} + +\subsubsection{@MakeMakeSubdirs@} + +Generate rules to recursively recreate Makefiles as part of the +specified step in the build. If @$(TOP)@ is set to an absolute +path, don't prepend the @../@ prefix. This makes running things +outside of the source tree much easier. + +\begin{code} +#ifndef MakeMakeSubdirs +#define MakeMakeSubdirs(dirs,target) @@\ +target:: @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in dirs ;\ @@\ + do \ @@\ + echo "making Makefiles in $(CURRENT_DIR)/$$i..."; \ @@\ + case "$$i" in \ @@\ + ./?*/?*/?*/?*) newtop=../../../../ sub=subsubsubsub;; \ @@\ + ./?*/?*/?*) newtop=../../../ sub=subsubsub;; \ @@\ + ./?*/?*) newtop=../../ sub=subsub;; \ @@\ + ./?*) newtop=../ sub=sub;; \ @@\ + */?*/?*/?*) newtop=../../../../ sub=subsubsubsub;; \ @@\ + */?*/?*) newtop=../../../ sub=subsubsub;; \ @@\ + */?*) newtop=../../ sub=subsub;; \ @@\ + *) newtop=../ sub=sub;; \ @@\ + esac; \ @@\ + case "$(TOP)" in \ @@\ + /?*) newtop= upprefix= ;; \ @@\ + *) upprefix=../ ;; \ @@\ + esac; \ @@\ + $(MAKE) $${sub}dirMakefiles UPPREFIX=$$upprefix NEWTOP=$$newtop \ @@\ + MAKEFILE_SUBDIR=$$i NEW_CURRENT_DIR=$(CURRENT_DIR)/$$i;\ @@\ + done +#endif /* MakeMakeSubdirs */ +\end{code} + +\subsubsection{@MakeNsubdirMakefiles@} + +Generate rules to create sub Makefiles. + +\begin{code} +#ifndef MakeNsubdirMakefiles +#define MakeNsubdirMakefiles() @@\ +subdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles @@\ + @@\ +subsubdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles @@\ + @@\ +subsubsubdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles @@\ + @@\ +subsubsubsubdirMakefiles: @@\ + $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak @@\ + -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \ @@\ + echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \ @@\ + $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \ @@\ + else exit 0; fi @@\ + cd $(MAKEFILE_SUBDIR); $(JMAKE_CMD) -DTopDirPwd=$(TOP_PWD) -DTopDir=$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(TOP) -DCurDir=$(NEW_CURRENT_DIR); \ @@\ + $(NEWTOP)$(JRESTOREDEPS); \ @@\ + $(MAKE) $(MFLAGS) NEWTOP= Makefile Makefiles +#endif /* MakeNsubdirMakefiles */ +\end{code} + +\subsubsection{@MakefileSubdirs@} + +Generate rules to create \tr{Makefiles}. + +\begin{code} +#ifndef MakefileSubdirs +#define MakefileSubdirs(dirs) @@\ +MakeMakeSubdirs(dirs,Makefiles) @@\ + @@\ +MakeNsubdirMakefiles() +#endif /* MakefileSubdirs */ +\end{code} + +\begin{code} +#ifndef MakeDirectories +#define MakeDirectories(step,dirs) @@\ +step:: @@\ + $(MKDIRHIER) dirs +#endif +\end{code} + +\begin{code} +#ifndef LinkDirectories +#define LinkDirectories(step,dirs,todir) @@\ +step:: @@\ + @case '${MFLAGS}' in *[ik]*) set +e;; esac; \ @@\ + for i in dirs ; \ @@\ + do \ @@\ + echo "linking $$i to" todir; \ @@\ + $(LNDIR) todir $$i; \ @@\ + done +#endif +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-DEF.jm b/web/glasgow/lit2x-0.16/mkworld/plat-DEF.jm new file mode 100644 index 0000000000..bcdbb93eea --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-DEF.jm @@ -0,0 +1,27 @@ +# line 8 "plat-DEF.ljm" +#ifndef OSMajorVersion +#define OSMajorVersion 0 +#endif +#ifndef OSMinorVersion +#define OSMinorVersion 0 +#endif + +#ifndef HasExecableScripts +#define HasExecableScripts YES /* can execute scripts with #! */ +#endif + +#ifndef ConstructMFLAGS +#define ConstructMFLAGS NO /* build MFLAGS from MAKEFLAGS */ +#endif +#if ConstructMFLAGS +MFLAGS = -$(MAKEFLAGS) +#endif + +#ifndef BourneShell /* to force shell in Makefile */ +#define BourneShell /bin/sh +#endif +SHELL = BourneShell +# line 35 "plat-DEF.ljm" +#ifndef CppHaveSysVishTimesH +#define CppHaveSysVishTimesH /*nothing*/ +#endif diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-DEF.ljm b/web/glasgow/lit2x-0.16/mkworld/plat-DEF.ljm new file mode 100644 index 0000000000..a4d1051222 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-DEF.ljm @@ -0,0 +1,38 @@ +%************************************************************************ +%* * +\section[mkworld-plat-GEN]{{\em Defaults} for platform-specific things} +%* * +%************************************************************************ + +\begin{code} +#ifndef OSMajorVersion +#define OSMajorVersion 0 +#endif +#ifndef OSMinorVersion +#define OSMinorVersion 0 +#endif + +#ifndef HasExecableScripts +#define HasExecableScripts YES /* can execute scripts with #! */ +#endif + +#ifndef ConstructMFLAGS +#define ConstructMFLAGS NO /* build MFLAGS from MAKEFLAGS */ +#endif +#if ConstructMFLAGS +MFLAGS = -$(MAKEFLAGS) +#endif + +#ifndef BourneShell /* to force shell in Makefile */ +#define BourneShell /bin/sh +#endif +SHELL = BourneShell +\end{code} + +Have System V-ish \tr{times.h}, with \tr{times} routine, rather than +Berkeley-style \tr{time.h} with \tr{ftime}, etc. +\begin{code} +#ifndef CppHaveSysVishTimesH +#define CppHaveSysVishTimesH /*nothing*/ +#endif +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-TRIGGERS.jm b/web/glasgow/lit2x-0.16/mkworld/plat-TRIGGERS.jm new file mode 100644 index 0000000000..4ccac86ea8 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-TRIGGERS.jm @@ -0,0 +1,50 @@ +# line 1 "plat-TRIGGERS.ljm" +# line 29 "plat-TRIGGERS.ljm" +#ifdef sun +#define PlatformFile plat-sun.jm +#define PlatformIncludeFile <plat-sun.jm> + +#undef sun +#define SunArchitecture +#endif /* sun */ +# line 45 "plat-TRIGGERS.ljm" +#ifdef linux +#define PlatformFile plat-linux.jm +#define PlatformIncludeFile <plat-linux.jm> + +#undef linux +#define LinuxArchitecture +#endif /* linux */ +# line 61 "plat-TRIGGERS.ljm" +#if defined(__alpha) && defined(__osf__) +#define PlatformFile plat-alpha.jm +#define PlatformIncludeFile <plat-alpha.jm> + +#undef __alpha +#undef __osf__ +#define AlphaArchitecture +#endif /* alpha */ +# line 85 "plat-TRIGGERS.ljm" +#ifdef mipsriscos +#define PlatformFile plat-mipsriscos.jm +#define PlatformIncludeFile <plat-mipsriscos.jm> + +#undef mipsriscos +#undef mips +#define MipsRiscosArchitecture /* for OS type */ +#define MipsArchitecture /* for chipset type */ +/* now a dubious HostPlatform definition (there are various "mips" machines) ... */ + +/* ToDo: I admit these are done to suit the Glasgow /bin/arch */ +/* It should probably be "umips" or "umipse[bl]", as appropriate */ +#ifdef SYSTYPE_SYSV +#define HostPlatform mips3000 +#else +#define HostPlatform mips +#endif +#endif /* mipsriscos */ +# line 258 "plat-TRIGGERS.ljm" +#ifndef PlatformIncludeFile +#define PlatformFile could-not-determine-the-platform-from-trigger-symbols +#define PlatformIncludeFile PlatformFile +#endif diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-TRIGGERS.ljm b/web/glasgow/lit2x-0.16/mkworld/plat-TRIGGERS.ljm new file mode 100644 index 0000000000..74fbc927d9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-TRIGGERS.ljm @@ -0,0 +1,290 @@ +%************************************************************************ +%* * +\section[mkworld-plat-TRIGGERS]{Detecting the ``trigger symbol'' for this platform} +%* * +%************************************************************************ + +See the end of this section for how to add support for another platform. + +Note: Only a handful of platforms have been tested with these +configuration files (ToDo). + +You do basically three things here: +\begin{enumerate} +\item +Set @PlatformFile@, etc. +\item +Turn {\em off} any vendor-supplied ``this-is-a-BLAH'' symbol(s). +\item +Turn {\em on} our own ``this-is-a-FOO-Architecture'' symbol(s). +\end{enumerate} + +%************************************************************************ +%* * +\subsection[trigger-Sun]{Trigger stuff for Suns} +%* * +%************************************************************************ + +\begin{code} +#ifdef sun +#define PlatformFile plat-sun.jm +#define PlatformIncludeFile <plat-sun.jm> + +#undef sun +#define SunArchitecture +#endif /* sun */ +\end{code} + +%************************************************************************ +%* * +\subsection[trigger-Linux]{Trigger stuff for Linux} +%* * +%************************************************************************ + +\begin{code} +#ifdef linux +#define PlatformFile plat-linux.jm +#define PlatformIncludeFile <plat-linux.jm> + +#undef linux +#define LinuxArchitecture +#endif /* linux */ +\end{code} + +%************************************************************************ +%* * +\subsection[trigger-Alpha]{Trigger stuff for DEC Alpha running OSF1} +%* * +%************************************************************************ + +\begin{code} +#if defined(__alpha) && defined(__osf__) +#define PlatformFile plat-alpha.jm +#define PlatformIncludeFile <plat-alpha.jm> + +#undef __alpha +#undef __osf__ +#define AlphaArchitecture +#endif /* alpha */ +\end{code} + +%************************************************************************ +%* * +\subsection[trigger-MIPS-RiscOS]{Trigger stuff for MIPS machines running RISCos} +%* * +%************************************************************************ + +OLD: OLD: OLD: + +@mipsriscos@ used instead of @riscos@ because another company (Acorn +Computers Ltd in the UK) has a RISC OS... MIPS RISC/os cpp has no +unique symbol: build @jmake@ with +@BOOTSTRAPCFLAGS=-Dmipsriscos@ + +\begin{code} +#ifdef mipsriscos +#define PlatformFile plat-mipsriscos.jm +#define PlatformIncludeFile <plat-mipsriscos.jm> + +#undef mipsriscos +#undef mips +#define MipsRiscosArchitecture /* for OS type */ +#define MipsArchitecture /* for chipset type */ +/* now a dubious HostPlatform definition (there are various "mips" machines) ... */ + +/* ToDo: I admit these are done to suit the Glasgow /bin/arch */ +/* It should probably be "umips" or "umipse[bl]", as appropriate */ +#ifdef SYSTYPE_SYSV +#define HostPlatform mips3000 +#else +#define HostPlatform mips +#endif +#endif /* mipsriscos */ +\end{code} + +%************************************************************************ +%* * +\subsection[triggers-UNTESTED]{Untested trigger stuff for other machines} +%* * +%************************************************************************ + +COMPLETELY UNTESTED (and so commented out): + +\begin{pseudocode} +#ifdef ultrix +#define PlatformIncludeFile <ultrix.cf> +#define PlatformFile ultrix.cf +#ifdef vax +#undef vax +#define VaxArchitecture +/* hypothetical HostPlatform; we do not have one */ +#define HostPlatform vax +#endif /* vax */ +#ifdef mips +#undef mips +#define MipsArchitecture +/* hypothetical HostPlatform; we do not have one */ +#define HostPlatform pmax +#endif /* mips */ +#undef ultrix +#define UltrixArchitecture +#endif /* ultrix */ + +#if defined(vax) && !defined(UltrixArchitecture) +#define PlatformIncludeFile <bsd.cf> +#define PlatformFile bsd.cf +#undef vax +#define VaxArchitecture +#endif +\end{pseudocode} + +\begin{pseudocode} +#ifdef hpux +#define PlatformIncludeFile <hp.cf> +#define PlatformFile hp.cf +#undef hpux +#define HPArchitecture +#endif /* hpux */ + +#ifdef att +#define PlatformIncludeFile <att.cf> +#define PlatformFile att.cf +#undef att +#define ATTArchitecture +#endif /* att */ + +#ifdef apollo +#define PlatformIncludeFile <apollo.cf> +#define PlatformFile apollo.cf +#undef apollo +#define ApolloArchitecture +#endif /* apollo */ + +#ifdef sony +#define PlatformIncludeFile <sony.cf> +#define PlatformFile sony.cf +#undef sony +#define SonyArchitecture +#endif /* sony */ + +#ifdef M4310 +#define PlatformIncludeFile <pegasus.cf> +#define PlatformFile pegasus.cf +#undef M4310 +#define PegasusArchitecture +#endif /* M4310 */ + +#ifdef M4330 +#define PlatformIncludeFile <m4330.cf> +#define PlatformFile m4330.cf +#undef M4330 +#define M4330Architecture +#endif /* M4330 */ + +#ifdef macII +/* A/UX cpp has no unique symbol: build jmake with BOOTSTRAPCFLAGS=-DmacII */ +#define PlatformIncludeFile <macII.cf> +#define PlatformFile macII.cf +#undef macII +#define MacIIArchitecture +#endif /* macII */ + +#ifdef CRAY +#define PlatformIncludeFile <cray.cf> +#define PlatformFile cray.cf +#undef cray +#undef CRAY +#define CrayArchitecture +#endif /* CRAY */ + +#ifdef sgi +#define PlatformIncludeFile <sgi.cf> +#define PlatformFile sgi.cf +#undef sgi +#define SGIArchitecture +#undef mips +#define MipsArchitecture +#endif + +#ifdef stellar +#define PlatformIncludeFile <stellar.cf> +#define PlatformFile stellar.cf +#undef stellar +#define StellarArchitecture +#endif + +/* + * A convenience for people running on rt's since they define ibm032, and for + * people running AIX (note that AOS will no longer be supported by IBM). + */ +#if defined(ibm032) && !defined(ibm) +#define ibm +#endif + +#if defined(aix) && !defined(ibm) +#define ibm +#endif + +#if defined(ibm) +#define PlatformIncludeFile <ibm.cf> +#define PlatformFile ibm.cf +#undef ibm +#define IBMArchitecture +#ifdef i386 +#undef i386 +#define PS2Architecture +#endif +#ifdef ibm032 +#undef ibm032 +#define RtArchitecture +#endif +#ifdef aix +#undef aix +#define AIXArchitecture +#endif +#endif /* ibm */ +\end{pseudocode} + +%************************************************************************ +%* * +\subsection[triggers-failed]{If no trigger symbol worked...} +%* * +%************************************************************************ + +We don't allow guessing at the platform: this will bomb gruesomely in +short order; it might mean that @BOOTSTRAPCFLAGS@ was not set when +building @jmake@. +\begin{code} +#ifndef PlatformIncludeFile +#define PlatformFile could-not-determine-the-platform-from-trigger-symbols +#define PlatformIncludeFile PlatformFile +#endif +\end{code} + +%************************************************************************ +%* * +\subsection[triggers-adding-platform]{To add support for another platform...} +%* * +%************************************************************************ + +\begin{enumerate} +\item +Identify a machine-specific CPP (``trigger'') symbol. If your preprocessor +doesn't have any built in, you'll need to add the symbol to the +@cpp_argv@ table in \tr{utils/jmake/jmake.c} and rebuild @jmake@ with the +@BOOTSTRAPCFLAGS@ variable set (see the macII for an example). + +\item +Add all machine-specific CPP symbols (either defined by you or by +the preprocessor or compiler) to the @predefs@ table in +@util/makedepend/main.c@. + +\item +Put a new \tr{#ifdef} block above that defines @PlatformIncludeFile@, +@PlatformFile@, etc., for your new platform and then @#undefs@ the +machine-specific preprocessor symbols (to avoid problems with file +names). + +\item +Create suitable \tr{*.jm} files (or ``literate'' equivalents). +\end{enumerate} diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-alpha.jm b/web/glasgow/lit2x-0.16/mkworld/plat-alpha.jm new file mode 100644 index 0000000000..47c16c49d6 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-alpha.jm @@ -0,0 +1,20 @@ +# line 8 "plat-alpha.ljm" +#define HostPlatform alpha + +#define OSName OSF1 +#define OSMajorVersion 1 +#define OSMinorVersion 2 + +#define HasSysVishArAndRanlib YES + +#define CppHaveSysVishTimesH -DHAVE_SYSV_ISH_TIMES_H + +BUILDPLATFORM=HostPlatform + +/* Whenever we run the "std C compiler", give it this flag + (not really platform-ish, but a convenient place to put it) +*/ +#define PlatformCcOpts -ansi -Wall /* full ANSI, please */ + +/* temp: just for debugging */ +#define GhcNormalHighLevelAsmDefaultOpts ('-ansi') diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-alpha.ljm b/web/glasgow/lit2x-0.16/mkworld/plat-alpha.ljm new file mode 100644 index 0000000000..e06129c19b --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-alpha.ljm @@ -0,0 +1,27 @@ +%************************************************************************ +%* * +\section[mkworld-plat-alpha]{Platform configuration stuff for DEC Alpha} +%* * +%************************************************************************ + +\begin{code} +#define HostPlatform alpha + +#define OSName OSF1 +#define OSMajorVersion 1 +#define OSMinorVersion 2 + +#define HasSysVishArAndRanlib YES + +#define CppHaveSysVishTimesH -DHAVE_SYSV_ISH_TIMES_H + +BUILDPLATFORM=HostPlatform + +/* Whenever we run the "std C compiler", give it this flag + (not really platform-ish, but a convenient place to put it) +*/ +#define PlatformCcOpts -ansi -Wall /* full ANSI, please */ + +/* temp: just for debugging */ +#define GhcNormalHighLevelAsmDefaultOpts ('-ansi') +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-linux.jm b/web/glasgow/lit2x-0.16/mkworld/plat-linux.jm new file mode 100644 index 0000000000..56969a3aab --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-linux.jm @@ -0,0 +1,26 @@ +# line 11 "plat-linux.ljm" +#undef i386 /* move to trigger file? (ToDo) */ + +#define iX86Architecture YES +#define i486Architecture YES + +#define HostPlatform i486 + +#define LinuxOSPlatform YES +#define OSName Linux 0.99 +#define OSMajorVersion 0 +#define OSMinorVersion 99 +#define HaveGcc YES /* nothing else on linux... */ + +BUILDPLATFORM=HostPlatform + +/* Whenever we run the "std C compiler", give it this flag */ +#define PlatformCcOpts -m486 + +/*----------------------------------------------------------------------------- + Added by simonm... +-----------------------------------------------------------------------------*/ + +#define MakeCmd make -r /* make ignores implicit rules */ + +/* #define UseFlexForLexCmd we've only got flex on Linux */ diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-linux.ljm b/web/glasgow/lit2x-0.16/mkworld/plat-linux.ljm new file mode 100644 index 0000000000..d176614831 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-linux.ljm @@ -0,0 +1,36 @@ +%************************************************************************ +%* * +\section[mkworld-plat-linus]{Linux-specific configuration stuff} +%* * +%************************************************************************ + +[This file prepared by Andr\'e Santos, the Linux Functional +Programming King (andre\@dcs.glasgow.ac.uk).] + +\begin{code} +#undef i386 /* move to trigger file? (ToDo) */ + +#define iX86Architecture YES +#define i486Architecture YES + +#define HostPlatform i486 + +#define LinuxOSPlatform YES +#define OSName Linux 0.99 +#define OSMajorVersion 0 +#define OSMinorVersion 99 +#define HaveGcc YES /* nothing else on linux... */ + +BUILDPLATFORM=HostPlatform + +/* Whenever we run the "std C compiler", give it this flag */ +#define PlatformCcOpts -m486 + +/*----------------------------------------------------------------------------- + Added by simonm... +-----------------------------------------------------------------------------*/ + +#define MakeCmd make -r /* make ignores implicit rules */ + +/* #define UseFlexForLexCmd we've only got flex on Linux */ +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-mipsriscos.jm b/web/glasgow/lit2x-0.16/mkworld/plat-mipsriscos.jm new file mode 100644 index 0000000000..472a264fa7 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-mipsriscos.jm @@ -0,0 +1,51 @@ +# line 50 "plat-mipsriscos.ljm" +/* + SET VERSION NUMBERS BEFORE MAKING MAKEFILES +*/ + +#define OSMajorVersion 4 +#define OSMinorVersion 51 + +#define CCompilerMajorVersion 2 +#define CCompilerMinorVersion 11 + + +#define BootstrapCFlags -Dmipsriscos + +/* + For BSD environment, need -ltermcap for v?printf. It's not in + the BSD C library! (Yet.) +*/ + +#define InstallCmd /etc/mipsinstall +#define InstFileFlags -f + +#ifndef UsrLibDir +#if SystemV +#define UsrLibDir /usr/lib +#else +#define UsrLibDir /usr/bsd43/usr/lib +#endif +#endif + +#ifndef IncludeRoot +#if SystemV +#define IncludeRoot /usr/include +#else +#define IncludeRoot /usr/include/bsd43 +#endif +#endif + +#define HasVarargs YES +/* + Make sure to use signal semantics that are consistent with + the compilation environment. +*/ +#if SystemV +#define HasVoidSignalReturn YES +#else +#define HasVoidSignalReturn NO +#endif + +/* does this work? or can it be done better? ToDo */ +BUILDPLATFORM=HostPlatform diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-mipsriscos.ljm b/web/glasgow/lit2x-0.16/mkworld/plat-mipsriscos.ljm new file mode 100644 index 0000000000..1bb5496856 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-mipsriscos.ljm @@ -0,0 +1,100 @@ +%************************************************************************ +%* * +\section[mkworld-plat-mipsriscos]{Configuration stuff for MIPS machines running RISCos} +%* * +%************************************************************************ + +Derived from the Paul DuBois's configuration stuff. + +NOTES: + +The MIPS RISC/os modifications are for MIPS machines running RISC/os 4.0 +or later. + +To make makefiles for RISC/os you MUST set your environment +variable JMAKEINCLUDE: + setenv JMAKEINCLUDE "-I. -Dmipsriscos -DSYSTYPE_SYSV" + (or) setenv JMAKEINCLUDE "-I. -Dmipsriscos -DSYSTYPE_BSD" +as appropriate. Cpp does not set these on RISC/os; cc does, but cc is not used +with jmake. + +For RISC/os it is important that the compiler, linker, include files and +libraries be compatible with each other. This can mostly be taken care of +by specifying the -systype {sysv,bsd43} option in the definition of CcCmd, +which will alert the compiler which versions of itself, the linker and +libraries are to be used, and for the most part, the proper include files. +This works whether your PATH setting causes /bin/cc or /usr/bsd43/bin/cc +to be found first. (-systype cannot be specified in StandardCppDefines, +because those get passed to makedepend, and makedepend gets confused +because -systype takes a following argument.) + +If installed versions of jmake or makedepend are used, it is important +that they have been compiled in the same environment as that used to +compile this project, or you will get sysv/bsd conflicts. It may be +best to compile them for both environments and install in /usr/bin and +/bsd43/usr/bin as appropriate. + +The compiled version of makedepend works properly subject to the above +caveat, and is much faster than the script version. The script version +(define UseCCMakeDepend) always works and needs no special hacking to know +about compilation environment, but it's slower. It also generates warnings +about "--" and -O which can be ignored. util/makedepend/Jmakefile was hacked +from the X11R4 release to recognize how to set INCLUDEDIR properly for RISC/os. + +The Jmakefiles contain commands to format the man pages and install them as +required; however since RISC/os does not include nroff this will typically +not be effective. If you have the BSD or DWB packages installed, you may +be in better shape. + +\begin{code} +/* + SET VERSION NUMBERS BEFORE MAKING MAKEFILES +*/ + +#define OSMajorVersion 4 +#define OSMinorVersion 51 + +#define CCompilerMajorVersion 2 +#define CCompilerMinorVersion 11 + + +#define BootstrapCFlags -Dmipsriscos + +/* + For BSD environment, need -ltermcap for v?printf. It's not in + the BSD C library! (Yet.) +*/ + +#define InstallCmd /etc/mipsinstall +#define InstFileFlags -f + +#ifndef UsrLibDir +#if SystemV +#define UsrLibDir /usr/lib +#else +#define UsrLibDir /usr/bsd43/usr/lib +#endif +#endif + +#ifndef IncludeRoot +#if SystemV +#define IncludeRoot /usr/include +#else +#define IncludeRoot /usr/include/bsd43 +#endif +#endif + +#define HasVarargs YES +/* + Make sure to use signal semantics that are consistent with + the compilation environment. +*/ +#if SystemV +#define HasVoidSignalReturn YES +#else +#define HasVoidSignalReturn NO +#endif + +/* does this work? or can it be done better? ToDo */ +BUILDPLATFORM=HostPlatform +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-sun.jm b/web/glasgow/lit2x-0.16/mkworld/plat-sun.jm new file mode 100644 index 0000000000..7c4a98b539 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-sun.jm @@ -0,0 +1,32 @@ +# line 8 "plat-sun.ljm" +#define SunOSPlatform YES /* set to NO if not running SunOS */ +#define OSName SunOS 4.1 +#define OSMajorVersion 4 +#define OSMinorVersion 1 + +#if OSMajorVersion >=4 && OSMinorVersion >= 1 +#define ConstructMFLAGS 1 +#endif + +#if OSMajorVersion >= 4 +#define HasSunOSSharedLibraries YES +#endif + +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#undef sparc +#undef __sparc +#undef __sparc__ + +#define SparcArchitecture +/* HostPlatform should probably be "sparc" but this suits Glasgow /bin/arch */ +#define HostPlatform sun4 + +#else /* ! sparc */ + +/* OK, a wild guess ... */ +#define m68kArchitecture +#define HostPlatform sun3 + +#endif /* ! sparc */ + +BUILDPLATFORM=HostPlatform diff --git a/web/glasgow/lit2x-0.16/mkworld/plat-sun.ljm b/web/glasgow/lit2x-0.16/mkworld/plat-sun.ljm new file mode 100644 index 0000000000..1b11184366 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/plat-sun.ljm @@ -0,0 +1,39 @@ +%************************************************************************ +%* * +\section[mkworld-plat-sun]{Sun-specific configuration stuff} +%* * +%************************************************************************ + +\begin{code} +#define SunOSPlatform YES /* set to NO if not running SunOS */ +#define OSName SunOS 4.1 +#define OSMajorVersion 4 +#define OSMinorVersion 1 + +#if OSMajorVersion >=4 && OSMinorVersion >= 1 +#define ConstructMFLAGS 1 +#endif + +#if OSMajorVersion >= 4 +#define HasSunOSSharedLibraries YES +#endif + +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#undef sparc +#undef __sparc +#undef __sparc__ + +#define SparcArchitecture +/* HostPlatform should probably be "sparc" but this suits Glasgow /bin/arch */ +#define HostPlatform sun4 + +#else /* ! sparc */ + +/* OK, a wild guess ... */ +#define m68kArchitecture +#define HostPlatform sun3 + +#endif /* ! sparc */ + +BUILDPLATFORM=HostPlatform +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/site-DEF.jm b/web/glasgow/lit2x-0.16/mkworld/site-DEF.jm new file mode 100644 index 0000000000..4e9fab42a9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/site-DEF.jm @@ -0,0 +1,45 @@ +# line 1 "site-DEF.ljm" +# line 8 "site-DEF.ljm" +/* TopDir and CurDir likely defined on command line */ +#ifndef TopDir +#define TopDir . +#endif +TOP = TopDir + +#ifndef TopDirPwd +#define TopDirPwd / +#endif +TOP_PWD = TopDirPwd /* absolute pathname of TOP */ + +#ifndef CurDir +#define CurDir . +#endif +CURRENT_DIR = CurDir + +#ifndef TmpDir /* I do not know why this was /usr/tmp */ +#define TmpDir /tmp +#endif +TMPDIR = TmpDir /* temporary files */ + +#ifndef BootstrapCFlags +#define BootstrapCFlags /*none*/ +#endif +BOOTSTRAPCFLAGS = BootstrapCFlags /* set if cpp doesn't have uniq sym */ +# line 36 "site-DEF.ljm" +#ifndef ManDirectoryRoot +#define ManDirectoryRoot /usr/man +#endif + +#ifndef DefaultInfoPath +#define DefaultInfoPath /usr/local/lib/info:. +#endif + +#ifndef IncludeTestDirsInBuild +#define IncludeTestDirsInBuild NO +#endif + +/* Misc. misc. */ + +#ifndef RemoveTargetByMoving +#define RemoveTargetByMoving NO /* affects Jmake.rules */ +#endif diff --git a/web/glasgow/lit2x-0.16/mkworld/site-DEF.ljm b/web/glasgow/lit2x-0.16/mkworld/site-DEF.ljm new file mode 100644 index 0000000000..368542dea0 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/site-DEF.ljm @@ -0,0 +1,53 @@ +%************************************************************************ +%* * +\section[mkworld-site-GEN]{{\em Defaults} for site-selectable things} +%* * +%************************************************************************ + +\begin{code} +/* TopDir and CurDir likely defined on command line */ +#ifndef TopDir +#define TopDir . +#endif +TOP = TopDir + +#ifndef TopDirPwd +#define TopDirPwd / +#endif +TOP_PWD = TopDirPwd /* absolute pathname of TOP */ + +#ifndef CurDir +#define CurDir . +#endif +CURRENT_DIR = CurDir + +#ifndef TmpDir /* I do not know why this was /usr/tmp */ +#define TmpDir /tmp +#endif +TMPDIR = TmpDir /* temporary files */ + +#ifndef BootstrapCFlags +#define BootstrapCFlags /*none*/ +#endif +BOOTSTRAPCFLAGS = BootstrapCFlags /* set if cpp doesn't have uniq sym */ +\end{code} + +\begin{code} +#ifndef ManDirectoryRoot +#define ManDirectoryRoot /usr/man +#endif + +#ifndef DefaultInfoPath +#define DefaultInfoPath /usr/local/lib/info:. +#endif + +#ifndef IncludeTestDirsInBuild +#define IncludeTestDirsInBuild NO +#endif + +/* Misc. misc. */ + +#ifndef RemoveTargetByMoving +#define RemoveTargetByMoving NO /* affects Jmake.rules */ +#endif +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/site.dist b/web/glasgow/lit2x-0.16/mkworld/site.dist new file mode 100644 index 0000000000..94b8c9a109 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/site.dist @@ -0,0 +1,147 @@ +/************************************************************************ + +General site-specific configuration information: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is where _general_ facts about your local computing environment +are recorded. + +_Project-specific_ facts go in "site-<project>.jm", and facts specific +to a ``setup'' of a project (unlikely...) go in +"site-<project>-<setup>.jm". + +As you will see, the general style for setting these configuration facts is: + + #ifndef ABuildParameter + #define ABuildParameter myvalue + #endif + +This particular file is for the Computing Science Dept at Glasgow +University. +************************************************************************/ + +#ifndef PerlCmd +#if defined(LinuxOSPlatform) +#define PerlCmd /usr/bin/perl +#else +#define PerlCmd /usr/local/bin/perl +#endif /* ! Linux */ +#endif /* PerlCmd */ + +/* For "make tags", we recommend "etags" from the Emacs distribution. + (we supply a variant in the GHC distribution; grasp-utils/etags) + If not readily available on your search PATH, say where to find it here. + */ +#ifndef CTagsCmd +#define CTagsCmd $(ETAGS) +#endif + +/* + * Site-specific compiler things: for Glasgow + */ + +/* --------------- C compiler --------------------------------- */ +/* we have gcc [by which we mean version 2.n] for sun4s and sun3s; + IT IS GOOD TO SAY `YES' ! + (It is *essential* for the Glasgow Haskell compiler) + */ +#ifndef HaveGcc +#if defined(SparcArchitecture) \ + || defined(m68kArchitecture) \ + || defined(AlphaArchitecture) \ + || defined(LinuxOSPlatform) +#define HaveGcc YES +#else +#define HaveGcc NO +#endif /* ! one of those */ +#endif /* ! HaveGcc */ + +#ifndef WhatGccIsCalled /* version 2.n, please */ +#if defined(m68kArchitecture) +#define WhatGccIsCalled gcc-m68k /* to tell the truth, we cross-compile */ +#else +#define WhatGccIsCalled gcc +#endif /* m68k */ +#endif /* ! WhatGccIsCalled */ + +/* Set UseGcc to YES if you want to use it for "ordinary" C compilations. + YES, by default. "UseGcc" *and* "HaveGcc" both have to be YES for + anything to happen. + + This is *independent* of whether you set "UseGccForNormalGhcAsm" + and/or "UseGccForOptGhcAsm", which are GHC-specific. +*/ + +#if ! defined(UseGcc) && HaveGcc == YES +#define UseGcc YES +#endif /* ! UseGcc */ + +/* --------------- "standard" Haskell compiler --------------------------- */ + +/* What do we *have*? + We have Chalmers "hbc" for sun4s + We have Glasgow Haskell (called "glhc" at Glasgow) for sun4s and sun3s +*/ +#ifndef HaveChalmersHBC +#if defined(SparcArchitecture) \ + || defined(LinuxOSPlatform) +#define HaveChalmersHBC YES +#else +#define HaveChalmersHBC NO +#endif /* ! one of those */ +#endif /* ! HaveChalmersHBC */ + +#ifndef HaveGlasgowHaskell +#if defined(m68kArchitecture) \ + || defined(SparcArchitecture) \ + || defined(AlphaArchitecture) +#define HaveGlasgowHaskell YES +#else +#define HaveGlasgowHaskell NO +#endif /* ! m68k or sparc */ +#endif /* ! HaveGlasgowHaskell */ + +#ifndef WhatGhcIsCalled /* Glasgow Haskell compiler */ +#define WhatGhcIsCalled ghc +#endif + +/* What do we *use* for our "standard Haskell compiler"? + A "setup" may very well set this (mkworld/site-<project>-<setup>.jm); + the default is Glasgow Haskell. +*/ +#if !defined(UseGlasgowHaskell) && !defined(UseChalmersHBC) +#define UseGlasgowHaskell YES +#endif + +/* Finally: set "HaskellCompileCmd" (your "standard Haskell compiler") +*/ +#ifndef HaskellCompileCmd +#if HaveGlasgowHaskell == YES && UseGlasgowHaskell == YES +#define HaskellCompileCmd WhatGhcIsCalled +#else /* ! ...GlasgowHaskell */ +#if HaveChalmersHBC == YES && UseChalmersHBC == YES +#define HaskellCompileCmd hbc +#else +#define HaskellCompileCmd no_default_haskell_compiler_defined +#endif /* ! ...ChalmersHBC */ +#endif /* ! ...GlasgowHaskell */ +#endif /* ! HaskellCompileCmd */ + +/* --------------- V misc stuff --------------------------- */ + +/* Your main directory for GNU Info files should come first. + If in doubt, get an Emacs person to do "C-h v Info-directory" + to tell you where Emacs looks for Info files. +*/ +#ifndef DefaultInfoPath +#if defined(LinuxOSPlatform) +#define DefaultInfoPath /usr/emacs/info:. +#else +#define DefaultInfoPath /local/doc/info:. +#endif +#endif + +/* ugly, ain't it ? */ +#ifndef TgrindHelperCmd +#define TgrindHelperCmd /usr/local/tex/lib/tgrind/HostPlatform/tfontedpr +#endif diff --git a/web/glasgow/lit2x-0.16/mkworld/suffixes-GEN.jm b/web/glasgow/lit2x-0.16/mkworld/suffixes-GEN.jm new file mode 100644 index 0000000000..8a399a7ac5 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/suffixes-GEN.jm @@ -0,0 +1,154 @@ +# line 31 "suffixes-GEN.ljm" +#ifndef LitSuffixRule +#define LitSuffixRule(beforesuff,aftersuff) @@\ +CAT2(beforesuff,aftersuff): @@\ + $(RM) $@ @@\ + $(LIT2PGM) $(LIT2PGMFLAGS) -o $@ $< @@\ + @chmod 444 $@ @@\ + @@\ +beforesuff.itxi: @@\ + $(RM) $@ @@\ + $(LIT2TEXI) -c $(LIT2TEXIFLAGS) -o $@ $< @@\ + @chmod 444 $@ @@\ + @@\ +beforesuff.itex: @@\ + $(RM) $@ @@\ + $(LIT2LATEX) -c $(LIT2LATEXFLAGS) -o $@ $< @@\ + @chmod 444 $@ +#endif /* LitSuffixRule */ +# line 59 "suffixes-GEN.ljm" +#ifndef NormalLibraryObjectRule +#define NormalLibraryObjectRule() @@\ +.c.o: @@\ + RemoveTarget ($@) @@\ + $(CC) -c $(CFLAGS) $*.c +#endif +# line 84 "suffixes-GEN.ljm" +#ifndef HaskellSuffixRules +#define HaskellSuffixRules() @@\ +SuffixRule_o_hi() @@\ +SuffixRule_lhs_o() @@\ +SuffixRule_hs_o() +#endif /* !HaskellSuffixRules */ +# line 97 "suffixes-GEN.ljm" +#ifndef SuffixRule_o_hi +#define SuffixRule_o_hi() @@\ +.o.hi: @@\ + @if [ ! -f $@ ] ; then \ @@\ + echo $(RM) $< ; \ @@\ + $(RM) $< ; \ @@\ + set +e ; \ @@\ + echo $(MAKE) HC="$(HC)" HCFLAGS="$(HCFLAGS)" $(MFLAGS) $< ; \ @@\ + $(MAKE) HC="$(HC)" HCFLAGS="$(HCFLAGS)" $(MFLAGS) $< ; \ @@\ + if [ $$? -ne 0 ] ; then \ @@\ + exit 1; \ @@\ + fi ; \ @@\ + fi +#endif /* !SuffixRule_o_hi */ +# line 114 "suffixes-GEN.ljm" +#ifndef SuffixRule_hs_o +#define SuffixRule_hs_o() @@\ +.hs.o: \ +_body_HaskellCompileWithSpecifiedFlags($<,$*,hs,-c $(HCFLAGS)) +#endif /* !SuffixRule_hs_o */ + +#ifndef SuffixRule_lhs_o +#define SuffixRule_lhs_o() @@\ +.lhs.o: \ +_body_HaskellCompileWithSpecifiedFlags($<,$*,lhs,-c $(HCFLAGS)) +#endif /* !SuffixRule_lhs_o */ +# line 136 "suffixes-GEN.ljm" +#ifndef DocProcessingSuffixRules +#define DocProcessingSuffixRules() @@\ +.tex.dvi: @@\ + $(RM) $@ @@\ + $(LTX) $< @@\ + @@\ +.verb.tex: @@\ + $(RM) $*.tex @@\ + expand $*.verb | $(VERBATIM) > $*.tex @@\ + @@\ +.tib.tex: @@\ + $(RM) $*.tex $*.verb-t.tex @@\ + $(TIB) $*.tib @@\ + expand $*.tib-t.tex | $(VERBATIM) > $*.tex @@\ + $(RM) $*.tib-t.tex @@\ + @@\ +.fig.ps: @@\ + $(RM) $@ @@\ + fig2dev -L ps $< $@ @@\ + @@\ +.fig.tex: @@\ + $(RM) $@ @@\ + fig2dev -L latex $< $@ + +#endif /* ! DocProcessingSuffixRules */ +# line 170 "suffixes-GEN.ljm" +.SUFFIXES: .xdvi .ps .dvi .tex .fig .tib .verb .itex .itxi .lit \ + _p.o .o .s .hi .hc .lhc .lhs .hs \ + .prl .lprl \ + .sh .lsh \ + .c .lc .h .lh .lex .llex .y \ + .ljm .jm +# line 185 "suffixes-GEN.ljm" +.s.o: + $(RM) $@ + $(AS) $(ASFLAGS) -o $@ $< || $(RM) $@ +# line 200 "suffixes-GEN.ljm" +LitSuffixRule(.ljm,.jm) /* mkworld */ + +#if SuffixRules_WantLiterate == YES + +LitSuffixRule(.lit,/*none*/) /* no language really */ +LitSuffixRule(.lhs,.hs) /* Haskell */ +LitSuffixRule(.lhc,.hc) /* Haskell assembler (C) */ +LitSuffixRule(.lprl,.prl) /* Perl */ +LitSuffixRule(.lsh,.sh) /* Bourne shell */ +LitSuffixRule(.lc,.c) /* C */ +LitSuffixRule(.lh,.h) +LitSuffixRule(.llex,.lex) /* Lex */ + +/* extra rule... flex can't handle #line's yet */ +/* also: save the .lex file in case of some debugging need */ +.llex.c: + $(RM) $@ $*.lex $*.lex.save + $(LIT2PGM) $(LIT2PGMFLAGS) $< > $*.lex + $(FLEX) $*.lex && mv $*.lex $*.lex.save && mv lex.yy.c $*.c + +#endif /* SuffixRules_WantLiterate */ +# line 234 "suffixes-GEN.ljm" +.y.c: + @echo please use an explicit "YaccRunWithExpectMsg" macro + +.lex.c: /* ToDo: should make it do flex */ + $(RM) $@ + $(LEX) -t $(LFLAGS) $< > $@ || ( $(RM) $@ && exit 1 ) +# line 244 "suffixes-GEN.ljm" +#if CCompilerGroksMinusCMinusO == YES +.c.o: + $(RM) $@ + $(CC) $(CFLAGS) -c $< -o $@ +.c.s: + $(RM) $@ + $(CC) $(CFLAGS) -S $< -o $@ + +#else /* ! CCompilerGroksMinusCMinusO */ +.c.o: + $(RM) $@ + $(CC) $(CFLAGS) -c $< + @if [ \( $(@D) != '.' \) -a \( $(@D) != './' \) ] ; then \ + echo mv $(@F) $@ ; \ + mv $(@F) $@ ; \ + fi +.c.s: + $(RM) $@ + $(CC) $(CFLAGS) -S $< + @if [ \( $(@D) != '.' \) -a \( $(@D) != './' \) ] ; then \ + echo mv $(@F) $@ ; \ + mv $(@F) $@ ; \ + fi +#endif /* ! CCompilerGroksMinusCMinusO */ +# line 287 "suffixes-GEN.ljm" +#if SuffixRules_WantDocProcessing == YES +DocProcessingSuffixRules() +#endif /* SuffixRules_WantDocProcessing */ diff --git a/web/glasgow/lit2x-0.16/mkworld/suffixes-GEN.ljm b/web/glasgow/lit2x-0.16/mkworld/suffixes-GEN.ljm new file mode 100644 index 0000000000..ad1fe6d2b7 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/suffixes-GEN.ljm @@ -0,0 +1,290 @@ +%************************************************************************ +%* * +\section[mkworld-suffix-rules]{Default stuff for suffix rules} +%* * +%************************************************************************ + +We are keen on suffix rules, rather than pattern rules, because not +all makes do the latter. Sigh. + +Suffix rules come in three blobs: (1)~the unavoidable ones [few]; +(2)~the ``always for this project'' ones [turn-off-able]; and (3)~the +per-Jmakefile ones (you must ``ask for'' these in each Jmakefile where +you need them. + +%************************************************************************ +%* * +\subsection[mkworld-suffix-macros]{Macros for making up suffix rules} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsubsection[mkworld-suffix-macros-literate]{Suffix-rule macros for literate stuff} +%* * +%************************************************************************ + +The following rule generator assumes the @beforesuff->aftersuff@ is +known to the literate programming system. + +\begin{code} +#ifndef LitSuffixRule +#define LitSuffixRule(beforesuff,aftersuff) @@\ +CAT2(beforesuff,aftersuff): @@\ + $(RM) $@ @@\ + $(LIT2PGM) $(LIT2PGMFLAGS) -o $@ $< @@\ + @chmod 444 $@ @@\ + @@\ +beforesuff.itxi: @@\ + $(RM) $@ @@\ + $(LIT2TEXI) -c $(LIT2TEXIFLAGS) -o $@ $< @@\ + @chmod 444 $@ @@\ + @@\ +beforesuff.itex: @@\ + $(RM) $@ @@\ + $(LIT2LATEX) -c $(LIT2LATEXFLAGS) -o $@ $< @@\ + @chmod 444 $@ +#endif /* LitSuffixRule */ +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffix-macros-C]{Suffix-rule macros for C} +%* * +%************************************************************************ + +For objects in libraries: these rules are invoked when you want to +override some default suffix rules. +\begin{code} +#ifndef NormalLibraryObjectRule +#define NormalLibraryObjectRule() @@\ +.c.o: @@\ + RemoveTarget ($@) @@\ + $(CC) -c $(CFLAGS) $*.c +#endif +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffix-macros-Haskell]{Suffix-rule macros for Haskell} +%* * +%************************************************************************ + +There are several varying flavours of Haskell-related suffix rules; +each such ``set'' of suffix rules should include...: + +\begin{verbatim} +.o -> .hi # hacky pseudo-dependency to mk .hi file if non-existent +.lhs -> .o +.hs -> .o +\end{verbatim} + +This is the {\em default}; a project or setup could override it. +\begin{code} +#ifndef HaskellSuffixRules +#define HaskellSuffixRules() @@\ +SuffixRule_o_hi() @@\ +SuffixRule_lhs_o() @@\ +SuffixRule_hs_o() +#endif /* !HaskellSuffixRules */ +\end{code} + +We use the internal mkworld CPP macro +@_body_HaskellCompileWithSpecifiedFlags@, which is shared w/ other +mkworld stuff. This keeps the magic to exactly one place. + +\begin{code} +#ifndef SuffixRule_o_hi +#define SuffixRule_o_hi() @@\ +.o.hi: @@\ + @if [ ! -f $@ ] ; then \ @@\ + echo $(RM) $< ; \ @@\ + $(RM) $< ; \ @@\ + set +e ; \ @@\ + echo $(MAKE) HC="$(HC)" HCFLAGS="$(HCFLAGS)" $(MFLAGS) $< ; \ @@\ + $(MAKE) HC="$(HC)" HCFLAGS="$(HCFLAGS)" $(MFLAGS) $< ; \ @@\ + if [ $$? -ne 0 ] ; then \ @@\ + exit 1; \ @@\ + fi ; \ @@\ + fi +#endif /* !SuffixRule_o_hi */ +\end{code} + +\begin{code} +#ifndef SuffixRule_hs_o +#define SuffixRule_hs_o() @@\ +.hs.o: \ +_body_HaskellCompileWithSpecifiedFlags($<,$*,hs,-c $(HCFLAGS)) +#endif /* !SuffixRule_hs_o */ + +#ifndef SuffixRule_lhs_o +#define SuffixRule_lhs_o() @@\ +.lhs.o: \ +_body_HaskellCompileWithSpecifiedFlags($<,$*,lhs,-c $(HCFLAGS)) +#endif /* !SuffixRule_lhs_o */ +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffix-macros-doc]{Suffix-rule macros for document processing} +%* * +%************************************************************************ + +You have to ask for these. + +\begin{code} +#ifndef DocProcessingSuffixRules +#define DocProcessingSuffixRules() @@\ +.tex.dvi: @@\ + $(RM) $@ @@\ + $(LTX) $< @@\ + @@\ +.verb.tex: @@\ + $(RM) $*.tex @@\ + expand $*.verb | $(VERBATIM) > $*.tex @@\ + @@\ +.tib.tex: @@\ + $(RM) $*.tex $*.verb-t.tex @@\ + $(TIB) $*.tib @@\ + expand $*.tib-t.tex | $(VERBATIM) > $*.tex @@\ + $(RM) $*.tib-t.tex @@\ + @@\ +.fig.ps: @@\ + $(RM) $@ @@\ + fig2dev -L ps $< $@ @@\ + @@\ +.fig.tex: @@\ + $(RM) $@ @@\ + fig2dev -L latex $< $@ + +#endif /* ! DocProcessingSuffixRules */ +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-suffix-rule-text]{Generate actual suffix-rule text} +%* * +%************************************************************************ + +\begin{code} +.SUFFIXES: .xdvi .ps .dvi .tex .fig .tib .verb .itex .itxi .lit \ + _p.o .o .s .hi .hc .lhc .lhs .hs \ + .prl .lprl \ + .sh .lsh \ + .c .lc .h .lh .lex .llex .y \ + .ljm .jm +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffixes-general]{Suffix rules---very general ones} +%* * +%************************************************************************ + +\begin{code} +.s.o: + $(RM) $@ + $(AS) $(ASFLAGS) -o $@ $< || $(RM) $@ +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffixes-literate]{Suffix rules for literate programming} +%* * +%************************************************************************ + +The \tr{.ljm->.jm} rule isn't optional, because the mkworld system +uses it. + +\begin{code} +LitSuffixRule(.ljm,.jm) /* mkworld */ + +#if SuffixRules_WantLiterate == YES + +LitSuffixRule(.lit,/*none*/) /* no language really */ +LitSuffixRule(.lhs,.hs) /* Haskell */ +LitSuffixRule(.lhc,.hc) /* Haskell assembler (C) */ +LitSuffixRule(.lprl,.prl) /* Perl */ +LitSuffixRule(.lsh,.sh) /* Bourne shell */ +LitSuffixRule(.lc,.c) /* C */ +LitSuffixRule(.lh,.h) +LitSuffixRule(.llex,.lex) /* Lex */ + +/* extra rule... flex can't handle #line's yet */ +/* also: save the .lex file in case of some debugging need */ +.llex.c: + $(RM) $@ $*.lex $*.lex.save + $(LIT2PGM) $(LIT2PGMFLAGS) $< > $*.lex + $(FLEX) $*.lex && mv $*.lex $*.lex.save && mv lex.yy.c $*.c + +#endif /* SuffixRules_WantLiterate */ +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffixes-C]{Suffix rules for C/lex/yacc programming} +%* * +%************************************************************************ + +See also the ``literate lex'' (llex) rule in the literate section, above. + +We don't support the \tr{.y.c} suffix rule; an explicit +@YaccRunWithExpectMsg@ is better. +\begin{code} +.y.c: + @echo please use an explicit "YaccRunWithExpectMsg" macro + +.lex.c: /* ToDo: should make it do flex */ + $(RM) $@ + $(LEX) -t $(LFLAGS) $< > $@ || ( $(RM) $@ && exit 1 ) +\end{code} + +NB: avoid \tr{-o <something>} because of braindead C compilers. +\begin{code} +#if CCompilerGroksMinusCMinusO == YES +.c.o: + $(RM) $@ + $(CC) $(CFLAGS) -c $< -o $@ +.c.s: + $(RM) $@ + $(CC) $(CFLAGS) -S $< -o $@ + +#else /* ! CCompilerGroksMinusCMinusO */ +.c.o: + $(RM) $@ + $(CC) $(CFLAGS) -c $< + @if [ \( $(@D) != '.' \) -a \( $(@D) != './' \) ] ; then \ + echo mv $(@F) $@ ; \ + mv $(@F) $@ ; \ + fi +.c.s: + $(RM) $@ + $(CC) $(CFLAGS) -S $< + @if [ \( $(@D) != '.' \) -a \( $(@D) != './' \) ] ; then \ + echo mv $(@F) $@ ; \ + mv $(@F) $@ ; \ + fi +#endif /* ! CCompilerGroksMinusCMinusO */ +\end{code} + +%************************************************************************ +%* * +\subsubsection[mkworld-suffixes-haskell]{Suffix rules for Haskell programming} +%* * +%************************************************************************ + +Suffix rules for Haskell are {\em not} put in by default. A Jmakefile +must ask for one specifically, using one of the macros defined in +macros section, above (\sectionref{mkworld-suffix-macros-Haskell}). + +%************************************************************************ +%* * +\subsubsection[mkworld-suffixes-docs]{Suffix rules for document processing (LaTeX/tib/fig/etc)} +%* * +%************************************************************************ + +\begin{code} +#if SuffixRules_WantDocProcessing == YES +DocProcessingSuffixRules() +#endif /* SuffixRules_WantDocProcessing */ +\end{code} diff --git a/web/glasgow/lit2x-0.16/mkworld/utils-GEN.jm b/web/glasgow/lit2x-0.16/mkworld/utils-GEN.jm new file mode 100644 index 0000000000..46e2d3c97a --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/utils-GEN.jm @@ -0,0 +1,1096 @@ +# line 25 "utils-GEN.ljm" +#ifndef ArCmd +#if HasSysVishArAndRanlib == YES +#define ArCmd ar clqs +#else +#define ArCmd ar clq +#endif +#endif +AR = ArCmd +# line 36 "utils-GEN.ljm" +#ifndef ArchCmd +#define ArchCmd arch +#endif +ARCH_CMD = ArchCmd + +#ifndef MachCmd +#define MachCmd mach +#endif +MACH_CMD = MachCmd + +#ifndef AsCmd +#define AsCmd as +#endif +AS = AsCmd + +#ifndef WhatGccIsCalled /* version 2.n, please */ +#define WhatGccIsCalled gcc +#endif + +#ifndef CcCmd +#if (HaveGcc == YES) && (UseGcc == YES) +#define CcCmd WhatGccIsCalled +#else +#define CcCmd cc +#endif /* ! HaveGcc etc */ +#endif /* CcCmd */ +CC = CcCmd + +#ifndef CompressCmd +#define CompressCmd compress +#endif +COMPRESS = CompressCmd + +#ifndef CpCmd +#define CpCmd cp +#endif +CP = CpCmd + +#ifndef CppCmd +#define CppCmd /lib/cpp +#endif +#ifndef PreProcessCmd +#define PreProcessCmd CcCmd -E +#endif +CPP = CppCmd $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) /* simple filters */ +PREPROCESSCMD = PreProcessCmd $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) /* preferred; mdep */ + +#ifndef InstallCmd +#define InstallCmd install +#endif /* InstallCmd */ +INSTALL = InstallCmd +#ifndef InstallingByDefault +#define InstallingByDefault 0 +#endif +INSTALLING = InstallingByDefault + +#ifndef LexCmd +#ifdef UseFlexForLexCmd +#define LexCmd flex +#else +#define LexCmd lex +#endif +#endif +#ifndef FlexCmd +#define FlexCmd flex -s +#endif +LEX = LexCmd +FLEX = FlexCmd $(EXTRA_FLEX_FLAGS) /* this is asking for it... */ + +/* the installed Haskell compiler */ +#ifndef HaskellCompileCmd +#define HaskellCompileCmd hc +#endif +HC = HaskellCompileCmd + +#ifndef LaTeXCmd +#define LaTeXCmd latex +#endif +LATEX = LaTeXCmd +/* see also the LaTeX-wrapper script, LTX, in AllProjects */ + +#ifndef LdCmd +#define LdCmd ld +#endif +LD = LdCmd + +#ifndef LintCmd +#define LintCmd lint +#endif +LINT = LintCmd + +#ifndef LnCmd +#define LnCmd ln -s +#endif /* LnCmd */ +LN = LnCmd + +#ifndef MakeCmd +#define MakeCmd make +#endif +/* this might be useful at some point ... */ +#ifndef MakeCmdIsGnuMake +#define MakeCmdIsGnuMake NO +#endif +MAKE = MakeCmd + +#ifndef MvCmd +#define MvCmd mv +#endif +MV = MvCmd + +#ifndef NroffCmd +#define NroffCmd nroff +#endif +#ifndef ManMacros +#define ManMacros -man +#endif +#ifndef MsMacros +#define MsMacros -ms +#endif +NROFF = NroffCmd +MANMACROS = ManMacros +MSMACROS = MsMacros + +#ifndef PerlCmd +#define PerlCmd /usr/bin/perl +#endif +PERL = PerlCmd + +#ifndef PicCmd +#define PicCmd pic +#endif +PIC = PicCmd + +#ifndef PrinterCmd +#define PrinterCmd lpr +#endif +PRINTER = PrinterCmd + +#ifndef RanlibCmd +#if HasSysVishArAndRanlib == YES +#define RanlibCmd /bin/true /* does nothing */ +#else +#define RanlibCmd ranlib +#endif +#endif +RANLIB = RanlibCmd + +#ifndef RmCmd +#define RmCmd rm -f +#endif +RM = RmCmd +/* a project may want to override CLEAN_CMD */ + +/* see the comment about not having #*, under CleanTarget rule in Jmake.rules */ +/* ToDo: what about bbl files? */ +#ifndef FilesToClean +#define FilesToClean *.CKP *.ln *.BAK *.bak *.o core a.out errs ,* *.a .emacs_* tags TAGS \ + *.ind *.ilg *.idx *.idx-prev *.aux *.aux-prev *.dvi *.log *.toc *.lot *.lof \ + *.blg *.info *.itxi *.itex *.cb +#endif +/* you can override this in various ways... */ +/* Real Men (TM) will have the following in their veryclean stuff: + Makefile + .??*~ *~ (emacs backup files) + *.tex *.texi + *.lex.c *.yacc.c [however this should be done...] + *.orig *.rej (patch droppings) +*/ +#ifndef ExtraFilesToBeVeryClean +#define ExtraFilesToBeVeryClean .??*~ *~ *.orig *.rej +#endif +CLEAN_CMD = $(RM) FilesToClean +STD_VERY_CLEAN = ExtraFilesToBeVeryClean + +#ifndef SoelimCmd +#ifndef UseSoelim +#define SoelimCmd cat /* fake it */ +#else +#if defined(UseInstalledUtils) +#define SoelimCmd soelim +#else +#define SoelimCmd $(SOELIMSRC)/soelim +#endif /* UseInstalledUtils */ +#endif /* UseSoelim */ +#endif /* SoelimCmd */ +SOELIM = SoelimCmd + +#ifndef CTagsCmd +#define CTagsCmd $(ETAGS) +#endif +CTAGS = CTagsCmd + +#ifndef StripCmd +#define StripCmd strip +#endif +STRIP = StripCmd + +#ifndef TblCmd +#define TblCmd tbl +#endif +TBL = TblCmd + +#ifndef TeXCmd +#define TeXCmd tex +#endif +TEX = TeXCmd + +#ifndef TgrindCmd +#define TgrindCmd tgrind +#endif +/* the program that really does the tgrind'ing */ +#ifndef TgrindHelperCmd +#define TgrindHelperCmd /usr/local/lib/tgrind/tfontedpr +#endif +TGRIND = TgrindCmd +TGRIND_HELPER = TgrindHelperCmd + +#ifndef TibCmd +#define TibCmd tib /* you could define this to "cat" if you don't have "tib"... */ +#endif /* (I didn't say it would be pretty...) */ +TIB = TibCmd + +#ifndef TimeCmd +#define TimeCmd time +#endif +TIME = TimeCmd + +#ifndef TroffCmd +#define TroffCmd troff +#endif +TROFF = TroffCmd + +#ifndef YaccCmd +#define YaccCmd yacc +#endif +YACC = YaccCmd + +/* Note on the <pgm>NeededHere rules: they don't really check that + * the program elsewhere in the sources is really up-to-date; + * they really just arrange to go build it if it doesn't exist at all. + * This is usually good enough. + */ + +/* general idea behind these things (__* is an internal macro) ... */ + +#ifndef __SomeUtilNeededHere +#if defined(UseInstalledUtils) +#define __SomeUtilNeededHere(target,neededthing,neededthingsrcdir,neededthingmaketarg) /**/ +#else +#define __SomeUtilNeededHere(target,neededthing,neededthingsrcdir,neededthingmaketarg) @@\ + @@\ +target:: neededthing @@\ + @@\ +neededthing: @@\ + @echo "checking $@ over in" neededthingsrcdir "first..."; \ @@\ + cd neededthingsrcdir; $(MAKE) neededthingmaketarg; \ @@\ + echo "okay, continuing in $(CURRENT_DIR)" +#endif /* ! UseInstalledUtils */ +#endif /* __SomeUtilNeededHere */ + +/*# ------------------------------------------------ */ +/*# OTHER GENERALLY-USEFUL UTILS (w/ source provided) */ + +#ifndef UseInstalledUtils +UTILSRC = $(TOP)/grasp-utils +SCRIPTSRC = $(UTILSRC)/scripts +#endif + +/*# Configuration stuff (jmake, its friends and templates) */ + +#ifndef JmkmfCmd +#if defined(UseInstalledUtils) +#define JmkmfCmd jmkmf +#else +#define JmkmfCmd jmkmf_used_only_with_installed_utils +#endif +#endif + +#ifndef JrestoredepsCmd +#if defined(UseInstalledUtils) +#define JrestoredepsCmd jrestoredeps +#else +#define JrestoredepsCmd $(JMAKESRC)/jrestoredeps +#endif +#endif + +#ifndef JmakeCmd +#if defined(UseInstalledUtils) +#define JmakeCmd jmake +#else +#define JmakeCmd $(JMAKESRC)/jmake +#endif +#endif +/* + * JmakeNeededHere -- generate rules to compile jmake if its source is + * within this project's source tree. + * + * [doesn't quite fit std pattern in __SomeUtilNeededHere] + */ +#ifndef JmakeNeededHere +#if defined(UseInstalledUtils) +#define JmakeNeededHere(target) /**/ +#else +#define JmakeNeededHere(target) @@\ +target:: $(JMAKE) @@\ + @@\ +$(JMAKE): @@\ + @(cd $(JMAKESRC); if [ -f Makefile ]; then \ @@\ + echo "checking $@ in $(JMAKESRC) first..."; $(MAKE) all; else \ @@\ + echo "bootstrapping $@ from Makefile.BOOT in $(JMAKESRC) first..."; \ @@\ + $(MAKE) -f Makefile.BOOT BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS); fi; \ @@\ + echo "okay, continuing in $(CURRENT_DIR)") +#endif /* ! UseInstalledUtils */ +#endif /* JmakeNeededHere */ + +JMKMF = JmkmfCmd +JRESTOREDEPS = JrestoredepsCmd +JMAKE = JmakeCmd + +/* the project config dir is assumed to be relative to $(TOP) */ + +#if defined(UseInstalledUtils) +#if defined(HaveProjectMkworldDir) +JMAKE_CMD = $(JMKMF) -P $(PROJECTLABEL) -S $(SETUPLABEL) -C $(PROJ_MKWORLD_DIR) - $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#else +JMAKE_CMD = $(JMKMF) -P $(PROJECTLABEL) -S $(SETUPLABEL) - $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#endif /* !HaveProjectMkworldDir */ + +#else /* ! using installed jmake */ +JMAKESRC = $(TOP)/mkworld + +#if ProjectIsNone == YES +#define ProjectJmFiles /*nothing*/ +#define SetupJmFiles /*nothing*/ +#else /* have a project... */ +#define ProjectJmFiles \ + $(PROJ_MKWORLD_DIR)/site-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/only4-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/suffixes-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/macros-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/utils-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/install-$(PROJECTLABEL).jm + +#if SetupIsStd == YES +#define SetupJmFiles /*nothing*/ +#else /* have project & a setup... */ +#define SetupJmFiles \ + $(PROJ_MKWORLD_DIR)/site-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/only4-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/suffixes-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/macros-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/utils-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/install-$(PROJECTLABEL)-$(SETUPLABEL).jm +#endif +#endif +MYJCONFIGFILES = $(JMAKESRC)/TEMPLATE.jm \ + $(JMAKESRC)/plat-TRIGGERS.jm \ + $(JMAKESRC)/PlatformFile \ + $(JMAKESRC)/plat-DEF.jm \ + $(JMAKESRC)/site.jm \ + $(JMAKESRC)/site-DEF.jm \ + $(JMAKESRC)/suffixes-GEN.jm \ + $(JMAKESRC)/macros-GEN.jm \ + $(JMAKESRC)/utils-GEN.jm \ + $(JMAKESRC)/install-GEN.jm ProjectJmFiles SetupJmFiles + +#if defined(HaveProjectMkworldDir) +JMAKE_CMD = $(NEWTOP)$(JMAKE) -P $(PROJECTLABEL) -S $(SETUPLABEL) -C $(NEWTOP)$(PROJ_MKWORLD_DIR) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#else +JMAKE_CMD = $(NEWTOP)$(JMAKE) -P $(PROJECTLABEL) -S $(SETUPLABEL) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#endif /* ! HaveProjectMkworldDir */ +#endif /* ! using installed jmake */ + + +/*# GNU info system [hacked] */ + +#ifndef InfoCmd +#if defined(UseInstalledUtils) +#define InfoCmd info +#else +#define InfoCmd $(INFOSRC)/info +#endif +#endif +#ifndef MakeinfoCmd +#if defined(UseInstalledUtils) +#define MakeinfoCmd makeinfo +#else +#define MakeinfoCmd $(INFOSRC)/makeinfo +#endif +#endif +#ifndef PostMakeinfoCmd +#if defined(UseInstalledUtils) +#define PostMakeinfoCmd postmakeinfo +#else +#define PostMakeinfoCmd $(INFOSRC)/postmakeinfo +#endif +#endif +#ifndef InfoStuffNeededHere +#if defined(UseInstalledUtils) +#define InfoStuffNeededHere(target) /**/ +#else +#define InfoStuffNeededHere(target) \ +__SomeUtilNeededHere(target,$(INFO) $(MAKEINFO) $(POSTMAKEINFO),$(INFOSRC),all) +#endif /* ! UseInstalledUtils */ +#endif /* InfoStuffNeededHere */ +INFO = InfoCmd /* who _knows_ where these might be ... */ +MAKEINFO = MakeinfoCmd +POSTMAKEINFO = PostMakeinfoCmd +#ifndef UseInstalledUtils +INFOSRC = $(LITSRC)/info-utils +#endif + +/*# literate programming system */ +#ifndef Lit2PgmCmd +#if defined(UseInstalledUtils) +#define Lit2PgmCmd lit2pgm +#else +#define Lit2PgmCmd $(LITSRC)/lit2pgm +#endif +#endif +#ifndef Lit2TexiCmd +#if defined(UseInstalledUtils) +#define Lit2TexiCmd lit2texi +#else +#define Lit2TexiCmd $(LITSRC)/lit2texi +#endif +#endif +#ifndef Lit2LaTeXCmd +#if defined(UseInstalledUtils) +#define Lit2LaTeXCmd lit2latex +#else +#define Lit2LaTeXCmd $(LITSRC)/lit2latex +#endif +#endif +#ifndef MkDependLitCmd +#if defined(UseInstalledUtils) +#define MkDependLitCmd mkdependlit +#else +#define MkDependLitCmd $(LITSRC)/mkdependlit +#endif +#endif +#ifndef Lit2ChangeLogCmd +#if defined(UseInstalledUtils) +#define Lit2ChangeLogCmd lit2changelog +#else +#define Lit2ChangeLogCmd $(LITSRC)/lit2changelog +#endif +#endif + +/* NB: this *NeededHere rule offers LIMITED guarantee that + the literate-programming stuff is up-to-date when used +*/ +#ifndef LitStuffNeededHere +#if defined(UseInstalledUtils) +#define LitStuffNeededHere(target) /**/ +#else +#define LitStuffNeededHere(target) \ + @@\ +target:: $(LITSRC)/lit2pgm $(LITSRC)/lit2texi $(LITSRC)/lit2latex $(LITSRC)/mkdependlit $(LITSRC)/lit2changelog $(LITSRC)/lit-deatify @@\ + @@\ +$(LITSRC)/lit2pgm $(LITSRC)/lit2texi $(LITSRC)/lit2latex $(LITSRC)/mkdependlit $(LITSRC)/lit2changelog $(LITSRC)/lit-deatify: @@\ + @(cd $(LITSRC); if [ -f lit2pgm ]; then \ @@\ + echo "checking $@ in $(LITSRC) first..."; $(MAKE) all; else \ @@\ + echo "bootstrapping $@ with ./lit2pgm.BOOT in $(LITSRC) first..."; \ @@\ + $(MAKE) LIT2PGM="./lit2pgm.BOOT -Alit2pgm" lit-deatify all; fi; \ @@\ + echo "okay, continuing in $(CURRENT_DIR)") +#endif /* ! UseInstalledUtils */ +#endif /* LitStuffNeededHere */ + +LIT2PGM = Lit2PgmCmd +/* sometimes, we _must_ use the installed version of lit2pgm, + * e.g., for building lit2pgm itself + */ +LIT2TEXI = Lit2TexiCmd +LIT2LATEX = Lit2LaTeXCmd +MKDEPENDLIT = MkDependLitCmd +LIT2CHANGELOG = Lit2ChangeLogCmd +#ifndef UseInstalledUtils +LITSRC = $(TOP)/literate +#endif + +/*# mkdepend scripts for various languages */ +/*# ["mkdependlit" is under literate programming stuff above] */ + +/* for these MkDepend things, we use the scripts only [for now] */ + +#ifndef MkDependCSrc +#define MkDependCSrc $(SCRIPTSRC) +#endif +#ifndef MkDependCCmd +#if defined(UseInstalledUtils) +#define MkDependCCmd mkdependC +#else +#define MkDependCCmd $(MKDEPENDCSRC)/mkdependC +#endif /* ! installed */ +#endif /* MkDependCCmd */ + +/* + MkdependCNeededHere -- generate rules to build the mkdependC program + if its source is within this project's source tree. + + [kind of a weird one, for now at least] +*/ +#ifndef MkDependCNeededHere +#if defined(UseInstalledUtils) +#define MkDependCNeededHere(target) /**/ +#else +#define MkDependCNeededHere(target) \ +__SomeUtilNeededHere(target,$(MKDEPENDC),$(MKDEPENDCSRC),mkdependC) +#endif /* UseInstalledUtils */ +#endif /* MkDependCNeededHere */ +MKDEPENDC = MkDependCCmd +#ifndef UseInstalledUtils +MKDEPENDCSRC = MkDependCSrc +#endif + +#ifndef MkDependHSCmd /* this is the default; hope you have it! */ +#define MkDependHSCmd mkdependHS +#endif +#ifndef MkDependHSNeededHere /* ditto */ +#define MkDependHSNeededHere(targets) /*no such thing*/ +#endif +MKDEPENDHS = MkDependHSCmd + +/* mkdependlit is with the literate stuff above */ + +/* tags utilities */ + +#ifndef PerlTagsSrc +#define PerlTagsSrc $(SCRIPTSRC) +#endif +#if defined(UseInstalledUtils) +#define PerlTagsCmd perltags +#else +#define PerlTagsCmd $(PERLTAGSSRC)/perltags +#endif + +#ifndef PerlTagsNeededHere +#if defined(UseInstalledUtils) +#define PerlTagsNeededHere(target) /**/ +#else +#define PerlTagsNeededHere(target) \ +__SomeUtilNeededHere(target,$(PERLTAGS),$(PERLTAGSSRC),perltags) +#endif /* UseInstalledUtils */ +#endif /* PerlTagsNeededHere */ +PERLTAGS = PerlTagsCmd +#ifndef UseInstalledUtils +PERLTAGSSRC = PerlTagsSrc +#endif + +/*# misc utilities */ + +#ifndef FastmakeCmd +#if defined(UseInstalledUtils) +#define FastmakeCmd fastmake +#else +#define FastmakeCmd $(FASTMAKESRC)/fastmake +#endif +#endif +#ifndef FastmakeNeededHere +#if defined(UseInstalledUtils) +#define FastmakeNeededHere(target) /**/ +#else +#define FastmakeNeededHere(target) \ +__SomeUtilNeededHere(target,$(FASTMAKE),$(FASTMAKESRC),fastmake) +#endif /* ! UseInstalledUtils */ +#endif /* FastmakeNeededHere */ +FASTMAKE = FastmakeCmd +#ifndef UseInstalledUtils +FASTMAKESRC = $(SCRIPTSRC) +#endif + +#ifndef LtxCmd +#if defined(UseInstalledUtils) +#define LtxCmd ltx +#else +#define LtxCmd $(LTXSRC)/ltx +#endif +#endif +#ifndef LtxNeededHere +#if defined(UseInstalledUtils) +#define LtxNeededHere(target) /**/ +#else +#define LtxNeededHere(target) \ +__SomeUtilNeededHere(target,$(LTX),$(LTXSRC),ltx) +#endif /* ! UseInstalledUtils */ +#endif /* LtxNeededHere */ +LTX = LtxCmd /* a LaTeX-wrapper script */ +#ifndef UseInstalledUtils +LTXSRC = $(SCRIPTSRC) +#endif + +#ifndef MkdirHierCmd +#if defined(UseInstalledUtils) +#define MkdirHierCmd mkdirhier +#else +#define MkdirHierCmd $(MKDIRHIERSRC)/mkdirhier +#endif +#endif +#ifndef MkdirHierNeededHere +#if defined(UseInstalledUtils) +#define MkdirHierNeededHere(target) /**/ +#else +#define MkdirHierNeededHere(target) \ +__SomeUtilNeededHere(target,$(MKDIRHIER),$(MKDIRHIERSRC),mkdirhier) +#endif /* ! UseInstalledUtils */ +#endif /* MkdirHierNeededHere */ +MKDIRHIER = MkdirHierCmd +#ifndef UseInstalledUtils +MKDIRHIERSRC = $(SCRIPTSRC) +#endif + +/* Simon Marlow says: Lndir is sometimes dubious; if you + have GNU cp, define "LndirCmd" to: cp -Rsv +*/ +#ifndef LndirCmd +#if defined(UseInstalledUtils) +#define LndirCmd lndir +#else +#define LndirCmd $(LNDIRSRC)/lndir +#endif +#endif +#ifndef LndirNeededHere +#if defined(UseInstalledUtils) +#define LndirNeededHere(target) /**/ +#else +#define LndirNeededHere(target) \ +__SomeUtilNeededHere(target,$(LNDIR),$(LNDIRSRC),lndir) +#endif /* ! UseInstalledUtils */ +#endif /* LndirNeededHere */ +LNDIR = LndirCmd +#ifndef UseInstalledUtils +LNDIRSRC = $(SCRIPTSRC) +#endif + +#ifndef MsubCmd +#if defined(UseInstalledUtils) +#define MsubCmd msub +#else +#define MsubCmd $(MSUBSRC)/msub +#endif /* ! installed */ +#endif /* MsubCmd */ +/* MsubNeededHere - generate rules to build the msub program + if its source is within this project's source tree. This rule + should be included manually once in each Jmakefile that generates + targets with msub. (Ideally it would be invoked automatically from + within each msub-target-generating rule, but then you have a million + sets of these rules in the Makefile. Ugh. This could be avoided if + there were some way for a rule to void itself after being invoked + once.) +*/ +#ifndef MsubNeededHere +#if defined(UseInstalledUtils) +#define MsubNeededHere(target) /**/ +#else +#define MsubNeededHere(target) \ +__SomeUtilNeededHere(target,$(MSUB),$(MSUBSRC),msub) +#endif /* ! UseInstalledUtils */ +#endif /* MsubNeededHere */ +MSUB = MsubCmd +#ifndef UseInstalledUtils +MSUBSRC = $(UTILSRC)/msub +#endif + +#ifndef EtagsCmd +#if defined(UseInstalledUtils) +#define EtagsCmd etags +#else +#define EtagsCmd $(ETAGSSRC)/etags +#endif /* ! installed */ +#endif /* EtagsCmd */ +#ifndef EtagsNeededHere +#if defined(UseInstalledUtils) +#define EtagsNeededHere(target) /**/ +#else +#define EtagsNeededHere(target) \ +__SomeUtilNeededHere(target,$(ETAGS),$(ETAGSSRC),etags) +#endif /* ! UseInstalledUtils */ +#endif /* EtagsNeededHere */ +ETAGS = EtagsCmd +#ifndef UseInstalledUtils +ETAGSSRC = $(UTILSRC)/etags +#endif + +#ifndef VerbatimCmd +#if defined(UseInstalledUtils) +#define VerbatimCmd verbatim +#else +#define VerbatimCmd $(VERBATIMSRC)/verbatim +#endif /* ! installed */ +#endif /* VerbatimCmd */ +#ifndef VerbatimNeededHere +#if defined(UseInstalledUtils) +#define VerbatimNeededHere(target) /**/ +#else +#define VerbatimNeededHere(target) \ +__SomeUtilNeededHere(target,$(VERBATIM),$(VERBATIMSRC),verbatim) +#endif /* ! UseInstalledUtils */ +#endif /* VerbatimNeededHere */ +VERBATIM = VerbatimCmd +#ifndef UseInstalledUtils +VERBATIMSRC = $(UTILSRC)/verbatim +#endif + +#ifndef RunStdTestCmd +#if defined(UseInstalledUtils) +#define RunStdTestCmd runstdtest +#else +#define RunStdTestCmd $(RUNSTDTESTSRC)/runstdtest +#endif +#endif +#ifndef RunStdTestNeededHere +#if defined(UseInstalledUtils) +#define RunStdTestNeededHere(target) /**/ +#else +#define RunStdTestNeededHere(target) \ +__SomeUtilNeededHere(target,$(RUNSTDTEST),$(RUNSTDTESTSRC),runstdtest) +#endif /* ! UseInstalledUtils */ +#endif /* RunStdTestNeededHere */ +RUNSTDTEST = RunStdTestCmd +#ifndef UseInstalledUtils +RUNSTDTESTSRC = $(SCRIPTSRC) +#endif +# line 768 "utils-GEN.ljm" +/* for the whole nasty business of flags for programs, + some naming conventions are worth remembering; for program <foo>: + + <foo>FLAGS what is actually passed to <foo>; usually + built from pieces below + + ALLPROJ_<foo>_<things> <things> needed for _all_ runs of <foo>; + probably set in one of the AllProject* + config files. + PLAT_<foo>_<things> <things> (options, defines, etc.) needed for + all runs of <foo> *on this platform*; + probably set in <platform>.cf. + PROJ_<foo>_<things> <things> needed for all runs of <foo> + related to this project; probably set in + one of the Project-* config files. + <foo>_<things> <things> needed for runs of <foo> in this + directory; set in its Jmakefile. + EXTRA_<foo>_<things> name reserved for adding <things> from the + command line. + GLUED_<foo>_<things> all the above, glued together; not for + human use. + + <foo>_OPTS the usual name for options + <foo>_DEFINES CPP #defines + <foo>_INCLUDES CPP #includes + <foo>_IMPORTS Haskell "import"s + + As a contrived example, the "makeinfo" program is usually called + with the $(MAKEINFOFLAGS), which would likely be put together as... + + ALLPROJ_MAKEINFO_OPTS = + PLAT_MAKEINFO_OPTS = + PROJ_MAKEINFO_OPTS = + MAKEINFO_OPTS = + EXTRA_MAKEINFO_OPTS = + GLUED_MAKEINFO_OPTS = + MAKEINFOFLAGS = $(GLUED_MAKEINFO_OPTS) + + and used as... + + $(MAKEINFO) $(MAKEINFOFLAGS) ... + + The related CPP names are as you would expect: e.g., + ProjectMakeinfoOpts for PROJ_MAKEINFO_OPTS, ... + + For systems of interacting programs (e.g., cpp, cc, lint, as, and ld), + things can be [considerably] messier. + +*/ + +/* CPP definitions for CPP #includes; -I must be explicit */ + +/* I have not separated use of CPP w/ CC vs standalone... */ + +#ifndef AllProjectsCppIncludes +#define AllProjectsCppIncludes /*none*/ +#endif +#ifndef PlatformCppIncludes +#define PlatformCppIncludes /*none*/ +#endif +#ifndef ProjectCppIncludes +#define ProjectCppIncludes /*none*/ +#endif +#ifndef SetupCppIncludes +#define SetupCppIncludes /*none*/ +#endif +GenerateOptionsMakeVars(CPP,INCLUDES,AllProjectsCppIncludes,PlatformCppIncludes,ProjectCppIncludes,SetupCppIncludes) + +/* CPP definitions for #defines */ + +#ifndef AllProjectsCppDefines +#define AllProjectsCppDefines /*none*/ +#endif +#ifndef PlatformCppDefines +#define PlatformCppDefines /**/ +#endif /* PlatformCppDefines */ +#ifndef ProjectCppDefines +#define ProjectCppDefines /*none*/ +#endif +#ifndef SetupCppDefines +#define SetupCppDefines /*none*/ +#endif +GenerateOptionsMakeVars(CPP,DEFINES,AllProjectsCppDefines,PlatformCppDefines,ProjectCppDefines,SetupCppDefines) + +/*# C-compiler (and cpp ... and lint) options */ + +#ifndef AllProjectsCcOpts +#define AllProjectsCcOpts /*none*/ +#endif +#ifndef PlatformCcOpts +#define PlatformCcOpts /*none*/ +#endif +#ifndef ProjectCcOpts +#define ProjectCcOpts /*none*/ +#endif +#ifndef SetupCcOpts +#define SetupCcOpts /*none*/ +#endif +GenerateOptionsMakeVars(CC,OPTS,AllProjectsCcOpts,PlatformCcOpts,ProjectCcOpts,SetupCcOpts) + +CFLAGS = $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) $(GLUED_CC_OPTS) + +/*# Haskell compiler (and cpp ... and lint) options */ + +#ifndef AllProjectsHcOpts +#define AllProjectsHcOpts /*none*/ +#endif +#ifndef PlatformHcOpts +#define PlatformHcOpts /*none*/ +#endif +#ifndef ProjectHcOpts +#define ProjectHcOpts /*none*/ +#endif +#ifndef SetupHcOpts +#define SetupHcOpts /*none*/ +#endif +GenerateOptionsMakeVars(HC,OPTS,AllProjectsHcOpts,PlatformHcOpts,ProjectHcOpts,SetupHcOpts) + +#ifndef AllProjectsHcImports +#define AllProjectsHcImports /*none*/ +#endif +#ifndef PlatformHcImports +#define PlatformHcImports /*none*/ +#endif +#ifndef ProjectHcImports +#define ProjectHcImports /*none*/ +#endif +#ifndef SetupHcImports +#define SetupHcImports /*none*/ +#endif +GenerateOptionsMakeVars(HC,IMPORTS,AllProjectsHcImports,PlatformHcImports,ProjectHcImports,SetupHcImports) +HCFLAGS = $(GLUED_HC_IMPORTS) $(GLUED_CPP_DEFINES) $(GLUED_HC_OPTS) + +/*# linker options */ + +#ifndef AllProjectsLdOpts +#define AllProjectsLdOpts /*none*//* -X -r "combine" flags (?) */ +#endif +#ifndef PlatformLdOpts +#define PlatformLdOpts /*none*/ +#endif +#ifndef ProjectLdOpts +#define ProjectLdOpts /*none*/ +#endif +#ifndef SetupLdOpts +#define SetupLdOpts /*none*/ +#endif +#ifndef AllProjectsLdLibraries +#define AllProjectsLdLibraries /*none*/ +#endif +#ifndef PlatformLdLibraries +#define PlatformLdLibraries /*none*/ +#endif +#ifndef ProjectLdLibraries +#define ProjectLdLibraries /*none*/ +#endif +#ifndef SetupLdLibraries +#define SetupLdLibraries /*none*/ +#endif +GenerateOptionsMakeVars(LD,OPTS,AllProjectsLdOpts,PlatformLdOpts,ProjectLdOpts,SetupLdOpts) +GenerateOptionsMakeVars(LD,LIBRARIES,AllProjectsLdLibraries,PlatformLdLibraries,ProjectLdLibraries,SetupLdLibraries) +LDOPTIONS = $(GLUED_LD_OPTS) /* ToDo: and the libraries ? */ + +/* lint stuff not tidied up yet */ + +#ifndef LintLibFlag +#define LintLibFlag -C +#endif +#ifndef LintOpts +#define LintOpts -axz +#endif +LINTLIBFLAG = LintLibFlag +LINTOPTS = LintOpts +LINTFLAGS = $(LINTOPTS) -DLINT $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) + +/*# literate-stuff options */ + +/* some options are common (general) to all lit2* pgms; others specific */ + +#ifndef AllProjectsGenLitOpts +#define AllProjectsGenLitOpts /*none*/ +#endif +#ifndef PlatformGenLitOpts +#define PlatformGenLitOpts /*none*/ +#endif +#ifndef ProjectGenLitOpts +#define ProjectGenLitOpts /*none*/ +#endif +#ifndef SetupGenLitOpts +#define SetupGenLitOpts /*none*/ +#endif +GenerateOptionsMakeVars(GENLIT,OPTS,AllProjectsGenLitOpts,PlatformGenLitOpts,ProjectGenLitOpts,SetupGenLitOpts) + +#ifndef AllProjectsLit2pgmOpts +#define AllProjectsLit2pgmOpts /*none*/ +#endif +#ifndef PlatformLit2pgmOpts +#define PlatformLit2pgmOpts /*none*/ +#endif +#ifndef ProjectLit2pgmOpts +#define ProjectLit2pgmOpts /*none*/ +#endif +#ifndef SetupLit2pgmOpts +#define SetupLit2pgmOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2PGM,OPTS,AllProjectsLit2pgmOpts,PlatformLit2pgmOpts,ProjectLit2pgmOpts,SetupLit2pgmOpts) +#ifndef AllProjectsLit2texiOpts +#define AllProjectsLit2texiOpts /*none*/ +#endif +#ifndef PlatformLit2texiOpts +#define PlatformLit2texiOpts /*none*/ +#endif +#ifndef ProjectLit2texiOpts +#define ProjectLit2texiOpts /*none*/ +#endif +#ifndef SetupLit2texiOpts +#define SetupLit2texiOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2TEXI,OPTS,AllProjectsLit2texiOpts,PlatformLit2texiOpts,ProjectLit2texiOpts,SetupLit2texiOpts) +#ifndef AllProjectsLit2latexOpts +#define AllProjectsLit2latexOpts /*none*/ +#endif +#ifndef PlatformLit2latexOpts +#define PlatformLit2latexOpts /*none*/ +#endif +#ifndef ProjectLit2latexOpts +#define ProjectLit2latexOpts /*none*/ +#endif +#ifndef SetupLit2latexOpts +#define SetupLit2latexOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2LATEX,OPTS,AllProjectsLit2latexOpts,PlatformLit2latexOpts,ProjectLit2latexOpts,SetupLit2latexOpts) +#ifndef AllProjectsLit2changelogOpts +#define AllProjectsLit2changelogOpts /*none*/ +#endif +#ifndef PlatformLit2changelogOpts +#define PlatformLit2changelogOpts /*none*/ +#endif +#ifndef ProjectLit2changelogOpts +#define ProjectLit2changelogOpts /*none*/ +#endif +#ifndef SetupLit2changelogOpts +#define SetupLit2changelogOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2CHANGELOG,OPTS,AllProjectsLit2changelogOpts,PlatformLit2changelogOpts,ProjectLit2changelogOpts,SetupLit2changelogOpts) +#ifndef AllProjectsMkDependLitOpts +#define AllProjectsMkDependLitOpts /*none*/ +#endif +#ifndef PlatformMkDependLitOpts +#define PlatformMkDependLitOpts /*none*/ +#endif +#ifndef ProjectMkDependLitOpts +#define ProjectMkDependLitOpts /*none*/ +#endif +#ifndef SetupMkDependLitOpts +#define SetupMkDependLitOpts /*none*/ +#endif +GenerateOptionsMakeVars(MKDEPENDLIT,OPTS,AllProjectsMkDependLitOpts,PlatformMkDependLitOpts,ProjectMkDependLitOpts,SetupMkDependLitOpts) + +LIT2PGMFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2PGM_OPTS) +LIT2TEXIFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2TEXI_OPTS) +LIT2LATEXFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2LATEX_OPTS) +LIT2CHANGELOGFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2CHANGELOG_OPTS) +MKDEPENDLITFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_MKDEPENDLIT_OPTS) + +/* same for other MkDepend things */ + +#ifndef AllProjectsMkDependCOpts +#define AllProjectsMkDependCOpts /*none*/ +#endif +#ifndef PlatformMkDependCOpts +#define PlatformMkDependCOpts /*none*/ +#endif +#ifndef ProjectMkDependCOpts +#define ProjectMkDependCOpts /*none*/ +#endif +#ifndef SetupMkDependCOpts +#define SetupMkDependCOpts /*none*/ +#endif +GenerateOptionsMakeVars(MKDEPENDC,OPTS,AllProjectsMkDependCOpts,PlatformMkDependCOpts,ProjectMkDependCOpts,SetupMkDependCOpts) +MKDEPENDCFLAGS = $(GLUED_MKDEPENDC_OPTS) + +#ifndef AllProjectsMkDependHSOpts +#define AllProjectsMkDependHSOpts /*none*/ +#endif +#ifndef PlatformMkDependHSOpts +#define PlatformMkDependHSOpts /*none*/ +#endif +#ifndef ProjectMkDependHSOpts +#define ProjectMkDependHSOpts /*none*/ +#endif +#ifndef SetupMkDependHSOpts +#define SetupMkDependHSOpts /*none*/ +#endif +GenerateOptionsMakeVars(MKDEPENDHS,OPTS,AllProjectsMkDependHSOpts,PlatformMkDependHSOpts,ProjectMkDependHSOpts,SetupMkDependHSOpts) +MKDEPENDHSFLAGS = $(GLUED_MKDEPENDHS_OPTS) + +/* same for tags stuff */ + +#ifndef AllProjectsCTagsOpts +#define AllProjectsCTagsOpts -e -w /* emacs-style; no warnings */ +#endif +#ifndef PlatformCTagsOpts +#define PlatformCTagsOpts /*none*/ +#endif +#ifndef ProjectCTagsOpts +#define ProjectCTagsOpts /*none*/ +#endif +#ifndef SetupCTagsOpts +#define SetupCTagsOpts /*none*/ +#endif +GenerateOptionsMakeVars(CTAGS,OPTS,AllProjectsCTagsOpts,PlatformCTagsOpts,ProjectCTagsOpts,SetupCTagsOpts) +CTAGSFLAGS = $(GLUED_CTAGS_OPTS) + +#ifndef AllProjectsPerlTagsOpts +#define AllProjectsPerlTagsOpts /*none*/ +#endif +#ifndef PlatformPerlTagsOpts +#define PlatformPerlTagsOpts /*none*/ +#endif +#ifndef ProjectPerlTagsOpts +#define ProjectPerlTagsOpts /*none*/ +#endif +#ifndef SetupPerlTagsOpts +#define SetupPerlTagsOpts /*none*/ +#endif +GenerateOptionsMakeVars(PERLTAGS,OPTS,AllProjectsPerlTagsOpts,PlatformPerlTagsOpts,ProjectPerlTagsOpts,SetupPerlTagsOpts) +PERLTAGSFLAGS = $(GLUED_PERLTAGS_OPTS) + +/* and for "runstdtest" */ + +#ifndef AllProjectsRunStdTestOpts +#define AllProjectsRunStdTestOpts /*none*/ +#endif +#ifndef PlatformRunStdTestOpts +#define PlatformRunStdTestOpts /*none*/ +#endif +#ifndef ProjectRunStdTestOpts +#define ProjectRunStdTestOpts /*none*/ +#endif +#ifndef SetupRunStdTestOpts +#define SetupRunStdTestOpts /*none*/ +#endif +GenerateOptionsMakeVars(RUNSTDTEST,OPTS,AllProjectsRunStdTestOpts,PlatformRunStdTestOpts,ProjectRunStdTestOpts,SetupRunStdTestOpts) +RUNSTDTEST_FLAGS = $(GLUED_RUNSTDTEST_OPTS) + +/* CPP definitions for #defines */ + +#ifndef AllProjectsJmakeDefines +#define AllProjectsJmakeDefines /*none*/ +#endif +#ifndef PlatformJmakeDefines +#define PlatformJmakeDefines /**/ +#endif /* PlatformJmakeDefines */ +#ifndef ProjectJmakeDefines +#define ProjectJmakeDefines /*none*/ +#endif +#ifndef SetupJmakeDefines +#define SetupJmakeDefines /*none*/ +#endif +GenerateOptionsMakeVars(JMAKE,DEFINES,AllProjectsJmakeDefines,PlatformJmakeDefines,ProjectJmakeDefines,SetupJmakeDefines) +JMAKEFLAGS = $(GLUED_JMAKE_DEFINES) diff --git a/web/glasgow/lit2x-0.16/mkworld/utils-GEN.ljm b/web/glasgow/lit2x-0.16/mkworld/utils-GEN.ljm new file mode 100644 index 0000000000..6d3faecda9 --- /dev/null +++ b/web/glasgow/lit2x-0.16/mkworld/utils-GEN.ljm @@ -0,0 +1,1130 @@ +%************************************************************************ +%* * +\section[mkworld-utils-GEN]{General stuff about ``utilities''} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsection[mkworld-utils-what]{What they are (intro)} +%* * +%************************************************************************ + +%************************************************************************ +%* * +\subsection[mkworld-utils-where]{Where they are} +%* * +%************************************************************************ + +Generally-useful utils that are pre-supposed (but a project might want +diff ones). + +For @ar@, the \tr{l} means to use \tr{.} for temp files; the \tr{s} in +the SystemV-ish case takes the place of \tr{ranlib}. +\begin{code} +#ifndef ArCmd +#if HasSysVishArAndRanlib == YES +#define ArCmd ar clqs +#else +#define ArCmd ar clq +#endif +#endif +AR = ArCmd +\end{code} + +\begin{code} +#ifndef ArchCmd +#define ArchCmd arch +#endif +ARCH_CMD = ArchCmd + +#ifndef MachCmd +#define MachCmd mach +#endif +MACH_CMD = MachCmd + +#ifndef AsCmd +#define AsCmd as +#endif +AS = AsCmd + +#ifndef WhatGccIsCalled /* version 2.n, please */ +#define WhatGccIsCalled gcc +#endif + +#ifndef CcCmd +#if (HaveGcc == YES) && (UseGcc == YES) +#define CcCmd WhatGccIsCalled +#else +#define CcCmd cc +#endif /* ! HaveGcc etc */ +#endif /* CcCmd */ +CC = CcCmd + +#ifndef CompressCmd +#define CompressCmd compress +#endif +COMPRESS = CompressCmd + +#ifndef CpCmd +#define CpCmd cp +#endif +CP = CpCmd + +#ifndef CppCmd +#define CppCmd /lib/cpp +#endif +#ifndef PreProcessCmd +#define PreProcessCmd CcCmd -E +#endif +CPP = CppCmd $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) /* simple filters */ +PREPROCESSCMD = PreProcessCmd $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) /* preferred; mdep */ + +#ifndef InstallCmd +#define InstallCmd install +#endif /* InstallCmd */ +INSTALL = InstallCmd +#ifndef InstallingByDefault +#define InstallingByDefault 0 +#endif +INSTALLING = InstallingByDefault + +#ifndef LexCmd +#ifdef UseFlexForLexCmd +#define LexCmd flex +#else +#define LexCmd lex +#endif +#endif +#ifndef FlexCmd +#define FlexCmd flex -s +#endif +LEX = LexCmd +FLEX = FlexCmd $(EXTRA_FLEX_FLAGS) /* this is asking for it... */ + +/* the installed Haskell compiler */ +#ifndef HaskellCompileCmd +#define HaskellCompileCmd hc +#endif +HC = HaskellCompileCmd + +#ifndef LaTeXCmd +#define LaTeXCmd latex +#endif +LATEX = LaTeXCmd +/* see also the LaTeX-wrapper script, LTX, in AllProjects */ + +#ifndef LdCmd +#define LdCmd ld +#endif +LD = LdCmd + +#ifndef LintCmd +#define LintCmd lint +#endif +LINT = LintCmd + +#ifndef LnCmd +#define LnCmd ln -s +#endif /* LnCmd */ +LN = LnCmd + +#ifndef MakeCmd +#define MakeCmd make +#endif +/* this might be useful at some point ... */ +#ifndef MakeCmdIsGnuMake +#define MakeCmdIsGnuMake NO +#endif +MAKE = MakeCmd + +#ifndef MvCmd +#define MvCmd mv +#endif +MV = MvCmd + +#ifndef NroffCmd +#define NroffCmd nroff +#endif +#ifndef ManMacros +#define ManMacros -man +#endif +#ifndef MsMacros +#define MsMacros -ms +#endif +NROFF = NroffCmd +MANMACROS = ManMacros +MSMACROS = MsMacros + +#ifndef PerlCmd +#define PerlCmd /usr/bin/perl +#endif +PERL = PerlCmd + +#ifndef PicCmd +#define PicCmd pic +#endif +PIC = PicCmd + +#ifndef PrinterCmd +#define PrinterCmd lpr +#endif +PRINTER = PrinterCmd + +#ifndef RanlibCmd +#if HasSysVishArAndRanlib == YES +#define RanlibCmd /bin/true /* does nothing */ +#else +#define RanlibCmd ranlib +#endif +#endif +RANLIB = RanlibCmd + +#ifndef RmCmd +#define RmCmd rm -f +#endif +RM = RmCmd +/* a project may want to override CLEAN_CMD */ + +/* see the comment about not having #*, under CleanTarget rule in Jmake.rules */ +/* ToDo: what about bbl files? */ +#ifndef FilesToClean +#define FilesToClean *.CKP *.ln *.BAK *.bak *.o core a.out errs ,* *.a .emacs_* tags TAGS \ + *.ind *.ilg *.idx *.idx-prev *.aux *.aux-prev *.dvi *.log *.toc *.lot *.lof \ + *.blg *.info *.itxi *.itex *.cb +#endif +/* you can override this in various ways... */ +/* Real Men (TM) will have the following in their veryclean stuff: + Makefile + .??*~ *~ (emacs backup files) + *.tex *.texi + *.lex.c *.yacc.c [however this should be done...] + *.orig *.rej (patch droppings) +*/ +#ifndef ExtraFilesToBeVeryClean +#define ExtraFilesToBeVeryClean .??*~ *~ *.orig *.rej +#endif +CLEAN_CMD = $(RM) FilesToClean +STD_VERY_CLEAN = ExtraFilesToBeVeryClean + +#ifndef SoelimCmd +#ifndef UseSoelim +#define SoelimCmd cat /* fake it */ +#else +#if defined(UseInstalledUtils) +#define SoelimCmd soelim +#else +#define SoelimCmd $(SOELIMSRC)/soelim +#endif /* UseInstalledUtils */ +#endif /* UseSoelim */ +#endif /* SoelimCmd */ +SOELIM = SoelimCmd + +#ifndef CTagsCmd +#define CTagsCmd $(ETAGS) +#endif +CTAGS = CTagsCmd + +#ifndef StripCmd +#define StripCmd strip +#endif +STRIP = StripCmd + +#ifndef TblCmd +#define TblCmd tbl +#endif +TBL = TblCmd + +#ifndef TeXCmd +#define TeXCmd tex +#endif +TEX = TeXCmd + +#ifndef TgrindCmd +#define TgrindCmd tgrind +#endif +/* the program that really does the tgrind'ing */ +#ifndef TgrindHelperCmd +#define TgrindHelperCmd /usr/local/lib/tgrind/tfontedpr +#endif +TGRIND = TgrindCmd +TGRIND_HELPER = TgrindHelperCmd + +#ifndef TibCmd +#define TibCmd tib /* you could define this to "cat" if you don't have "tib"... */ +#endif /* (I didn't say it would be pretty...) */ +TIB = TibCmd + +#ifndef TimeCmd +#define TimeCmd time +#endif +TIME = TimeCmd + +#ifndef TroffCmd +#define TroffCmd troff +#endif +TROFF = TroffCmd + +#ifndef YaccCmd +#define YaccCmd yacc +#endif +YACC = YaccCmd + +/* Note on the <pgm>NeededHere rules: they don't really check that + * the program elsewhere in the sources is really up-to-date; + * they really just arrange to go build it if it doesn't exist at all. + * This is usually good enough. + */ + +/* general idea behind these things (__* is an internal macro) ... */ + +#ifndef __SomeUtilNeededHere +#if defined(UseInstalledUtils) +#define __SomeUtilNeededHere(target,neededthing,neededthingsrcdir,neededthingmaketarg) /**/ +#else +#define __SomeUtilNeededHere(target,neededthing,neededthingsrcdir,neededthingmaketarg) @@\ + @@\ +target:: neededthing @@\ + @@\ +neededthing: @@\ + @echo "checking $@ over in" neededthingsrcdir "first..."; \ @@\ + cd neededthingsrcdir; $(MAKE) neededthingmaketarg; \ @@\ + echo "okay, continuing in $(CURRENT_DIR)" +#endif /* ! UseInstalledUtils */ +#endif /* __SomeUtilNeededHere */ + +/*# ------------------------------------------------ */ +/*# OTHER GENERALLY-USEFUL UTILS (w/ source provided) */ + +#ifndef UseInstalledUtils +UTILSRC = $(TOP)/grasp-utils +SCRIPTSRC = $(UTILSRC)/scripts +#endif + +/*# Configuration stuff (jmake, its friends and templates) */ + +#ifndef JmkmfCmd +#if defined(UseInstalledUtils) +#define JmkmfCmd jmkmf +#else +#define JmkmfCmd jmkmf_used_only_with_installed_utils +#endif +#endif + +#ifndef JrestoredepsCmd +#if defined(UseInstalledUtils) +#define JrestoredepsCmd jrestoredeps +#else +#define JrestoredepsCmd $(JMAKESRC)/jrestoredeps +#endif +#endif + +#ifndef JmakeCmd +#if defined(UseInstalledUtils) +#define JmakeCmd jmake +#else +#define JmakeCmd $(JMAKESRC)/jmake +#endif +#endif +/* + * JmakeNeededHere -- generate rules to compile jmake if its source is + * within this project's source tree. + * + * [doesn't quite fit std pattern in __SomeUtilNeededHere] + */ +#ifndef JmakeNeededHere +#if defined(UseInstalledUtils) +#define JmakeNeededHere(target) /**/ +#else +#define JmakeNeededHere(target) @@\ +target:: $(JMAKE) @@\ + @@\ +$(JMAKE): @@\ + @(cd $(JMAKESRC); if [ -f Makefile ]; then \ @@\ + echo "checking $@ in $(JMAKESRC) first..."; $(MAKE) all; else \ @@\ + echo "bootstrapping $@ from Makefile.BOOT in $(JMAKESRC) first..."; \ @@\ + $(MAKE) -f Makefile.BOOT BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS); fi; \ @@\ + echo "okay, continuing in $(CURRENT_DIR)") +#endif /* ! UseInstalledUtils */ +#endif /* JmakeNeededHere */ + +JMKMF = JmkmfCmd +JRESTOREDEPS = JrestoredepsCmd +JMAKE = JmakeCmd + +/* the project config dir is assumed to be relative to $(TOP) */ + +#if defined(UseInstalledUtils) +#if defined(HaveProjectMkworldDir) +JMAKE_CMD = $(JMKMF) -P $(PROJECTLABEL) -S $(SETUPLABEL) -C $(PROJ_MKWORLD_DIR) - $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#else +JMAKE_CMD = $(JMKMF) -P $(PROJECTLABEL) -S $(SETUPLABEL) - $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#endif /* !HaveProjectMkworldDir */ + +#else /* ! using installed jmake */ +JMAKESRC = $(TOP)/mkworld + +#if ProjectIsNone == YES +#define ProjectJmFiles /*nothing*/ +#define SetupJmFiles /*nothing*/ +#else /* have a project... */ +#define ProjectJmFiles \ + $(PROJ_MKWORLD_DIR)/site-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/only4-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/suffixes-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/macros-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/utils-$(PROJECTLABEL).jm \ + $(PROJ_MKWORLD_DIR)/install-$(PROJECTLABEL).jm + +#if SetupIsStd == YES +#define SetupJmFiles /*nothing*/ +#else /* have project & a setup... */ +#define SetupJmFiles \ + $(PROJ_MKWORLD_DIR)/site-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/only4-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/suffixes-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/macros-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/utils-$(PROJECTLABEL)-$(SETUPLABEL).jm \ + $(PROJ_MKWORLD_DIR)/install-$(PROJECTLABEL)-$(SETUPLABEL).jm +#endif +#endif +MYJCONFIGFILES = $(JMAKESRC)/TEMPLATE.jm \ + $(JMAKESRC)/plat-TRIGGERS.jm \ + $(JMAKESRC)/PlatformFile \ + $(JMAKESRC)/plat-DEF.jm \ + $(JMAKESRC)/site.jm \ + $(JMAKESRC)/site-DEF.jm \ + $(JMAKESRC)/suffixes-GEN.jm \ + $(JMAKESRC)/macros-GEN.jm \ + $(JMAKESRC)/utils-GEN.jm \ + $(JMAKESRC)/install-GEN.jm ProjectJmFiles SetupJmFiles + +#if defined(HaveProjectMkworldDir) +JMAKE_CMD = $(NEWTOP)$(JMAKE) -P $(PROJECTLABEL) -S $(SETUPLABEL) -C $(NEWTOP)$(PROJ_MKWORLD_DIR) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#else +JMAKE_CMD = $(NEWTOP)$(JMAKE) -P $(PROJECTLABEL) -S $(SETUPLABEL) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) $(JMAKEFLAGS) +#endif /* ! HaveProjectMkworldDir */ +#endif /* ! using installed jmake */ + + +/*# GNU info system [hacked] */ + +#ifndef InfoCmd +#if defined(UseInstalledUtils) +#define InfoCmd info +#else +#define InfoCmd $(INFOSRC)/info +#endif +#endif +#ifndef MakeinfoCmd +#if defined(UseInstalledUtils) +#define MakeinfoCmd makeinfo +#else +#define MakeinfoCmd $(INFOSRC)/makeinfo +#endif +#endif +#ifndef PostMakeinfoCmd +#if defined(UseInstalledUtils) +#define PostMakeinfoCmd postmakeinfo +#else +#define PostMakeinfoCmd $(INFOSRC)/postmakeinfo +#endif +#endif +#ifndef InfoStuffNeededHere +#if defined(UseInstalledUtils) +#define InfoStuffNeededHere(target) /**/ +#else +#define InfoStuffNeededHere(target) \ +__SomeUtilNeededHere(target,$(INFO) $(MAKEINFO) $(POSTMAKEINFO),$(INFOSRC),all) +#endif /* ! UseInstalledUtils */ +#endif /* InfoStuffNeededHere */ +INFO = InfoCmd /* who _knows_ where these might be ... */ +MAKEINFO = MakeinfoCmd +POSTMAKEINFO = PostMakeinfoCmd +#ifndef UseInstalledUtils +INFOSRC = $(LITSRC)/info-utils +#endif + +/*# literate programming system */ +#ifndef Lit2PgmCmd +#if defined(UseInstalledUtils) +#define Lit2PgmCmd lit2pgm +#else +#define Lit2PgmCmd $(LITSRC)/lit2pgm +#endif +#endif +#ifndef Lit2TexiCmd +#if defined(UseInstalledUtils) +#define Lit2TexiCmd lit2texi +#else +#define Lit2TexiCmd $(LITSRC)/lit2texi +#endif +#endif +#ifndef Lit2LaTeXCmd +#if defined(UseInstalledUtils) +#define Lit2LaTeXCmd lit2latex +#else +#define Lit2LaTeXCmd $(LITSRC)/lit2latex +#endif +#endif +#ifndef MkDependLitCmd +#if defined(UseInstalledUtils) +#define MkDependLitCmd mkdependlit +#else +#define MkDependLitCmd $(LITSRC)/mkdependlit +#endif +#endif +#ifndef Lit2ChangeLogCmd +#if defined(UseInstalledUtils) +#define Lit2ChangeLogCmd lit2changelog +#else +#define Lit2ChangeLogCmd $(LITSRC)/lit2changelog +#endif +#endif + +/* NB: this *NeededHere rule offers LIMITED guarantee that + the literate-programming stuff is up-to-date when used +*/ +#ifndef LitStuffNeededHere +#if defined(UseInstalledUtils) +#define LitStuffNeededHere(target) /**/ +#else +#define LitStuffNeededHere(target) \ + @@\ +target:: $(LITSRC)/lit2pgm $(LITSRC)/lit2texi $(LITSRC)/lit2latex $(LITSRC)/mkdependlit $(LITSRC)/lit2changelog $(LITSRC)/lit-deatify @@\ + @@\ +$(LITSRC)/lit2pgm $(LITSRC)/lit2texi $(LITSRC)/lit2latex $(LITSRC)/mkdependlit $(LITSRC)/lit2changelog $(LITSRC)/lit-deatify: @@\ + @(cd $(LITSRC); if [ -f lit2pgm ]; then \ @@\ + echo "checking $@ in $(LITSRC) first..."; $(MAKE) all; else \ @@\ + echo "bootstrapping $@ with ./lit2pgm.BOOT in $(LITSRC) first..."; \ @@\ + $(MAKE) LIT2PGM="./lit2pgm.BOOT -Alit2pgm" lit-deatify all; fi; \ @@\ + echo "okay, continuing in $(CURRENT_DIR)") +#endif /* ! UseInstalledUtils */ +#endif /* LitStuffNeededHere */ + +LIT2PGM = Lit2PgmCmd +/* sometimes, we _must_ use the installed version of lit2pgm, + * e.g., for building lit2pgm itself + */ +LIT2TEXI = Lit2TexiCmd +LIT2LATEX = Lit2LaTeXCmd +MKDEPENDLIT = MkDependLitCmd +LIT2CHANGELOG = Lit2ChangeLogCmd +#ifndef UseInstalledUtils +LITSRC = $(TOP)/literate +#endif + +/*# mkdepend scripts for various languages */ +/*# ["mkdependlit" is under literate programming stuff above] */ + +/* for these MkDepend things, we use the scripts only [for now] */ + +#ifndef MkDependCSrc +#define MkDependCSrc $(SCRIPTSRC) +#endif +#ifndef MkDependCCmd +#if defined(UseInstalledUtils) +#define MkDependCCmd mkdependC +#else +#define MkDependCCmd $(MKDEPENDCSRC)/mkdependC +#endif /* ! installed */ +#endif /* MkDependCCmd */ + +/* + MkdependCNeededHere -- generate rules to build the mkdependC program + if its source is within this project's source tree. + + [kind of a weird one, for now at least] +*/ +#ifndef MkDependCNeededHere +#if defined(UseInstalledUtils) +#define MkDependCNeededHere(target) /**/ +#else +#define MkDependCNeededHere(target) \ +__SomeUtilNeededHere(target,$(MKDEPENDC),$(MKDEPENDCSRC),mkdependC) +#endif /* UseInstalledUtils */ +#endif /* MkDependCNeededHere */ +MKDEPENDC = MkDependCCmd +#ifndef UseInstalledUtils +MKDEPENDCSRC = MkDependCSrc +#endif + +#ifndef MkDependHSCmd /* this is the default; hope you have it! */ +#define MkDependHSCmd mkdependHS +#endif +#ifndef MkDependHSNeededHere /* ditto */ +#define MkDependHSNeededHere(targets) /*no such thing*/ +#endif +MKDEPENDHS = MkDependHSCmd + +/* mkdependlit is with the literate stuff above */ + +/* tags utilities */ + +#ifndef PerlTagsSrc +#define PerlTagsSrc $(SCRIPTSRC) +#endif +#if defined(UseInstalledUtils) +#define PerlTagsCmd perltags +#else +#define PerlTagsCmd $(PERLTAGSSRC)/perltags +#endif + +#ifndef PerlTagsNeededHere +#if defined(UseInstalledUtils) +#define PerlTagsNeededHere(target) /**/ +#else +#define PerlTagsNeededHere(target) \ +__SomeUtilNeededHere(target,$(PERLTAGS),$(PERLTAGSSRC),perltags) +#endif /* UseInstalledUtils */ +#endif /* PerlTagsNeededHere */ +PERLTAGS = PerlTagsCmd +#ifndef UseInstalledUtils +PERLTAGSSRC = PerlTagsSrc +#endif + +/*# misc utilities */ + +#ifndef FastmakeCmd +#if defined(UseInstalledUtils) +#define FastmakeCmd fastmake +#else +#define FastmakeCmd $(FASTMAKESRC)/fastmake +#endif +#endif +#ifndef FastmakeNeededHere +#if defined(UseInstalledUtils) +#define FastmakeNeededHere(target) /**/ +#else +#define FastmakeNeededHere(target) \ +__SomeUtilNeededHere(target,$(FASTMAKE),$(FASTMAKESRC),fastmake) +#endif /* ! UseInstalledUtils */ +#endif /* FastmakeNeededHere */ +FASTMAKE = FastmakeCmd +#ifndef UseInstalledUtils +FASTMAKESRC = $(SCRIPTSRC) +#endif + +#ifndef LtxCmd +#if defined(UseInstalledUtils) +#define LtxCmd ltx +#else +#define LtxCmd $(LTXSRC)/ltx +#endif +#endif +#ifndef LtxNeededHere +#if defined(UseInstalledUtils) +#define LtxNeededHere(target) /**/ +#else +#define LtxNeededHere(target) \ +__SomeUtilNeededHere(target,$(LTX),$(LTXSRC),ltx) +#endif /* ! UseInstalledUtils */ +#endif /* LtxNeededHere */ +LTX = LtxCmd /* a LaTeX-wrapper script */ +#ifndef UseInstalledUtils +LTXSRC = $(SCRIPTSRC) +#endif + +#ifndef MkdirHierCmd +#if defined(UseInstalledUtils) +#define MkdirHierCmd mkdirhier +#else +#define MkdirHierCmd $(MKDIRHIERSRC)/mkdirhier +#endif +#endif +#ifndef MkdirHierNeededHere +#if defined(UseInstalledUtils) +#define MkdirHierNeededHere(target) /**/ +#else +#define MkdirHierNeededHere(target) \ +__SomeUtilNeededHere(target,$(MKDIRHIER),$(MKDIRHIERSRC),mkdirhier) +#endif /* ! UseInstalledUtils */ +#endif /* MkdirHierNeededHere */ +MKDIRHIER = MkdirHierCmd +#ifndef UseInstalledUtils +MKDIRHIERSRC = $(SCRIPTSRC) +#endif + +/* Simon Marlow says: Lndir is sometimes dubious; if you + have GNU cp, define "LndirCmd" to: cp -Rsv +*/ +#ifndef LndirCmd +#if defined(UseInstalledUtils) +#define LndirCmd lndir +#else +#define LndirCmd $(LNDIRSRC)/lndir +#endif +#endif +#ifndef LndirNeededHere +#if defined(UseInstalledUtils) +#define LndirNeededHere(target) /**/ +#else +#define LndirNeededHere(target) \ +__SomeUtilNeededHere(target,$(LNDIR),$(LNDIRSRC),lndir) +#endif /* ! UseInstalledUtils */ +#endif /* LndirNeededHere */ +LNDIR = LndirCmd +#ifndef UseInstalledUtils +LNDIRSRC = $(SCRIPTSRC) +#endif + +#ifndef MsubCmd +#if defined(UseInstalledUtils) +#define MsubCmd msub +#else +#define MsubCmd $(MSUBSRC)/msub +#endif /* ! installed */ +#endif /* MsubCmd */ +/* MsubNeededHere - generate rules to build the msub program + if its source is within this project's source tree. This rule + should be included manually once in each Jmakefile that generates + targets with msub. (Ideally it would be invoked automatically from + within each msub-target-generating rule, but then you have a million + sets of these rules in the Makefile. Ugh. This could be avoided if + there were some way for a rule to void itself after being invoked + once.) +*/ +#ifndef MsubNeededHere +#if defined(UseInstalledUtils) +#define MsubNeededHere(target) /**/ +#else +#define MsubNeededHere(target) \ +__SomeUtilNeededHere(target,$(MSUB),$(MSUBSRC),msub) +#endif /* ! UseInstalledUtils */ +#endif /* MsubNeededHere */ +MSUB = MsubCmd +#ifndef UseInstalledUtils +MSUBSRC = $(UTILSRC)/msub +#endif + +#ifndef EtagsCmd +#if defined(UseInstalledUtils) +#define EtagsCmd etags +#else +#define EtagsCmd $(ETAGSSRC)/etags +#endif /* ! installed */ +#endif /* EtagsCmd */ +#ifndef EtagsNeededHere +#if defined(UseInstalledUtils) +#define EtagsNeededHere(target) /**/ +#else +#define EtagsNeededHere(target) \ +__SomeUtilNeededHere(target,$(ETAGS),$(ETAGSSRC),etags) +#endif /* ! UseInstalledUtils */ +#endif /* EtagsNeededHere */ +ETAGS = EtagsCmd +#ifndef UseInstalledUtils +ETAGSSRC = $(UTILSRC)/etags +#endif + +#ifndef VerbatimCmd +#if defined(UseInstalledUtils) +#define VerbatimCmd verbatim +#else +#define VerbatimCmd $(VERBATIMSRC)/verbatim +#endif /* ! installed */ +#endif /* VerbatimCmd */ +#ifndef VerbatimNeededHere +#if defined(UseInstalledUtils) +#define VerbatimNeededHere(target) /**/ +#else +#define VerbatimNeededHere(target) \ +__SomeUtilNeededHere(target,$(VERBATIM),$(VERBATIMSRC),verbatim) +#endif /* ! UseInstalledUtils */ +#endif /* VerbatimNeededHere */ +VERBATIM = VerbatimCmd +#ifndef UseInstalledUtils +VERBATIMSRC = $(UTILSRC)/verbatim +#endif + +#ifndef RunStdTestCmd +#if defined(UseInstalledUtils) +#define RunStdTestCmd runstdtest +#else +#define RunStdTestCmd $(RUNSTDTESTSRC)/runstdtest +#endif +#endif +#ifndef RunStdTestNeededHere +#if defined(UseInstalledUtils) +#define RunStdTestNeededHere(target) /**/ +#else +#define RunStdTestNeededHere(target) \ +__SomeUtilNeededHere(target,$(RUNSTDTEST),$(RUNSTDTESTSRC),runstdtest) +#endif /* ! UseInstalledUtils */ +#endif /* RunStdTestNeededHere */ +RUNSTDTEST = RunStdTestCmd +#ifndef UseInstalledUtils +RUNSTDTESTSRC = $(SCRIPTSRC) +#endif +\end{code} + +%************************************************************************ +%* * +\subsection[mkworld-utils-flags]{Feeding flags to them} +%* * +%************************************************************************ + +\begin{code} +/* for the whole nasty business of flags for programs, + some naming conventions are worth remembering; for program <foo>: + + <foo>FLAGS what is actually passed to <foo>; usually + built from pieces below + + ALLPROJ_<foo>_<things> <things> needed for _all_ runs of <foo>; + probably set in one of the AllProject* + config files. + PLAT_<foo>_<things> <things> (options, defines, etc.) needed for + all runs of <foo> *on this platform*; + probably set in <platform>.cf. + PROJ_<foo>_<things> <things> needed for all runs of <foo> + related to this project; probably set in + one of the Project-* config files. + <foo>_<things> <things> needed for runs of <foo> in this + directory; set in its Jmakefile. + EXTRA_<foo>_<things> name reserved for adding <things> from the + command line. + GLUED_<foo>_<things> all the above, glued together; not for + human use. + + <foo>_OPTS the usual name for options + <foo>_DEFINES CPP #defines + <foo>_INCLUDES CPP #includes + <foo>_IMPORTS Haskell "import"s + + As a contrived example, the "makeinfo" program is usually called + with the $(MAKEINFOFLAGS), which would likely be put together as... + + ALLPROJ_MAKEINFO_OPTS = + PLAT_MAKEINFO_OPTS = + PROJ_MAKEINFO_OPTS = + MAKEINFO_OPTS = + EXTRA_MAKEINFO_OPTS = + GLUED_MAKEINFO_OPTS = + MAKEINFOFLAGS = $(GLUED_MAKEINFO_OPTS) + + and used as... + + $(MAKEINFO) $(MAKEINFOFLAGS) ... + + The related CPP names are as you would expect: e.g., + ProjectMakeinfoOpts for PROJ_MAKEINFO_OPTS, ... + + For systems of interacting programs (e.g., cpp, cc, lint, as, and ld), + things can be [considerably] messier. + +*/ + +/* CPP definitions for CPP #includes; -I must be explicit */ + +/* I have not separated use of CPP w/ CC vs standalone... */ + +#ifndef AllProjectsCppIncludes +#define AllProjectsCppIncludes /*none*/ +#endif +#ifndef PlatformCppIncludes +#define PlatformCppIncludes /*none*/ +#endif +#ifndef ProjectCppIncludes +#define ProjectCppIncludes /*none*/ +#endif +#ifndef SetupCppIncludes +#define SetupCppIncludes /*none*/ +#endif +GenerateOptionsMakeVars(CPP,INCLUDES,AllProjectsCppIncludes,PlatformCppIncludes,ProjectCppIncludes,SetupCppIncludes) + +/* CPP definitions for #defines */ + +#ifndef AllProjectsCppDefines +#define AllProjectsCppDefines /*none*/ +#endif +#ifndef PlatformCppDefines +#define PlatformCppDefines /**/ +#endif /* PlatformCppDefines */ +#ifndef ProjectCppDefines +#define ProjectCppDefines /*none*/ +#endif +#ifndef SetupCppDefines +#define SetupCppDefines /*none*/ +#endif +GenerateOptionsMakeVars(CPP,DEFINES,AllProjectsCppDefines,PlatformCppDefines,ProjectCppDefines,SetupCppDefines) + +/*# C-compiler (and cpp ... and lint) options */ + +#ifndef AllProjectsCcOpts +#define AllProjectsCcOpts /*none*/ +#endif +#ifndef PlatformCcOpts +#define PlatformCcOpts /*none*/ +#endif +#ifndef ProjectCcOpts +#define ProjectCcOpts /*none*/ +#endif +#ifndef SetupCcOpts +#define SetupCcOpts /*none*/ +#endif +GenerateOptionsMakeVars(CC,OPTS,AllProjectsCcOpts,PlatformCcOpts,ProjectCcOpts,SetupCcOpts) + +CFLAGS = $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) $(GLUED_CC_OPTS) + +/*# Haskell compiler (and cpp ... and lint) options */ + +#ifndef AllProjectsHcOpts +#define AllProjectsHcOpts /*none*/ +#endif +#ifndef PlatformHcOpts +#define PlatformHcOpts /*none*/ +#endif +#ifndef ProjectHcOpts +#define ProjectHcOpts /*none*/ +#endif +#ifndef SetupHcOpts +#define SetupHcOpts /*none*/ +#endif +GenerateOptionsMakeVars(HC,OPTS,AllProjectsHcOpts,PlatformHcOpts,ProjectHcOpts,SetupHcOpts) + +#ifndef AllProjectsHcImports +#define AllProjectsHcImports /*none*/ +#endif +#ifndef PlatformHcImports +#define PlatformHcImports /*none*/ +#endif +#ifndef ProjectHcImports +#define ProjectHcImports /*none*/ +#endif +#ifndef SetupHcImports +#define SetupHcImports /*none*/ +#endif +GenerateOptionsMakeVars(HC,IMPORTS,AllProjectsHcImports,PlatformHcImports,ProjectHcImports,SetupHcImports) +HCFLAGS = $(GLUED_HC_IMPORTS) $(GLUED_CPP_DEFINES) $(GLUED_HC_OPTS) + +/*# linker options */ + +#ifndef AllProjectsLdOpts +#define AllProjectsLdOpts /*none*//* -X -r "combine" flags (?) */ +#endif +#ifndef PlatformLdOpts +#define PlatformLdOpts /*none*/ +#endif +#ifndef ProjectLdOpts +#define ProjectLdOpts /*none*/ +#endif +#ifndef SetupLdOpts +#define SetupLdOpts /*none*/ +#endif +#ifndef AllProjectsLdLibraries +#define AllProjectsLdLibraries /*none*/ +#endif +#ifndef PlatformLdLibraries +#define PlatformLdLibraries /*none*/ +#endif +#ifndef ProjectLdLibraries +#define ProjectLdLibraries /*none*/ +#endif +#ifndef SetupLdLibraries +#define SetupLdLibraries /*none*/ +#endif +GenerateOptionsMakeVars(LD,OPTS,AllProjectsLdOpts,PlatformLdOpts,ProjectLdOpts,SetupLdOpts) +GenerateOptionsMakeVars(LD,LIBRARIES,AllProjectsLdLibraries,PlatformLdLibraries,ProjectLdLibraries,SetupLdLibraries) +LDOPTIONS = $(GLUED_LD_OPTS) /* ToDo: and the libraries ? */ + +/* lint stuff not tidied up yet */ + +#ifndef LintLibFlag +#define LintLibFlag -C +#endif +#ifndef LintOpts +#define LintOpts -axz +#endif +LINTLIBFLAG = LintLibFlag +LINTOPTS = LintOpts +LINTFLAGS = $(LINTOPTS) -DLINT $(GLUED_CPP_INCLUDES) $(GLUED_CPP_DEFINES) + +/*# literate-stuff options */ + +/* some options are common (general) to all lit2* pgms; others specific */ + +#ifndef AllProjectsGenLitOpts +#define AllProjectsGenLitOpts /*none*/ +#endif +#ifndef PlatformGenLitOpts +#define PlatformGenLitOpts /*none*/ +#endif +#ifndef ProjectGenLitOpts +#define ProjectGenLitOpts /*none*/ +#endif +#ifndef SetupGenLitOpts +#define SetupGenLitOpts /*none*/ +#endif +GenerateOptionsMakeVars(GENLIT,OPTS,AllProjectsGenLitOpts,PlatformGenLitOpts,ProjectGenLitOpts,SetupGenLitOpts) + +#ifndef AllProjectsLit2pgmOpts +#define AllProjectsLit2pgmOpts /*none*/ +#endif +#ifndef PlatformLit2pgmOpts +#define PlatformLit2pgmOpts /*none*/ +#endif +#ifndef ProjectLit2pgmOpts +#define ProjectLit2pgmOpts /*none*/ +#endif +#ifndef SetupLit2pgmOpts +#define SetupLit2pgmOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2PGM,OPTS,AllProjectsLit2pgmOpts,PlatformLit2pgmOpts,ProjectLit2pgmOpts,SetupLit2pgmOpts) +#ifndef AllProjectsLit2texiOpts +#define AllProjectsLit2texiOpts /*none*/ +#endif +#ifndef PlatformLit2texiOpts +#define PlatformLit2texiOpts /*none*/ +#endif +#ifndef ProjectLit2texiOpts +#define ProjectLit2texiOpts /*none*/ +#endif +#ifndef SetupLit2texiOpts +#define SetupLit2texiOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2TEXI,OPTS,AllProjectsLit2texiOpts,PlatformLit2texiOpts,ProjectLit2texiOpts,SetupLit2texiOpts) +#ifndef AllProjectsLit2latexOpts +#define AllProjectsLit2latexOpts /*none*/ +#endif +#ifndef PlatformLit2latexOpts +#define PlatformLit2latexOpts /*none*/ +#endif +#ifndef ProjectLit2latexOpts +#define ProjectLit2latexOpts /*none*/ +#endif +#ifndef SetupLit2latexOpts +#define SetupLit2latexOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2LATEX,OPTS,AllProjectsLit2latexOpts,PlatformLit2latexOpts,ProjectLit2latexOpts,SetupLit2latexOpts) +#ifndef AllProjectsLit2changelogOpts +#define AllProjectsLit2changelogOpts /*none*/ +#endif +#ifndef PlatformLit2changelogOpts +#define PlatformLit2changelogOpts /*none*/ +#endif +#ifndef ProjectLit2changelogOpts +#define ProjectLit2changelogOpts /*none*/ +#endif +#ifndef SetupLit2changelogOpts +#define SetupLit2changelogOpts /*none*/ +#endif +GenerateOptionsMakeVars(LIT2CHANGELOG,OPTS,AllProjectsLit2changelogOpts,PlatformLit2changelogOpts,ProjectLit2changelogOpts,SetupLit2changelogOpts) +#ifndef AllProjectsMkDependLitOpts +#define AllProjectsMkDependLitOpts /*none*/ +#endif +#ifndef PlatformMkDependLitOpts +#define PlatformMkDependLitOpts /*none*/ +#endif +#ifndef ProjectMkDependLitOpts +#define ProjectMkDependLitOpts /*none*/ +#endif +#ifndef SetupMkDependLitOpts +#define SetupMkDependLitOpts /*none*/ +#endif +GenerateOptionsMakeVars(MKDEPENDLIT,OPTS,AllProjectsMkDependLitOpts,PlatformMkDependLitOpts,ProjectMkDependLitOpts,SetupMkDependLitOpts) + +LIT2PGMFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2PGM_OPTS) +LIT2TEXIFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2TEXI_OPTS) +LIT2LATEXFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2LATEX_OPTS) +LIT2CHANGELOGFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_LIT2CHANGELOG_OPTS) +MKDEPENDLITFLAGS = $(GLUED_GENLIT_OPTS) $(GLUED_MKDEPENDLIT_OPTS) + +/* same for other MkDepend things */ + +#ifndef AllProjectsMkDependCOpts +#define AllProjectsMkDependCOpts /*none*/ +#endif +#ifndef PlatformMkDependCOpts +#define PlatformMkDependCOpts /*none*/ +#endif +#ifndef ProjectMkDependCOpts +#define ProjectMkDependCOpts /*none*/ +#endif +#ifndef SetupMkDependCOpts +#define SetupMkDependCOpts /*none*/ +#endif +GenerateOptionsMakeVars(MKDEPENDC,OPTS,AllProjectsMkDependCOpts,PlatformMkDependCOpts,ProjectMkDependCOpts,SetupMkDependCOpts) +MKDEPENDCFLAGS = $(GLUED_MKDEPENDC_OPTS) + +#ifndef AllProjectsMkDependHSOpts +#define AllProjectsMkDependHSOpts /*none*/ +#endif +#ifndef PlatformMkDependHSOpts +#define PlatformMkDependHSOpts /*none*/ +#endif +#ifndef ProjectMkDependHSOpts +#define ProjectMkDependHSOpts /*none*/ +#endif +#ifndef SetupMkDependHSOpts +#define SetupMkDependHSOpts /*none*/ +#endif +GenerateOptionsMakeVars(MKDEPENDHS,OPTS,AllProjectsMkDependHSOpts,PlatformMkDependHSOpts,ProjectMkDependHSOpts,SetupMkDependHSOpts) +MKDEPENDHSFLAGS = $(GLUED_MKDEPENDHS_OPTS) + +/* same for tags stuff */ + +#ifndef AllProjectsCTagsOpts +#define AllProjectsCTagsOpts -e -w /* emacs-style; no warnings */ +#endif +#ifndef PlatformCTagsOpts +#define PlatformCTagsOpts /*none*/ +#endif +#ifndef ProjectCTagsOpts +#define ProjectCTagsOpts /*none*/ +#endif +#ifndef SetupCTagsOpts +#define SetupCTagsOpts /*none*/ +#endif +GenerateOptionsMakeVars(CTAGS,OPTS,AllProjectsCTagsOpts,PlatformCTagsOpts,ProjectCTagsOpts,SetupCTagsOpts) +CTAGSFLAGS = $(GLUED_CTAGS_OPTS) + +#ifndef AllProjectsPerlTagsOpts +#define AllProjectsPerlTagsOpts /*none*/ +#endif +#ifndef PlatformPerlTagsOpts +#define PlatformPerlTagsOpts /*none*/ +#endif +#ifndef ProjectPerlTagsOpts +#define ProjectPerlTagsOpts /*none*/ +#endif +#ifndef SetupPerlTagsOpts +#define SetupPerlTagsOpts /*none*/ +#endif +GenerateOptionsMakeVars(PERLTAGS,OPTS,AllProjectsPerlTagsOpts,PlatformPerlTagsOpts,ProjectPerlTagsOpts,SetupPerlTagsOpts) +PERLTAGSFLAGS = $(GLUED_PERLTAGS_OPTS) + +/* and for "runstdtest" */ + +#ifndef AllProjectsRunStdTestOpts +#define AllProjectsRunStdTestOpts /*none*/ +#endif +#ifndef PlatformRunStdTestOpts +#define PlatformRunStdTestOpts /*none*/ +#endif +#ifndef ProjectRunStdTestOpts +#define ProjectRunStdTestOpts /*none*/ +#endif +#ifndef SetupRunStdTestOpts +#define SetupRunStdTestOpts /*none*/ +#endif +GenerateOptionsMakeVars(RUNSTDTEST,OPTS,AllProjectsRunStdTestOpts,PlatformRunStdTestOpts,ProjectRunStdTestOpts,SetupRunStdTestOpts) +RUNSTDTEST_FLAGS = $(GLUED_RUNSTDTEST_OPTS) + +/* CPP definitions for #defines */ + +#ifndef AllProjectsJmakeDefines +#define AllProjectsJmakeDefines /*none*/ +#endif +#ifndef PlatformJmakeDefines +#define PlatformJmakeDefines /**/ +#endif /* PlatformJmakeDefines */ +#ifndef ProjectJmakeDefines +#define ProjectJmakeDefines /*none*/ +#endif +#ifndef SetupJmakeDefines +#define SetupJmakeDefines /*none*/ +#endif +GenerateOptionsMakeVars(JMAKE,DEFINES,AllProjectsJmakeDefines,PlatformJmakeDefines,ProjectJmakeDefines,SetupJmakeDefines) +JMAKEFLAGS = $(GLUED_JMAKE_DEFINES) +\end{code} |